You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不同采样率、采样数的音频缓冲区如何实现相加混合

不同参数音频帧混合实现方案

核心逻辑

要混合采样率、采样数不一致的音频帧,必须先将所有输入帧的采样率、通道数、时长三个参数统一到和输出帧一致,再逐采样点相加,否则采样点无法对齐,混合结果会出现杂音、时长错乱等问题。


实现步骤

  1. 确定输出帧的基准参数
  • 采样率:根据业务需求选择,常见可选48000(音视频通话、直播场景)或44100(音乐场景),此处以48000为例
  • 通道数:统一为所有输入帧的最大通道数,或业务指定值,此处以单声道1为例
  • 输出采样数:先计算每个输入帧的时长时长 = 单通道采样数 / 采样率,输出时长取所有输入帧的最大时长,输出采样数 = 输出时长 * 输出采样率,向上取整即可。
    以你给出的示例计算:

    input1时长 = 1000 / 48000 ≈ 0.0208s
    input2时长 = 600 / 44100 ≈ 0.0136s
    输出取最大时长0.0208s,对应采样数 = 0.0208 * 48000 = 1000

  1. 统一所有输入帧的通道数
  • 多声道转单声道:每个位置的采样值为所有通道对应采样值的平均值
  • 单声道转多声道:将单声道采样值复制到所有通道对应位置即可
  1. 对所有输入帧做重采样,统一为输出采样率
    可以用成熟的开源库(如libsamplerate、FFmpeg swresample)实现,也可以自己实现简单的线性插值重采样,核心逻辑是根据输入输出采样率的比值,计算目标采样点对应的原音频位置,用相邻的两个采样点插值得到新采样值。
  2. 对齐采样数
    重采样后所有输入帧已经是输出采样率,将采样数少于输出采样数的输入帧,在尾部补0,直到和输出采样数一致。
  3. 逐采样点相加并限幅
    两个采样值相加后可能超出音频归一化范围[-1.0, 1.0],需要做限幅处理避免爆音:大于1.0的设为1.0,小于-1.0的设为-1.0。

完整示例代码

#include <stdlib.h>
#include <math.h>

// 音频帧结构定义
typedef struct {
    int sample_rate;    // 该缓冲区的采样率,通常为48000或44100
    int no_channels;    // 音频通道数
    int no_samples;     // 每通道的音频采样数
    float* p_data;      // 音频数据
} AudioFrame;

// 简单线性插值重采样实现(仅支持单声道)
float* resample_mono(float* input, int in_sample_rate, int in_samples, int out_sample_rate, int* out_samples) {
    *out_samples = (int)ceil((double)in_samples * out_sample_rate / in_sample_rate);
    float* output = (float*)malloc(*out_samples * sizeof(float));
    double ratio = (double)in_sample_rate / out_sample_rate;

    for (int i = 0; i < *out_samples; i++) {
        double pos = i * ratio;
        int idx = (int)pos;
        double frac = pos - idx;
        if (idx >= in_samples - 1) {
            output[i] = input[in_samples - 1];
        } else {
            output[i] = input[idx] * (1 - frac) + input[idx + 1] * frac;
        }
    }
    return output;
}

AudioFrame mix_two_frames(AudioFrame input1, AudioFrame input2) {
    AudioFrame output;
    // 1. 确定输出基准参数
    output.sample_rate = 48000;
    output.no_channels = 1;
    double dur1 = (double)input1.no_samples / input1.sample_rate;
    double dur2 = (double)input2.no_samples / input2.sample_rate;
    double max_dur = fmax(dur1, dur2);
    output.no_samples = (int)ceil(max_dur * output.sample_rate);
    output.p_data = (float*)calloc(output.no_samples, sizeof(float)); // 初始化为0

    // 2. 重采样输入1到输出采样率
    int resampled1_samples;
    float* resampled1 = resample_mono(input1.p_data, input1.sample_rate, input1.no_samples, output.sample_rate, &resampled1_samples);
    // 写入输出缓冲区
    for (int i = 0; i < resampled1_samples && i < output.no_samples; i++) {
        output.p_data[i] += resampled1[i];
    }
    free(resampled1);

    // 3. 重采样输入2到输出采样率
    int resampled2_samples;
    float* resampled2 = resample_mono(input2.p_data, input2.sample_rate, input2.no_samples, output.sample_rate, &resampled2_samples);
    // 写入输出缓冲区
    for (int i = 0; i < resampled2_samples && i < output.no_samples; i++) {
        output.p_data[i] += resampled2[i];
    }
    free(resampled2);

    // 4. 限幅防止爆音
    for (int i = 0; i < output.no_samples; i++) {
        if (output.p_data[i] > 1.0f) output.p_data[i] = 1.0f;
        if (output.p_data[i] < -1.0f) output.p_data[i] = -1.0f;
    }

    return output;
}

内容的提问来源于stack exchange,提问作者cerutti davide

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:39:03