Playing raw float32 stereo samples with raylib

3 days ago 4
ARTICLE AD BOX

I am trying to play raw audio samples with raylib. All examples I can find are with a mono output, and playing a mono signal works fine. However, when I try to play signal, it gets distorted.

Currently, I am using minimp3 to load an mp3 file and decode the mp3 data into channel left and right. This works fine; when I play the data from either left or right, I get a clean audio output without distortions.

However, when I try to combine both channels and use a stereo output, the result is a very distorted version of the input. This is my code.

package main import ( "encoding/binary" "math" "os" rl "github.com/gen2brain/raylib-go/raylib" "github.com/tosone/minimp3" ) func main() { rl.InitWindow(800, 450, "Audiotest") defer rl.CloseWindow() rl.SetTargetFPS(60) // Load Music file, err := os.ReadFile("some_music.mp3") if err != nil {panic(err)} // Decode music file into raw data dec, audio_data, err := minimp3.DecodeFull(file) audio_f32_left := make([]float32, 0) audio_f32_right := make([]float32, 0) for i := 0; i<len(audio_data) - 10; i+=4 { tmp := make([]byte, 4) tmp[0] = audio_data[i] tmp[1] = audio_data[i+1] tmp_r := make([]byte, 4) tmp_r[0] = audio_data[i+2] tmp_r[1] = audio_data[i+3] bits := binary.LittleEndian.Uint32(tmp) f := math.Float32frombits(bits) audio_f32_left = append(audio_f32_left, f) bits_r := binary.LittleEndian.Uint32(tmp_r) f_r := math.Float32frombits(bits_r) audio_f32_right = append(audio_f32_right, f_r) } counter := 0 if err != nil {panic(err)} // Init Audio rl.InitAudioDevice() rl.SetAudioStreamBufferSizeDefault(4096) stream := rl.LoadAudioStream(uint32(dec.SampleRate), 16, 2) rl.SetAudioStreamCallback(stream, func(data []float32, frames int) { if dec.Channels == 1 { // this works for i := 0; i<frames; i += 1 { data[i] = audio_f32_left[i + counter] counter += 1 } } if dec.Channels == 2 { // This is distorted for i := 0; i<frames; i += 1 { f1 := audio_f32_right[i+counter] f2 := audio_f32_left[i+counter] bits1 := math.Float32bits(f1) bits2 := math.Float32bits(f2) bytes1 := make([]byte, 4) bytes2 := make([]byte, 4) binary.LittleEndian.PutUint32(bytes1, bits1) binary.LittleEndian.PutUint32(bytes2, bits2) bytes1[2] = bytes2[0] bytes1[3] = bytes2[1] bits_combined := binary.LittleEndian.Uint32(bytes1) data[i] = math.Float32frombits(bits_combined) counter += 1 } } }) rl.PlayAudioStream(stream) for !rl.WindowShouldClose() { rl.BeginDrawing() rl.ClearBackground(rl.Black) rl.EndDrawing() } rl.UnloadAudioStream(stream) rl.CloseAudioDevice() }

Note that when I change LoadAudioStream(uint32(dec.SampleRate), 16, 2) to LoadAudioStream(uint32(dec.SampleRate), 16, 1), only the left channel plays, but it sounds allright.

I believe that this has something to do with how the stereo channels need to be interleaved, but I could not find any documentation whatsoever on this. At first, I tried to cast just 4 bytes as float32 but that also results in distortion; this is why the more complicated "tangling" code exists (just experimentation).

Please note that I am aware that a simple music API for raylib exists, but when I get this working my intention is not just to play music from files.

Read Entire Article