I have been using WAVEFORMATEX
with WaveOut to play audio in Windows, in stereo at rates from 44.1KHz to 192KHz using WAVE_FORMAT_IEEE_FLOAT
. The program is written in C++ and compiled in MinGW. This is all working correctly:
Now I'm trying to expand to quadraphonic multi-channel output, which seems to require WAVEFORMATEXTENSIBLE
, a superset of WAVEFORMATEX
. Here is the relevant code with those changes applied:
WAVEFORMATEXTENSIBLE wfx;
memset( &wfx, 0, sizeof(wfx) );
wfx.Format.nChannels = want.channels;
wfx.dwChannelMask = (want.channels == 4) ? 0x33 : ((want.channels == 1) ? 0x4 : 0x3);
wfx.Format.nSamplesPerSec = want.freq;
wfx.Format.cbSize = sizeof(wfx) - sizeof(wfx.Format);
MMRESULT wave_out_result = ~MMSYSERR_NOERROR;
if( userdata.HighRes )
{
wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx.SubFormat = {0x00000003,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}; //KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
wfx.Format.wBitsPerSample = 32;
wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nBlockAlign * wfx.Format.nSamplesPerSec;
wave_out_result = waveOutOpen( &WaveOutHandle, WAVE_MAPPER, &(wfx.Format), (DWORD_PTR) &WaveOutCallback, 0, CALLBACK_FUNCTION );
}
if( wave_out_result != MMSYSERR_NOERROR )
{
if( userdata.HighRes )
fprintf( stderr, "waveOutOpen returned %i%s when attempting float output\n", wave_out_result, (wave_out_result == WAVERR_BADFORMAT)?" (WAVERR_BADFORMAT)":"" );
wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.SubFormat = {0x00000001,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}; //KSDATAFORMAT_SUBTYPE_PCM
wfx.Format.wBitsPerSample = 16;
wfx.Samples.wValidBitsPerSample = wfx.Format.wBitsPerSample;
wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8;
wfx.Format.nAvgBytesPerSec = wfx.Format.nBlockAlign * wfx.Format.nSamplesPerSec;
wave_out_result = waveOutOpen( &WaveOutHandle, WAVE_MAPPER, &(wfx.Format), (DWORD_PTR) &WaveOutCallback, 0, CALLBACK_FUNCTION );
if( wave_out_result == MMSYSERR_NOERROR )
userdata.HighRes = false;
else
fprintf( stderr, "waveOutOpen returned %i%s when attempting int16 output\n", wave_out_result, (wave_out_result == WAVERR_BADFORMAT)?" (WAVERR_BADFORMAT)":"" );
}
If I set Format.nChannels = 2; dwChannelMask = 0x3;
for stereo, the first waveOutOpen
attempt using IEEE-float format fails with return code WAVERR_BADFORMAT
, but the second try using PCM format succeeds.
If I try Format.nChannels = 4; dwChannelMask = 0x33;
for quadraphonic, both IEEE-float and PCM waveOutOpen
attempts fail with WAVERR_BADFORMAT
.
However if I set Format.cbSize = 0;
then everything works correctly with 2 channels in either format, which makes sense since that is essentially what I'd been doing with WAVEFORMATEX
before. But this does not work with 4 channels.
What have I gotten wrong here? My ultimate goal is quadraphonic or 5.1 surround output in IEEE-float format. I'm especially baffled why I can't even get stereo IEEE-float output to work using WAVEFORMATEXTENSIBLE
but it works perfectly with WAVEFORMATEX
.
If are using a
WAVEFORMATEXTENSIBLE
structure, you have to indicate that by setting the correct format tag in the "base"WAVEFORMATEX
.See the documentation of the Format member of WAVEFORMATEXTENSIBLE.
This makes it possible for the called code (that only has a pointer to a
WAVEFORMATEX
) to discern if it is dealing with aWAVEFORMATEX
or anWAVEFORMATEXTENSIBLE
structure.In the case of
WAVEFORMATEXTENSIBLE
the actual audio format is then uniquely identified by theSubFormat
member.