将16位立体声音频转换为16位单声道音频。

7

我正在尝试将WAVE文件中的16位立体声音频转换为16位单声道音频,但是遇到了一些问题。我已经尝试将8位立体声音频转换为单声道,并且效果很好。以下是用于此操作的代码:

if( bitsPerSample == 8 )
{
    dataSize /= 2;
    openALFormat = AL_FORMAT_MONO8;

    for( SizeType i = 0; i < dataSize; i++ )
    {
        pData[ i ] = static_cast<Uint8>(
                        (   static_cast<Uint16>( pData[ i * 2 ] ) +
                        static_cast<Uint16>( pData[ i * 2 + 1 ] ) ) / 2
        );
    }

但是,现在我正在尝试处理16位音频,但我无法使其正常工作。我只能听到一些奇怪的噪音。我已经尝试将"monoSample"设置为"left"(Uint16 monoSample = left;),并且该通道的音频数据非常好。右通道也是一样。你们中的任何人能看出我做错了什么吗? 以下是代码(pData是字节数组):

if( bitsPerSample == 16 )
{
    dataSize /= 2;
    openALFormat = AL_FORMAT_MONO16;

    for( SizeType i = 0; i < dataSize / 2; i++ )
    {
        Uint16 left =   static_cast<Uint16>( pData[ i * 4 ] ) |
                        ( static_cast<Uint16>( pData[ i * 4 + 1 ] ) << 8 );

        Uint16 right =  static_cast<Uint16>( pData[ i * 4 + 2 ] ) |
                        ( static_cast<Uint16>( pData[ i * 4 + 3 ] ) << 8 );

        Uint16 monoSample = static_cast<Uint16>(
                                (   static_cast<Uint32>( left ) +
                                static_cast<Uint32>( right ) ) / 2
            );

        // Set the new mono sample.
        pData[ i * 2 ] =  static_cast<Uint8>( monoSample );
        pData[ i * 2 + 1 ] =  static_cast<Uint8>( monoSample >> 8 );
    }
}
1个回答

10
在一个16位立体声WAV文件中,每个样本是16位的,并且样本是交错的。我不确定你为什么使用按位或运算符,但是可以直接检索数据,而无需进行移位操作。下面的非便携代码(假设sizeof(short)== 2)说明了这一点。
unsigned size = header.data_size;
char *data = new char[size];

// Read the contents of the WAV file in to data

for (unsigned i = 0; i < size; i += 4)
{
  short left = *(short *)&data[i];
  short right = *(short *)&data[i + 2];
  short monoSample = (int(left) + right) / 2;
}

此外,8位WAV文件是无符号的,而16位WAV文件是有符号的。为了对它们进行平均,确保将其存储在适当大小的有符号类型中。请注意,其中一个样本被暂时提升为int类型,以防止溢出。
正如Stix在下面的评论中指出的那样,简单的平均可能不会产生最佳结果。您的里程可能会有所不同。
此外,Greg Hewgill正确地指出了这假定机器是小端字节序的。

你为什么要除以2?那会使原始信号下降3 dB。 - stix
哦,你修好了哈哈。 - RamblingMad
4
根据数据准确性的要求,您可能不希望对信号进行平均。例如,如果左声道有一个50 dB 200 Hz音调,右声道有一个50 dB 600 Hz音调,则在单声道流中会得到两个47 dB音调。在我看来,最好只是把它们加在一起,因为这样会产生原始信号的复制,只是缺少方向信息。 - stix
谢谢,使用带符号的短整型数值来表示左、右和单声道采样已经解决了问题。为什么16位单声道文件是带符号的,而8位文件不是呢? - grimgrom
为了完整性,你应该注意到关于可移植性,你也要假设是小端机(因为样本是以小端存储的)。 - Greg Hewgill
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接