Audio Unit によるリアルタイム・タイムストレッチ(2. タイムストレッチ)

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です