私は最近、iOSでOpenALを使用してピッチシフトを行うことが可能であることを発見しました。
ホランスのサウンドバンクプレーヤーを見ています。範囲全体に散らばった15程度のピアノの音を取り込み、どのサンプルに最も近いかを判断し、そのサンプルを適切な量だけピッチシフトすることで、任意の音を演奏します。これはそれを行うコードです:
- (void) noteOn: (int) midiNoteNumber
gain: (float) gain
{
if (!initialized)
{
NSLog(@"SoundBankPlayer is not initialized yet");
return;
}
int sourceIndex = [self findAvailableSource];
if (sourceIndex != -1)
{
alGetError(); // clear any errors
Note* note = notes + midiNoteNumber;
if (note->bufferIndex != -1)
{
Buffer* buffer = buffers + note->bufferIndex;
Source* source = sources + sourceIndex;
source->noteIndex = midiNoteNumber;
alSourcef(source->sourceId, AL_PITCH, note->pitch / buffer->pitch);
alSourcei(source->sourceId, AL_LOOPING, AL_FALSE);
alSourcef(source->sourceId, AL_REFERENCE_DISTANCE, 100.0f);
alSourcef(source->sourceId, AL_GAIN, gain);
float sourcePos[] = { note->panning, 0.0f, 0.0f };
alSourcefv(source->sourceId, AL_POSITION, sourcePos);
alSourcei(source->sourceId, AL_BUFFER, AL_NONE);
alSourcei(source->sourceId, AL_BUFFER, buffer->bufferId);
ALenum error;
if ((error = alGetError()) != AL_NO_ERROR)
{
NSLog(@"Error attaching buffer to source: %x", error);
return;
}
alSourcePlay(source->sourceId);
if ((error = alGetError()) != AL_NO_ERROR)
{
NSLog(@"Error starting source: %x", error);
return;
}
}
}
}
この線がピッチシフトを行っていることがわかります。
alSourcef(source->sourceId, AL_PITCH, note->pitch / buffer->pitch);
残念ながら、これはCPUを大量に消費するため、ノートのバンドルを同時に再生するのには適していません。ダイナミックにピッチシフトしています。
私が欲しいのは、ピアノの音ごとにバッファーを作成し、このピッチシフトテクノロジーを使用してこれらのバッファーにデータを入力することです。しかし、スピーカーから再生するのではなく、openALを使用してサウンドをバッファーに再生する方法がわかりません。
alSourcePlay(source-> sourceId);の出力をパイプする方法はありますか。
バッファに?
これができない場合、どのような選択肢がありますか?DSPDimensionの記事のsmbPitchShiftを使用してみましたが、忠実度が高くありません。ピアノの音のアタックフェーズが実際に失われています。私はDirac3の無料バージョンを使用できると思います...(現時点ではフルバージョンのお金はありませんが、無料バージョンではモノラル処理が可能だと思うので、それをハックできます)。他に選択肢はありますか?
編集:私はそれ以来Dirac3をテストしました、そしてそれは同じ問題を共有します。攻撃を包み込んでいるようです。OpenALのピッチシフターはどういうわけかDirac3がしないことをしているようです。