翻訳元:[[https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/AQRecord/RecordingAudio.html|Audio Queue Services Programming Guide: Recording Audio]] ※以前のwikiで本章は翻訳途中だったため、10.9のリファレンスから再翻訳しています。 ====== 音声の記録 ====== Audio Queue Serviceを使って録音する際、その保存先はディスク上のファイル、ネットワークの接続先、メモリ内のオブジェクトなど、殆ど何でも選択出来ます。 本章では最も一般的なシナリオである、ディスクのファイルへの基本的な録音方法を解説します。 本章はMac OS X Core Audio SDKのいくつかのC++クラスを用いた、ANSI-Cベースの録音の実装について解説します。Objective-Cベースの例は、[[http://developer.apple.com/devcenter/ios/|iOS Dev Center]]の//SpeakHere//サンプルコードをご覧ください。 アプリケーションに録音機能を追加するには、一般的に以下の手順を踏みます: - 状態(state)、フォーマット、ファイルパス情報を管理する独自構造体を定義する。 - 実際の録音を担うAudio Queueコールバック関数を書く。 - (任意で)Audio Queue Bufferの最適なサイズを決めるコードを書く。マジッククッキーを使うフォーマットで録音するなら、マジッククッキーが機能するコードを書く。 - 独自構造体のフィールドを埋める。これにはファイルへのパスは勿論、Audio Queueがファイルへ送る録音データストリームの指定も含む。 - 録音Audio Queueを生成し、Audio Queue Bufferセット作成のために問い合わせる。また、記録に使うファイルを作成する。 - Audio Queueに録音開始を伝える。 - 録音が終わったらAudio Queueを停止し、そして破棄する。Audio Queueは保持するバッファを破棄する。 以降、本章ではこれら手順の詳細を解説します。 ===== 状態を管理する独自構造体の定義 ===== Audio Queue Serviceを使った録音ソリューション開発の第1ステップは、独自構造体の定義です。 この構造体を使い、音声フォーマットとAudio Queueの状態管理を行います。 リスト2-1は構造体の例です: **リスト 2-1** 録音Audio Queueの独自構造体 static const int kNumberBuffers = 3; // 1 struct AQRecorderState { AudioStreamBasicDescription mDataFormat; // 2 AudioQueueRef mQueue; // 3 AudioQueueBufferRef mBuffers[kNumberBuffers]; // 4 AudioFileID mAudioFile; // 5 UInt32 bufferByteSize; // 6 SInt64 mCurrentPacket; // 7 bool mIsRunning; // 8 }; この構造体のフィールドの解説です。 - 使用するAudio Queue Bufferの数の設定。 -- ''AudioStreamBasicDescription''構造体(''CoreAudioType.h''より)は、ディスクに書き込む音声データフォーマットを表します。このフォーマットは''mQueue''フィールドで指定されるAudio Queueによって使用されます。 .. ''mDataFormat''フィールドは、“[[Set Up an Audio Format for Recording]]”で解説されるように、最初はあなたのプログラムのコードによって埋められます。“[[Getting the Full Audio Format from an Audio Queue]]”で解説するように、Audio Queueに''kAudioQueueProperty_StreamDescription''プロパティを問い合わせて、このフィールドを更新するのが良い方法です。Mac OS X v10.5では、代わりに''kAudioConverterCurrentInputStreamDescription''プロパティを使います。 .. ''AudioStreamBasicDescription''構造体の詳細は、[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/Reference/reference.html|Core Audio Data Types Reference]]をご覧ください。 - あなたのアプリケーションによって生成される録音Audio Queue。 - そのAudio Queueによって管理されるAudio Queue Bufferへのポインタの配列。 - プログラムが音声データを記録するファイルを表すAudio Fileオブジェクト。 - 各Audio Queue Bufferの大きさのバイト数。この値は、以下のサンプルの''DeriveBufferSize''関数で、Audio Queueが生成されAudio Queueが開始される前に計算されます。“[[Write a Function to Derive Recording Audio Queue Buffer Size]]”をご覧ください。 - 現在のAudio Queue Bufferから書き出される最初のパケットのパケットインデックス。 - Audio Queueが実行中かどうかを示すブール値。 ===== 録音Audio Queueコールバックの実装 ===== 次に、録音Audio Queueコールバックを書きます。 このコールバックには2つの目的(main things)があります: * 新しく埋められたAudio Queue Bufferの内容を記録中のファイルに書き出す。 * (先ほど中身をディスクに書き出した)Audio Queue Bufferをバッファーキューに加える。 本項ではコールバック宣言の例を示してから、それら2つの仕事を個別に解説し、最後に録音コールバックの全体を示します。 録音Audio Queueコールバックの役割像については、を見直して下さい。 ==== 録音Audio Queueコールバックの宣言 ==== リスト2-2は録音Audio Queueコールバック関数の宣言例で、''AudioQueue.h''ヘッダで''AudioQueueInputCallback''として宣言されています: **リスト 2-2** 録音Audio Queueコールバック宣言 static void HandleInputBuffer ( void *aqData, // 1 AudioQueueRef inAQ, // 2 AudioQueueBufferRef inBuffer, // 3 const AudioTimeStamp *inStartTime, // 4 UInt32 inNumPackets, // 5 const AudioStreamPacketDescription *inPacketDesc // 6 ) コードの働きを見てみましょう: - 典型的には''aqData''は、“[[#状態を管理する独自構造体の定義]]”で解説したAudio Queueの状態データを含む独自構造体で - このコールバックを所持するAudio Queueです。 - 録音で入ってくる音声データを含むAudio Queue Bufferです。 - Audio Queue Bufferの先頭サンプルのサンプル時間です(簡易的な録音では必要ありません)。 - ''inPacketDesc''パラメータが持つパケット記述子の数。''0''はCBRデータを表します。 - パケット記述子を必要とする圧縮音声データ形式のための、バッファ内のパケット用のエンコーダが提示するパケット記述子。 ==== Audio Queue Bufferをディスクへ書き出す ==== 録音Audio Queueコールバックの最初の仕事は、Audio Queue Bufferをディスクに書き出す事です。 このバッファは、たった今コールバックのAudio Queueが入力デバイスからの新しい音声データで埋めたものです。 リスト2-3で示すように、コールバックは''AudioFile.h''ヘッダファイルの''AudioFileWritePackets''関数を使います。 **リスト 2-3** Audio Queue Bufferをディスクに書き出す AudioFileWritePackets ( // 1 pAqData->mAudioFile, // 2 false, // 3 inBuffer->mAudioDataByteSize, // 4 inPacketDesc, // 5 pAqData->mCurrentPacket, // 6 &inNumPackets, // 7 inBuffer->mAudioData // 8 ); コードの働きを見てみましょう: - ''AudioFile.h''ヘッダファイルで宣言されている''AudioFileWritePackets''関数は1つのバッファの内容を音声データファイルに書き出します。 - 音声ファイルオブジェクト(''AudioFileID''型)は書き出し先の音声ファイルを表します。''pAqData''変数はリスト2-1で解説したデータ構造体へのポインタです。 - ''false''は、関数が書き込み時にデータをキャッシュすべきではない事を示します。 - 書き出す音声データのバイト数です。''inBuffer''変数はAudio Queueがコールバックに渡したAudio Queue Bufferを表します。 - 音声データのパケット記述子配列です。NULLはパケット記述子が必要ない事を示します(CBRの音声データなど)。 - 書き出す先頭パケットのパケットインデックスです。 - 入力では出力するパケット数を表します。出力では実際に出力されたパケット数が返ります。 - 音声ファイルに書き出す新しい音声データです。 ==== Audio Buffer Queueをキューに加える ==== Audio Queue Bufferの音声データは音声ファイルに書き出されたので、リスト2-4で示す通り、コールバックはそのバッファをキューに戻します。 バッファキューに戻した時点で、そのバッファは待ち行列に並び、次なる入力音声データの受け入れ態勢が整います。 **リスト 2-4** ディスクへ出力後のAudio Queue Bufferのエンキュー AudioQueueEnqueueBuffer ( // 1 pAqData->mQueue, // 2 inBuffer, // 3 0, // 4 NULL // 5 ); コードの働きを見てみましょう: - ''AudioQueueEnqueueBuffer''関数はAudio Queue BufferをAudio Queueのバッファキューに追加します。 - 指定したAudio Queue Bufferを追加するAudio Queue。''pAqData''変数はリスト2-1で解説したデータ構造体へのポインタです。 - キューに追加するAudio Queue Buffer。 - Audio Queue Bufferのデータのパケット記述子の数。本パラメータは録音では使わないので、''0''を設定します。 - Audio Queue Bufferのデータのパケット記述子配列。本パラメータは録音では使わないので、''0''を設定します。 ==== 完全な録音Audio Queueコールバック ==== リスト2-5は完全な録音Audio Queueコールバックの基礎バージョンです。 本ドキュメント内の他のコード例と同様、以下のリストはエラー処理を考慮していません。 **リスト 2-5** 録音Audio Queueコールバック関数 static void HandleInputBuffer ( void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc ) { AQRecorderState *pAqData = (AQRecorderState *) aqData; // 1 if (inNumPackets == 0 && // 2 pAqData->mDataFormat.mBytesPerPacket != 0) inNumPackets = inBuffer->mAudioDataByteSize / pAqData->mDataFormat.mBytesPerPacket; if (AudioFileWritePackets ( // 3 pAqData->mAudioFile, false, inBuffer->mAudioDataByteSize, inPacketDesc, pAqData->mCurrentPacket, &inNumPackets, inBuffer->mAudioData ) == noErr) { pAqData->mCurrentPacket += inNumPackets; // 4 } if (pAqData->mIsRunning == 0) // 5 return; AudioQueueEnqueueBuffer ( // 6 pAqData->mQueue, inBuffer, 0, NULL ); } コードの働きを見てみましょう: - インスタンス化を行う際にAudio Queueオブジェクトに供給される、様々な状態データと共に書き出し先の音声ファイルを表すAudio Fileオブジェクトを含む独自構造体。“[[状態を管理する独自構造体の定義]]”をご覧ください。 - Audio Queue BufferがCBRデータを含む場合、バッファ内のパケット数を算出する。この値はバッファ内の合計バイト数を1パケット毎のバイト数(定数)で割った値に等しい。VBRデータでは、Audio Queueはコールバック呼び出し時のバッファ内のパケットデータ数を提供する。 - バッファの内容を音声データファイルに書き出す。詳しい解説は“[[#Audio Queue Bufferをディスクへ書き出す]]”をご覧ください。 - 音声データの書き出しが成功すれば、音声データファイルのパケットインデックスをインクリメントし、バッファの次の音声データ書き出しに備える。 - Audio Queueが停止していたら関数を抜ける。 - 今しがた中身が音声ファイルに書き出されたAudio Queue Bufferをキューに戻す。詳しい解説は“[[Audio Buffer Queueをキューに加える]]”をご覧ください。 ===== 録音Audio Queue Bufferサイズを計算する関数の実装 ===== Audio Queue Serviceは使用するAudio Queue Bufferサイズの特定を、アプリケーションが行うと期待します。 リスト2-6はその方法の1つです。 It derives a buffer size large enough to hold a given duration of audio data. ここでの計算は録音する音声データ形式を考慮に入れます。 フォーマットは、音声チャンネル数などの、バッファサイズに影響するであろう全ての要因を含みます。 **リスト 2-6** 録音Audio Queue Bufferサイズの算出 void DeriveBufferSize ( AudioQueueRef audioQueue, // 1 AudioStreamBasicDescription &ASBDescription, // 2 Float64 seconds, // 3 UInt32 *outBufferSize // 4 ) { static const int maxBufferSize = 0x50000; // 5 int maxPacketSize = ASBDescription.mBytesPerPacket; // 6 if (maxPacketSize == 0) { // 7 UInt32 maxVBRPacketSize = sizeof(maxPacketSize); AudioQueueGetProperty ( audioQueue, kAudioQueueProperty_MaximumOutputPacketSize, // in Mac OS X v10.5, instead use // kAudioConverterPropertyMaximumOutputPacketSize &maxPacketSize, &maxVBRPacketSize ); } Float64 numBytesForTime = ASBDescription.mSampleRate * maxPacketSize * seconds; // 8 *outBufferSize = UInt32 (numBytesForTime < maxBufferSize ? numBytesForTime : maxBufferSize); // 9 } コードの働きを見てみましょう: - サイズを特定したいバッファを持つAudio Queue。 - Audio Queueの''AudioStreamBasicDescription''構造体。 - 音声の秒数を単位とした、必要とするAudio Queue Bufferの大きさ。 - 出力で、バイト数を単位としたAudio Aueue Bufferのサイズ。 - Audio Queue Bufferサイズの上限(バイト数)。この例では320KBに設定されている。これはサンプリング周波数96kHz/24ビット/ステレオでおよそ5秒に対応する。 - CBR音声データ用に、''AudioStreamBasicDescription''構造体からパケットサイズ(定数)を得る。この値を最大パケットサイズとして使う。 - この割り当ては、その音声データの録音がCBRかVBRかを特定する副作用をもたらす。VBRならば、Audio Queueの''AudioStreamBasicDescription''構造体のbytes-per-packetの値は0を示す。 - VBR音声データ用に、Audio Queueに見積もり最大パケットサイズを問い合わせる。 - バイト数でバッファサイズを計算する。 - 必要ならば、前述の上限値にバッファサイズを制限する。 ===== Audio File用マジッククッキーの設定 ===== MPEG-4 AACなどのいくつかの圧縮音声形式は、オーディオメタデータを含む構造を利用します。 これら構造を**マジッククッキー**と呼びます。 Audio Queue Serviceを使ってこのような形式で録音する際は、録音開始前にAudio Queueからマジッククッキーを取得し、それをAudio Fileに追加しなければなりません。 リスト2-7はAudio Queueからマジッククッキーを得る方法と、Audio Fileへの適用方法を示します。 Your code would call a function like this before recording, and then again after recording—some codecs update magic cookie data when recording has stopped. **リスト 2-7** Audio File用マジッククッキーの設定 OSStatus SetMagicCookieForFile ( AudioQueueRef inQueue, // 1 AudioFileID inFile // 2 ) { OSStatus result = noErr; // 3 UInt32 cookieSize; // 4 if ( AudioQueueGetPropertySize ( // 5 inQueue, kAudioQueueProperty_MagicCookie, &cookieSize ) == noErr ) { char* magicCookie = (char *) malloc (cookieSize); // 6 if ( AudioQueueGetProperty ( // 7 inQueue, kAudioQueueProperty_MagicCookie, magicCookie, &cookieSize ) == noErr ) result = AudioFileSetProperty ( // 8 inFile, kAudioFilePropertyMagicCookieData, cookieSize, magicCookie ); free (magicCookie); // 9 } return result; // 10 } コードの働きを見てみましょう: - 録音に使うAudio Queue。 - 記録に使うAudio File。 - この関数の成否を表す返値変数。 - マジッククッキーのデータサイズを保持する変数。 - Audio Queueからマジッククッキーのデータサイズを取得し、''cookieSize''変数に格納します。 - マジッククッキー情報を保持するバイト列を確保します。 - Audio Queueの''kAudioQueueProperty_MagicCookie''プロパティを問い合わせてマジッククッキーを取得します。 - 記録するAudio Fileにマジッククッキーを設定します。''AudioFileSetProperty''関数は''AudioFile.h''ヘッダファイルで宣言されています。 - 一時クッキー変数のメモリを解放します。 - 関数の成否を返します。 ===== 録音音声フォーマットの構成 ===== 本項ではAudio Queueの音声データ形式の構成方法を説明します。 Audio Queueはファイルへの記録にこのフォーマットを使用します。 音声データ形式の構成には、次の事柄を特定します: * 音声データ形式の種類(リニアPCM, AAC, その他など) * サンプリング周波数(44.1kHzなど) * 音声チャンネル数(ステレオには2など) * ビット深度(16ビットなど) * パケット毎のフレーム数(例えばリニアPCMでは1フレーム毎パケット) * 音声ファイルの種類(CAF, AIFF, その他など) * そのファイル種別が要求する音声データ形式の詳細 リスト2-8は、各属性を固定値とした録音用の音声形式の構成を示します。 製品コードでは、通常、音声形式の幾つかないし全ての項目をユーザーが設定できるようにすべきでしょう。 いずれのアプローチでも、目的は“[[#状態を管理する独自構造体の定義]]”で解説した''AQRecorderState''独自構造体の''mDataFormat''のフィールドを埋めることです。 **リスト 2-8** Audio Queueの音声データ形式の指定 AQRecorderState aqData; // 1 aqData.mDataFormat.mFormatID = kAudioFormatLinearPCM; // 2 aqData.mDataFormat.mSampleRate = 44100.0; // 3 aqData.mDataFormat.mChannelsPerFrame = 2; // 4 aqData.mDataFormat.mBitsPerChannel = 16; // 5 aqData.mDataFormat.mBytesPerPacket = // 6 aqData.mDataFormat.mBytesPerFrame = aqData.mDataFormat.mChannelsPerFrame * sizeof (SInt16); aqData.mDataFormat.mFramesPerPacket = 1; // 7 AudioFileTypeID fileType = kAudioFileAIFFType; // 8 aqData.mDataFormat.mFormatFlags = // 9 kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; コードの働きを見てみましょう: - ''AQRecorderState''独自構造体の実体を生成します。構造体の''mDataFormat''フィールドは''AudioStreamBasicDescription''構造体を含みます。''mDataFormat''フィールドでセットされた値は、Audio Queueの音声フォーマットの初期定義を提供します—それはまた、記録先ファイルの音声フォーマットでもあります。リスト2-10では、より完全な音声フォーマット仕様を取得しますが、Core Audioはそれらをフォーマットタイプとファイルタイプに基づいて提供します。 - 音声データタイプをリニアPCMとして定義します。利用可能なデータ形式の完全なリストは//[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/Reference/reference.html|Core Audio Data Types Reference]]//をご覧下さい。 - サンプリング周波数を44.1kHzとします。 - チャンネル数は2とします。 - チャンネルあたりのビット深度は16とします。 - パケットあたりのバイト数とフレームあたりのバイト数は4とします(2チャンネル×サンプルあたり2バイト)。 - パケットあたりのフレーム数は1とします。 - ファイルタイプはAIFFとします。利用可能なファイルタイプの完全なリストは''AudioFile.h''ヘッダファイルの音声ファイルタイプ列挙値をご覧下さい。“[[0200_aboutaudioqueues#コーデックと音声データ形式を使う]]”で解説したように、インストール済みコーデックが存在するあらゆるファイルタイプを書くことが出来ます。 - 特定のファイルタイプで必要となるフォーマットフラグを設定します。 ===== 録音Audio Queueの生成 ===== それでは、録音コールバックと音声データ形式を設定して、録音Audio Queueの生成と設定をします。 ==== 録音Audio Queueを生成する ==== リスト2-9は録音Audio Queueの作り方を示したものです。 ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueNewInput|AudioQueueNewInput]]''関数が、前のステップで構成したコールバック、独自構造体、音声データ形式を使う点に注目して下さい。 **リスト 2-9** 録音Audio Queueの生成 AudioQueueNewInput ( // 1 &aqData.mDataFormat, // 2 HandleInputBuffer, // 3 &aqData, // 4 NULL, // 5 kCFRunLoopCommonModes, // 6 0, // 7 &aqData.mQueue // 8 ); コードの働きを見てみましょう: - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueNewInput|AudioQueueNewInput]]''関数は新しい録音Audio Queueを生成します。 - 録音に使う音声データ形式です。“[[#録音用音声フォーマットの構成]]”をご覧下さい。 - 録音Audio Queueが使うコールバック関数です。“[[#録音Audio Queueコールバックの実装]]”をご覧下さい。 - 録音Audio Queueの独自データ構造体です。“[[#状態を管理する独自構造体の定義]]”をご覧下さい。 - コールバックを呼び出す実行ループを指定します。''NULL''はデフォルトの挙動を示し、Audio Queue内部のスレッドでコールバックが呼ばれます。これは典型的な使い方で、アプリケーションのユーザーインタフェーススレッドが録音停止の入力を待つ間、Audio Queueによる録音を許可します。 - コールバック呼び出しの実行ループモードです。通常、ここには''kCFRunLoopCommonModes''定数を使います。 - 将来拡張用です。''0''を指定して下さい。 - 新たに確保された録音Audio Queueが出力されます。 ==== Audio Queueから完全な音声形式を取得する ==== Audio Queueの実体が出来ると(“[[#録音Audio Queueの生成]]”をご覧下さい)、Audio Queueは特に圧縮フォーマットにおいて、あなたが持っているものより完全に''AudioStreamBasicDescription''構造体を埋めるでしょう。 完全なフォーマット記述を取得するには、リスト2-10で示すように''AudioQueueGetProperty''関数を呼びます。 記録先のAudio Fileを作る際は、その完全な音声フォーマットをしようします(“[[#Audio Fileの生成]]”をご覧下さい)。 **リスト 2-10** Audio Queueから音声フォーマットを得る UInt32 dataFormatSize = sizeof (aqData.mDataFormat); // 1 AudioQueueGetProperty ( // 2 aqData.mQueue, // 3 kAudioQueueProperty_StreamDescription, // 4 // Mac OS Xでは代わりに↓を使ってください // kAudioConverterCurrentInputStreamDescription &aqData.mDataFormat, // 5 &dataFormatSize // 6 ); コードの働きを見てみましょう: - Audio Queueに音声データ形式を問い合わせる時に使う、プロパティ値の期待サイズを得ます。 - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueGetProperty|AudioQueueGetProperty]]''関数はAudio Queueから指定のプロパティ値を得ます。 - 音声データ形式を取得するAudio Queueです。 - Audio Queueのデータ形式値を得るためのプロパティIDです。 - 出力で、Audio Queueから得られた''AudioStreamBasicDescription''構造体による完全な音声データ形式です。 - 入力では、''AudioStreamBasicDescription''構造体の期待サイズです。出力では、実際のサイズが入ります。あなたの録音アプリケーションでは、この値を利用する必要はありません。 ===== Audio Fileの生成 ===== 生成と設定が行われたAudio Queueを使って、リスト2-11のように録音データを保存するAudio Fileを生成します。 Audio Fileは、前述のAudio Queueの独自構造体に格納されたデータ形式とファイル形式仕様を使います。 **リスト 2-11** 記録用Audio Fileの生成 CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation ( // 1 NULL, // 2 (const UInt8 *) filePath, // 3 strlen (filePath), // 4 false // 5 ); AudioFileCreateWithURL ( // 6 audioFileURL, // 7 fileType, // 8 &aqData.mDataFormat, // 9 kAudioFileFlags_EraseFile, // 10 &aqData.mAudioFile // 11 ); コードの働きを見てみましょう: - ''CFURL.h''ヘッダファイルで宣言される''[[https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFURLRef/Reference/reference.html#//apple_ref/doc/c_ref/CFURLCreateFromFileSystemRepresentation|CFURLCreateFromFileSystemRepresentation]]''関数は、記録に使うファイルを表す''CFURL''オブジェクトを生成します。 - ''NULL''(または''kCFAllocatorDefault'')を使うと、現在のデフォルトメモリアロケータを使います。 - ''CFURL''オブジェクトに変換したいファイルシステムパスです。製品コードでは、通常、''filePath''からユーザー指定の値を得ます。 - ファイルシステムパスのバイト数です。 - ''false''は''filePath''がディレクトリではなくファイルである事を示します。 - ''AudioFile.h''ヘッダファイルの''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html#//apple_ref/doc/c_ref/AudioFileCreateWithURL|AudioFileCreateWithURL]]''関数は、音声ファイルの新規作成ないし既存ファイルの初期化を行います。 - 新規音声ファイルの作成、もしくは既存ファイルの初期化の対象となるURLです。URLは手順1の[[https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFURLRef/Reference/reference.html#//apple_ref/doc/c_ref/CFURLCreateFromFileSystemRepresentation|CFURLCreateFromFileSystemRepresentation]]に由来します。 - 新しいファイルのファイルタイプです。本章のサンプルコードでは、前に''kAudioFileAIFFType''ファイルタイプ定数を経由してAIFFに設定されています。“[[#録音音声フォーマットの構成]]”をご覧下さい。 - ''AudioStreamBasicDescription''構造体として指定される、ファイルに記録する音声のデータ形式です。本章のサンプルコードでは、これも“[[#録音音声フォーマットの構成]]”で設定されています。 - ファイルが既に存在していた場合、そのファイルを消します。 - 出力で、記録先の音声ファイルを表す(''AudioFileID''型の)Audio Fileオブジェクトです。 ===== Audio Queue Bufferサイズの設定 ===== 録音中に使うAudio Queue Bufferセットを準備する前に、先に書いた''DeriveBufferSize''関数(“[[#録音Audio Queue Bufferサイズを計算する関数の実装]]”をご覧下さい)を使います。 このサイズを使用する録音Audio Queueのサイズに割り当てます。 リスト2-12がその様子を示します: **リスト 2-12** Audio Queue Bufferサイズの設定 DeriveBufferSize ( // 1 aqData.mQueue, // 2 aqData.mDataFormat, // 3 0.5, // 4 &aqData.bufferByteSize // 5 ); コードの働きを見てみましょう: - “[[#録音Audio Queue Bufferサイズを計算する関数の実装]]”で解説した''DeriveBufferSize''関数は、妥当なAudio Queue Bufferサイズを設定します。 - バッファサイズを設定するAudio Queueです。 - 記録するファイルの音声データ形式です。“[[#録音音声フォーマットの構成]]”をご覧下さい。 - 各Audio Queue Bufferが保持する音声の秒数です。通常、ここで設定している0.5秒が良い選択です。 - 出力で、各Audio Queue Bufferサイズがバイト数で返ります。この値はAudio Queueの独自構造体の中に置かれます。 ===== Audio Queue Bufferセットの準備 ===== それでは、(“[[#録音Audio Queueの生成]]”で)生成したAudio Queueに、Audio Queue Bufferセットを準備するように命令します。 リスト 2-13はそのデモンストレーションです。 **リスト 2-13** Audio Queue Bufferセットの準備 for (int i = 0; i < kNumberBuffers; ++i) { // 1 AudioQueueAllocateBuffer ( // 2 aqData.mQueue, // 3 aqData.bufferByteSize, // 4 &aqData.mBuffers[i] // 5 ); AudioQueueEnqueueBuffer ( // 6 aqData.mQueue, // 7 aqData.mBuffers[i], // 8 0, // 9 NULL // 10 ); } コードの働きを見てみましょう: - Audio Queue Buffer確保とキュー追加のためにイテレートします。 - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueAllocateBuffer|AudioQueueAllocateBuffer]]''関数はAudio QueueにAudio Queue Bufferを確保するよう指示します。 - バッファを確保し所持するAudio Queueです。 - 新しく確保されるAudio Queue Bufferのバイト数です。“[[#録音Audio Queue Bufferサイズを計算する関数の実装]]”をご覧下さい。 - 新しく確保されたAudio Queue Bufferが出力されます。バッファへのポインタはAudio Queueと共に使う独自構造体の中に置かれます。 - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueEnqueueBuffer|AudioQueueEnqueueBuffer]]''関数はバッファキューの最後にAudio Queue Bufferを追加します。 - キューに加えるAudio Queue Bufferを持つAudio Queue。 - キューに加えるAudio Queue Buffer。 - 録音におけるバッファのキュー追加では、本パラメータは使用しません。 - 録音におけるバッファのキュー追加では、本パラメータは使用しません。 ===== 録音 ===== リスト2-14で示されるように、これまでのコードの全てが録音のとてもシンプルな工程に繋がりました。 **リスト 2-14** 録音 aqData.mCurrentPacket = 0; // 1 aqData.mIsRunning = true; // 2 AudioQueueStart ( // 3 aqData.mQueue, // 4 NULL // 5 ); // ユーザーインターフェーススレッドにおいてユーザーが録音を止めるまで待つ AudioQueueStop ( // 6 aqData.mQueue, // 7 true // 8 ); aqData.mIsRunning = false; // 9 コードの働きを見てみましょう: - Audio Fileの先頭から記録するためにパケットインデックスを''0''に初期化します。 - Audio Queueが実行中を表すフラグを独自構造体にセットします。このフラグは録音Audio Queueコールバックで使用されます。 - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueStart|AudioQueueStart]]''関数は、Audio Queue自身のスレッドでAudio Queueを開始します。 - 開始するAudio Queue。 - ''NULL''を使うと、Audio Queueが直ちに録音を開始する事を示します。 - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueStop|AudioQueueStop]]''関数は録音Audio Queueを停止しリセットします。 - 停止するAudio Queue。 - ''true''を使うと、同期的に止めます。停止における同期と非同期の説明は“[[0200_aboutaudioqueues#Audio Queueの状態と制御]]”をご覧ください。 - Audio Queueが非実行中を示すフラグを独自構造体にセットします。 ===== 録音後の後始末 ===== 録音が終わったら、Audio Queueを破棄しAudio Fileを閉じます。 リスト 2-15はこれらの手順を示します。 **リスト 2-15** 録音後の後始末 AudioQueueDispose ( // 1 aqData.mQueue, // 2 true // 3 ); AudioFileClose (aqData.mAudioFile); // 4 コードの働きを見てみましょう: - ''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueDispose|AudioQueueDispose]]''関数はAudio Queueと、バッファを含むその全ての資源を破棄します。 - 破棄したいAudio Queue。 - ''true''を使うとAudio Queueを同期的に(すなわち、即座に)破棄します - 記録に使ったAudio Fileを閉じます。''[[https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html#//apple_ref/doc/c_ref/AudioFileClose|AudioFileClose]]''関数は''AudioFile.h''ヘッダファイルで宣言されています。