mackron / dr_libs

Audio decoding libraries for C/C++, each in a single source file.
Other
1.24k stars 205 forks source link

Streaming of Stereo ADPCM Wav not working properly #177

Closed Ghabry closed 3 years ago

Ghabry commented 3 years ago

Hello,

I'm the developer of a RPG Maker compatible game engine called https://github.com/EasyRPG

I wanted to replace our handrolled wav reader with dr_wav but I noticed a problem:

Our Audio API is stream based, we ask the audio library to read 8KB of data each time. With dr_wav this works flawless for PCM Mono and Stereo and ADPCM Mono but with Stereo ADPCM there are noticable gaps and the music plays slower than normal.

How I use your API: Guess this is correct because it works for 3 out of 4 files?

(length is our buffer size)

drwav_uint64 decoded = drwav_read_pcm_frames_s16(
  &handle,
  length / (handle.channels * sizeof(drwav_int16)),
  reinterpret_cast<drwav_int16*>(buffer));

I attached the problematic samples. Mono streams fine, Stereo streams with problems. Can you help me figuring this out?

Audio.zip

mackron commented 3 years ago

Sorry I didn't get to this sooner. I just played your sample file with this program and it's working fine: https://github.com/mackron/dr_libs/blob/dev/tests/wav/dr_wav_playback.c. It's just a simple program which uses miniaudio to play the file.

It looks like you're calling drwav_read_pcm_frames_s16() correctly. If a stereo sound source plays back slowly it sometimes means that the returned samples are treated as mono rather than stereo. To clarify, the return value of that function will be the number of PCM frames. To get the total number of samples, multiply it by the channel count. I would check that. Are you able to post the code just after the call to drwav_read_pcm_frames_s16()?

Ghabry commented 3 years ago

The entire code is here: https://github.com/Ghabry/easyrpg-player/blob/dr_wav/src/decoder_wav.cpp#L99

The problem is that this is part of our audio library so it is hard to follow the code flow.

Basicly "GetFormat" configures our resampler (we resample everything to 2 channel, 44100 and mix the channels together).

"Decode" fills a buffer. length is the buffer length in byte.

Because we also support non-filesystems such as ZIP there are custom read and seek functions configured for drwav. They could also have a bug.

mackron commented 3 years ago

I had a quick look at your code and on the surface is seems to be doing things correct. I'm suspecting something is not getting converted between bytes and samples properly, but I'm not sure where exactly. I think your callbacks are correct. Are you able to upload a sample of what it sounds like so I can get an idea on the nature of the glitching? Also, are your double sure that the stereo PCM sound is actually stereo and is actually working? It's seems very strange that one would work and the other wouldn't.

Lastly, I ran your samples files from earlier against my automated test program (https://github.com/mackron/dr_libs/blob/master/tests/wav/dr_wav_decoding.c) and it works fine. That program compares the results with libsndfile. Considering this, and that the playback program I linked to you earlier are working fine, I think it's unlikely to be an issue in dr_wav.

Ghabry commented 3 years ago

okay thanks for the quick feedback. I wanted to ensure first on whose side the error is. We also support libsndfile as a 2nd library and there it plays fine btw (But I prefer dr_wav because it can actually stream, libsndfile parses most audio files completely before playing making it unsuitable on systems with slow IO)

I suspect now our resampler.

Will provide you a broken, decoded sample later when I'm at my coding PC, thanks!

Ghabry commented 3 years ago

Sorry for not responding. I finally had time to look at it again.

To conclude this issue: It was my fault. Before I had other bufferting issues, so I added lots of debug output and enabled ASAN to investigate the issue.

In the end this was also the problem: The slow code caused buffer underflows because I did not fill the playback buffer quick enough.

After fixing this it works flawless.