A Day In The Life

とあるプログラマの備忘録

AVAudioRecorder の基本的な使い方

AVAudioRecorder クラスの日本語の情報があまりなくて実装するときに結構ハマったので実装方法をまとめておきます。

オーディオ情報の設定

まずアプリでオーディオのどのような機能(再生とか録音)を使うかを設定します。AVAudioSession クラスの setCategory メソッドを使って設定します。このコードは UIApplicationDelegate の実装クラスあたりに書いておくのがいいと思います。

@implementation HogeAppDelegate
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  AVAudioSession *audioSession = [AVAudioSession sharedInstance];
  NSError *error = nil;
  // 使用している機種が録音に対応しているか
  if ([audioSession inputIsAvailable]) {
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
  }
  if(error){
    NSLog(@"audioSession: %@ %d %@", [error domain], [error code], [[error userInfo] description]);
    return;
  }
  // 録音機能をアクティブにする
  [audioSession setActive:YES error:&error];
  if(error){
    NSLog(@"audioSession: %@ %d %@", [error domain], [error code], [[error userInfo] description]);
    return;
  }
}
@end

録音処理

AVAudioRecorder クラスのインスタンスを生成するときに録音データの保存場所を指定します。record メソッドで録音開始、stop メソッドで録音終了します。録音で使用したファイルは何もしなければそのまま保存されます。録音ファイルを削除したい時は deleteRecording メソッドを使うと削除できます。
また meteringEnabled プロパティを YES にすると録音中に音量を取ることができます。

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
@interface RecordingViewController : UIViewController <AVAudioRecorderDelegate> {
  AVAudioRecorder *recorder;
}
@end
// ここを間違えると実機で動作しなくなるので注意!!!
#define DocumentsFolder [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]
@implementation RecordingViewController
- (void)viewDidLoad {
  // 録音データを保存する場所
  NSString *path = [NSString stringWithFormat:@"%@/ファイル名.caf",
      DocumentsFolder];
  NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
  // 録音の設定 AVNumberOfChannelsKey チャンネル数1
  NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
      [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
      [NSNumber numberWithInt: kAudioFormatLinearPCM], AVFormatIDKey,
      [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
      [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
      [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
      [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
      nil];
  // インスタンス生成(エラー処理は省略)
  NSError *error = nil;
  recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
  recorder.delegate = self;
  // 録音ファイルの準備(すでにファイルが存在していれば上書きしてくれる)
  [recorder prepareToRecord];
  // 録音中に音量をとるかどうか
  recorder.meteringEnabled = YES;
  // 録音開始
  [recorder record];
}
- (void)viewDidDisappear:(BOOL)animated {
  // 録音終了
  [recorder stop];
  // 録音データの削除。stop メソッドを呼ぶ前に呼んではいけない
  [recorder deleteRecording];
}
// 録音が終わったら呼ばれるメソッド
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
  NSLog(@"%@", @"録音終了");
}
- (void)dealloc {
  recorder.delegate = nil;
  [recorder release];
  [super dealloc];
}
@end

AVNumberOfChannelsKey を1に設定しているのは iPhone に付いているマイクが1つだからです。iPhone の本体向かって右側にマイクが付いてます。

注意点

#defineのところ(9行目)で音声を保存する場所を指定しています。ここを

// リソースにファイルを保存することは出来ません!
#define DocumentsFolder [[NSBundle mainBundle] resourcePath]

にするとシミュレータでは動きますが実機では動きません。Resourcesにある音声を再生することは出来るのですがResourcesに録音ファイルを保存することはできません。
あと録音ファイルの拡張子は.cafにするのが無難だと思います。ここも間違えるとシミュレータでは動くけど実機だと動かないという現象が起こるので気をつけてください。録音に使えるファイルの種類はこちらのページが参考になります。

音量の取り方

AVAudioRecorder#updateMeters メソッドを呼んだあとに peakPowerForChannel または averagePowerForChannel メソッドで音量がとれます。音量は0〜-160dbの間でとれます。0が最大音量で-160が最小音量です。

[recorder updateMeters];
// 0番目のチャンネルの音を取得
NSLog(@"%g", [recorder peakPowerForChannel:0]);
NSLog(@"%g", [recorder averagePowerForChannel:0]);

なんで音量の値がマイナスなのかはこちらの説明を読むとだいたいわかります。