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

Posted

技术标签:

【中文标题】将 16 位立体声转换为 16 位单声道声音【英文标题】:Convert 16 bit stereo sound to 16 bit mono sound 【发布时间】:2014-05-06 21:31:51 【问题描述】:

我正在尝试将 16 位立体声从 WAVE 文件转换为 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】:

在 16 位立体声 WAV 文件中,每个样本为 16 位,并且样本是交错的。我不确定您为什么使用按位 OR,但您可以直接检索数据而无需移位。下面的不可移植代码(假设 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 在下面的 cmets 中所指出的,简单的平均可能不会给出最好的结果。您的里程可能会有所不同。

此外,Greg Hewgill 正确地指出,这是假设机器是 little-endian 的。

【讨论】:

应该是i += 4 不是吗?否则,您的左通道将只是您的右通道是最后一次迭代。 为什么要除以 2?这会将原始信号降低 3 dB。 哦,你修好了哈哈 它除以二,因为它是两个样本的平均值。 根据数据准确性的要求,您可能不希望对信号进行平均。例如,如果左声道有 50 dB 200 Hz 音调,右声道有 50 dB 600 Hz 音调,则单声道流中将有两个 47 dB 音调。在我看来,最好将它们简单地加在一起,因为这会导致原始信号的复制,只是缺少方向信息。

以上是关于将 16 位立体声转换为 16 位单声道声音的主要内容,如果未能解决你的问题,请参考以下文章

如何从原始 16 位、44100 赫兹、立体声 PCM 获得正确的声音(立体声)

如何用声卡采集声音信号 然后用到MATLAB里面

怎么将8位的WAV声音文件转换为16位?

ue4 将音频从 48 立体声转换为 16 单声道

将 .caf 文件从立体声转换为单声道

在 C 中将立体声 wav 转换为单声道