20160825音频开发之AVAudioRecoder

来源:互联网 发布:osiris数据库 编辑:程序博客网 时间:2024/06/01 10:13

上一篇博文介绍了一下AVAudioPlayer,本文分享一下我学习AVAudioRecoder录制音频的相关内容。

打开你的iPhone,自带一个录音功能的应用---语音备忘录,界面简洁,功能很给力。即时通信软件,发送语音消息应该是常用的功能,目前一些K歌App也有录音这个功能,所以在开发中AVAudioRecorder也是比较重要的,高效灵活的使用还是很有必要的。


我下载过几款很棒的音频应用,比如全民K歌,弹琴吧,我可以用弹琴吧调试我的吉他,这个功能很强大,我再也不用我的调音器了。还有全民K歌,这款软件最强大功能是评分,其中有个细节引起我的注意。根据我的声音的强度的高低绘制不同的曲线,我在思考这个功能是如何实现的。今天找到了答案,通过 Metering(声音计量),可以通过这个技术将声音信号转化,以可视化的形式呈现。


AVAudioRecorder 有两个方法返回声音的分贝值。

- (float)peakPowerForChannel:(NSUInteger)channelNumber; /* returns peak power in decibels for a given channel */- (float)averagePowerForChannel:(NSUInteger)channelNumber; /* returns average power in decibels for a given channel */

分贝值有个计算公式应该是 db = 10lgM (M表示声音强度吧),目前我们通过上面的两个函数得到db,平均分贝,峰值分贝。

我们希望将前面得到的分贝值的结果转化我线性的0到1形式,这需要一个转化的方式,如果我们把一次计算的结果记录下来,那么下次的计算就不需要了,因此提供下面的一个方法

#define MIN_DB -60.0f#define TABLE_SIZE 300@implementation THMeterTable {    float _scaleFactor;    NSMutableArray *_meterTable;}- (id)init {    self = [super init];    if (self) {        float dbResolution = MIN_DB / (TABLE_SIZE - 1);        _meterTable = [NSMutableArray arrayWithCapacity:TABLE_SIZE];        _scaleFactor = 1.0f / dbResolution;        float minAmp = dbToAmp(MIN_DB);        float ampRange = 1.0 - minAmp;        float invAmpRange = 1.0 / ampRange;        for (int i = 0; i < TABLE_SIZE; i++) {            float decibels = i * dbResolution;            float amp = dbToAmp(decibels);            float adjAmp = (amp - minAmp) * invAmpRange;            _meterTable[i] = @(adjAmp);        }    }    return self;}float dbToAmp(float dB) {    return powf(10.0f, 0.05f * dB);}- (float)valueForPower:(float)power {    if (power < MIN_DB) {        return 0.0f;    } else if (power >= 0.0f) {        return 1.0f;    } else {        int index = (int) (power * _scaleFactor);        return [_meterTable[index] floatValue];    }}@end

该类的主要的功能是:

//It creates an internal table storing the precomputed db -> linear

// values.

其中关键是_meterTable 保存一个列表

-(float)valueForPower:(float)power

这个接口提供查询。

接着是界面上的转化,重新绘制,或许要用到定时器,进行轮询。可以考虑用这个CADisplayLink作为解决方案。参考下面这段代码


    self.levelTimer = [CADisplayLink displayLinkWithTarget:self                                                  selector:@selector(updateMeter)];    self.levelTimer.frameInterval = 5;    [self.levelTimer addToRunLoop:[NSRunLoop currentRunLoop]                          forMode:NSRunLoopCommonModes];


其中要主要frameInterval这个参数,参考文档

/* Defines how many display frames must pass between each time the

 * display link fires. Default value is one, which means the display

 * link will fire for every display frame. Setting the interval to two

 * will cause the display link to fire every other display frame, and

 * so on. The behavior when using values less than one is undefined. *


我的理解:如果是默认,定时器的刷新率是屏幕的刷新同步,应该是每秒60次,如果设置frameInterval = 5,则刷新率应该是 60 / 5 = 12。


本文 

   完!







0 0