我正在开发一个iPad应用程序,该程序将AUSampler AudioUnit与其他AudioUnit一起使用来播放音频。 AUSampler从SoundFont2文件加载预设。
当一次演奏太多音符或演奏音符的速度太快时,音频会短暂地退出,然后再完全退出。然后,采样器将无法使用,直到从SoundFont重新加载预设为止。仅在某些乐器上会发生这种情况(特别是预设88、90和94,在常规MIDI中分别是Pad 1(新年龄),Pad 3(polysynth)和Pad 7(光晕))
通过打开XCode中的“所有异常”断点,我可以看到当AudioToolbox尝试为正在播放的音符创建新的VoiceZone时出现此问题。但是,此异常在我的代码下方的调用堆栈中的某个较低位置捕获,并且AudioUnitRender不会返回任何错误。
我最好的猜测是,“Pad”乐器使用的采样时间更长,因此快速/联合演奏许多音符会比AudioToolbox占用更多的内存。
以前是否有人遇到过此问题,如果是,是否有办法避免音频丢失,或至少检测到它们以优雅地处理它们?
一些细节:
AUSampler的
me.masterMixerUnit
)。 audioOutputCallback
设置为RemoteIO单元回溯(在`AURemoteIO::IOThread上):
* thread #14: tid = 0x3203, 0x368c8498 libc++abi.dylib`__cxa_throw, stop reason = breakpoint 1.2
frame #0: 0x368c8498 libc++abi.dylib`__cxa_throw
frame #1: 0x35d46a60 AudioToolbox`VoiceZone::operator new(unsigned long) + 340
frame #2: 0x35d46b6a AudioToolbox`VoiceZone::NewVoiceZone(SamplerNote*, ZoneState*, float, float, unsigned long) + 86
frame #3: 0x35d3f846 AudioToolbox`SamplerNote::Configure(InstrumentState*) + 1106
frame #4: 0x35d3ff2c AudioToolbox`non-virtual thunk to SamplerNote::Attack(MusicDeviceNoteParams const&) + 24
frame #5: 0x35d551ea AudioToolbox`SynthNote::AttackNote(SynthPartElement*, SynthGroupElement*, unsigned long, unsigned long long, unsigned long, MusicDeviceNoteParams const&) + 58
frame #6: 0x35d5485a AudioToolbox`SynthGroupElement::NoteOn(SynthNote*, SynthPartElement*, unsigned long, unsigned long, MusicDeviceNoteParams const&) + 70
frame #7: 0x35d3d220 AudioToolbox`SamplerElement::StartNote(SynthPartElement*, unsigned long, unsigned long, MusicDeviceNoteParams const&) + 344
frame #8: 0x35d3c4fa AudioToolbox`Sampler::RealTimeStartNote(SynthGroupElement*, unsigned long, unsigned long, MusicDeviceNoteParams const&) + 94
frame #9: 0x35d530a0 AudioToolbox`AUInstrumentBase::PerformEvents(AudioTimeStamp const&) + 164
frame #10: 0x35d5313c AudioToolbox`AUInstrumentBase::Render(unsigned long&, AudioTimeStamp const&, unsigned long) + 20
frame #11: 0x35d3c564 AudioToolbox`Sampler::Render(unsigned long&, AudioTimeStamp const&, unsigned long) + 68
frame #12: 0x35c2435a AudioToolbox`AUBase::DoRenderBus(unsigned long&, AudioTimeStamp const&, unsigned long, AUOutputElement*, unsigned long, AudioBufferList&) + 210
frame #13: 0x35c24184 AudioToolbox`AUBase::DoRender(unsigned long&, AudioTimeStamp const&, unsigned long, unsigned long, AudioBufferList&) + 496
frame #14: 0x35c23f8a AudioToolbox`AUMethodRender(void*, unsigned long*, AudioTimeStamp const*, unsigned long, unsigned long, AudioBufferList*) + 50
... render methods of other AudioUnits in chain ...
frame #32: 0x00081aaa SoundBrush 2`audioOutputCallback + 194 at SoundEngine.mm:1375
在以下我的回调中调用AudioUnitRender期间引发异常:
static OSStatus audioOutputCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
//get a reference to the SoundEngine
SoundEngine *me = (__bridge SoundEngine *)inRefCon;
// render the sound
OSStatus err = AudioUnitRender(me.masterMixerUnit,
ioActionFlags,
inTimeStamp,
kAudioUnitBus_Output,
inNumberFrames,
ioData);
if (err != noErr) NSLog(@"AudioUnitRender failed [%ld]", err);
// ... do some processing ...
return err;
}
最佳答案
如果在正常情况下音质良好,我猜这可能不是由您的AU链中的编程错误引起的,而是由OS无法足够快地处理该块引起的。
检测音频丢失的最简单方法是在开始处理之前获得系统时间(以微秒为单位),然后在完成操作后再次进行测量。通过查看采样率和缓冲区大小,您应该能够确定是否能够在给定的时间内交付样本。
如果发现确实存在性能下降的问题,那么您应该做的第一件事就是增加缓冲区大小。之后,您应该尝试以几种基本方式优化代码。通过Instruments(即探查器)运行算法,并查找任何明显的瓶颈。避免在render回调内部分配对象;这将对系统造成额外的压力。
我也建议在台式计算机上运行处理代码,以确保该问题确实是由iPad的性能引起的。