【问题标题】:How to mix voice audio如何混合语音音频
【发布时间】:2011-04-24 17:55:48
【问题描述】:

我目前正在开发一个简单的 VoIP 项目,其中多个客户端将他的声音发送到服务器,然后服务器会将这些声音混合在一起。

但是,我不能使用简单的数学加法直接混合它。每个周期,客户端会向混音器发送 3584 字节的语音数据。

以下是接收缓冲区中包含的值的 sn-p:

BYTE buffer[3584];

    [0] 0        unsigned char
    [1] 192 'À'  unsigned char
    [2] 176 '°'  unsigned char
    [3] 61 '='   unsigned char
    [4] 0        unsigned char
    [5] 80 'P'   unsigned char
    [6] 172 '¬'  unsigned char
    [7] 61 '='   unsigned char
    [8] 0        unsigned char
    [9] 144 ''    unsigned char
    [10]    183 '·' unsigned char
    [11]    61 '='  unsigned char
     .
     .
     .

我不太确定缓冲区内的模式是如何从客户端以这种方式生成的,但我认为它可能是波形模式。现在假设我有另一个类似的数据,我如何将声音混合在一起。

请帮忙。谢谢。

【问题讨论】:

  • 您是否尝试过将简单数学加法的结果除以输入缓冲区的数量(算术平均值)?
  • @smerlin 我试过了,但我能听到的只是沉默。还有什么方法可以试试?
  • @Chicko Bueno:它应该适用于未压缩的 PCM 数据,可能是您的音频数据被 John Zwinck 指出的那样压缩。
  • @smerlin 据我所知,客户端提供未压缩的 PCM 数据。这让我很头疼。
  • @smerlin 无论如何,如果我有 3 个客户,你能不能给我一个简单的数学公式?也许我做错了。

标签: c++ audio voip signals


【解决方案1】:

您需要确定您的 VoIP 系统是否使用压缩。可能确实如此,在这种情况下,您需要做的第一件事是解压缩流,然后混合它们,然后重新压缩。

【讨论】:

    【解决方案2】:

    如果它是原始 PCM 数据,这可能是一个浮点数组(不太可能是由于所呈现的字节模式)或单整数,因此请尝试使用它。混合到 PCM 流是相当简单的,只需将它们加在一起并除以 2(使用其他权重进行音量控制)。

    【讨论】:

    • 除以二可避免溢出(如果您使用较大的类型作为临时 - 通常为 32 位),但也会使每个语音降低 3db。在混音器中,您通常不想降低声音的音量 - 但这可能会导致溢出,因此您可能必须实施一种好的(甚至是粗略的)限制器形式(甚至只是饱和添加限制)或自动增益控制。请注意,如果两个信号都低于 -3db 点,则它们不能溢出(在该样本处)。
    【解决方案3】:

    我再次查看了您的数据,它们似乎是浮点值,我在上一篇文章中弄错的原因可能与我在大端系统上工作了一段时间有关。但是,您的数据是小端 IEEE 浮点数。这是我转换后得到的值。

    0.089630127 -> 0x0090b73d
    0.084136963 -> 0x0050ac3d
    0.086303711 -> 0x00c0b03d
    

    如您所见,这些值相当小,因此您在应用音量时可能需要考虑到这一点;通常的约定是将这些数据分别设置在 0..1 或 -1..1 之间,分别表示最小和最大音量。

    这是我几年前写的一个混合循环的一部分,作为参考,完整的混合器是available here

       for(int i = 0; i < a_Sample->count() / a_Sample->channels(); i++){
                float l_Volume = a_Sample->volume() * m_MasterVolume;
    
                *l_Output++ += *l_Left * l_PanLeft * l_Volume;
                *l_Output++ += *l_Right * l_PanRight * l_Volume;
    
                l_Left  += a_Sample->channels();
                l_Right += a_Sample->channels();
        }
    

    请注意,对于输出,您可能需要将数据转换为有符号整数,因此如果这是混音器或输出设备的责任,则可以正确通信。

    【讨论】:

    • 谢谢!这真的很有帮助!
    【解决方案4】:

    正如其他人所提到的,您必须知道缓冲区的格式。您不能简单地直接对字节进行操作(嗯,您可以,但它会变得相当复杂)。大多数原始 PCM 数据通常是 44100 位/秒,16 位,2 通道。然而,情况并非总是如此。每一个都可以是不同的。它不会对它产生太大影响,但它是一个例子。但是,即使是 WAV 文件也可以是其他格式(如 IEEE Float)。您需要将缓冲区正确解释为适当的数据类型才能对其进行操作。

    喜欢:

    BYTE buffer[3584];
    if (SampleTypeIsPcm16Bit())
    {
        short *data = reinterpret_cast<short *>(buffer);
        // Rock on
    }
    else if (SampleTypeIsFloat())
    {
        float *data = reinterpret_cast<float *>(buffer);
        // Rock on
    }
    

    当然,您可以使用模板使其更通用,但请忽略它以了解 :P。

    请记住,如果您要处理浮点数,则需要将它们限制在 -1.0 和 1.0 的范围内。

    那么,您目前是不是说“加两个值并除以二”(Jasper 提到)不起作用?当您只听到静音时,您是如何播放数据的?我想知道这是否是个问题,因为如果您的数学运算不正确,您可能会听到音频故障(爆裂声/咔嗒声/等),而不仅仅是静音。

    【讨论】:

    • 谢谢杰森。实际上,我只是在做混合部分。我的搭档正在做语音捕捉和回放。当我尝试 Jasper 技术时,我是一个无声播放。没有爆裂声、咔哒声或高潮声音:P。假设声音不是 PCM 格式(原始/二进制数据),我该如何混合它们?
    • 嗯,很难说。这完全取决于您正在处理的音频流的格式。在将它们混合在一起之前,您确实需要知道这一点(因为不同的技术会对不同的类型产生不同的影响)。甚至不完全清楚这是否是所有音频数据(因为它可能是包含音频数据而不是所有音频数据的专有容器)。
    猜你喜欢
    • 2021-02-13
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    相关资源
    最近更新 更多