2016.4.17 追記:Swift版を書きました
Core Audioを使用して、マイクから音を検知する方法をメモしておきます。
実装方法
ヘッダをインポートします。
#import <AudioToolbox/AudioToolbox.h>
音声入力用のキューと監視タイマーを準備しておきます。
@interface AudioViewController : UIViewController { AudioQueueRef _queue; // 音声入力用のキュー NSTimer *_timer; // 監視タイマー }
記録するデータフォーマットを決めます。
AudioStreamBasicDescription dataFormat; dataFormat.mSampleRate = 44100.0f; dataFormat.mFormatID = kAudioFormatLinearPCM; dataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; dataFormat.mBytesPerPacket = 2; dataFormat.mFramesPerPacket = 1; dataFormat.mBytesPerFrame = 2; dataFormat.mChannelsPerFrame = 1; dataFormat.mBitsPerChannel = 16; dataFormat.mReserved = 0;
▼各項目の意味
データ型 | メンバ名 | 意味 |
---|---|---|
Float64 | mSampleRate | サンプリング周波数(1秒間のフレーム数) |
UInt32 | mFormatID | フォーマットID(リニアPCM、MP3、AACなど) |
UInt32 | mFormatFlags | フォーマットフラグ(エンディアン、整数or浮動小数点数) |
UInt32 | mBytesPerPacket | 1パケット(データを読み書きする単位)のバイト数 |
UInt32 | mFramesPerPacket | 1パケットのフレーム数 |
UInt32 | mBytesPerFrame | 1フレームのバイト数 |
UInt32 | mChannelsPerFrame | 1フレームのチャンネル数 |
UInt32 | mBitsPerChannel | 1チャンネルのビット数 |
UInt32 | mReserved | ? |
音の監視を開始します。
AudioQueueNewInput(&dataFormat, AudioInputCallback, (__bridge void *)(self), CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_queue); AudioQueueStart(_queue, NULL);
今回は音を検知するだけで、録音の必要はないので AudioInputCallback
は空にしておきます。
static void AudioInputCallback( void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions, const AudioStreamPacketDescription *inPacketDescs) { }
マイクのレベルを取得できるように、レベルメータを有効化しておきます。
UInt32 enabledLevelMeter = true; AudioQueueSetProperty(_queue, kAudioQueueProperty_EnableLevelMetering, &enabledLevelMeter, sizeof(UInt32));
一定時間ごとにマイクレベルを監視します。ここでは NSTimer
を使用しました。
_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(detectVolume:) userInfo:nil repeats:YES];
一定時間ごとにレベルを取得して、画面に表示します。
- (void)detectVolume:(NSTimer *)timer { // レベルを取得 AudioQueueLevelMeterState levelMeter; UInt32 levelMeterSize = sizeof(AudioQueueLevelMeterState); AudioQueueGetProperty(_queue, kAudioQueueProperty_CurrentLevelMeterDB, &levelMeter, &levelMeterSize); // 最大レベル、平均レベルを表示 self.peakTextField.text = [NSString stringWithFormat:@"%.2f", levelMeter.mPeakPower]; self.averageTextField.text = [NSString stringWithFormat:@"%.2f", levelMeter.mAveragePower]; }
通常、mPeakPower
、mAveragePower
には負の値がセットされており、音量に比例して値も大きくなっていきます。最大値は 0 になります。
最後に忘れずにキューを空にして停止します。
AudioQueueFlush(_queue); AudioQueueStop(_queue, NO); AudioQueueDispose(_queue, YES);
サンプルコード
注意点
- ユーザがマイクの使用を許可していない場合、音の検知はできません
応用できそうなアプリ
- 声や拍手などに反応するゲームアプリなど
- iPhoneに息を吹きかけると何かがめくれるアプリ(実際にありましたねw)