schellingb / ZillaLib

Sleek multiplatform C++ 2D and 3D game creation!
https://zillalib.github.io/
zlib License
109 stars 8 forks source link

ZL_SoundLoadFromBuffer loaded sample has noise at the end #9

Closed laxa88 closed 4 years ago

laxa88 commented 4 years ago

https://github.com/schellingb/ZillaLib/blob/dd90e8356a4ccb370e151d4bfae4623b8fe46ae7/Source/ZL_Audio.cpp#L359

I'm trying to load my own audio samples using Blargg's GME:

short buf[buf_size * 2]; // two channels
gme_play(emu, buf_size * 2, buf); // generate audio samples into buf
snd = ZL_SoundLoadFromBuffer(buf, buf_size * (sizeof(short) ), 0);
snd.Play(false);

It seems that there is a bit at the end where the audio produces noise; I'm not sure whether the noise comes from the buf itself or whether it's a bug in the logic. I did a quick test for comparison, this noise issue doesn't happen for OGG-loaded files. I'm still investigating -- Currently, my solution to remove the noise is as follows:

if (pos + (read << 2) >= snd->totalsamples)

But it feels somewhat hacky, and I'm not sure if this solves the underlying problem. 🤔 In the meantime, I'm just wondering if you have any idea on why this is happening?

laxa88 commented 4 years ago

Ah okay, it was a bug in my code after all.

short buf[buf_size * 2]; // produces noise at the end
short* buf = new short[buf_size * 2]; // no noise
short* buf = (short*)malloc(buf_size * 2 * sizeof(short)); // no noise

I assumed short buf[] would be the same as short* buf = new short[] but I guess there's some difference. 🤔

tobybear commented 4 years ago

The difference is that the first construct allocates the memory for the array on the stack, while the second and third option allocate it on the heap. Functionally they are the same. However, arrays are initialized with random values (what is at that point in memory respectively), so chances are you will get your noise also with the "new short[]" method at some point. You should always initialize/clear your buffer before using it so you don't get that noise! This can be done with an explicit constructor or memset or even a simple for loop.

laxa88 commented 4 years ago

@tobybear Thank you for the explanation, that really helped give me more context. 😄

I tried:

short buf[buf_size * 2] = { 0 }; // produces noise
short buf[buf_size * 2]; for (int p = 0; p < buf_size * 2; p++) buf[p] = 0; // produces noise
short buf[buf_size * 2]; memset(buf, 0, buf_size * 2); // produces noise

So I was quite puzzled why the noise was still occuring, then your hint about "stack vs heap" and "arrays are initialized with random values" gave me a clue; My mistake was declaring buf as a local variable, so in the case of for stack ( short buf[] ), the memory gets deallocated (and reset to random vales, hence the noise) when it goes out of scope 🤔

In the case of heap ( short* buf ), memory is explicitly allocated and deallocated by the programmer hence there won't be any noise even after buf goes out of scope. 🎉