音频混音算法的实现



1、线性叠加后求平均

优点:不会产生溢出,噪音较小;

缺点:衰减过大,影响通话质量;

1
2
3
4
5
short  remix(short buffer1,short buffer2)
{
    int value = buffer1 + buffer2;
    return (short)(value/2);
}

2、归一化混音(自适应加权混音算法)

思路:使用更多的位数(32 bit)来表示音频数据的一个样本,混完音后在想办法降低其振幅,使其仍旧分布在16 bit所能表示的范围之内,这种方法叫做归一法;

方法:为避免发生溢出,使用一个可变的衰减因子对语音进行衰减。这个衰减因子也就代表语音的权重,衰减因子随着音频数据的变化而变化,所以称为自适应加权混音。当溢出时,衰减因子较小,使得溢出的数据在衰减后能够处于临界值以内,而在没有溢出时,又让衰减因子慢慢增大,使数据较为平缓的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void Mix(char sourseFile[10][SIZE_AUDIO_FRAME],int number,char *objectFile)
{
    //归一化混音
    int const MAX=32767;
    int const MIN=-32768;
 
    double f=1;
    int output;
    int i = 0,j = 0;
    for (i=0;i<SIZE_AUDIO_FRAME/2;i++)
    {
        int temp=0;
        for (j=0;j<number;j++)
        {
            temp+=*(short*)(sourseFile[j]+i*2);
        }                
        output=(int)(temp*f);
        if (output>MAX)
        {
            f=(double)MAX/(double)(output);
            output=MAX;
        }
        if (output<MIN)
        {
            f=(double)MIN/(double)(output);
            output=MIN;
        }
        if (f<1)
        {
            f+=((double)1-f)/(double)32;
        }
        *(short*)(objectFile+i*2)=(short)output;
    }
}

3、Symbian6.1上实现的混音是个比较麻烦的问题,因为程序只能同时播放一个音乐,实现混音就需要程序自己来实现。下面是我从newlc上找到的一个关于PCM脉冲编码的音频信号的混音实现,其中包含了一个关键的混音算法!

1
2
3
4
if( data1 < 0 && data2 < 0)
    date_mix = data1+data2 - (data1 * data2 / -(pow(2,16-1)-1));
else
    date_mix = data1+data2 - (data1 * data2 / (pow(2,16-1)-1));

4、切割时间片,重采样算法

可以把各个通道的声音叠到一起,让声音的采样率按倍增加,如果提高声音的播放频率,声音可以正常的播放,声音实现了叠加;如果不想修改声音的播放输出频率,可以通过声音的重采样后输出自己想要的输出频率;


5、下面是上面的混音的测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
#define IN_FILE1 "1.wav"
#define IN_FILE2 "2.wav"
#define OUT_FILE "remix.pcm"
 
#define SIZE_AUDIO_FRAME (2)
 
void Mix(char sourseFile[10][SIZE_AUDIO_FRAME],int number,char *objectFile)
{
    //归一化混音
    int const MAX=32767;
    int const MIN=-32768;
 
    double f=1;
    int output;
    int i = 0,j = 0;
    for (i=0;i<SIZE_AUDIO_FRAME/2;i++)
    {
        int temp=0;
        for (j=0;j<number;j++)
        {
            temp+=*(short*)(sourseFile[j]+i*2);
        }                
        output=(int)(temp*f);
        if (output>MAX)
        {
            f=(double)MAX/(double)(output);
            output=MAX;
        }
        if (output<MIN)
        {
            f=(double)MIN/(double)(output);
            output=MIN;
        }
        if (f<1)
        {
            f+=((double)1-f)/(double)32;
        }
        *(short*)(objectFile+i*2)=(short)output;
    }
}
 
int main()
{
    FILE * fp1,*fp2,*fpm;
    fp1 = fopen(IN_FILE1,"rb");
    fp2 = fopen(IN_FILE2,"rb");
    fpm = fopen(OUT_FILE,"wb");
     
    short data1,data2,date_mix;
    int ret1,ret2;
    char sourseFile[10][2];
 
    while(1)
    {
        ret1 = fread(&data1,2,1,fp1);
        ret2 = fread(&data2,2,1,fp2);
        *(short*) sourseFile[0] = data1;
        *(short*) sourseFile[1] = data2;
         
        if(ret1>0 && ret2>0)
        {
            Mix(sourseFile,2,(char *)&date_mix);
            /*
            if( data1 < 0 && data2 < 0)
                date_mix = data1+data2 - (data1 * data2 / -(pow(2,16-1)-1));
            else
                date_mix = data1+data2 - (data1 * data2 / (pow(2,16-1)-1));*/
                 
            if(date_mix > pow(2,16-1) || date_mix < -pow(2,16-1))
                printf("mix error\n");
        }
        else if( (ret1 > 0) && (ret2==0))
        {
            date_mix = data1;
        }
        else if( (ret2 > 0) && (ret1==0))
        {
            date_mix = data2;
        }
        else if( (ret1 == 0) && (ret2 == 0))
        {
            break;
        }
        fwrite(&date_mix,2,1,fpm);
    }
    fclose(fp1);
    fclose(fp2);
    fclose(fpm);
    printf("Done!\n");
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值