今回はタイムストレッチの処理を行う実装の説明を行います。
前回の prepareAUGraph 関数を追記/修正することになります。
「2. AUNodeの作成」において、componentSubType が kAudioUnitSubType_AUiPodTimeOther の AUNode を追加することで、タイムストレッチの処理を行うことができます。
「5. Nodeの接続」は以下のようになります。
AUConverter -> AUiPodTimeOther -> Remote IO
- (OSStatus)prepareAUGraph { // 1. AUGraphの準備 NewAUGraph(&_graph); AUGraphOpen(_graph); // 2. AUNodeの作成 AudioComponentDescription cd; cd.componentType = kAudioUnitType_FormatConverter; cd.componentSubType = kAudioUnitSubType_AUConverter; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; AUNode converterNode; AUGraphAddNode(_graph, &cd, &converterNode); AUGraphNodeInfo(_graph, converterNode, NULL, &_converterUnit); cd.componentType = kAudioUnitType_FormatConverter; cd.componentSubType = kAudioUnitSubType_AUiPodTimeOther; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; AUNode aUiPodTimeNode; AUGraphAddNode(_graph, &cd, &aUiPodTimeNode); AUGraphNodeInfo(_graph, aUiPodTimeNode, NULL, &_aUiPodTimeUnit); cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_RemoteIO; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; AUNode remoteIONode; AUGraphAddNode(_graph, &cd, &remoteIONode); AUGraphNodeInfo(_graph, remoteIONode, NULL, &_remoteIOUnit); // 3. Callbackの作成 AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = renderCallback; callbackStruct.inputProcRefCon = self; AUGraphSetNodeInputCallback(_graph, converterNode, 0, // bus number &callbackStruct); // 4. 各NodeをつなぐためのASBDの設定 AudioStreamBasicDescription asbd = {0}; UInt32 size = sizeof(asbd); // converter IO AudioUnitSetProperty(_converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &_outputFormat, size); AudioUnitSetProperty(_converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &_outputFormat, size); // aUiPodTime IO AudioUnitSetProperty(_aUiPodTimeUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &_outputFormat, size); AudioUnitSetProperty(_aUiPodTimeUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &_outputFormat, size); // remoteIO I AudioUnitSetProperty(_remoteIOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &_outputFormat, size); // 5. Nodeの接続 // AUConverter -> AUiPodTimeOther AUGraphConnectNodeInput(_graph, converterNode, 0, aUiPodTimeNode, 0); // AUiPodTimeOther -> Remote IO AUGraphConnectNodeInput(_graph, aUiPodTimeNode, 0, remoteIONode, 0); // 6. AUiPodTimeOtherへ設定するためのプロキシオブジェクトを作成 // (次回に説明するため、今回はコメント) // _aUiPodTimeProxy = [[AUiPodTimeProxy alloc] initWithReverbUnit:_aUiPodTimeUnit]; // 7. AUGraphを初期化 AUGraphInitialize(_graph); return ret; }
タイムストレッチの値を変更するための処理は、上記でコメントしている箇所にて行うことになります。説明は次回に行います。
(追記:2015/03/23)
現時点での最新OS(iOS 8)で確認したところ、kAudioUnitSubType_AUiPodTimeOther についてもFloat32型での定義扱いになっているようです。(最初に本記事を書いた頃はそうではなかったのですが)
そのため、上記はそのまま使うと実行時エラーになると思います。
修正方法は、「イコライザーを追加しました(Tune Changer)」を参考にしていただければと思います。