今回はタイムストレッチの処理を行う実装の説明を行います。
前回の 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)」を参考にしていただければと思います。