将 WAVEFORMATEXTENSIBLE 与 WAVE_FORMAT_IEEE_FLOAT、waveOutOpen returns WAVERR_BADFORMAT 结合使用
Using WAVEFORMATEXTENSIBLE with WAVE_FORMAT_IEEE_FLOAT, waveOutOpen returns WAVERR_BADFORMAT
我一直在使用 WAVEFORMATEX
和 WaveOut 在 Windows 中使用 WAVE_FORMAT_IEEE_FLOAT
以 44.1KHz 到 192KHz 的速率在立体声中播放音频。该程序用 C++ 编写,并在 MinGW 中编译。这一切都正常工作:
现在我正在尝试扩展到四声道多声道输出, 这似乎需要 WAVEFORMATEXTENSIBLE
,WAVEFORMATEX
的超集。以下是应用了这些更改的相关代码:
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)":"" );
}
如果我为立体声设置 Format.nChannels = 2; dwChannelMask = 0x3;
,第一次 waveOutOpen
尝试使用 IEEE-float 格式失败并返回 return 代码 WAVERR_BADFORMAT
,但第二次尝试使用 PCM 格式成功。
如果我尝试 Format.nChannels = 4; dwChannelMask = 0x33;
四声道,IEEE-float 和 PCM waveOutOpen
尝试都会失败 WAVERR_BADFORMAT
。
但是,如果我设置 Format.cbSize = 0;
,那么任何格式的 2 个通道都可以正常工作,这是有道理的,因为这基本上是我之前对 WAVEFORMATEX
所做的。但这不适用于 4 个通道。
我哪里弄错了? 我的最终目标是以 IEEE-float 格式输出四声道或 5.1 环绕声。我特别困惑为什么我什至不能使用 WAVEFORMATEXTENSIBLE
使立体声 IEEE-float 输出工作,但它与 WAVEFORMATEX
.
完美配合
如果使用 WAVEFORMATEXTENSIBLE
结构,您必须通过在“base”中设置正确的格式标签来指明 WAVEFORMATEX
。
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
请参阅 WAVEFORMATEXTENSIBLE 的 Format 成员的文档。
这使得被调用的代码(只有一个指向 WAVEFORMATEX
的指针)可以辨别它是在处理 WAVEFORMATEX
还是 WAVEFORMATEXTENSIBLE
结构。
在 WAVEFORMATEXTENSIBLE
的情况下,实际的音频格式由 SubFormat
成员唯一标识。
我一直在使用 WAVEFORMATEX
和 WaveOut 在 Windows 中使用 WAVE_FORMAT_IEEE_FLOAT
以 44.1KHz 到 192KHz 的速率在立体声中播放音频。该程序用 C++ 编写,并在 MinGW 中编译。这一切都正常工作:
现在我正在尝试扩展到四声道多声道输出, 这似乎需要 WAVEFORMATEXTENSIBLE
,WAVEFORMATEX
的超集。以下是应用了这些更改的相关代码:
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)":"" );
}
如果我为立体声设置 Format.nChannels = 2; dwChannelMask = 0x3;
,第一次 waveOutOpen
尝试使用 IEEE-float 格式失败并返回 return 代码 WAVERR_BADFORMAT
,但第二次尝试使用 PCM 格式成功。
如果我尝试 Format.nChannels = 4; dwChannelMask = 0x33;
四声道,IEEE-float 和 PCM waveOutOpen
尝试都会失败 WAVERR_BADFORMAT
。
但是,如果我设置 Format.cbSize = 0;
,那么任何格式的 2 个通道都可以正常工作,这是有道理的,因为这基本上是我之前对 WAVEFORMATEX
所做的。但这不适用于 4 个通道。
我哪里弄错了? 我的最终目标是以 IEEE-float 格式输出四声道或 5.1 环绕声。我特别困惑为什么我什至不能使用 WAVEFORMATEXTENSIBLE
使立体声 IEEE-float 输出工作,但它与 WAVEFORMATEX
.
如果使用 WAVEFORMATEXTENSIBLE
结构,您必须通过在“base”中设置正确的格式标签来指明 WAVEFORMATEX
。
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
请参阅 WAVEFORMATEXTENSIBLE 的 Format 成员的文档。
这使得被调用的代码(只有一个指向 WAVEFORMATEX
的指针)可以辨别它是在处理 WAVEFORMATEX
还是 WAVEFORMATEXTENSIBLE
结构。
在 WAVEFORMATEXTENSIBLE
的情况下,实际的音频格式由 SubFormat
成员唯一标识。