パート4はRecording With Audio Queuesです。
まずは、UtilityFunctionsから見ていきましょう。見やすくフォーマットされた文字列を表示するためのカスタム関数NSPrintを定義しています。ブログの著者さんはこの記事を参考にしたようです。
void NSPrint(NSString *format, ...) { // [1]
va_list args; // [2]
va_start(args, format);
NSString *string = [[NSString alloc] initWithFormat:format arguments:args]; // [3]
va_end(args);
fprintf(stdout, "%s", [string UTF8String]); // [4]
#if !__has_feature(objc_arc)
[string release]; // [5]
#endif
}
[1] … はC言語の文法で、この関数は「いくつかの引数を得られる」という意味です。stdarg.hに宣言されている va_list, va_start, va_endを使うことが出来ます。
[2] va_list型の変数argsを作成しています。va_listはvariable argument list(可変の変数のリスト)の略で、…の内容が格納されます。このva_listにはva_startとva_endの中でアクセスすることが出来ます。
[3] NSStringの標準のinitializerのinitWithFormatでインスタンス*stringを作り、arguments:に引数argsを渡しています。
[4] fprintfはC言語の関数で、fprintf(ストリーム、フォーマット、…(文字列))のように使います。
[5] ARC (Automatic Reference Counting)がない場合は手動でstringをリリースします。
次は、エラーの有無をチェックするカスタム関数CheckErrorです。
void CheckError(OSStatus error, const char *operation) {
if (error == noErr) {
return;
}
char errorString[20]; // [6]
*(UInt32 *)(errorString + 1) = CFSwapInt32HostToBig(error); // [7] we have 4 bytes and we put them in Big-endian ordering. 1st byte the biggest
if (isprint(errorString[1]) && isprint(errorString[2]) && // [8]
isprint(errorString[3]) && isprint(errorString[4])) {
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
} else {
sprintf(errorString, "%d", (int) error);
}
NSLog(@"Error: %s (%s)\n", operation, errorString);
exit(1);
}
[6] 20バイトの空のcharの配列を作成しています。
[7] *(errorString + 1) のerrorString + 1 はポインタ演算です。errorString配列の2番目の要素(つまりerrorString[1]と同じ)にCFSwapInt32HostToBig(error)の戻り値unsigned intを代入しています。Big-endianは、UInt32の4byteのうち、最初のbyteが一番大きな値となるメモリ上の保存方法です。
[8] isprint( ) はC言語の関数で、そのcharがcharとして表示可能かをチェックするものです。例として’a’は表示可能、’\t’は表示可能ではない、となります。
次に、デフォルトのインプットデバイスのサンプルレートを確認するカスタム関数を見てみましょう。
void GetDefaultInputDeviceSampleRate(Float64 *oSampleRate) {
AudioObjectPropertyAddress propertyAddress; // [9]
propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0; // master element
AudioDeviceID deviceID = 0;
UInt32 propertySize = sizeof(AudioDeviceID);
CheckError(AudioObjectGetPropertyData(kAudioObjectSystemObject,
&propertyAddress,
0,
NULL,
&propertySize,
&deviceID), "Getting default input device ID from Audio System Object"); // [9]'
propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate; // [10]
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(Float64);
CheckError(AudioObjectGetPropertyData(deviceID,
&propertyAddress,
0,
NULL,
&propertySize,
oSampleRate), "Getting nominal sample rate for the default device"); // [10]'
}
[9] ~ [9]’ でdeviceIDを求め、[10] ~ [10]’でsampleRateを求めています。どちらもCore AudioのAudioObjectGetPropertyData( )関数を使っています。
// 以下執筆中。。。