2010年5月8日土曜日

サウンドファイルの再生

サウンドファイルを再生する時は、AVFoundationライブラリのAVAudioPlayerクラスを使います。AVFoundationライブラリはiPhone OS 2.2以降で使用できるようになったようです。

xcodeにAVFoundation.frameworkを追加し、リソースにサウンドファイルを追加します。
ヘッダに@import "AVFoundation/AVAudioPlayer.h"を追加しておきます。
また、AVAudioPlayerクラスを利用するクラスを定義するヘッダに「プロトコル」を追加しておきます。


@interface クラス名 : NSObject




@end

クラス宣言の右端に「, AVAudioPlayer」を追加しました。
「プロトコル」とは、C++、C#で言うところの「仮想関数」のようなものです。
Objective-Cはクラスの多重継承を禁止しています。このため、仮想関数を使って、あるクラスから自クラスと継承クラス以外のクラスのメソッドを呼出す仕組みが備わっています。
これと似た機能がObjective-Cでは「プロトコル」というものです。
上記のようにプロトコルの指定が無い場合はワーニングが出ますが、プロトコルの指定が無くても実装したメソッドを呼出してはくれるようです。
C#等では確か仮想関数は必ず実装しなければならなかった記憶がありますが、Objective-Cの場合は必ずしもプロトコルに宣言されているメソッドを実装しなければならないわけではないようです。


    // 自アプリのバンドル(パッケージ)を開く
    NSBundle* bundle = [NSBundle mainBundle];
   
    // バンドル内の音声ファイルパスを生成
    NSString* path = [bundle pathForResource:@"alarm001" ofType:@"m4a"];
   
    // 音声ファイルパスからURLを生成
    NSURL* url = [NSURL fileURLWithPath:path];
   
    // AVAudioPlayerのインスタンス生成
    AVAudioPlayer* avap = [ [AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
   
    // 再生終了時に自クラス内のaudioPlayerDidFinishPlayingを呼出す
    avap.delegate = self;
   
    // 音声ファイルを再生
    [avap play];


NSBundleクラスは、自分のアプリケーションを開くクラスです。
以前アプリケーションの実態はただのフォルダだと書いたことがありますが、リソースファイルにサウンドファイルを追加してビルドすると、サウンドファイルが自分のアプリケーションのフォルダ(アプリケーション名.app)にコピーされます。
このサウンドファイルを自アプリケーションから開くために、フォルダをNSBundleクラスを使ってオープンします。

バンドル(フォルダ)をオープンしたら、サウンドファイルのパスをNSBundleクラスのpathForResourceメソッドを使って生成します。引数にはサウンドファイル(ファイル名)とファイルタイプ(拡張子)を指定します。

パス文字列が生成できたら、NSURLクラスのfileURLWithPathメソッドでNSURLクラスのインスタンスを生成します。

AVAudioPlayerクラスのインスタンスを生成します。初期化の引数でサウンドファイルのURLを渡します。

「avap.delegate = self;」となっている所は、再生終了時やエラー時にAVAudioPlayerクラスがイベントを発生させますが、イベントを呼出す先のオブジェクトを指定します。
上記では「self」となっているので自クラスを指定しています。ちなみにObjective-Cでは自オブジェクトのことを「self」と表記します。C++、C#では「this」だったので少し違いますね。

最後に「[avap play];」としてサウンドファイルを再生させます。

上記だけではサウンドの再生終了時やエラー時のイベントを補足できないので、以下のように各イベント時にcallbackさせるイベントも作成しておきます。


// 再生終了
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer*) avap
                        successfully: (BOOL)flag
{
    [avap release];
}

// 割り込み発生
- (void) audioPlayerBeginInterruption: (AVAudioPlayer*) avap
{
}

// 割り込み終了
- (void) audioPlayerEndInterruption: (AVAudioPlayer*) avap
{
    [avap play];
}

// エラー発生
- (void) audioPlayerDecodeErrorDidOccur: (AVAudioPlayer*) avap
                                    error:(NSError*)error
{
    [avap release];
}

「audioPlayerDidFinishPlaying」は、サウンドファイルの再生が終了した時にAVAudioPlayerオブジェクトが呼出してくれるメソッドです。メソッドは先ほど「avap.delegate = self;」としましたので、自クラス内に上記メソッドを作っておく必要があります。中身は、再生が終了してavapインスタンスが必要なくなったので「[avap release];」として解放してやります。
もちろん、再度インスタンスを使う場合はreleaseする必要はありませんが、メモリリークになるといけないので最終的には必ずreleaseしましょう。

「audioPlayerBeginInterruption」はサウンドファイルの再生中に電話等の割り込みが発生した場合に呼出されるメソッドです。再生の中断等は自動的に行われるようなのでここでは何も処理をさせていません。処理させていないので、メソッドの実装定義が無くても正常に動作します。

「audioPlayerEndInterruption」は上記割り込みが終了した時に呼出されます。
ここでは、中断されたサウンドファイルの再生を再開させています。

「audioPlayerDecodeErrorDidOccur」はサウンドファイルの再生中にデコードエラー等が発生した時に呼出されます。ここでもインスタンスが不要になったのでreleaseさせます。

0 件のコメント:

コメントを投稿