iOS: Pitch Shifting & Piping вывод из OpenAL в буфер - PullRequest
4 голосов
/ 06 декабря 2010

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

4 голосов
/ 07 декабря 2010

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

...