混音(Mixing)是指将多个音频信号合并成一个信号的过程。在处理 PCM(Pulse Code Modulation)音频数据时,混音通常涉及将两个或多个 PCM 音频流相加,并适当处理可能出现的溢出或剪切(clipping)问题。以下是 PCM 混音的详细步骤和示例代码。

博主博客

PCM 混音步骤

  1. 获取多个 PCM 音频流:假设我们有两个 PCM 音频流 pcm_data1pcm_data2,它们的采样率和量化深度相同。
  2. 对齐音频流:如果音频流的长度不同,需要对齐它们的长度。较短的音频流可以用零填充(zero-padding)以匹配较长的音频流。
  3. 混合音频流:将对应位置的样本相加,生成新的混合音频流。
  4. 处理溢出或剪切:对于可能的溢出或剪切问题,通常需要进行适当的处理,比如归一化或剪切限制。

示例代码

以下是一个简单的 Python 示例代码,用于混合两个 16 位 PCM 音频流。

import numpy as np

def mix_pcm(pcm_data1, pcm_data2):
    # 将两个 PCM 数据转换为 numpy 数组
    pcm_data1 = np.array(pcm_data1, dtype=np.int16)
    pcm_data2 = np.array(pcm_data2, dtype=np.int16)

    # 对齐音频流的长度
    max_len = max(len(pcm_data1), len(pcm_data2))
    if len(pcm_data1) < max_len:
        pcm_data1 = np.pad(pcm_data1, (0, max_len - len(pcm_data1)), 'constant')
    if len(pcm_data2) < max_len:
        pcm_data2 = np.pad(pcm_data2, (0, max_len - len(pcm_data2)), 'constant')

    # 混合音频流,防止溢出
    mixed_data = pcm_data1.astype(np.int32) + pcm_data2.astype(np.int32)

    # 防止溢出:将混合后的数据限制在 16 位 PCM 的范围内
    mixed_data = np.clip(mixed_data, -32768, 32767)

    # 转换回 16 位整数
    mixed_data = mixed_data.astype(np.int16)
    
    return mixed_data

# 示例 PCM 数据(16 位整数)
pcm_data1 = [1000, -2000, 1500, -2500, 3000, -3500]
pcm_data2 = [2000, -1000, 2500, -1500, 3500, -3000]

# 混合 PCM 数据
mixed_pcm_data = mix_pcm(pcm_data1, pcm_data2)
print(f"混合后的 PCM 数据: {mixed_pcm_data}")

解释

  1. 转换为 numpy 数组:使用 numpy 数组来便于进行数组操作。
  2. 对齐音频流的长度:使用 np.pad 对较短的音频流进行零填充,以对齐长度。
  3. 混合音频流:将两个音频流相加。为了防止溢出,使用 astype(np.int32) 将数据类型转换为 32 位整数。
  4. 防止溢出或剪切:使用 np.clip 将混合后的数据限制在 16 位 PCM 的范围(-32768 到 32767)。
  5. 转换回 16 位整数:最终将混合后的数据转换回 16 位整数类型。

注意事项

  1. 采样率和量化深度:混合的 PCM 音频流应具有相同的采样率和量化深度,否则会导致音频失真。
  2. 音量调整:在实际应用中,可以对每个音频流应用不同的增益(gain)以调整混合后音频的音量平衡。
  3. 相位问题:混合音频时应注意相位问题,尤其是在立体声或多通道音频处理中。

通过以上步骤和代码,可以实现基本的 PCM 音频混合处理,为音频应用程序提供基础支持。

公式

C = A + B - (A * B >> 0x10)

A 和 B 就是两路不同的音频数据,C 就是混音后的音频数据,当然,处理后,还需要对 C 进行防止数据溢出的处理,否则,可能会有爆音。

如果是 16bit音频数据,就是:

if (C > 32767) {
	C = 32767;
} else if (C < -32768) {
	C = -32768;
}

如果是 float音频数据,就是:

if (C > 1) {
	C = 1; 
} else if (C < -1) {
	C = -1;
}