【问题标题】:MIX AUDIO: Adding audio buffersMIX AUDIO:添加音频缓冲区
【发布时间】:2021-09-03 17:19:23
【问题描述】:

我有 2 个或更多音频帧,其结构如下:

   int sample_rate;    // The sample-rate of this buffer (48000 or 44100 normaly)
   int no_channels;    // The number of audio channels
   int no_samples;     // The number of audio samples per channel (n elements in data array)
   float* p_data;      // The audio data

添加 2 个音频缓冲区非常简单: 帧输入1; 帧输入2;

    frameOutput.sample_rate = 48000;
    frameOutput.no_channel = 1;
    frameOutput.no_sample = 1000;
    frameOutput.p_data = (float*)malloc(frameOutput.no_sample * frameOutput.no_channel * sizeof(float))

    for(int i=0; i<frameOutput.no_sample; i++){
         frameOutput.p_data[i] = frameInput1.p_data[i] + frameInput2.p_data[i];
     }

我用相同的样本创建了一个音频缓冲区,并为数据数组中的每个样本添加了输入帧

但如果我有不同 no_sample 或不同 sample_rate 的音频缓冲区?

例如:

     input1.sample_rate = 48000hz; input1.no_sample = 1000 ;
     input2.sample_rate = 44100hz; input2.no_sample = 600 ;

如何添加这两个输入?

【问题讨论】:

    标签: c++ c audio audiobuffer


    【解决方案1】:

    只需根据 sample_rate 缩放缓冲区中的地址:

    float in1_rate_scale = float(input1.sample_rate) / frameOutput.sample_rate;
    float in2_rate_scale = float(input2.sample_rate) / frameOutput.sample_rate;
    
    for (int i = 0; i < frameOutput.no_sample; i++) {
        frameOutput.p_data[i] = frameInput1.p_data[i*in1_rate_scale] + frameInput2.p_data[i * in2_rate_scale];
    }
    

    无论如何,请记住,仅添加“音量”值是错误的,当两个缓冲区中的响度都达到最大值时,您很容易溢出。但这是另一个问题,也是你面临的另一个问题。

    【讨论】:

    • 如果值以浮点格式存储,则溢出问题不大,因为浮点值不会溢出,除非/直到它们变得非常/不合理地大。
    • 确实如此,谢谢。无论如何,在大多数情况下,纯粹添加音频信号是不正确的。同样,这超出了这个问题的范围。
    • 没错,但问题是不仅采样率不同,而且采样的数量也不同,所以分配给不同帧缓冲区的内存维度也不同
    • @ceruttidavide,好吧,我的回答是基于您问题中可用的输入,它应该足以解决您提出的特定问题。如果您正在寻找更详细的答案,提供Minimal, Reproducible Example 以便人们可以提供帮助会有所帮助。
    【解决方案2】:

    我假设您的程序正在处理两个音频流,每个流都为您提供一系列音频缓冲区。

    如果是这样,那么每个缓冲区中的音频帧数不是音频的基本特征,而只是音频样本打包在一起的副作用(例如,流 A 的生产者决定将 1000 个样本放在一个缓冲区中,而流 B 的生产者决定只将 600 个样本放在一起)。

    理想情况下,您可以告诉您的两个流制作者为您提供具有固定(且相等)帧数的音频缓冲区,这样您就可以逐字添加样本,但如果您无法获得它们为此,您需要实现某种缓冲机制,将两个缓冲区中较大的“额外”帧保存在某种 FIFO 队列中,然后将它们用作下一次混合中的第一个样本手术。这可能会有点复杂,所以除非性能是您最关心的问题,否则我建议只为每个输入流保留一个音频帧的 FIFO 队列(例如 std::dequeue&lt;float&gt; 或类似的),并始终推送所有新收到的来自该输入流的音频帧流到该 FIFO 队列的尾部,然后在需要将音频混合在一起时根据需要从每个 FIFO 队列的头部弹出帧。这样,您就可以将音频的混合与输入音频缓冲区的大小分离,这样无论输入流为您生成什么,您的混合代码都可以正常工作。 (请注意,您可以产生的输出/混合音频缓冲区的最大大小将等于当时最短 FIFO 队列中的音频帧数)

    处理不同的采样率是一个更难解决的问题,特别是如果您希望输出音频具有良好的音质。为了正确处理它,您需要使用采样率转换器算法(例如libsamplerate)将一个流的采样率转换为等于另一个流的采样率(或者如果您更喜欢将两个流的采样率转换为等于输出流的采样率)。完成此操作后,您可以像以前一样将两个匹配速率的流逐个样本添加在一起。

    【讨论】:

    • 所以问题是我正在实时混合音频,性能绝对是项目的关键,而且我将接收的音频流不在我的控制之下,它们是由其他程序,我正在通过 ASIO 网络收集它们
    猜你喜欢
    • 1970-01-01
    • 2016-04-26
    • 2015-08-30
    • 1970-01-01
    • 2014-11-14
    • 1970-01-01
    • 2014-04-03
    • 2018-03-08
    • 2016-01-10
    相关资源
    最近更新 更多