Я недавно заметил, что в iOS можно использовать OpenAL для изменения высоты тона.
Я смотрю на звуковой банк Hollance. он берет приблизительно 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);
к сожалению, это нехорошо для одновременной игры пачки нот, так как это требует слишком много ресурсов процессора. это изменение высоты тона динамически.
я хочу создать буфер для каждой ноты пианино и заполнить эти буферы с помощью этой технологии смещения высоты тона. но я не вижу, как заставить openAL воспроизводить звук в буфер, а не воспроизводить его через динамики.
есть ли способ передать вывод
alSourcePlay (source-> SourceId);
в буфер?
Если я не могу этого сделать, каковы мои варианты? Я попытался использовать smbPitchShift из статьи DSPDimension, но это не дает хорошей точности: фаза атаки фортепианной ноты действительно потеряна. Думаю, я мог бы использовать бесплатную версию Dirac3 ... (у меня сейчас нет денег на полную версию, но я думаю, что бесплатная версия позволяет обрабатывать Mono, так что я могу ее взломать). есть ли другой вариант?
РЕДАКТИРОВАТЬ: С тех пор я проверил Dirac3, и он имеет ту же проблему. кажется, окутывает атаку. кажется, что устройство изменения высоты звука OpenAL каким-то образом делает то, что не делает Dirac3.