iOS: Pitch Shifting & Piping вывод из OpenAL в буфер

Недавно я заметил, что в 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.

1 ответ

Решение

alSourcePlayv позволяет воспроизводить несколько источников одновременно - максимальное количество источников зависит от платформы, но для iOS оно равно 32 (ответ на вопрос об аудио-ядре Apple, здесь для полноты)

Другие вопросы по тегам