多声道音频数据和 WAVE 文件
原始地址:http://msdn.microsoft.com/zh-cn/windows/hardware/gg463006
更新日期: 3月 7日 2007年
本文将介绍使用 WAVE 文件格式存储和传输多声道音频数据的标准。读者应该了解多媒体文件格式,尤其是音频文件格式。
文本还将介绍创作多声道音频流的方法,多声道音频流要求明确地定义声道/扬声器位置。可以使用以上任何格式表示高分辨率流中精度的位数。
本页内容
简介
多声道配置
表示高分辨率音频
使用 WAVE_FORMAT_EXTENSIBLE
WAVE_FORMAT_EXTENSIBLE 的定义
有关 WAVEFORMATEX 字段的详细信息
有关 Samples Union 的详细信息
使用 dwChannelMask 指定声道位置
有关 dwChannelMask 的详细信息
示例
简介
PC 已经成为当今应用程序的最佳多媒体平台。CD 质量的音频(立体声、16 位、44.1 kHz)通常是指 PC 平台上可以达到的最高音频质量。随着工业的向前发展,将不断创作超越目前定义标准的新内容,包括更高的采样率、更高的位深、多声道(好于立体声)音频流和播放系统。为了与新数据格式和传递机制并驾齐驱,必须创建一个标准来确保应用程序和硬件之间的统一性。
Microsoft 已经扩展了传统的单声道或立体声,以及 8 位或 16 位的格式。实现方式是将WAVE_FORMAT_PCM和WAVE_FORMAT_IEEE_FLOAT建立在一个名为WAVEFORMATEXTENSIBLE的结构的基础上。实际上,可以通过使用WAVEFORMATEXTENSIBLE,采用相同的方法来扩展任何当前注册的格式标记。使用 ksmedia.h 中定义的宏DEFINE_WAVEFORMATEX_GUID(x)为现有格式标记WAVEFORMATEXTENSIBLE的 SubFormat 字段创建 GUID(全局唯一标识符)。某些常用的 GUID 具有静态名称,可以用来替换宏。这些名称包括KSDATAFORMAT_SUBTYPE_PCM、KSDATAFORMAT_SUBTYPE_IEEE_FLOAT、KSDATAFORMAT_SUBTYPE_ALAW、KSDATAFORMAT_SUBTYPE_MULAW、KSDATAFORMAT_SUBTYPE_ADPCM和KSDATAFORMAT_SUBTYPE_MPEG。
没有注册格式标记的新格式只需为其格式类型定义一个新的 GUID。例如,已经定义但尚未匹配注册格式标记的其他格式 GUID 有MEDIASUBTYPE_DOLBY_AC3、MEDIASUBTYPE_DVD_LPCM_AUDIO和MEDIASUBTYPE_MPEG2_AUDIO。
使用WAVEFORMATEXTENSIBLE可以按本文定义的扬声器配置顺序指定某些声道,和/或指定表示样本容器中实际有效位数的内容。该结构仅用于WAVEFORMATEX无法令人满意的情况。
为WAVEFORMATEXTENSIBLE结构的 wFormatTag 字段定义的WAVE_FORMAT_EXTENSIBLE格式标记表示,在确定该结构描述的数据格式时将使用WAVEFORMATEXTENSIBLE的 SubFormat 字段。由于该格式结构包含一个 GUID,因此可以定义表示特定于供应商的 wave 协议或数据格式的子格式,无需向 Microsoft 注册新的 wave 格式标记。
多声道配置
WAVE_FORMAT_PCM 中的语义不明确性
根据未压缩 PCM wave 格式的传统解释,在多扬声器配置中不能将给定的声道连接到给定的扬声器。始终采用立体声扬声器配置,并且因为nChannels始终为 1 或 2,因此很容易将它们映射到扬声器对。通过专有的,未记录的映射处理nChannels>2 的文件,但可能性非常小,因为只能采用两个扬声器(因此是两个波输出)。
随着改进的音频输出配置的出现,如四声道(四个角)、3.1(左前、中前、右前、低频增强)、5.1(左前、中前、右前、左后、右后、低频增强)等,这种情况发生了改变。必须考虑很多可用于播放和创作的扬声器配置。
目前,用于 5.1 传递的流集合最有可能流化为六声道文件。但是,仍然存在用作同步单声道文件的包的多声道文件。如果不将功能划分为这些文件类型之一,则无法为WAVE_FORMAT_PCM定义默认的多声道扬声器配置。因此,如果nChannels>2,用于WAVE_FORMAT_PCM的声道到扬声器规范仍然不会被记录。
默认声道排序
确定将声道数量链接到扬声器位置的方法(从而提供多声道音频文件之间的统一性)是定义在音频文件中排列声道的顺序。多个外部标准定义了以下主声道布局的各个部分:
-
左前 - FL
-
右前 - FR
-
中前 - FC
-
低频 - LF
-
左后 - BL
-
右后 - BR
-
中央左前 - FLC
-
中央右前 - FRC
-
中后 - BC
-
左侧 - SL
-
右侧 - SR
-
顶部中央 - TC
-
顶部左前 - TFL
-
顶部前中央 - TFC
-
顶部右前 - TFR
-
顶部后左 - TBL
-
顶部后中央 - TBC
-
顶部右后 - TBR
与这些空间位置相对应的交错流中的声道必须按以上指定的顺序出现。这同样适用于声道子集不连续的情况。例如,如果流包含左、低音增强和右,则声道 1 为左,声道 2 为右,声道 3 为低音增强。这样便能够将多声道流链接到定义明确的多扬声器配置。
警告:用于低频声道的内容可能无法接收数据的扬声器上呈现。这是因为无法保证用户系统中低频扬声器的频率范围。为此,接收低频音频的扬声器可能会筛选掉它无法处理的频率。
表示高分辨率音频
WAVE_FORMAT_PCM 中的语义不明确性
枚举由WAVE_FORMAT_PCM进行的假设是非常重要的。其中一个假设就是nBlockAlign字段只包含一个样本集(一个块)。而且,块中的每个样本必须是字节对齐。每个样本占用的字节对齐空间称为样本的“容器”。此外,最后一个样本容器的结尾和块的实际结尾之间没有任何额外空间。换句话说,nBlockAlign必须是nChannels的整数倍,并且将该倍数视为样本的“容器大小”。
尽管这不一定是最初目的,但某些实体认为wBitsPerSample等于容器大小。换句话说,假设有效数据的位数等于容器的大小。这种假设同样适用于 8 位和 16 位音频。随着用于呈现器和捕获的高保真装备的出现,也出现了 20 位和 24 位流。在字节对齐流中指定样本的实际位分辨率变得非常重要;可接受的wBitsPerSample解释开始清晰起来,因为并不是所有软件都硬性强制它的值。很多情况下,它依然是容器大小。但是,在其他情况下,该字段用来表示实际有效数据的位数,而容器大小是从nBlockAlign和nChannels推断得出的(例如,wBitsPerSample= 20,nBlockAlign= 8,nChannels= 2)。
解决该问题必然导致出现WAVE_FORMAT_PCM的很多遗留问题,因此新格式包含一个阐明该语义不确定性的附加字段。新格式用来处理精度的实际位数不等于容器大小的情况,以及容器大小大于 16 位的所有情况。
为WAVE_FORMAT_PCM解决wBitsPerSample的语义不确定性不是本文的目的。但是,在新格式中将能够明确使用该字段。
指定实际位深
在新格式中,将wBitsPerSample严格定义为容器大小。容器必须是字节对齐,因此wBitsPerSample必须是 8 的倍数。一个新字段表达包含实际数据的确切位数,无论容器大小如何都是如此。当音频通过处理系统时,每个样本的有效数据位数可能有所不同。将每个样本对齐到最高位,这样很容易在样本的底部添加附加精度或者调整为更低的精度。容器大小可以单独操纵,不会隐式对数据精度进行任何更改。32 位容器(用于有效处理)中的 24 位流可以安全地传输到 24 位容器(用于有效存储空间)而不会丢失任何数据。
使用 WAVE_FORMAT_EXTENSIBLE
为了解决多声道排序和高精度数据的问题,Microsoft 定义了一个新的结构WAVE_FORMAT_EXTENSIBLE。此新结构不仅仅能够解决这些问题,而且还提供了一个自我注册新数据格式的机制。SubFormat字段设置为指定WAVE_FORMAT_EXTENSIBLE结构所描述数据类型的 GUID。
WAVE_FORMAT_EXTENSIBLE 的定义
WAVE_FORMAT_EXTENSIBLE的定义(在 MMREG.H 和 KSMEDIA.H 中)如下:
- typedef struct { WAVEFORMATEX Format; union { WORD wValidBitsPerSample; /* bits of precision */ WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ WORD wReserved; /* If neither applies, set to zero. */ } Samples; DWORD dwChannelMask; /* which channels are present in stream */ GUID SubFormat;} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
WAVEFORMATPCMEX 的定义
wave 格式WAVEFORMATEX尚未指定,不能用于高位深样本或多声道流。对于声道的空间位置链接到标准扬声器位置的情况,WAVEFORMATPCMEX比较合适。对于WAVEFORMATEXTENSIBLE结构,Format.cbSize字段必须设置为22,SubFormat字段必须设置为KSDATAFORMAT_SUBTYPE_PCM。
KSDATAFORMAT_SUBTYPE_PCM的定义(在 KSMEDIA.H 中)如下:
- #define STATIC_KSDATAFORMAT_SUBTYPE_PCM\ DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_PCM)DEFINE_GUIDSTRUCT("00000001-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_PCM);#define KSDATAFORMAT_SUBTYPE_PCM DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_PCM)
PWAVEFORMATPCMEX可以安全地转换为PWAVEFORMATEXTENSIBLE或PWAVEFORMATEX。
- typedef WAVEFORMATEXTENSIBLE WAVEFORMATPCMEX;typedef WAVEFORMATPCMEX *PWAVEFORMATPCMEX;typedef WAVEFORMATPCMEX NEAR *NPWAVEFORMATPCMEX;typedef WAVEFORMATPCMEX FAR *LPWAVEFORMATPCMEX;
WAVEFORMATIEEEFLOATEX 的定义
WAVE_FORMAT_IEEE_FLOAT(基于WAVEFORMATEX)无法成为高位深样本或多声道流的最佳格式,其原因与 wave 格式WAVE_FORMAT_PCM相同。对于声道的空间位置链接到标准扬声器位置的情况,WAVEFORMATIEEEFLOATEX比较合适。对于WAVEFORMATEXTENSIBLE结构,Format.cbSize字段必须设置为22,SubFormat字段必须设置为KSDATAFORMAT_SUBTYPE_IEEE_FLOAT。
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT的定义(在 KSMEDIA.H 中)如下:
- #define STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\ DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_IEEE_FLOAT) DEFINE_GUIDSTRUCT("00000003-0000-0010-8000-00aa00389b71", KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); #define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
PWAVEFORMATIEEEFLOATEX可以安全地转换为PWAVEFORMATEXTENSIBLE或PWAVEFORMATEX。
- typedef WAVEFORMATEXTENSIBLE WAVEFORMATPCMEX;typedef WAVEFORMATPCMEX *PWAVEFORMATPCMEX;typedef WAVEFORMATPCMEX NEAR *NPWAVEFORMATPCMEX;typedef WAVEFORMATPCMEX FAR *LPWAVEFORMATPCMEX;
有关 WAVEFORMATEX 字段的详细信息
后文是解释WAVEFORMATEX结构的字段所遵循的内容、新字段的描述以及力求阐明该格式用法的各种示例。
wFormatTag 是 WAVE_FORMAT_EXTENSIBLE
在新结构WAVEFORMATEXTENSIBLE中,wFormatTag字段必须设置为WAVE_FORMAT_EXTENSIBLE(在 MMREG.H 中定义)。KSDATAFORMAT_SUBTYPE_PCM和KSDATAFORMAT_SUBTYPE_IEEE_FLOAT本身都是子格式,但不是实际标记。
nChannels、nSamplesPerSec、nAvgBytesPerSec 未改变
nChannels、nSamplesPerSec和nAvgBytesPerSec的意义与WAVE_FORMAT_PCM相同。nChannels是每个块交错样本的数量--流中各个声道的数量。nSamplesPerSec是为流计划的采样率-- 1 秒钟应该处理的块数。nAvgBytesPerSec用来估计缓冲区大小,因此根据总块大小来计算此数值。实际上,nAvgBytesPerSec始终是nBlockAlign和nSamplesPerSec的乘积,如同在WAVE_FORMAT_PCM中一样。
wBitsPerSample 硬性定义为容器大小
在WAVEFORMATEXTENSIBLE中,wBitsPerSample明确定义为每个样本的容器大小。各个样本必须是字节对齐的,因此该值必须是 8 的整数倍。在新格式中,诸如(nChannels= 2;wBitsPerSample= 20;nBlockAlign= 5)这种情况是明令禁止的。
由于可变的比特率格式的本质(即无法提供静态的wBitsPerSample),规定一些特殊情况是非常有必要的。这些格式类型应该在wBitsPerSample 字段中指定0。
nBlockAlign 和声道对齐
对于 PCM 和 IEEE 浮点格式(基于WAVEFORMATEXTENSIBLE),nBlockAlign必须是nChannels和wBitsPerSample(除以 8)的乘积。这样便与WAVE_FORMAT_PCM中nBlockAlign的定义保持一致(对于假设wBitsPerSample为容器大小的情况)。
cbSize 至少为 22
对于WAVEFORMATEXTENSIBLE,cbSize至少必须设置为为 22。这是Samples并集 (2)、DWORD dwChannelMask(4) 和GUID guidSubFormat(16) 的大小的总和。这附加到原WAVEFORMATEX 格式(大小为 18)之后,因此WAVEFORMATPCMEX和WAVEFORMATIEEEFLOATEX结构是 64 位对齐。
有关 Samples Union 的详细信息
为了使WAVEFORMATEXTENSIBLE结构不超过 64 位限制,wValidBitsPerSample和wSamplesPerBlock一起合并到一个称为Samples的并集。还额外添加了一个名为wReserved的字段,以便将来使用。
有关 wValidBitsPerSample 的详细信息
字段wValidBitsPerSample用来明确表示信号中存在的精度的位数。大多数情况下,该值等于wBitsPerSample。但是,如果波形数据源自 20 位 A/D,则wValidBitsPerSample可以设置为 20,即使wBitsPerSample为 24 或 32 都是如此。本文的后面部分包含示例。
如果wValidBitsPerSample小于wBitsPerSample,则容器中实际的 PCM 数据为“左对齐”。样本本身对齐最高位;所有额外位位于容器的最低有效位部分。所有非有效数据位必须设置为 0。
wValidBitsPerSample的值不能超过wBitsPerSample的值。如果遇到这种情况,正确的操作是拒绝该数据格式。
处理数据时,实体可能更改wValidBitsPerSample。例如,应用程序应该知道,如果输出驱动程序表示它仅支持wValidBitsPerSample= 16,则wValidBitsPerSample= 24 的流必须调整为 16 位。
尽管从内存带宽的角度来看,这非常昂贵,但也可以更改wBitsPerSample。wValidBitsPerSample表示是否可以在不丢失数据的情况下减小容器大小 (wBitsPerSample)。wValidBitsPerSample= 20 的流;可以安全地将wBitsPerSample= 32(用于 32 位 CPU 进行处理)压缩为wBitsPerSample= 24(用于在磁盘存档)。如果没有wValidBitsPerSample,将无法知道有无数据丢失。
有关 wSamplesPerBlock 的详细信息
通常,知道音频数据的一个压缩块中包含多少样本是非常有用的。每个块具有固定数量样本的压缩格式使用wSamplesPerBlock。该值有助于获得缓冲区估计和位置信息。如果wSamplesPerBlock为0,则可变的样本数量包含在压缩视频数据的每个块中。这种情况下,需要采用其他方法获得缓冲区估计和位置信息。
有关 wReserved 的详细信息
如果wValidBitsPerSample或wSamplesPerBlock都不适用于WAVEFORMATEXTENSIBLE结构的音频数据,则将wReserved字段设置为 0。
使用 dwChannelMask 指定声道位置
为了说明只存在一个可能的扬声器子集,创建了一个新的字段dwChannelMask,用于指定声道到空间位置的映射。为了支持此字段,可以在 sdk\inc\ksmedia.h and sdk\inc\mmreg.h 中找到以下位图:
- #define SPEAKER_FRONT_LEFT 0x1#define SPEAKER_FRONT_RIGHT 0x2#define SPEAKER_FRONT_CENTER 0x4#define SPEAKER_LOW_FREQUENCY 0x8#define SPEAKER_BACK_LEFT 0x10#define SPEAKER_BACK_RIGHT 0x20#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80#define SPEAKER_BACK_CENTER 0x100#define SPEAKER_SIDE_LEFT 0x200#define SPEAKER_SIDE_RIGHT 0x400#define SPEAKER_TOP_CENTER 0x800#define SPEAKER_TOP_FRONT_LEFT 0x1000#define SPEAKER_TOP_FRONT_CENTER 0x2000#define SPEAKER_TOP_FRONT_RIGHT 0x4000#define SPEAKER_TOP_BACK_LEFT 0x8000#define SPEAKER_TOP_BACK_CENTER 0x10000#define SPEAKER_TOP_BACK_RIGHT 0x20000#define SPEAKER_RESERVED 0x80000000
这些值与各种外部标准中定义的主声道布局完全对应。
作为一个示例,假设nChannels= 4;dwChannelMask= 0x00000033。这表示音频声道应用于播放到左前、右前、左后和右后扬声器。在每个块中声道数据应该以该顺序交错。
使用WAVEFORMATEXTENSIBLE时,考虑保留除了此预定义的设置 18 之外的声道位置。人们应该对除此之外的声道顺序不进行任何假设,只假设 Microsoft 将遵从其他标准。
有关 dwChannelMask 的详细信息
字段dwChannelMask表示多声道流中存在的声道。最低有效位与左前扬声器对应,下一个最低有效位与右前扬声器对应,依此类推,按照第 2 部分中定义的顺序。必须按照指定的顺序(最低有效位在上面)提供dwChannelMask中指定的声道。换句话说,如果仅指定左前和中前,则左前应该位于交错流中的第一位。
如果nChannels小于dwChannelMask中设置的位数,则忽略dwChannelMask中的额外(最高位)位。如果nChannels超过dwChannelMask中设置的位数,则不会将其余声道指定给任何特定扬声器位置。音频设备将向未使用的输出端口呈现其余声道数据。
如果音频接收器(如 WDM 音频的内置内核混合器)不知道在没有扬声器位置的情况下如何处理额外声道,则不呈现数据。nChannels超过dwChannelMask中设置的位数可能会产生不一致的结果,应该尽可能避免这种情况。
例如,如果在多声道音频创作应用中,在任何单声道流上不需要扬声器位置,则dwChannelMask应该明确设置为0。dwChannelMask为0告知音频设备将第一个声道呈现到设备上的第一个端口,第二个声道呈现到设备上的第二个端口,依此类推。这也意味着,如果设备不知道如何处理原始音频流,则不应该接受dwChannelMask为0的多声道流。数字混合器或数字音频存储设备(硬盘、ADAT 等)之类的设备需要没有特定扬声器位置的格式。
dwChannelMask值 0xFFFFFFFF(或设置了 DWORD 最高位的任何值)是预先定义的,用于表示实体支持所有可能的声道配置。示例为 WDM 音频的内置内核混合器。不存在与dwChannelMask最高位相对应的位置,因此该值是不确定的。
该格式不处理与定义的值不对应的扬声器位置,但 Microsoft 保留将来定义它们的权利。
示例
多声道 16 位
以下WAVEFORMATPCMEX结构表示 16 位四声道音频使用左前、右前、左后和右后呈现:
- WAVEFORMATPCMEX waveFormatPCMEx;waveFormatPCMEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;waveFormatPCMEx.Format.nChannels = 4;waveFormatPCMEx.Format.nSamplesPerSec = 44100L;waveFormatPCMEx.Format.nAvgBytesPerSec = 352800L; waveFormatPCMEx.Format.nBlockAlign = 8; /* Same as the usual */waveFormatPCMEx.Format.wBitsPerSample = 16;waveFormatPCMEx.Format.cbSize = 22; /* After this to GUID */waveFormatPCMEx.wValidBitsPerSample = 16; /* All bits have data */waveFormatPCMEx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; // Quadraphonic = 0x00000033waveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; // Specify PCM
音频数据的四个声道按照以下方式放置到内存中,指向该内存的指针存储在WAVEHDR结构的lpData成员中。
字节 1 - 声道 1,左前,低等字节
字节 2 - 声道 1,左前,高等字节
字节 3 - 声道 2,右前,低等字节
字节 4 - 声道 2,右前,高等字节
字节 5 - 声道 3,左后,低等字节
字节 6 - 声道 3,左后,高等字节
字节 7 - 声道 4,右后,低等字节
字节 8 - 声道 4,右后,高等字节
字节 9 - 声道 1,左前,低等字节,样本 2
字节 10 - 声道 1,左前,高等字节,样本 2 等
同样,PWAVEFORMATPCMEX可以安全地转换为PWAVEFORMATEXTENSIBLE或PWAVEFORMATEX以便获得可移植性。
立体声 20 位,填充的 wBitsPerSample
以下WAVEFORMATPCMEX结构表示 20 位分辨率的两个声道放置到磁盘的 24 位容器中:
- WAVEFORMATPCMEX waveFormatPCMEx;waveFormatPCMEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;waveFormatPCMEx.Format.nChannels = 2;waveFormatPCMEx.Format.nSamplesPerSec = 44100L;waveFormatPCMEx.Format.nAvgBytesPerSec = 264600L; // Compute using nBlkAlign * nSamp/SecwaveFormatPCMEx.Format.nBlockAlign = 6;waveFormatPCMEx.Format.wBitsPerSample = 24; //Container has 3 bytes waveFormatPCMEx.Format.cbSize = 22;waveFormatPCMEx.wValidBitsPerSample = 20; // Top 20 bits have datawaveFormatPCMEx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | // Stereo = 0x00000003waveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; // Specify PCM
三字节音频数据的两个声道按照以下方式放置到内存中,指向该内存的指针存储在WAVEHDR结构的lpData成员中。
字节 1 - 声道 1,左前,低等字节,只有顶部四个位为有效数据位
字节 2 - 声道 1,左前,中等字节,全部是有效数据
字节 3 - 声道 1,左前,高等字节,全部是有效数据
字节 4 - 声道 2,右前,低等字节,顶部四个位为有效数据位
字节 5 - 声道 2,右前,中等字节,全部是有效数据
字节 6 - 声道 2,右前,高等字节,全部是有效数据
字节 7 - 声道 1,左前,低等字节,顶部四个位为有效数据位,样本 2
字节 8 - 声道 1,左前,中等字节,全部是有效数据,样本 2 等
注意:nAvgBytesPerSec使用块大小 (nBlockAlign) 计算,而不是容器大小 (wBitsPerSample) 或有效位的实际数量 (wValidBitsPerSample)。
采用 5.1 格式的 6 声道
以下WAVEFORMATPCMEX结构可以指定为解码器针对 5.1 扬声器布局生成音频流的输出结构。
- WAVEFORMATPCMEX waveFormatPCMEx;waveFormatPCMEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;waveFormatPCMEx.Format.nChannels = 6;waveFormatPCMEx.Format.nSamplesPerSec = 48000L;waveFormatPCMEx.Format.nAvgBytesPerSec = 864000L; // Compute using nBlkAlign * nSamp/Sec waveFormatPCMEx.Format.nBlockAlign = 18;waveFormatPCMEx.Format.wBitsPerSample = 24; //Container has 3 bytes waveFormatPCMEx.Format.cbSize = 22;waveFormatPCMEx.wValidBitsPerSample = 20; // Top 20 bits have datawaveFormatPCMEx.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | // SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | // SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHTwaveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; // Specify PCM
三字节音频数据的两个声道按照以下方式放置到内存中,并且指向该内存的指针存储在WAVEHDR结构的lpData成员中。
字节 1 - 声道 1,左前,低等字节,只有顶部四个位为有效数据位
字节 2 - 声道 1,左前,中等字节,全部是有效数据
字节 3 - 声道 1,左前,高等字节,全部是有效数据
字节 4 - 声道 2,右前,低序位字节,顶部四个位为有效数据位
字节 5 - 声道 2,右前,中等字节,全部是有效数据
字节 6 - 声道 2,右前,高等字节,全部是有效数据
字节 7 - 声道 3,中前,低序位字节,只有顶部四个位为有效数据位
字节 8 - 声道 3,中前,中等字节,全部是有效数据
字节 9 - 声道 3,中前,高等字节,全部是有效数据
字节 10 - 声道 4,低频、低序位字节,顶部四个字节为有效数据位
字节 11 - 声道 4,低频,中等字节,全部是有效数据
字节 12 - 声道 4,低频、高等字节,全部是有效数据
字节 13 - 声道 5,左后,低序位字节,只有顶部四个位为有效数据位
字节 14 - 声道 5,右后,中等字节,全部是有效数据
字节 15 - 声道 5,左后,高等字节,全部是有效数据
字节 16 - 声道 6,右后,低序位字节,顶部四个位为有效数据位
字节 17 - 声道 6,右后,中等字节,全部是有效数据
字节 18 - 声道 6,右后,高等字节,全部是有效数据
字节 19 - 声道 1,左前,低等字节,顶部四个位为有效数据位,样本 2
字节 20 - 声道 1,左前,中等字节,全部是有效数据,样本 2 等
未指定的位置声道,DWORD 容器
以下WAVEFORMATPCMEX结构表示 32 位分辨率的三个声道,放置到磁盘上的 32 位容器中,其中只有前两个声道局限于某一位置:
- WAVEFORMATPCMEX waveFormatPCMEx;waveFormatPCMEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;waveFormatPCMEx.Format.nChannels = 3;waveFormatPCMEx.Format.nSamplesPerSec = 48000L;waveFormatPCMEx.Format.nAvgBytesPerSec = 576000L; // Compute using nBlkAlign * nSamp/Sec waveFormatPCMEx.Format.nBlockAlign = 12;waveFormatPCMEx.Format.wBitsPerSample = 32; //Container has 4 bytes waveFormatPCMEx.Format.cbSize = 22;waveFormatPCMEx.wValidBitsPerSample = 23; // Top 23 bits have datawaveFormatPCMEx.dwChannelMask = SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER // Left, Right of Center = 0x000000C0WAVEFORMATPCMEX.SUBFORMAT = KSDATAFORMAT_SUBTYPE_PCM; // SPECIFY PCM
四字节音频数据的两个声道按照以下方式放置到内存中,指向该内存的指针存储在WAVEHDR结构的lpData成员中。
字节 1 - 声道 1,中央偏左,低等字节,无有效数据
字节 2 - 声道 1,中央偏左,中低等字节,只有顶部七个位为有效数据位
字节 3 - 声道 1,中央偏左,中高等字节,全部是有效数据
字节 4 - 声道 1,中央偏左,高序等节,全部是有效数据
字节 5 - 声道 2,中央偏右,低序位字节,无有效数据
字节 6 - 声道 2,中央偏右,中低等字节,顶部七个位为有效数据位
字节 7 - 声道 2,中央偏右,中高等字节,全部是有效数据
字节 8 - 声道 2,中央偏右,高等字节,全部是有效数据
字节 9 - 声道 3,未指定的位置,低等字节,无有效数据
字节 10 - 声道 3,未指定的位置,中低等字节,顶部七个位为有效数据位
字节 11 - 声道 3,未指定的位置,中高等字节,全部是有效数据
字节 12 - 声道 3,未指定的位置,高等字节,全部是有效数据
字节 13 - 声道 1,中央偏左,低等字节,无有效数据,样本 2
字节 14 - 声道 1,中央偏左,中低等字节,顶部七个位为有效数据位,样本 2 等
这些流可以通过缩放算法发送,该算法将小数值放置到低 9 位,仅对采用波形格式结构的值更改为:
- // All 32 bits have datawaveFormatPCMEx.wValidBitsPerSample = 32;
使用 WAVEFORMATIEEEFLOATEX 的示例
以下WAVEFORMATIEEEFLOATEX结构表示 32 位容器中 18 位数据的七个声道。声道 7 包含未分配空间位置的有效音频数据。
- PWAVEFORMATIEEEFLOATEX waveFormatIEEEFloatEx;waveFormatIEEEFloatEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;waveFormatIEEEFloatEx.Format.nChannels = 7;waveFormatIEEEFloatEx.Format.nSamplesPerSec = 48000L;waveFormatIEEEFloatEx.Format.nAvgBytesPerSec = 1344000L;waveFormatIEEEFloatEx.Format.nBlockAlign = 28;waveFormatIEEEFloatEx.Format.wBitsPerSample = 32;waveFormatIEEEFloatEx.Format.cbSize = 22;waveFormatIEEEFloatEx.wValidBitsPerSample = 18; //Top 18 bits have datawaveFormatIEEEFloatEx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;waveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; // 5.1 + unassigned chan
字节 1 - 声道 1,左前,低等字节,无有效数据
字节 2 - 声道 1,左前,中低等字节,只有顶部两个位为有效数据位
字节 3 - 声道 1,左前,中高等字节,全部是有效数据
字节 4 - 声道 1,左前,高等字节,全部是有效数据
字节 5 - 声道 2,右前,低序位字节,无有效数据
字节 6 - 声道 2,右前,中低等字节,顶部两个位为有效数据位
字节 7 - 声道 2,右前,中高等字节,全部是有效数据
字节 8 - 声道 2,右前,高等字节,全部是有效数据
字节 9 - 声道 3,中前,低等字节,无有效数据
字节 10 - 声道 3,中前,中低等字节,顶部两个位为有效数据位
字节 11 - 声道 3,中前,中高等字节,全部是有效数据
字节 12 - 声道 3,中前,高等字节,全部是有效数据
字节 13 - 声道 4,低频增强,低等字节,无有效数据
字节 14 - 声道 4,低频增强,中低等字节,顶部两个位为有效数据位
字节 15 - 声道 4,低频增强,中高等字节,全部是有效数据
字节 16 - 声道 4,低频增强,高等字节,全部是有效数据
字节 17 - 声道 5,左后,低等字节,无有效数据
字节 18 - 声道 5,左后,中低等字节,顶部两个位为有效数据位
字节 19 - 声道 5,左后,中高等字节,全部是有效数据
字节 20 - 声道 5,左后,高等字节,全部是有效数据
字节 21 - 声道 6,右后,低等字节,无有效数据
字节 22 - 声道 6,右后,中低等字节,顶部两个位为有效数据位
字节 23 - 声道 6,右后,中高等字节,全部是有效数据
字节 24 - 声道 6,右后,高等字节,全部是有效数据
字节 25 - 声道 7,未指定的位置,低等字节,无有效数据
字节 26 - 声道 7,未指定的位置,中低等字节,顶部两个位为有效数据位
字节 27 - 声道 7,未指定的位置,中高等字节,全部是有效数据
字节 28 - 声道 7,未指定的位置,高序等节,全部是有效数据
字节 29 - 声道 1,左前,低等字节,无有效数据,样本 2
字节 30 - 声道 1,左前,中低等字节,顶部两个位为有效数据位,样本 2 等
多个单声道流(无扬声器位置)
以下WAVEFORMATIEEEFLOATEX结构表示 32 位容器中 32 位浮点数据的 6 个声道。没有任何单声道专用于一个扬声器,因此音频设备采用升序将流发送到设备定义的端口。
- PWAVEFORMATIEEEFLOATEX waveFormatIEEEFloatEx;waveFormatIEEEFloatEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;waveFormatIEEEFloatEx.Format.nChannels = 6;waveFormatIEEEFloatEx.Format.nSamplesPerSec = 96000L;waveFormatIEEEFloatEx.Format.nAvgBytesPerSec = 1152000L;waveFormatIEEEFloatEx.Format.nBlockAlign = 24;waveFormatIEEEFloatEx.Format.wBitsPerSample = 32;waveFormatIEEEFloatEx.Format.cbSize = 22;waveFormatIEEEFloatEx.wValidBitsPerSample = 32;waveFormatIEEEFloatEx.dwChannelMask = 0;waveFormatPCMEx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
字节 1 - 单声道 1,低等字节,有效浮点数据
字节 2 - 单声道 1,中低等字节,有效浮点数据
字节 3 - 单声道 1,中高等字节,有效浮点数据
字节 4 - 单声道 1,高等字节,有效浮点数据
字节 5 - 单声道 2,低等字节,有效浮点数据
字节 6 - 单声道 2,中低等字节,有效浮点数据
字节 7 - 单声道 2,中高等字节,有效浮点数据
字节 8 - 单声道 2,高等字节,有效浮点数据
字节 9 - 单声道 3,低等字节,有效浮点数据
字节 10 - 单声道 3,中低等字节,有效浮点数据
字节 11 - 单声道 3,中高等字节,有效浮点数据
字节 12 - 单声道 3,高等字节,有效浮点数据
字节 13 - 单声道 4,低等字节,有效浮点数据
字节 14 - 单声道 4,中低等字节,有效浮点数据
字节 15 - 单声道 4,中高等字节,有效浮点数据
字节 16 - 单声道 4,高等字节,有效浮点数据
字节 17 - 单声道 5,低等字节,有效浮点数据
字节 18 - 单声道 5,中低等字节,有效浮点数据
字节 19 - 单声道 5,中高等字节,有效浮点数据
字节 20 - 单声道 5,高等字节,有效浮点数据
字节 21 - 单声道 6,低等字节,有效浮点数据
字节 22 - 单声道 6,中低等字节,有效浮点数据
字节 23 - 单声道 6,中高等字节,有效浮点数据
字节 24 - 单声道 6, 高等字节,有效浮点数据
字节 25 - 单声道 1,低等字节,有效浮点数据,样本 2
字节 26 - 单声道 1,中低等字节,有效浮点数据,样本 2 等