PCM音频和音量调节

声音的本质是一种能量波,由振动而产生的能量波,通过传输介质传输出去。声音有三个属性:

  • 音调(Pitch):声音频率的高低。表示人的听觉分辨一个声音的调子高低的程度。音调主要由声音的频率决定,同时也与声音强度有关

  • 音量:人主观上感觉声音的大小,由“振幅”(amplitude)和人离声源的距离决定,振幅越大响度越大,人和声源的距离越小,响度越大。(单位:分贝dB)

  • 音色:又称声音的品质,波形决定了声音的音色。声音因不同物体材料的特性而具有不同特性,音色本身是一种抽象的东西,但波形是把这个抽象直观的表现。音色不同,波形则不同。典型的音色波形有方波,锯齿波,正弦波,脉冲波等。不同的音色,通过波形,完全可以分辨的。

波长是决定音调高低;振幅是决定音量高低;波纹是决定音色。

PCM(Pulse Code Modulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准数字音频数据。

描述PCM数据主要有以下6个参数:

  1. Sample Rate : 采样频率。8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。
  2. Sample Size : 量化位数,描述数字信号所使用的位数。8位(8bit)代表2的8次方=256,16 位(16bit)则代表2的16次方=65536;采样位数越高,精度越高。
  3. Number of Channels : 通道个数。常见的音频有立体声(stereo)和单声道(mono)两种类型,立体声包含左声道和右声道。另外还有环绕立体声等其它不太常用的类型。
  4. Sign : 表示样本数据是否是有符号位,比如用一字节表示的样本数据,有符号的话表示范围为-128 ~ 127,无符号是0 ~ 255。
  5. Byte Ordering : 字节序。字节序是little-endian还是big-endian。通常均为little-endian。
  6. Integer Or Floating Point : 整形或浮点型。大多数格式的PCM样本数据使用整形表示,而在一些对精度要求高的应用方面,使用浮点类型表示PCM样本数据。

对于16位,单声道的音频,采样点幅值为2^15-1-2^15,即32767-32768,当乘以放大倍数后,需要对超出此范围的数据进行溢出处理,但是如果一个音频帧中溢出数据过多,就会造成音频失真,故要合理的动态的选择放大倍数。

下面是两种对16位,单声道的音频调节音量算法

/*
 *samples 音频数据
 *numSamples   音频数据长度
 *factor	振幅的系数 比如1.2
 */
static int adjustmentVolume(short *samples,int numSamples,float factor)
{
    int tmpValue;
    if (0 == factor)
    {
        memset((void *)samples,0,numSamples*sizeof(short));
        return numSamples;
    }
	else if(1.0 == factor)
	{
		return numSamples;
	}
	
    for (int i = 0; i<numSamples; i++)
    {
        tmpValue = samples[i] * factor; //这样运算出来仍然是整数
        if(tmpValue < -32768)
        {
            tmpValue = -32768;
        }
        else if (tmpValue > 32767)
        {
            tmpValue = 32767;
        }
        samples[i] = tmpValue;
    }
    return numSamples;
}

 

/*
 *samples 音频数据
 *numSamples   音频数据长度
 *factor	振幅的系数 比如1.2
 */
int adjustmentVolume(short *samples ,int numSamples, int factor){
    const short MIND = -0x8000;
    const short MAXD = 0x7FFF;
    short data = 0, maxData = 0, minData = 0;
    //获取一个音频帧中的最大值`max`和最小值`min`
    for (int i = 0; i < numSamples; i++) {
        data = samples[i];
        maxData = maxData > data ? maxData : data;
        minData = minData < data ? minData : data;
    }
    //根据获取到的最大值和最小值分别计算出在不失真的情况下,允许的放大倍数`maxfactor`和`minfactor`
    short maxfactor =  maxData != 0 ? MAXD/maxData : 1;
    short minfactor =  minData != 0 ? MIND/minData : 1;
    
	//取其最小值为允许的放大倍数`allowfactor`
    short allowfactor = maxfactor > minfactor ? minfactor : maxfactor;
    //选择合适的振幅的系数
	factor = factor > allowfactor ? allowfactor : factor;
		
    if (factor == 1) {
        return numSamples;
    }
    else if(0 == factor)
    {
        memset((void *)samples,0,numSamples*sizeof(short));
        return numSamples;
    }
    //对PCM数据放大
    long newData = 0;
    for (int i = 0; i < numSamples; i++) {
        data = samples[i];
        newData = data*factor;
        //边界值溢出处理
        if (newData < MIND) {
            newData = MIND;
        }else if (newData > MAXD) {
            newData = MAXD;
        }
        data = newData&0xffff;
        samples[i] = data;
    }
	
	return numSamples;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值