引用自:Tutorial: Detecting When A User Blows Into The Mic

If, a couple of years back, you’d told me that people would expect to be able to shake their phone or blow into the mic to make something happen I would have laughed. And here we are.

Detecting a shake gesture is straightforward, all the more so in 3.0 with the introduction of motion events.

Detecting when a user blows into the microphone is a bit more difficult. In this tutorial we’ll create a simple simple single-view app that writes a log message to the console when a user blows into the mic.

Source/Github

The code for this tutorial is available on GitHub. You can either clone the repository or downloadthis zip.

Overview

The job of detecting when a user blows into the microphone is separable into two parts: (1) taking input from the microphone and (2) listening for a blowing sound.

We’ll use the new-in-3.0 AVAudioRecorder class to grab the mic input. Choosing AVAudioRecorder lets us use Objective-C without — as other options require — dropping down to C.

The noise/sound of someone blowing into the mic is made up of low-frequency sounds. We’ll use a low pass filter to reduce the high frequency sounds coming in on the mic; when the level of the filtered signal spikes we’ll know someone’s blowing into the mic.

Creating The Project

Launch Xcode and create a new View-Based iPhone application called MicBlow:

  1. Create a new project using File > New Project… from Xcode’s menu
  2. Select View-based Application from the iPhone OS > Application section, click Choose…
  3. Name the project as MicBlow and click Save

Adding The AVFoundation Framework

In order to use the SDK’s AVAudioRecorder class, we’ll need to add the AVFoundation framework to the project:

  1. Expand the Targets branch in the Groups & Files panel of the project
  2. Control-click or right-click the MicBlow item
  3. Choose Add > Existing Frameworks…
  4. Click the + button at the bottom left beneath Linked Libraries
  5. Choose AVFoundation.framework and click Add
  6. AVFoundation.framework will now be listed under Linked Libraries. Close the window

Next, we’ll import the AVFoundation headers in our view controller’s interface file and set up an AVAudioRecorder instance variable:

  1. Expand the MicBlow project branch in the Groups & Files panel of the project
  2. Expand the Classes folder
  3. Edit MicBlowViewController.h by selecting it
  4. Update the file. Changes are bold:

#import <UIKit/UIKit.h>

#import <AVFoundation/AVFoundation.h>

#import <CoreAudio/CoreAudioTypes.h>


@interface MicBlowViewController : UIViewController {

AVAudioRecorder *recorder;

}

@end

To save a step later, we also imported the CoreAudioTypes headers; we’ll need some of its constants when we set up the AVAudioRecorder.

Taking Input From The Mic

We’ll set everything up and start listening to the mic in ViewDidLoad:

  1. Uncomment the boilerplate ViewDidLoad method
  2. Update it as follows. Changes are bold:

- (void)viewDidLoad {

[super viewDidLoad];

  NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];

  NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:

    [NSNumber numberWithFloat: 44100.0],                 AVSampleRateKey,

    [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,

    [NSNumber numberWithInt: 1],                         AVNumberOfChannelsKey,

     [NSNumber numberWithInt: AVAudioQualityMax],         AVEncoderAudioQualityKey,

    nil];

  NSError *error;

  recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];

   if (recorder) {

  [recorder prepareToRecord];

  recorder.meteringEnabled = YES;

  [recorder record];

  } else

  NSLog([error description]);

}

The primary function of AVAudioRecorder is, as the name implies, to record audio. As a secondary function it provides audio-level information. So, here we discard the audio input by dumping it to the /dev/null bit bucket — while I can’t find any documentation to support it, the consensus seems to be that /dev/null will perform the same as on any Unix — and explicitly turn on audio metering.

Note: if you’re adapting the code for your own use, be sure to send the prepareToRecord (or,record) message before setting the meteringEnabled property or the audio level metering won’t work.

Remember to release the recorder in dealloc. Changes are bold:

- (void)dealloc {

[recorder release];

[super dealloc];

}

Sampling The Audio Level

We’ll use a timer to check the audio levels approximately 30 times a second. Add an NSTimerinstance variable and its callback method to it in MicBlowViewController.h. Changes are bold:

#import <UIKit/UIKit.h>

#import <AVFoundation/AVFoundation.h>

#import <CoreAudio/CoreAudioTypes.h>

@interface MicBlowViewController : UIViewController {

AVAudioRecorder *recorder;

NSTimer *levelTimer;

}

- (void)levelTimerCallback:(NSTimer *)timer;

@end

Update the .m file’s ViewDidLoad to enable the timer. Changes are bold:

- (void)viewDidLoad {

[super viewDidLoad];

NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];

NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:

[NSNumber numberWithFloat: 44100.0],                 AVSampleRateKey,

[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,

[NSNumber numberWithInt: 1],                         AVNumberOfChannelsKey,

[NSNumber numberWithInt: AVAudioQualityMax],         AVEncoderAudioQualityKey,

nil];

NSError *error;

recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];

if (recorder) {

[recorder prepareToRecord];

recorder.meteringEnabled = YES;

[recorder record];

levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES];

} else

NSLog([error description]);

}

For now, we’ll just sample the audio input level directly/with no filtering. Add the implementation oflevelTimerCallback: to the .m file:

- (void)levelTimerCallback:(NSTimer *)timer {

[recorder updateMeters];

NSLog(@"Average input: %f Peak input: %f", [recorder averagePowerForChannel:0],

}

Sending the updateMeters message refreshes the average and peak power meters. The meter use a logarithmic scale, with -160 being complete quiet and zero being maximum input.

Don’t forget to release the timer in dealloc. Changes are bold:

- (void)dealloc {

[levelTimer release];

[recorder release];

[super dealloc];

}

Listening For A Blowing Sound

As mentioned in the overview, we’ll be using a low pass filter to diminish high frequencies sounds’ contribution to the level. The algorithm creates a running set of results incorporating past sample input; we’ll need an instance variable to hold the results. Update the .h file. Changes are bold:

#import <UIKit/UIKit.h>

#import <AVFoundation/AVFoundation.h>

#import <CoreAudio/CoreAudioTypes.h>

@interface MicBlowViewController : UIViewController {

AVAudioRecorder *recorder;

NSTimer *levelTimer;

double lowPassResults;

}

Implement the algorithm by replacing the levelTimerCallback: method with:

- (void)levelTimerCallback:(NSTimer *)timer {

[recorder updateMeters];

const double ALPHA = 0.05;

double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));

lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;

NSLog(@"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults);

}

Each time the timer’s callback method is triggered the lowPassResults level variable is recalculated. As a convenience, it’s converted to a 0-1 scale, where zero is complete quiet and one is full volume.

We’ll recognize someone as having blown into the mic when the low pass filtered level crosses a threshold. Choosing the threshold number is somewhat of an art. Set it too low and it’s easily triggered; set it too high and the person has to breath into the mic at gale force and at length. For my app’s need, 0.95 works. We’ll replace the log line with a simple conditional:

- (void)listenForBlow:(NSTimer *)timer {

[recorder updateMeters];

const double ALPHA = 0.05;

double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));

lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;

if (lowPassResults > 0.95)

NSLog(@"Mic blow detected");

}

Voila! You can detect when someone blows into the mic.

Caveats and Acknowledgements

This approach works well in most situations, but not universally: I’m writing this article in-flight. The roar of the engines constantly triggers the algorithm. Similarly, a noisy room will often have enough low-frequency sound to trigger the algorithm.

The algorithm was extracted/adapted from this Stack Overflow post. The post used theSCListener library for its audio level detection. SCListener pre-dates AVAudioRecorder; it was created to hide the details of dropping down to C to get audio input. With AVAudioRecorder this is no longer so tough.

Finally, this does work on the simulator. You just need to locate the built in mic on your Mac. To my surprise, the mic is located in the tiny hole to the left of the camera on my first generation Macbook.

Photo credit: http://www.flickr.com/photos/clickflashphotos/2744443467/

Similar articles:

  • Optimizing Your Tutorial – Setting The Table for an Effective Tutorial
  • Optimizing Your Mobile Tutorial – A Freemium Game Series
  • Must Read Interview with David Appleyard, Author of iPhone App Entrepreneur
  • Interview with AppifyWP creator and UX expert Cory Shaw

iOS麦克风运用——腾讯微博“吹一吹”相关推荐

  1. 任正非:华为的岗位没有年龄限制;腾讯微博将于9月28日停止运营;微软关闭Visual Studio Online|极客头条

    「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 国内要闻 腾讯微博将于9月28日停止运营 腾讯微博日前发布官 ...

  2. 腾讯微博android版本,腾讯微博 Android版

    腾讯微博这是专为Android用户打造的腾讯微博手机客户端,让您随时随地与亿万微博用户分享生活和资讯.腾讯微博Android客户端,专为Android用户打造,让您随时随地与亿万微博用户分享生活和资讯 ...

  3. 腾讯微博android版本,腾讯微博下载2017手机版下载-腾讯微博 安卓版v6.1.2-PC6安卓网...

    微博这东西小编就这么喜欢而已.不管是sina还是qq,丢不掉,逃不了.腾讯家的还不错.关联的朋友很多,总能在这里面找到熟悉的东西,QQ牵连的很强大 功能介绍 专为Android用户打造的腾讯微博手机客 ...

  4. HBuilder webApp开发(七)微信/QQ/新浪/腾讯微博分享

    HBuilder是支持微信分享(好友和朋友圈),QQ分享,新浪微博和腾讯微博分享. 但是在使用的过程中,官方给的文档似乎很坑爹. <分享插件配置> <分享插件开发指南> 都是2 ...

  5. android模仿腾讯微博客户端

    最近做了一个简单的腾讯微博,在这里分享给大家. 首先你需要去腾讯微博开放平台申请App Key 和 App Secret 1.搜索腾讯微博开放平台: 2.打开腾讯微博开放平台(http://dev.t ...

  6. 腾讯微博android版本,腾讯微博下载2021-腾讯微博app最新版本下载-腾讯微博下载安装...

    使用相关 腾讯微博怎么批量删除微博   批量删除方法 随着腾讯用户的增多,腾讯微博使用者的数量也逐渐增多,越来越多的人开始在微博中实时发布并记录自己的动态,或者进入微博关注自己感兴趣的发布者,由于腾讯 ...

  7. 腾讯微博API时间线相关接口返回的微博信息中head值使用问题

    腾讯微博API时间线相关接口返回的微博信息中head值表示作者头像url,这个链接直接访问并不能使用,需要再附加一个参数指定图片的大小(100.50),比如:[head]/100.

  8. 腾讯微博快速有效增加广播转播量的方法与技巧

    经过一段时间对腾讯微博的实践,对腾讯微博也算是有所收获,要做好腾讯微博,无非就是两个方面,一是增加听众数,二是增加广播的转播量,本篇写的是做好微博质量–即增加转播量的方法. 增加转播量不像增加听众数那 ...

  9. web-QQ(腾讯)-Email-TMessage(腾讯微博记事本)

    专题图编号:ylbtechOpenSource 1,功能描述 2,技术与环境 操作系统: windows 开发语言: C# 开发框架:   数据库: 无 开发软件: Microsoft Visual ...

  10. 腾讯微博即将关停,十年了,你用过吗?

    作者 | 李雪敬 出品 | 程序人生(ID:coder_life) 9月5日,腾讯微博宣布称将于9月28日停止运营和服务,届时将无法登陆,同时提醒用户可在腾讯微博关停前备份好个人的相关信息. 腾讯微博 ...

最新文章

  1. AI一分钟|腾讯AI绝艺让二子,仍战胜柯洁;Google与腾讯达成专利交叉授权许可协议
  2. 模拟电路技术之基础知识(一)
  3. 国二计算机考试技巧,全国计算机等级考试上机考试应试技巧(二)
  4. 《统计学习方法》(李航)读书笔记(转)
  5. Android标签库,JSP Struts之HTML标签库详解 _Android/移动互联网/物联网/_夜鹰教程网...
  6. [20160229]探究oracle的启动过程.txt
  7. 系统提示“无法删除文件,无法读取源文件或磁盘”的解决办法
  8. Oracle配置本地网络服务器测试不成功,无监听程序
  9. Codeforces407C Curious Array
  10. java实现Selenium自动化测试web
  11. wchar to char转换
  12. Win10任务栏总是弹出推荐Edge浏览器广告的解决方法
  13. C# CultureInfo中常用的InvariantCulture
  14. JSP实习实训管理系统myeclipse开发mysql数据库WEB结构java编程
  15. html程序员表白前端网页源码
  16. 基于javaweb的校园机房管理平台的设计与实现(毕业设计论文+程序源码)
  17. hive1.2.1实战操作电影大数据!
  18. 《怎样在股市获得稳健收益》精品课笔记
  19. 数据结构课程设计图书管理系统,C语言版。
  20. 实现科汛CMS在首页和栏目页或内容页调用专题文章名+栏目名+链接

热门文章

  1. 大话数据结构 —— 2.9 算法时间复杂度(合集)
  2. python爬虫(十三)selenium(Selenium入门、chromedriver、Phantomjs)
  3. 智能药盒的设计与实现
  4. 如何做出优雅的过渡效果? Dotween插件的简单介绍及示例代码
  5. 【渝粤教育】国家开放大学2018年秋季 0284-21T外国文学 参考试题
  6. Python中的turtle.right()方法的用法示例
  7. 阿里巴巴校招内推一面总结
  8. 平安科技软件+金山WPS测试面试题
  9. Angel investor
  10. 3-Coloring(奇偶涂色)