我最近发现在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);
不幸的是,这对于同时播放一组音符并不好,因为它需要太多的CPU。它是动态的音高变换。
我想要的是为每个钢琴音符创建一个缓冲区,并使用这种音高变换技术填充这些缓冲区。但我无法看到如何让openAL将声音播放到缓冲区而不是通过扬声器播放。
有没有办法管道输出 alSourcePlay(源 - >的SourceID);
进入缓冲区?
如果我不能这样做,我的选择是什么?我已经尝试过使用DSPDimension文章中的smbPitchShift,但它没有提供良好的保真度:钢琴音符的攻击阶段确实丢失了。我想我可以使用Dirac3的免费版本...(我目前没有完整版本的钱,但我认为免费版本允许Mono处理,所以我可以破解它)。还有其他选择吗?
编辑:我已经测试过Dirac3,它也有同样的问题。它似乎包围了攻击。似乎OpenAL的音高变换器以某种方式做了Dirac3没有做的事情。答案 0 :(得分:4)
alSourcePlayv允许您同时播放多个源 - 最大数量的源是平台相关的,但在iOS上为32(在Apple核心音频列表上回答,此处为完整性)