Hi everyone,
I’m creating an audio player using C++ and SDL in Visual Studio.
I’ve been following an example provided by armornick to cover the basics of loading a WAV file and creating a callback function:
So I can play an audio file fine, but what I’m interested in now is being able to draw a waveform of that audio file. I’m very new to SDL, and most of my audio programming has been with Pure Data so thre’s been a lot to learn.
My thought process is if I can collect the amplitude of each sample into an array and use graphics to render it. It would also be useful in creating some DSP functions if I could have direct access to each sample.
The confusion I’m having now is that the audio is supposedly 16-bit, yet only 8-bit values are being passed from the buffer to the stream. Does the callback concatenate the two bytes to make it a single 16-bit value before passing it to the sound card? To collect an accurate reading of the sample’s amplitude in bytes, would I need to do this process within the callback function and then send it to an array?
For another example, say I wanted to have the audio play at half the amplitude. My thinking is I would concatenate each byte in the callback with it’s subsequent byte to make it a single unsigned 16-bit, convert it to a signed 16-bit, divide that value, and split it back into two separate bytes before passing it through to the sound card. My assumption is that every sample’s amplitude is stored in two bytes which are then combined.
Or perhaps I’ve missed something entirely, or all my facts are muddled up. Any clarity on the subject would be greatly appreciated!
In particular It’d be helpful to know:
-How SDL creates a 16-bit value for each sample amplitude from the 8-bit values provided to the callback function
-What would be the best way of changing the amplitude of each sample
As well as anything else that may be helpful to know.
//some rough code for dividing the amplitude by 2:
Uint16 combinedSample;
long currentSample;
for (int s = 0; s <= streamLength; s += 2)
{
//concatenate every other byte with the subsequent one to produce a 16-bit binary
combinedSample = audio_pos[s+1] | (audio_pos[s] << 8);
//essentially convert it to unsigned, making the range from -32768 to 32767
currentSample = combinedSample - 32768;
//divide while it is still signed so the waveform retains its shape
currentSample /= 2;
//convert back to an unsigned 16 bit
currentSample += 32768;
currentSample = Uint16(currentSample);
combinedSample = currentSample;
//split back into two separate bytes and assign the samples their new value /2
audio_pos[s] = *((uint8_t*)&(combinedSample)+1);
audio_pos[s + 1] = *((uint8_t*)&(combinedSample)+0);
}
I’ve put this in the callback function, trying to change the amplitude of a short snippet of speech. The speech is still discernible, indicating not everything is ruined, but it becomes excessively distorted so I’m doing something wrong. The first part of this function seems suitable for simply gaining the amplitude of the sample.
I’ve also tried using this function in the main, applying it to the entire file, before the callback is ever even called but the result is the same.
Thanks in advance for any help.