我正在尝试创建音频表级别,同时使用 avaudiorecorder 录制用户语音。我可以尝试什么来实现这一目标?
实际上,代码非常简单,因为 AVAudioPlayer 和 AVAudioRecorder 已经内置了方法来帮助您上路。我的方法是这样的:
-updateMeters
和 averagePowerForChannel:
& peakPowerForChannel:
方法并调用委托方法来通知控制对象示例:
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
NSInvocationOperation *operation=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(updateMeter) object:nil];
[queue addOperation: operation];
和
-(void)updateMeter
{
do {
//don't forget:
[recorder updateMeters];
self.averagePower = [recorder averagePowerForChannel:0];
self.peakPower = [recorder peakPowerForChannel:0];
// we don't want to surprise a ViewController with a method call
// not in the main thread
[self.delegate performSelectorOnMainThread: @selector(meterLevelsDidUpdate:) withObject:self waitUntilDone:NO];
[NSThread sleepForTimeInterval:.05]; // 20 FPS
}while(someCondition);
}
如果您的视图控制器实现了
meterLevelsDidUpdate:
方法,您可以使用此方法来更新您的 Level Meter。
很简单,你可以使用 NSTimer 来实现:
- (void)startAudioMetering {
self.meterTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateAudioMeter)userInfo:nil repeats:YES];
}
- (void)stopAudioMetering {
[self.meterTimer invalidate];
}
- (void)updateAudioMeter { //called by timer
// audioRecorder being your instance of AVAudioRecorder
[self.audioRecorder updateMeters];
self.dBLevel = [self.audioRecorder averagePowerForChannel:0];
}
警告:创建 AVAudioRecorder 实例时,必须在调用prepareToRecord或record后调用meteringEnabled,否则不会更新Meters:
[self.audioRecorder prepareToRecord];
self.audioRecorder.meteringEnabled = YES;
Swift 代码基于 Tom 的答案:
NSOperationQueue().addOperationWithBlock({[weak self] in
repeat {
self?.audioRecorder.updateMeters()
self?.averagePower = self?.audioRecorder.averagePowerForChannel(0)
self?.peakPower = self?.audioRecorder.peakPowerForChannel(0)
self?.performSelectorOnMainThread(#selector(DictaphoneViewController.updateMeter), withObject: self, waitUntilDone: false)
NSThread.sleepForTimeInterval(0.05)//20 FPS
}
while (someCondition)
})
在里面做仪表 UI 的事情
func updateMeter(){//UI stuff here}
其实很简单, 您在缓冲区中获得的值有正有负(这就是波的工作原理),因此如果您对这些值求平均值,它将给您一个接近 0 的值。
因此,您要做的就是将所有值设为正值(使用 Math.abs() 函数),然后求平均值,它将返回声级。
希望这有帮助;)
interval:onScheduler:
:
返回一个信号,该信号在调度程序上的每个时间间隔发送当前日期/时间。
使用单个音频通道:
@weakify(self)
RACDisposable *metersDisposable = [[RACSignal // make sure you dispose it eventually
interval:0.1
onScheduler:[RACScheduler scheduler]]
subscribeNext:^(NSDate *) {
@strongify(self)
[recorder updateMeters];
auto averagePower = [recorder averagePowerForChannel:0];
auto peakPower = [recorder peakPowerForChannel:0];
// Inform the delegate or make other use of averagePower and peakPower
}];