I am trying to adjust the volume of each individual channel in a sine wave for stereo output.
I am simply outputting this using WASAPI, with a 32 bit IEEE-float stereo format.
I have a sine wave in 32 bit IEEE-Float format, and I try to set the left and right channel volumes by multiplying by a value between 0f and 1f.
There are 4 bytes per float, so I am dividing the total count of bytes in the buffer by 4.
Alternating between floats should be left and right channels, or am I mistaken?
For example:
|-------------Frame-------------|
(Left Channel) (Right Channel)
[0] [0] [0] [0] | [0] [0] [0] [0]
|----Sample----| |----Sample----|
Each sample should be a float value, right?
I used DBOUT to print the values of two samples for testing to make sure it all made sense. nChannels is 2, and nSamplesPerSec is 48000.
static inline float sin01(float alpha) {
return 0.5 * sin(alpha) + 0.5;
}
static inline float sin_minmax_Hz(float min, float max, float freq_Hz, float t) {
return (max - min) / 2.0 * sin01(t * freq_Hz * TWO_PI);
}
Invoke() {
BYTE* pData;
hr = audioclient->GetCurrentPadding(&pad);
int bytes_per_frame = wave_format.nChannels * 32 / 8;
actual_size = (buffer_framecount - pad);
count = actual_size * bytes_per_frame;
hr = renderclient->GetBuffer(actual_size, &pData);
float dt = 1.0 / (float)wave_format.nSamplesPerSec;
float freq = (float)wave_format.nSamplesPerSec / ((float)count / 4);
float* float_buffer = new float[count / 4];
for (int i = 0; i < count / 4; i++) {
static_assert(sizeof(float) == 4, "float size is expected to be 4 bytes");
float t = (float)i * dt;
float_buffer[i++] = sin_minmax_Hz(-1, 1, freq, t) * 0.5f; // should be half volume L channel
float_buffer[i] = sin_minmax_Hz(-1, 1, freq, t) * 0.25f; // should be quarter volume R channel
}
if (SUCCEEDED(hr)) {
std::memcpy(pData, float_buffer, count);
//DBOUT(float_buffer[20] << " < float : byte > " << pData[80] << " " << pData[81] << " " << pData[82] << " " << pData[83] << "\n");
//DBOUT(float_buffer[21] << " < float : byte > " << pData[84] << " " << pData[85] << " " << pData[86] << " " << pData[87] << "\n");
hr = renderclient->ReleaseBuffer(actual_size, 0);
EXIT_ON_ERROR(hr);
}
}
No matter what I try, the left and right channel output are the same.
The volume will be adjusted if I decrease both multipliers, but I can't get the left and right channel volumes to be any different.
Does anyone know where I am going wrong?
The DBOUT results were this for a random frame, which makes sense to me:
alternating between *0.5 and *0.25
0.282632 < float : byte > 21 181 144 62
0.141316 < float : byte > 21 181 16 62
Converted to hex for comparison:
hex: 15 B5 90 3E // 0x3E90B515 = 0.282632
hex: 15 B5 10 3E // 0x3E10B515 = 0.141316
I have also tried this way:
float freq = (float)wave_format.nSamplesPerSec / (float)actual_size;
float* float_buffer = new float[count / 4];
for (int i = 0; i < count / 8; ++i) {
float t = (float)i * dt;
float_buffer[2 * i] = sin_minmax_Hz(-1, 1, freq, t) * 0.5f;
float_buffer[2 * i + 1] = sin_minmax_Hz(-1, 1, freq, t) * 0.25f;
}
This is how I am getting the format:
hr = pAudioClient->GetCurrentSharedModeEnginePeriod((WAVEFORMATEX**)&wavefmt, ¤t_period);
Which is the equivalent of this (I double checked to verify):
WAVEFORMATEX wave_format = {};
wave_format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wave_format.nChannels = 2;
wave_format.nSamplesPerSec = 48000;
wave_format.nAvgBytesPerSec = 384000;
wave_format.nBlockAlign = 8;
wave_format.wBitsPerSample = 32;
Edit:
I just changed the frequency for the right channel only and it indeed played a different frequency on the right. If I then turn down the volume for the right, I can still hear the same frequency as the left channel, with a faint sound of the new frequency. So it appears that the right channel data is being mixed with the left channel somehow.
Well, I found the answer. Turns out this was not a programming issue, just a device settings issue.
I simply needed to disable audio enhancements on the device settings. There is still a MINOR amount of bleed, which is totally acceptable.
It's great that I spent three days trying to figure this out.. lol