Я недавно заметил, что в iOS можно использовать OpenAL для изменения высоты тона.iOS: Pitch Shifting & Piping выход из 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-обработку, поэтому я могу ее взломать). есть ли другой вариант?
EDIT: У меня с тех пор тестировался Dirac3, и он разделяет ту же проблему. он, похоже, нападает на атаку. кажется, что переключение Shift от OpenAL каким-то образом делает то, что Dirac3 не делает.
Я люблю вопросы с иллюстративным источником коды! Большое спасибо за это, это очень помогло мне! :) – cregox 2011-01-10 14:37:43
Не забудьте поднять его тогда;) – 2011-01-11 04:50:47