翻訳元:[[https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/AQPlayback/PlayingAudio.html|Audio Queue Services Programming Guide: Playing Audio]] ====== 音声の再生 ====== Audio Queue Serviceを使って音声を再生する際、その信号源はどんなものでも有り得ます。ディスク上のファイル、ソフトウェアシンセサイザ、メモリ上のオブジェクトなどです。 本章では最も一般的な方法-ディスク上のファイルの再生方法について説明します。 本文章中のコードサンプルは時々、Core Audio SDKのC++クラスを用いて簡単化されています。 しかし、Audio Queue Serviceの利用にあたって、Core Audio SDKとC++言語は必須ではありません。 より単純化するため、これらコード例は強力なエラー処理(robust error handling)を省いています。 Audio Queue Serviceを用いた録音/再生を実装する際は、潜在的なエラーを扱うためのコードを必ず追加するようにして下さい。 アプリケーションに音声再生機能を追加するには、通常、以下の段階を踏むと良いでしょう: - 状態、フォーマット、ファイルパス情報を管理する独自構造体を定義する。 - 実際に再生を行うAudio Queueコールバック関数を書く。 - Audio Queue Bufferに適したバッファサイズを決定するためのコードを書く。 - 再生するファイルを開き、その音声データ形式を決定する。 - 再生Audio Queueを生成し、それを再生用に設定する。 - Audio Queue Bufferを確保しデータを詰める。そしてAudio Queueに再生開始を伝える。再生終了時は、再生コールバックがAudio Queueに停止を伝える。 - Audio Queueを破棄する。各種リソースを開放する。 この章の残りで、これら段階をそれぞれ詳細に解説します。 ===== 状態管理用の独自構造体の定義 ===== 手始めに、音声形式とAudio Queueの状態の管理に使用する、独自構造体を定義します。 リスト3-1はその構造体の例です: **リスト3-1** 再生Audio Queue向けの独自構造体 static const int kNumberBuffers = 3; // 1 struct AQPlayerState { AudioStreamBasicDescription mDataFormat; // 2 AudioQueueRef mQueue; // 3 AudioQueueBufferRef mBuffers[kNumberBuffers]; // 4 AudioFileID mAudioFile; // 5 UInt32 bufferByteSize; // 6 SInt64 mCurrentPacket; // 7 UInt32 mNumPacketsToRead; // 8 AudioStreamPacketDescription *mPacketDescs; // 9 bool mIsRunning; // 10 }; この構造体の殆どのメンバ変数は、“[[音声の記録]]”の[[音声の記録#状態管理用の独自構造体の定義|“状態管理用の独自構造体の定義”]]で解説した、録音用独自構造体のそれと全く一緒(ないしそれに近い)です。 例えば、mDataFormat領域は、ここでは再生するファイルの形式を保持します。 録音の時は、この類似した領域はディスクへ書き出すファイルの形式を保持します。 では、この構造体の変数領域の解説をしましょう: - 使用するAudio Queue Bufferの個数を設定します。[[Audio Queueについて#Audio Queue Buffer|“Audio Queue Buffer”]]で解説したように、典型的には3が適した数字です。 - 再生するファイルの音声データ形式を表すAudioStreamBasicDescription (CoreAudioTypes.h)構造体です。この形式はmQueue変数のAudio Queueによって使用されます。mDataFormat領域は、“[[#ファイルの音声データ形式の取得]]”で解説するAudio FileへのkAudioFilePropertyDataFormatプロパティの問い合わせで埋められます。AudioStreamBasicDescription構造体の詳細は//[[http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/index.html|Core Audio Data Types Reference]]//をご覧下さい。 - アプリケーションによって生成される、再生用Audio Queueです。 - Audio Queueによって管理される、Audio Queue Bufferへのポインタを格納する配列です。 - 再生する音声ファイルを表すAudio Fileオブジェクトです。 - 各Audio Queue Bufferの大きさ(バイト数)です。この値は、Audio Queueが生成された後、再生が開始される前までに、本資料サンプル中のDeriveBufferSize関数で計算されます。詳しくは“[[#再生Audio Queue Bufferの大きさを求める関数の記述]]”をご覧下さい。 - 音声ファイルから再生する次のパケットのための、パケット番号(index)です。 - Audio Queueの再生コールバック呼び出し各回における、読み込むパケット数です。bufferByteSize変数のように、この値はAudio Queueの生成後、再生開始前までに本資料サンプル中のDeriveBufferSize関数で計算されます。 - VBRの音声データで、再生するファイルのパケット詳細情報の配列です。CBRデータでは、この領域の値はNULLです。 - Audio Queueが実行中か否かを示す論理値です。 ===== 再生Audio Queueコールバックの記述 ===== 次に、再生Audio Queueのコールバック関数を書きます。 このコールバックは、主に次の3つの事を行います: * 音声ファイルから決まった量のデータを読み込み、それをAudio Queue Bufferに入れる * Audio Queue BuffreをBuffer Queueに追加する(enqueue) * 音声ファイルから読み込むデータが無くなったときは、Audio Queueに停止指示を伝える。 本項では、以上3つの項目ごとにわけて解説を行い、コールバックの宣言例を示します。そして最終的に再生コールバック全体を披露します。 再生用コールバックの役割については、以前示した[[#図1-4]]を参照して下さい。 ==== 再生Audio Queueのコールバックの宣言 ==== リスト3-2は、再生用Audio Queueのコールバック関数の宣言例を示しており、これはAudioQueue.hヘッダファイルでAudioQueueOutputCallbackとして宣言されています: **リスト3-2** 再生用Audio Queueコールバックの宣言 static void HandleOutputBuffer ( void *aqData, // 1 AudioQueueRef inAQ, // 2 AudioQueueBufferRef inBuffer // 3 ) では、このコードの働きを見ていきましょう: - 通常、aqDataは、“[[#状態管理用の独自構造体の定義]]”で解説した、Audio Queueの状態情報を含む独自構造体です。 - このコールバックを所有するAudio Queueオブジェクトです。 - Audio Queue Bufferです。コールバックは、これに音声ファイルから読んだデータを詰めます。 ==== ファイルからデータを読み込みAudio Queue Bufferに入れる ==== 再生用Audio Queueコールバックの最初の仕事は、音声ファイルからデータを読み込んでAudio Queue Bufferに入れる事です。 リスト3-3はその方法を示しています。 **リスト3-3** ファイルからデータを読み込みAudio Queue Bufferに入れる AudioFileReadPackets ( // 1 pAqData->mAudioFile, // 2 false, // 3 &numBytesReadFromFile, // 4 pAqData->mPacketDescs, // 5 pAqData->mCurrentPacket, // 6 &numPackets, // 7 inBuffer->mAudioData // 8 ); では、このコードの働きを見ていきましょう: - AudioFileReadPackets関数は、AudioFile.hヘッダファイルで宣言されおり、Audio Fileからデータを読み込んでバッファへと入れます。 - データを読み込むAudio Fileです。 - falseを与え、関数が読み込みの際にデータをキャッシュしないように指示しています。 - 関数からの出力として、Audio Fileから読み込んだ音声データのバイト数が返ってきます。 - 関数からの出力として、Audio Fileから読み込んだデータのパケット詳細情報の配列が返ってきます。CBRのデータでは、この引数にはNULLを与えます。 - Audio Fileのパケット読み込み開始位置を表すパケット番号です(The packet index for the first packet to read from the audio file.) - 関数への入力として、Audio Fileから読み込むパケット数を与えます。関数からの出力として、実際に読んだパケット数が返ってきます。 - 関数からの出力として、Audio Fileから読み込んだデータを含む、満タンになったAudio Queue Bufferが返ってきます。 ==== Audio Queue BufferをBuffer Queueへ追加 ==== 音声ファイルからデータを読み込み、Audio Queue Bufferへの格納が完了したので、リスト3-4で示すようにコールバックはAudio Queue Bufferをエンキューします。 一度Buffer Queueに入れば、バッファ中の音声データはAudio Queueから出力装置に送る事が出来ます。 **リスト3-4** ディスクから読み込み後Audio Queue Bufferをエンキューする AudioQueueEnqueueBuffer ( // 1 pAqData->mQueue, // 2 inBuffer, // 3 (pAqData->mPacketDescs ? numPackets : 0), // 4 pAqData->mPacketDescs // 5 ); では、このコードの働きを見ていきましょう: - AudioQueueEnqueueBuffer関数はAudio Queue BufferをBuffer Queueに追加します。 - 対象のBuffer Queueを所有するAudio Queueです。 - エンキュー対象のAudio Queue Bufferです。 - Audio Queue Bufferに含まれるデータのパケット数です。CBRのデータでは、パケット詳細情報は使用しないので、0を与えます。 - パケット詳細情報を使用する圧縮音声データ用の、バッファ中のパケットを表すパケット詳細情報です。 ===== 再生Audio Queue Bufferの大きさを求める関数の記述 ===== Audio Queue Serviceはアプリケーションに、使用するAudio Queue Bufferの大きさの特定を期待します。 リスト3-7はそれを行うための一例です。 このコードは、与えられる音声データの時間を保持するのに十分に大きいサイズのバッファを求めます。 Audio Queueへのバッファ確保要求の条件として、アプリケーション中では、再生用Audio Queueを生成した後にDeriveBufferSize関数を呼びます。 “[[#再生Audio Queueの大きさの設定]]”をご覧下さい。 このコードは、“[[#録音Audio Queue Bufferの大きさを求める関数の記述]]”で見た類似した関数と比べて、2つの事項が追加されています。 再生では以下の事も行います: * コールバックがAudioFileReadPackets関数を呼び出す度に、読み込むパケット数を求めます。 * 過剰なディスクアクセスを避けるため、バッファサイズに下限を設けます。 この計算は、ディスクから読み込む音声データ形式を考慮します。 その形式には、音声チャンネル数といったバッファサイズに影響を及ぼす、全ての要因が含まれます。 **リスト3-7** 再生用Audio Queue Bufferの大きさを求める void DeriveBufferSize ( AudioStreamBasicDescription &ASBDesc, // 1 UInt32 maxPacketSize, // 2 Float64 seconds, // 3 UInt32 *outBufferSize, // 4 UInt32 *outNumPacketsToRead // 5 ) { static const int maxBufferSize = 0x50000; // 6 static const int minBufferSize = 0x4000; // 7 if (ASBDesc.mFramesPerPacket != 0) { // 8 Float64 numPacketsForTime = ASBDesc.mSampleRate / ASBDesc.mFramesPerPacket * seconds; *outBufferSize = numPacketsForTime * maxPacketSize; } else { // 9 *outBufferSize = maxBufferSize > maxPacketSize ? maxBufferSize : maxPacketSize; } if ( // 10 *outBufferSize > maxBufferSize && *outBufferSize > maxPacketSize ) *outBufferSize = maxBufferSize; else { // 11 if (*outBufferSize < minBufferSize) *outBufferSize = minBufferSize; } *outNumPacketsToRead = *outBufferSize / maxPacketSize; // 12 } では、このコードの働きを見ていきましょう: - Audio Queue用のAudioStreamBasicDescription構造体です。 - 再生する音声ファイル中の最大パケットサイズの見積もりです。プロパティIDkAudioFilePropertyPacketSizeUpperBoundを用いてAudioFileGetProperty関数(AudioFile.hヘッダファイル)を呼ぶ事で、この値を決定出来ます。“[[#再生Audio Queueの大きさの設定]]”をご覧下さい。 - 秒単位で指定する各Audio Queue Bufferの大きさです。 - 関数からの出力で、各Audio Queue Bufferの大きさがバイト単位が得られます。 - 関数からの出力で、再生用Audio Queueコールバックの呼び出し毎における、ファイルから読み込む音声データパケット数が得られます。 - Audio Queue Bufferの大きさの上限で、単位はバイトです。本例では、上限を320KBに設定しています。これは、標本化周波数96kHz/量子化ビット数24bitのステレオ音声で、おおよそ5秒の情報量です。 - Audio Queue Bufferの大きさの下限で、単位はバイトです。本例では、下限を16KBに設定しています。 - 1パケット毎のフレーム数が固定されている音声データ形式の場合に、Audio Queue Bufferの大きさを求めます。 - 1パケット毎のフレーム数が固定されていない音声データ形式の場合に、最大パケットサイズと先に設定した上限バッファサイズを元に適切なAudio Queue Bufferの大きさを求めます。 - 求めたバッファ容量が先に設定した上限を超えていた場合、概算の最大パケットサイズも考慮しつつ、容量を上限値にします。 - 求めたバッファ容量が先に設定した下限を下回っていた場合、容量を下限値にします。 - コールバック呼び出し毎における、ファイルから読み込むパケット数を計算します。 ===== 再生する音声ファイルを開く ===== 今度は再生する音声ファイルを開きます。それには次の3つの段階を経ます: - 再生したい音声ファイルを表すCFURLオブジェクトを得ます。 - ファイルを開きます。 - ファイルの音声データ形式を得ます。 ==== 音声ファイルのCFURLオブジェクトの取得 ==== リスト3-8は、再生したい音声ファイルのCFURLオブジェクトの取得方法の例です。 このCFURLオブジェクトは、次の段階で、ファイルを開くのに使用します。 **リスト3-8** 音声ファイルのCFURLオブジェクトを得る CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation ( // 1 NULL, // 2 (const UInt8 *) filePath, // 3 strlen (filePath), // 4 false // 5 ); ではコードの働きを見て行きましょう: - CFURL.hヘッダファイルで宣言されるCFURLCreateFromFileSystemRepresentation関数はCFURLオブジェクトを生成し、再生するファイルを表します。 - 現在のデフォルトメモリアロケータを使用するように、NULL(またはkCFAllocatorDefault)を与えます。 - CFURLオブジェクトに変換したいファイルのパスです。製品版のコードでは、通常、filePathの値はユーザーが指定した値となるでしょう。 - ファイルパスのバイト数です。 - falseはfilePathがファイルを表しており、ディレクトリでは無い事を示します。 ==== 音声ファイルを開く ==== リスト3-9は再生する音声ファイルの開き方の例です。 **リスト3-9** 再生する音声ファイルを開く AQPlayerState aqData; // 1 OSStatus result = AudioFileOpenURL ( // 2 audioFileURL, // 3 fsRdPerm, // 4 0, // 5 &aqData.mAudioFile // 6 ); CFRelease (audioFileURL); // 7 ではコードの働きを見て行きましょう: - AQPlayerState独自構造体(“[[#状態管理用の独自構造体を定義する]]”をご覧下さい)のインスタンスを生成します。再生する音声ファイルを開く際、音声ファイルを表すAudio Fileオブジェクト(AudioFileID型)を保持する場所として、このインスタンスを使用します。 - AudioFile.hヘッダファイルで宣言されるAudioFileOpenURLは、再生したいファイルを開きます。 - 再生するファイルのCFURLオブジェクトです。 - 再生するファイルに適用するファイルパーミッションです。使用可能なパーミッションは[[http://developer.apple.com/documentation/Carbon/Reference/File_Manager/Reference/reference.html|File Manager’s File Access Permission Constants]]列挙体で定義されています。本例ではファイルを読み込みのパーミッションを指定しています。 - オプションで使うファイルタイプのヒントです。0を指定しているので、本例ではこの機構を使用しません。 - 関数からの出力で、Audio Fileオブジェクトを置くための独自構造体のmAudioFile変数へのポインタを指定します。 - 手順1で生成したCFURLオブジェクトを解放します。 ==== ファイルの音声データ形式の取得 ==== リスト3-10はファイルの音声データ形式の取得方法を示しています。 **リスト3-10** ファイルの音声データ形式を得る UInt32 dataFormatSize = sizeof (aqData.mDataFormat); // 1 AudioFileGetProperty ( // 2 aqData.mAudioFile, // 3 kAudioFilePropertyDataFormat, // 4 &dataFormatSize, // 5 &aqData.mDataFormat // 6 ); ではコードの働きを見て行きましょう: - 音声データ形式をAudio Fileに問い合わせる際に使用する、プロパティ値の予想される大きさを得ます。 - AudioFileGetProperty関数は、AudioFile.hヘッダファイルで宣言され、Audio Fileの特定のプロパティ値を得ることが出来ます。 - Audio Fileオブジェクト(AudioFileID型)は、音声データ形式の取得対象のファイルを表します。 - 音声ファイルのデータ形式を得る為のプロパティIDです。 - 関数への入力として、音声ファイルのデータ形式を表すAudioStreamBasicDescription構造体の予定サイズを指定します。関数からの出力として、実際の大きさが返ってきます。再生用アプリケーションではこの値を利用する必要はありません。 - 関数からの出力として、Audio Fileから得られた完全な音声データ形式がAudioStreamBasicDescriptionの形で返ってきます。この行では、ファイルの音声データ形式を、Audio Queueの独自構造体に格納する事によって、それをAudio Queueに適用します。 ===== 再生Audio Queueの生成 ===== リスト3-11は再生Audio Queueの生成方法を示しています。 気をつけるべき事は、AudioQueueNewOutput関数は再生するファイルの音声データ形式に加えて、独自構造体と先の手順で設定したコールバックも使用するという事です。 **リスト3-11** 再生Audio Queueの生成 AudioQueueNewOutput ( // 1 &aqData.mDataFormat, // 2 HandleOutputBuffer, // 3 &aqData, // 4 CFRunLoopGetCurrent (), // 5 kCFRunLoopCommonModes, // 6 0, // 7 &aqData.mQueue // 8 ); ではコードの働きを見て行きましょう: - AudioQueueNewOutput関数は、新規再生用Audio Queueを生成します。 - Audio Queueが再生に使用する、ファイルの音声データ形式です。“[[#ファイルの音声データ形式を得る]]”をご覧下さい。 - 再生用Audio Queueで使用するコールバック関数です。“[[#再生用Audio Queueのコールバックを書く]]”をご覧下さい。 - 再生用Audio Queueで使用する独自データ構造体です。“[[#状態管理用の独自構造体を定義する]]”をご覧下さい。 - 現在の実行ループで、この中において再生用Audio Queueのコールバックが呼び出されます。 - コールバック呼び出しにおける実行ループの動作モードです。ここでは通常、kCFRunLoopCommonModes定数が使用されます。 - 予約済みです。0にしなければなりません。 - 関数からの出力として、新しく確保された再生用Audio Queueが返ってきます。 ===== 再生Audio Queueの各種サイズを設定する ===== 次は再生用Audio Queueの各種サイズを設定します。 これらサイズは、音声ファイルから読み込みを開始する前、Audio Queueのバッファを確保する時に使用します。 本項で揚げるコードは以下のサイズの設定のし方を示します: * Audio Queue Bufferサイズ * 再生用Audio Queueコールバック呼び出しで読み込むパケット数 * バッファの持つ音声データのパケット詳細情報を保持する配列のサイズ ==== バッファ容量と読み込むパケット数の設定 ==== リスト3-12は、以前に記述したDeriveBufferSize関数(“[[#再生用Audio Queue Bufferの大きさを求める関数を書く]]”をご覧下さい)の使い方の実例です。 ここでの目標は、各Audio Queue Bufferごとにバイト単位で容量を設定し、再生用Audio Queueコールバック呼び出しにおける読み込みパケット数を決定することです。 このコードは、最大パケットサイズを控え目に見積もります。そしてこのサイズは、Core AudioがkAudioFilePropertyPacketSizeUpperBoundプロパティで提供するものです。 殆どの場合において、このテクニックを使うことは、音声ファイル全体を検査し実際の最大パケットサイズを得るために時間をかけることよりも、良い選択です(おおよそですが、この方が速いです)。 **リスト3-12** 再生Audio Queue Bufferの容量と読み込むパケット数を設定する UInt32 maxPacketSize; UInt32 propertySize = sizeof (maxPacketSize); AudioFileGetProperty ( // 1 aqData.mAudioFile, // 2 kAudioFilePropertyPacketSizeUpperBound, // 3 &propertySize, // 4 &maxPacketSize // 5 ); DeriveBufferSize ( // 6 aqData.mDataFormat, // 7 maxPacketSize, // 8 0.5, // 9 &aqData.bufferByteSize, // 10 &aqData.mNumPacketsToRead // 11 ); ではコードの働きを見ていきましょう: - AudioFileGetProperty関数(AudioFile.hヘッダファイルで宣言)は、音声ファイルの特定のプロパティ値を得る関数です。ここでは、再生するファイルの音声データパケットサイズを、バイト単位で控え目に得るために使用しています。 - 再生するファイルを表す音声ファイルオブジェクト(AudioFileID型)です。“[[#音声ファイルを開く]]”をご覧下さい。 - 音声ファイルに含まれるパケットサイズの控え目な上限(conservative upper bound)を得るプロパティIDです。 - 関数からの出力で、kAudioFilePropertyPacketSizeUpperBoundプロパティのバイト単位のサイズです。 - 関数からの出力で、再生するファイルのパケットサイズの控え目な上限(conservative upper bound)のバイト数です。 - “[[#再生用Audio Queue Bufferの大きさを求める関数を書く]]”で解説したDeriveBufferSize関数が、バッファ容量と再生用Audio Queueコールバックの呼び出し毎に読み込むパケット数を設定します。 - 再生したいファイルの音声データ形式です。“[[#ファイルの音声データ形式を得る]]”をご覧下さい。 - ソースリストの5行目で得た、音声ファイルに含まれる最大パケットサイズの概算値です。 - 各Audio Queue Bufferが保持すべき音声の秒数です。ここでは0.5秒に設定しており、これは一般的に良い選択です。 - 関数からの出力で、各Audio Queue Bufferの大きさがバイト数で返ってきます。この値はAudio Queueのための独自構造体の中に置かれます。 - 関数からの出力で、再生用Audio Queueコールバックの呼び出しごとに読み込むパケット数です。この値もAudio Queueのための独自構造体の中に置かれます。 ===== 再生Audio Queueにマジッククッキーを設定 ===== MPEG 4 AACといった幾つかの圧縮音声形式は、音声メタデータを格納するための構造体を使用します。 これら構造体は**マジッククッキー**と呼ばれます。 マジッククッキーを持つファイル形式をAudio Queue Serviceを使って再生する時は、再生を始める前に音声ファイルよりマジッククッキーを取得し、それをAudio Queueに追加します。 リスト3-14では、ファイルからマジッククッキーを取得し、Audio Queueへの適用のし方を示しています。 あなたのプログラムの中で、再生前にこのリストの関数を呼び出せばよいでしょう。 **リスト 3-14** 再生Audio Queueにマジッククッキーを設定する UInt32 cookieSize = sizeof (UInt32); // 1 bool couldNotGetProperty = // 2 AudioFileGetPropertyInfo ( // 3 aqData.mAudioFile, // 4 kAudioFilePropertyMagicCookieData, // 5 &cookieSize, // 6 NULL // 7 ); if (!couldNotGetProperty && cookieSize) { // 8 char* magicCookie = (char *) malloc (cookieSize); AudioFileGetProperty ( // 9 aqData.mAudioFile, // 10 kAudioFilePropertyMagicCookieData, // 11 &cookieSize, // 12 magicCookie // 13 ); AudioQueueSetProperty ( // 14 aqData.mQueue, // 15 kAudioQueueProperty_MagicCookie, // 16 magicCookie, // 17 cookieSize // 18 ); free (magicCookie); // 19 } コードの働きを見て行きましょう: - マジッククッキーデータの見込みサイズを設定します。 - [[http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_toolbox/chapter_4_section_4.html#//apple_ref/doc/c_ref/AudioFileGetPropertyInfo|AudioFileGetPropertyInfo]]関数の結果を捕捉します。成功ならば、この関数は返り値NoErrを返し、これは真理値のfalseと等価です。 - AudioFile.hヘッダファイルで宣言されている[[http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_toolbox/chapter_4_section_4.html#//apple_ref/doc/c_ref/AudioFileGetPropertyInfo|AudioFileGetPropertyInfo]]関数は、特定のプロパティの値の大きさを得ます。プロパティ値を保持する変数の容量を設定するために、この関数を使用します。 - 再生する音声ファイルを表すAudio Fileオブジェクト(AudioFileID型)です。 - 音声ファイルのマジッククッキーデータを表すプロパティIDです。 - 関数への入力として、マジッククッキーデータ容量の概算値を与えます。出力として、実際の大きさが返ってきます。 - NULLを指定し、プロパティの読み書き属性に興味がないことを示します (#原文:Uses NULL to indicate that you don’t care about the read/write access for the property.) - 音声ファイルがマジッククッキーを含んでいれば、クッキー保持用のメモリを確保します。 - AudioFile.hヘッダファイルで宣言されている[[http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_toolbox/chapter_4_section_4.html#//apple_ref/doc/c_ref/AudioFileGetProperty|AudioFileGetProperty]]は、特定のプロパティの値を得ます。今回の場合、プロパティは音声ファイルのマジッククッキーです。 - マジッククッキーの取得と再生対象の音声ファイルを表すAudio Fileオブジェクト(AudioFileID型)です。 - 音声ファイルのマジッククッキーデータを表すプロパティIDです。 - 関数への入力として、[[http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_toolbox/chapter_4_section_4.html#//apple_ref/doc/c_ref/AudioFileGetPropertyInfo|AudioFileGetPropertyInfo]]関数を使って取得したmagicCookie変数の大きさを与えます。出力として、マジッククッキーの実際の大きさがバイト数単位で、magicCookie変数へ書き込まれます。 - 関数からの出力で、音声ファイルのマジッククッキーです。 - [[http://developer.apple.com/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueSetProperty|AudioQueueSetProperty]]関数は、Audio Queueにプロパティ値を設定します。今回の場合、再生する音声ファイルと適合するマジッククッキーを、Audio Queueに設定します。 - マジッククッキーを設定したいAudio Queueです。 - Audio Queueのマジッククッキーを表すプロパティIDです。 - 再生するファイルから得たマジッククッキーです。 - マジッククッキーのバイト数です。 - マジッククッキー用に確保したメモリを解放します。 ===== Audio Queue Bufferの確保と準備 ===== (“[[再生Audio Queueの生成]]”で)生成したAudio Queueに、Audio Queue Buffer集合を設定する準備を行います。 リスト3-15は、その作業の例です。 **リスト 3-15** 再生用のAudio Queue Bufferの確保と準備 aqData.mCurrentPacket = 0; // 1 for (int i = 0; i < kNumberBuffers; ++i) { // 2 AudioQueueAllocateBuffer ( // 3 aqData.mQueue, // 4 aqData.bufferByteSize, // 5 &aqData.mBuffers[i] // 6 ); HandleOutputBuffer ( // 7 &aqData, // 8 aqData.mQueue, // 9 aqData.mBuffers[i] // 10 ); } このコードの働きを見て行きましょう: - Audio Queueコールバックがバッファにデータを入れ始める時(手順7)、音声ファイルの先頭から読み込みを開始するように、パケットインデックスを0にします。 - Audio Queue Buffer集合の生成と準備を行います(このkNumberBuffersは、[[#状態管理用の独自構造体の定義]]で3に設定してあります) - [[http://developer.apple.com/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueAllocateBuffer|AudioQueueAllocateBuffer]]関数は、メモリを確保しAudio Queue Bufferを作成します。 - Audio Queue Bufferを確保するAudio Queueです。 - 新規Audio Queue Bufferのバイト数容量です。 - 関数からの出力で、新規Audio Queue Bufferを独自構造体のmBuffers配列に加えます。 - HandleOutputBuffer関数は、あなたが書く再生Audio Queueコールバックです。“[[#再生Audio Queueコールバックの記述]]”をご覧下さい。 - Audio Queueのための独自構造体です。 - コールバックを呼び出すAudio Queueです。 - Audio Queueコールバックに渡すAudio Queue Bufferです。 ===== Audio Queueの再生利得の設定 ===== Audio Queueで再生を開始する前に、Audio Queueの利得をAudio Queueパラメータという仕組みにより設定します。 リスト3-16は、この作業のし方を示しています。 パラメータ機構のより詳しい情報は[[“Audio Queueパラメータ”]]をご覧下さい。 **リスト 3-16** Audio Queueの再生利得の設定 Float32 gain = 1.0; // 1 // 利得設定はここで任意に書き換えることが出来ます AudioQueueSetParameter ( // 2 aqData.mQueue, // 3 kAudioQueueParam_Volume, // 4 gain // 5 ); コードの働きを見て行きましょう: - Audio Queueで使用する利得を0(消音)〜1(単位利得)の間で設定します。 - [[http://developer.apple.com/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueSetParameter|AudioQueueSetParameter]]関数は、パラメータの値をAudio Queueに設定します。 - パラメータを設定するAudio Queueです。 - 設定するパラメータの識別子です。kAudioQueueParam_Volume定数は、Audio Queueの利得を設定します。 - Audio Queueに適用する利得値です。 ===== Audio Queueの開始と実行 ===== これまでの全てのコードで、ファイル再生の工程が整いました。 この項は、リスト3-17に示すように、Audio Queueの開始とファイル再生中の実行ループの管理についてが含まれます。 **リスト 3-17** Audio Queueの開始と実行 aqData.mIsRunning = true; // 1 AudioQueueStart ( // 2 aqData.mQueue, // 3 NULL // 4 ); do { // 5 CFRunLoopRunInMode ( // 6 kCFRunLoopDefaultMode, // 7 0.25, // 8 false // 9 ); } while (aqData.mIsRunning); CFRunLoopRunInMode ( // 10 kCFRunLoopDefaultMode, 1, false ); コードの働きを見て行きましょう: - Audio Queueが実行中であることを示す、独自構造体の中のフラグを設定します。 - [[http://developer.apple.com/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueStart|AudioQueueStart]]関数は、Audio QueueをAudio Queue自身のスレッド(its own thread)で開始します。 - Audio Queueを開始します。 - NULLを指定し、Audio Queueが再生をすぐに開始するようにします。 - Audio Queueが停止したかどうかをチェックするため、独自構造体のmIsRunningメンバを定期的に監視します(#原文:Polls the custom structure’s mIsRunning field regularly to check if the audio queue has stopped.) - [[http://developer.apple.com/documentation/CoreFoundation/Reference/CFRunLoopRef/Reference/reference.html#//apple_ref/doc/c_ref/CFRunLoopRunInMode|CFRunLoopRunInMode]]関数で、Audio Queueのスレッドに含まれる実行ループを実行します。 - 実行ループのモードは標準(default)を使用します。 - 実行ループの実行時間を0.25秒に設定します。 - (#未訳:Uses false to indicate that the run loop should continue for the full time specified.) - Audio Queueの停止後、再生中のAudio Queue Bufferが確実に終わるように、少しだけ余分に実行ループを実行します。 ===== 再生後の後始末 ===== ファイルの再生が終了したら、Audio Queueを破棄し、音声ファイルを閉じ、残りの全ての資源を解放します。 リスト3-18はこれらの手順を示しています。 **リスト 3-18** 音声ファイル再生後の掃除 AudioQueueDispose ( // 1 aqData.mQueue, // 2 true // 3 ); AudioFileClose (aqData.mAudioFile); // 4 free (aqData.mPacketDescs); // 5 コードの働きを見て行きましょう: - [[http://developer.apple.com/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueDispose|AudioQueueDispose]]関数は、Audio Queueとそれが包含するバッファを含む全ての資源を破棄します。 - 破棄したいAudio Queueです。 - Audio Queueの破棄が同期的に行われるようにtrueを使用します。 - 再生したAudio Fileを閉じます。[[http://developer.apple.com/documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html#//apple_ref/doc/c_ref/AudioFileClose|AudioFileClose]]関数は、AudioFile.hヘッダファイルで宣言されています。 - パケット詳細情報の保持に使用したメモリを解放します。