如果一对夫妇几年前,你告诉我,人们会想到要对着麦克风能够撼动他们的电话或打击,使事情发生,我会笑。我们在这里。
检测一摇手势是直接的,更何况在3.0中引入的运动事件。
检测是一个比较困难的,当用户对着麦克风打击。在本教程中,我们将创建一个简单的简单的单一视图写入日志消息到控制台的应用程序,当用户对着麦克风打击。
来源/ Github上
本教程中的代码是可以在GitHub上。您可以克隆你的仓库或下载这个zip。
概观
检测当用户对着麦克风吹作业分成两部分:(1)从麦克风输入及(2)为发泡剂的声音听。
我们将使用新的3.0 AVAudioRecorder
类,抢麦克风输入。选择AVAudioRecorder让我们使用的Objective-C没有-其他选项-下降到C
有人吹入麦克风噪音/声音是由低频率的声音。我们将使用一个低通滤波器,以减少高频率声音的麦克风,滤波后的信号尖峰时,我们就知道有人对着麦克风吹。
创建项目
启动Xcode和创建一个新的基于视图的iPhone应用程序称为MicBlow的:
- 从Xcode的菜单中创建一个新的项目,使用“文件”>“新建项目...
- 选择基于视图的应用程序的iPhone OS应用部分,单击“ 选择...
- 将项目命名为为MicBlow,单击“ 保存“
加入AVFoundation框架
为了使用SDK的AVAudioRecorder类,我们将需要添加的AVFoundation框架的项目:
- 在项目组和文件面板,展开“ 目标分支
- 控制单击或右键单击的MicBlow项目
- 选择添加>现有框架...
- 点击下方链接库的左下角的+按钮
- 选择“ AVFoundation.framework“,并单击“ 添加“
- 现在将AVFoundation.framework 链接库下上市。关闭窗口
下一步,我们将在我们的视图控制器的接口文件导入AVFoundation头高达一个AVAudioRecorder实例变量设置:
- 在项目组和文件面板展开的MicBlow项目分支
- 展开“ 类“文件夹中
- 通过选择, 编辑MicBlowViewController.h
- 更新文件。变化是大胆的:
#导入<UIKit/UIKit.h>的 进口<AVFoundation/AVFoundation.h>#导入<CoreAudio/CoreAudioTypes.h>@接口MicBlowViewController的UIViewController {AVAudioRecorder *记录;}@结束
要保存步骤后,我们也进口的CoreAudioTypes
头,我们需要一些常数时,我们成立了AVAudioRecorder
。
以从麦克风输入
我们将设置一切,并开始听麦克风在viewDidLoad:
- 取消对样板viewDidLoad中的方法
- 更新如下。变化是大胆的:
- (无效)viewDidLoad中{ [超级viewDidLoad中]; NSURL * URL = [NSURL fileURLWithPath:@“/ dev / null的”]; NSDictionary中设置= [的NSDictionary dictionaryWithObjectsAndKeys的: 的NSNumber numberWithFloat:44100.0,AVSampleRateKey 的NSNumber numberWithInt:kAudioFormatAppleLossless] AVFormatIDKey 的NSNumber numberWithInt:1],AVNumberOfChannelsKey 的NSNumber numberWithInt:AVAudioQualityMax] AVEncoderAudioQualityKey 零; NSError *错误; 录音机= [AVAudioRecorder ALLOC] initWithURL:URL设置:设置错误:错误]; (录像机){ [录像机prepareToRecord; recorder.meteringEnabled = YES; [录音机记录]; 其他 NSLog的([错误描述]);}
AVAudioRecorder
的主要功能是,正如其名称所暗示的,录制音频。作为一个辅助功能,它提供了音频级别的信息。所以,在这里,我们丢弃的音频输入通过转储到/ dev / null的比特斗-虽然我不能找到任何文件,以支持它,共识似乎是/ dev / null的执行一样,在任何Unix -明确打开音频计量。
注:如果你适应代码供自己使用,一定要发送prepareToRecord的
消息之前(或记录
)设置meteringEnabled
财产或音频电平表将无法正常工作。
记住要释放的dealloc
录音机。变化是大胆的:
- (无效)的dealloc { [录音机释放]; [超级的dealloc];}
采样的音频电平
我们将使用一个定时器检查音频水平约30次。的NSTimer
实例变量和它的回调方法添加到它在MicBlowViewController.h。变化是大胆的:
#导入<UIKit/UIKit.h>“#导入<AVFoundation/AVFoundation.h>#导入<CoreAudio/CoreAudioTypes.h>@接口MicBlowViewController的UIViewController { AVAudioRecorder *记录;的NSTimer *水平小时;} - (无效)水平时回电:(的NSTimer *)小时;@结束
更新。m文件的viewDidLoad中
启用定时器。变化是大胆的:
- (无效)viewDidLoad中{ [超级viewDidLoad中]; NSURL * URL = [NSURL fileURLWithPath:@“/ dev / null的”]; NSDictionary中设置= [的NSDictionary dictionaryWithObjectsAndKeys的: 的NSNumber numberWithFloat:44100.0,AVSampleRateKey 的NSNumber numberWithInt:kAudioFormatAppleLossless] AVFormatIDKey 的NSNumber numberWithInt:1],AVNumberOfChannelsKey 的NSNumber numberWithInt:AVAudioQualityMax] AVEncoderAudioQualityKey 零; NSError *错误; 录音机= [AVAudioRecorder ALLOC] initWithURL:URL设置:设置错误:错误]; (录像机){ [录像机prepareToRecord; recorder.meteringEnabled = YES; [录音机记录]; [levelTimer =的NSTimer scheduledTimerWithTimeInterval的:0.03目标:自我选择:选择器(levelTimerCallback :) USERINFO的:无重复:YES]; 其他 NSLog的([错误描述]);}
现在,我们就品尝直接/无过滤音频输入电平。执行添加levelTimerCallback
。m文件:
- (无效)水平时回电:(的NSTimer *){小时 [录音机updateMeters的]; NSLog的(@“平均输入:%F峰值输入:%F”,[录音机averagePowerForChannel:0],[录音机peakPowerForChannel的:0]);}
发送updateMeters的
消息刷新平均功率和峰值功率计。仪表使用对数刻度,-160是完整的安静和零为最大输入。
不要忘了释放的dealloc
定时器。变化是大胆的:
- (无效)的dealloc { [levelTimer释放]; [录音机释放]; [超级的dealloc];}
听声音吹
概述中提到,我们会使用一个低通滤波器,以减少高频率声音的贡献水平。该算法创建一个运行组的结果,结合过去的样本输入;我们需要一个实例变量来保存结果。更新。h文件。变化是大胆的:
#导入<UIKit/UIKit.h>“#导入<AVFoundation/AVFoundation.h>#导入<CoreAudio/CoreAudioTypes.h>@接口MicBlowViewController的UIViewController { AVAudioRecorder *记录; 的NSTimer *水平小时;双lowPassResults;}
实现该算法通过更换levelTimerCallback
方法:
- (无效)水平时回电:(的NSTimer *){小时 [录音机updateMeters的]; 常量双ALPHA = 0.05; 双peakPowerForChannel = POW(10,(0.05 * [录音机peakPowerForChannel的:0])); lowPassResults = ALPHA * peakPowerForChannel +(1.0 - ALPHA)* lowPassResults; NSLog的(@“平均输入:%F峰值输入:%F低通结果:%F”,[录音机averagePowerForChannel:0],[录音机peakPowerForChannel的:0],lowPassResults);}
每次触发定时器的回调方法的lowPassResults
水平重新计算变量。为方便起见,它转换成一个0-1的规模,其中零完整的安静,一个是全卷。
我们会承认有人为吹入麦克风时的低通滤波水平越过一个门槛。选择阈值数量在某种程度上是一门艺术。设置太低了,它很容易触发设置过高而该人在对着麦克风呼吸在烈风长度的。对于我的应用程序的需要,0.95工程。一个简单的条件,我们将更换日志行:
- (无效)listenForBlow:(的NSTimer *){小时 [录音机updateMeters的]; 常量双ALPHA = 0.05; 双peakPowerForChannel = POW(10,(0.05 * [录音机peakPowerForChannel的:0])); lowPassResults = ALPHA * peakPowerForChannel +(1.0 - ALPHA)* lowPassResults;(lowPassResults> 0.95) NSLog的(@“麦克风打击检出”);}
瞧!对着麦克风,您可以检测到有人打击。
警告和致谢
在大多数情况下,这种方法效果很好,但并不普遍:在飞行中,我写这篇文章的。发动机的轰鸣声不断触发算法。同样,一个嘈杂的房间往往会产生足够的低频声音触发算法。
算法提取/改编自这个堆栈溢出后。后采用其音频电平检测的SCListener库。SCListener日期前AVAudioRecorder;创建它下降到C来获取音频输入隐藏的细节。随着AVAudioRecorder不再那么艰难。
最后,这确实在模拟器上工作。你只需要找到你的Mac上内置的麦克风。我惊讶的是,麦克风的位置在我的第一代的MacBook在相机左侧的小孔。