翻訳元:[[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''ヘッダファイルで宣言されています。