经常有人问我如何计算录音时音量大小。iOS平台是有api可以直接调用的,但是Android平台上没有比较好的办法,因此我们就不得不自己计算了。


之所以有计算音量这个需求,是因为很多应用希望根据音量的大小实现一些动画效果。因此,从这个需求出发,只要能根据说话时声音的大小,获取到的音量值有变化即可,而不必过分纠缠于到底范围多少才是准确的。因为计算的方法有很多种,不同的方法计算出来的值肯定是不同的,但是只要能反映出大小变化,我们的目的就达到了。


下面我以Android录音为例,介绍一下其中的一种计算方法。大家可以根据自己的需要重新计算,或者是对我这个计算出来的值做一些数学变换,从而满足自己的需要。


需要提前说明的是,网上也有类似的一些计算方法,但是千万不能照搬过来,因为这个和录音的编码和录音数据的类型是有关系的。


录音的编码主要有两种:8位pcm和16位pcm。8位pcm用一个字节表示语音的一个点,16位pcm用两个字节,也就是一个short来表示语音的一个点。需要特别注意的是,如果你用的16位pcm编码,而取录音数据用的是byte的话,需要自己将两个bye转换成一个short。将两个byte转换成一个short,有小端和大端两种,一般默认情况都是小端,但是有的开源库,比如lamemp3需要的就是大端,这个要根据不同的情况进行不同的处理。


下面以Android为例,介绍一下用平均值计算音量的方法。


private double calculateVolume(short[] buffer){

double sumVolume = 0.0;

double avgVolume = 0.0;

double volume = 0.0;

for(short b : buffer){

sumVolume += Math.abs(b);

}

avgVolume = sumVolume / buffer.length;

volume = Math.log10(1 + avgVolume) * 10;

return volume;

}


这个方法传递的是short类型的数据,所以录音的编码肯定是16位pcm,这样可以直接计算而不需要转换了。相信大家都听过声波这个东西,大家用音频编辑软件Adobe audition 打开一段声音:



从这里我们可以看到,声音是高低起伏变化的,有波峰波谷,说白了就是有正有负。因此在计算的时候,我们需要先求绝对值,要不然就上下抵消。求完绝对值然后进行累加,再除以整个数据的长度,就得到了这段语音数据的平均值了。


但是这样直接计算出来的结果比较大,不利于我们使用,因此对它进行了取对数再乘以10:


volume = Math.log10(1 + avgVolume) * 10;


这些可以根据自己的需要进行运算,我这边只是一个简单的例子。


还有一个特别需要注意的问题是:如果你录音的编码是16为pcm,而录音数据数据是byte,需要将两个byte转为一个short进行处理,建议用小端的方式。


private doublecalculateVolume(byte[] buffer){

double sumVolume = 0.0;

double avgVolume = 0.0;

double volume = 0.0;

for(int i = 0; i < buffer.length; i+=2){

int v1 = buffer[i] & 0xFF;

int v2 = buffer[i + 1] & 0xFF;

int temp = v1 + (v2 << 8);// 小端

if (temp >= 0x8000) {

temp = 0xffff - temp;

}

sumVolume += Math.abs(temp);

}

avgVolume = sumVolume / buffer.length / 2;

volume = Math.log10(1 + avgVolume) * 10;

return volume;

}


关于用小端的方式,将两个byte转为一个short的那些移位运算,应该不难,这里不做过多的解释了。


以上就是用平均值的方法计算音量大小的方法,但是在iOS中,你自己不需要计算了,直接调用系统的api即可。


iOS获取录音是系统音量的步骤:


1、在开始录音之前,要设置获取系统音量的属性


// 设置获取音量大小的属性

UInt32 enabledLevelMeter = true;

AudioQueueSetProperty(_audioQueue, kAudioQueueProperty_EnableLevelMetering, &enabledLevelMeter, sizeof(UInt32));


2、调用系统api获取音量,此方法可以在 缓冲器的回调函数中调用,也可以自己用一个定时器来调用


AudioQueueLevelMeterState levelMeter;

UInt32 levelMeterSize = sizeof(AudioQueueLevelMeterState);

AudioQueueGetProperty(_audioQueue, kAudioQueueProperty_CurrentLevelMeterDB, &levelMeter, &levelMeterSize);

double volume = levelMeter.mAveragePower


当然,你如果不想用系统的音量值,也可以像上面那样自己计算,这取决于你的需要。


最后我把android的获取录音音量大小的demo上传到附件中了,大家可以参考。

更多相关文章

  1. Android(安卓)基础知识之 VelocityTracker使用(提供手指速度计算,
  2. Android游戏编程之音频编程
  3. Android视频编辑器(五)音频编解码、从视频中分离音频、音频混音、
  4. Android实时获取音量(单位:分贝)
  5. Android(安卓)监听系统媒体音量变化
  6. 说说Android桌面(Launcher应用)背后的故事(七)——又是一个附属
  7. 获取mic音量大小
  8. RingTest
  9. Android(安卓)Audio代码分析14 - testPlaybackHeadPositionIncre

随机推荐

  1. Android开发环境的搭建步骤
  2. Android(安卓)Studio(十一):代码混淆及打
  3. android音频、视频、拍照基础操作
  4. android 中遥控器键值的添加和修改
  5. android通知栏消息
  6. Android开发:Android快速开发不可或缺的11
  7. 复习TextView(查漏补缺)
  8. 移植rtmpdump(librtmp)到android
  9. Java/Android引用类型及其使用分析
  10. Android保存图片到系统相册