1

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, &current_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.

  • The first thing I'd always do is check if my assumptions are correct. https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/ns-mmeapi-waveformatex / https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible - poke at the WASAPI and display the actual values produced. From what you describe I think you have the 2nd case (EXTENSIBLE). Sharing these values could be useful. – Yakk - Adam Nevraumont May 11 '23 at 15:38
  • 1
    @Yakk-AdamNevraumont I've added in the format for reference, thanks – MaxMarantix May 11 '23 at 16:01
  • I'd guess something somewhere is combining the channels. Have you tried just playing a stereo audio file through another application to verify your computer is configured correctly? Have you tried playing different sounds on the two channels (e.g. sine waves of different frequencies). Does the output frequency match your expectations? – Alan Birtles May 11 '23 at 16:06
  • 1
    @AlanBirtles 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. Investigating further.. Thanks – MaxMarantix May 11 '23 at 17:39
  • What do you get if you mute the signal in one channel completely? – Paul Sanders May 11 '23 at 22:03

1 Answers1

0

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

enter image description here