2

AUSampler AudioUnit を他の AudioUnit と組み合わせて使用​​し、オーディオを再生する iPad アプリケーションを開発しています。AUSampler は、SoundFont2 ファイルからプリセットを読み込みます。

一度に再生されるノートの数が多すぎるか、ノートの再生が速すぎると、オーディオが完全にドロップアウトする前に一時的にドロップアウトし始めます。サンプラーは、プリセットがサウンドフォントからリロードされるまで使用できません。これは、一部のインストゥルメントでのみ発生します (特にプリセット 88、90、および 94。General MIDI では、それぞれパッド 1 (ニューエイジ)、パッド 3 (ポリシンセ)、およびパッド 7 (ハロー) です)。

XCode で All Exceptions ブレークポイントをオンにすると、再生中のノートに対して AudioToolbox が新しい VoiceZone を作成しようとすると、問題が発生することがわかります。ただし、この例外はコードの下のコール スタックのどこかでキャッチされ、AudioUnitRender はエラーを返しません。

私の推測では、「パッド」インストゥルメントはより長いサンプルを使用するため、多くのノートをすばやく/同時に再生すると、AudioToolbox で使用できるよりも多くのメモリが使用されます。

以前にこの問題に遭遇した人はいますか?もしそうなら、オーディオのドロップアウトを回避する方法、または少なくともそれらを検出して適切に処理する方法はありますか?

いくつかの詳細:

  • サウンドフォントは ~150 MB で、General MIDI に準拠したさまざまなプリセット/インストゥルメントが含まれています
  • AUSampler は、AUMultiChannelMixer ( me.masterMixerUnit) に接続する一連のエフェクト ユニットの先頭にあります。audioOutputCallbackRemoteIO ユニットの出力要素の入力コールバックとして設定されます。

バックトレース (`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;
}
4

1 に答える 1

1

通常の状態で音質が良好であれば、ドロップアウトの原因は AU チェーンのプログラミング エラーではなく、OS がブロックを十分に高速に処理できないことが原因であると推測できます。

オーディオのドロップアウトを検出する最も簡単な方法は、処理を開始する前にシステム時間をマイクロ秒単位で取得し、完了後に再度測定することです。サンプル レートとバッファ サイズを調べることで、指定された時間内にサンプルを配信できたかどうかを判断できるはずです。

実際にパフォーマンスが原因でドロップアウトが発生していることが判明した場合は、最初に行うべきことは、バッファー サイズを増やすことです。それに続いて、いくつかの基本的な方法でコードを最適化してください。Instruments (つまり、プロファイラー) を介してアルゴリズムを実行し、明らかなボトルネックを探します。レンダー コールバック内でのオブジェクトの割り当ては避けてください。これにより、システムに余分な負荷がかかります。

また、問題が実際に iPad のパフォーマンスによって引き起こされていることを確認するために、デスクトップ コンピューターで処理コードを実行することをお勧めします。

于 2012-12-11T08:35:06.793 に答える