c语言实现常见几种混音算法

本文介绍了三种常见的混音算法:直接相加法、简单平均法和自适应权重法,并提供了C语言的代码实现。直接相加法简单但可能导致音量叠加问题,简单平均法易于实现但缺乏动态调整,自适应权重法则能动态调整权重以避免音频溢出,但算法复杂度较高。代码示例展示了如何使用这些算法对音频进行混音操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

                                                                         目录

                                                      一、常见三种混音算法

                                                                 1.直接相加法

                                                                 2.简单平均法

                                                                 3.自适应权重法

                                                     二、代码实现混音算法

 

一、常见三种混音算法

  1. 直接相加法

void additiveMixing(const float* input1, const float* input2, float* output, int length)

{

    for (int i = 0; i < length; i++)

    {

        output[i] = input1[i] + input2[i];

    }

}

直接相加法混音是一种简单而常见的混音算法,其优缺点如下:

优点:

简单易懂:直接相加法混音算法非常简单,容易理解和实现,无需复杂的计算。

低计算开销:由于不涉及复杂的信号处理算法,直接相加法混音的计算开销相对较低,适用于实时处理等需要快速响应的应用场景。

缺点:

音量叠加问题:直接相加法混音仅是将多个音频信号简单地相加,可能导致音量过高,产生音频削波或失真的问题。在混音过程中可能需要对音频信号进行归一化处理,以避免超过合理范围的音量。

信号干扰:如果混音的音频信号存在频率冲突或相位差异,直接相加法混音可能会导致信号间的干扰或相互抵消。这可能会产生不良的音频效果或部分信号的消失。

 

    2.简单平均法:

void averageMixing(float *input1, float *input2, float *output, int length)

{

    float gain1 = 1;

    float gain2 = 0.5;

    for (int i = 0; i < length; i++)

    {

        output[i] = (input1[i] * gain1 + input2[i] * gain2) / 2.0f;

    }

}

其优缺点如下:

优点:

简单易实现,计算速度快,能够自己按照比例混音

缺点:

无法对音频信号进行动态调整,可能导致混音后的声音过于平淡。

 

    3.自适应权重法

void adaptiveWeightingMixing(float *input1, float *input2, float *output, int length)

{

  float factor = 1;//衰减因子 初始值为1

  float MAX = 3.4028235E38;

  float MIN = -3.4028235E38;

  float mixVal;

 

  for (int i = 0; i < length; i++)

  {

      mixVal = (input1[i]+input2[i])*factor;

      if (mixVal>MAX)

      {

          factor = MAX/mixVal;

          mixVal = MAX;

      }

      if (mixVal<MIN){

          factor = MIN/mixVal;

          mixVal = MIN;

      }

      if (factor < 1)

      {

          //SETPSIZE为f的变化步长,通常的取值为(1-f)/VALUE,此处取SETPSIZE 为 32   VALUE值可以取 8, 16, 32,64,128.

          factor += (1 - factor) / 32;

      }

      output[i] = mixVal;

 

  }

}

自适应权重法相对于上面两种更为复杂。其优缺点如下:

优点:

动态调整权重:

能通过衰减因子factor动态调整音频信号的权重,以避免混音溢出边界(超出最大或最小值)。这样可以有效避免音频削波或失真的问题。

提供动态范围控制:通过根据混音结果调整衰减因子f的大小,自适应权重法可以对混音信号的动态范围进行控制,使其适应不同音频输入的音量差异。

缺点(相对而言):

算法复杂度较高:相较于简单相加法,自适应权重法需要进行较多的条件判断和计算,因此算法复杂度较高,可能对系统性能产生一定影响。

可能引入音频伪影:在自适应权重法中,权重的动态调整过程可能引入一定的音频伪影。这是由于频域的快速变化导致的,可能会对音频质量产生一定的影响。

 

二、代码实现案例

代码获取,公主号(gh_bffeac6359e7)回复:c语言实现混音算法代码

通过tinywav第三方库实现wav的读写,读取两个wav文件并选择混音模式,混音后写入新的wav文件,以下是代码一部分。

#include <math.h>

#include <assert.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include "../inc/tinywav.h"

 

#define _USE_MATH_DEFINES

#define BLOCK_SIZE 240

#define sampleRate 48000

 

enum mix_style_

{

  Additive_Mixing = 1,

  Average_Mixing = 2,

  Adaptive_Weighting_Mixing = 3

};

 

void additiveMixing(const float* input1, const float* input2, float* output, int length)

{

    for (int i = 0; i < length; i++)

    {

        output[i] = input1[i] + input2[i];

    }

}

 

void averageMixing(float *input1, float *input2, float *output, int length)

{

    float gain1 = 1;

    float gain2 = 0.5;

    for (int i = 0; i < length; i++)

    {

        output[i] = (input1[i] * gain1 + input2[i] * gain2) / 2.0f;

    }

}

 

void adaptiveWeightingMixing(float *input1, float *input2, float *output, int length)

{

  float factor = 1;//衰减因子 初始值为1

  float MAX = 3.4028235E38;

  float MIN = -3.4028235E38;

  float mixVal;

 

  for (int i = 0; i < length; i++)

  {

      mixVal = (input1[i]+input2[i])*factor;

      if (mixVal>MAX)

      {

          factor = MAX/mixVal;

          mixVal = MAX;

      }

      if (mixVal<MIN){

          factor = MIN/mixVal;

          mixVal = MIN;

      }

      if (factor < 1)

      {

          //SETPSIZE为f的变化步长,通常的取值为(1-f)/VALUE,此处取SETPSIZE 为 32   VALUE值可以取 8, 16, 32,64,128.

          factor += (1 - factor) / 32;

      }

      output[i] = mixVal;

 

  }

}


 

int main(int argc, char *argv[])

{

  char* outputPath = "./wav_file/output.wav";

  if (argc < 4)

  {

    printf("open failed,please input such as: ./mix test1.wav test2.wav 1~3 \n");

    printf("1.procress with Additive Mixing\n");

    printf("2.procress with Average  Mixing\n");

    printf("3.procress with Adaptive Weighting Mixing\n");

    return -1;

  }

   

  TinyWav twReaderWav1,twReaderWav2;

  tinywav_open_read(&twReaderWav1, argv[1], TW_INLINE);

  tinywav_open_read(&twReaderWav2, argv[2], TW_INLINE);

 

  int16_t wav1_channels   = twReaderWav1.numChannels;

  int32_t wav1_samplerate = twReaderWav1.h.SampleRate;

  TinyWavSampleFormat  wav1_sampFmt   = twReaderWav1.sampFmt;

  TinyWavChannelFormat wav1_chanfmt   = twReaderWav1.chanFmt;

 

  int16_t wav2_channels   = twReaderWav2.numChannels;

  int32_t wav2_samplerate = twReaderWav2.h.SampleRate;

  TinyWavSampleFormat  wav2_sampFmt   = twReaderWav2.sampFmt;

  TinyWavChannelFormat wav2_chanfmt   = twReaderWav2.chanFmt;

  if(wav1_channels != 1 || wav1_samplerate!=48000 || wav2_channels != 1 || wav2_samplerate!=48000)

  {

    printf("wav channel must be 1 channel and samplerate 48000\n");

    return -1;

  }

 

  TinyWav twWriter;

  tinywav_open_write(&twWriter, 1, 48000, TW_INT16, TW_INLINE, outputPath);

 

  int wav1_totalNumSamples = twReaderWav1.numFramesInHeader;

  int wav1_samplesProcessed = 0;

  int wav2__totalNumSamples = twReaderWav2.numFramesInHeader;

  int wav2_samplesProcessed = 0;

 

  int wav1_block_count = 0;

  int wav2_block_count = 0;

  float wav1_data[BLOCK_SIZE] = {0};

  float wav2_data[BLOCK_SIZE] = {0};

  float out_data [BLOCK_SIZE] = {0};

  int mix_style = atoi(argv[3]);

 

  while (wav1_samplesProcessed < wav1_totalNumSamples)

  {

    int wav1_samplesRead = tinywav_read_f(&twReaderWav1, wav1_data, BLOCK_SIZE);

    wav1_samplesProcessed += wav1_samplesRead;

 

    if(wav2_samplesProcessed < wav2__totalNumSamples)

    {

      int wav2_samplesRead = tinywav_read_f(&twReaderWav2, wav2_data, BLOCK_SIZE);

      wav2_samplesProcessed += wav2_samplesRead;

      switch (mix_style)

      {

      case Additive_Mixing:

        additiveMixing(wav1_data,wav2_data,out_data,BLOCK_SIZE);

        break;

 

      case Average_Mixing:

        averageMixing(wav1_data,wav2_data,out_data,BLOCK_SIZE);

        break;

 

      case Adaptive_Weighting_Mixing:

        adaptiveWeightingMixing(wav1_data,wav2_data,out_data,BLOCK_SIZE);

        break;

 

      default:

        break;

      }

      int samplesWritten = tinywav_write_f(&twWriter, out_data, BLOCK_SIZE);

    }

   

  }

 

  tinywav_close_read(&twReaderWav1);

  tinywav_close_read(&twReaderWav2);

  tinywav_close_write(&twWriter);

  return 0;

}

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值