1

私のアプリは基本的に次々とノートを再生し、毎回どのノートが再生されているかを表示したいと考えています。各音符は UI の四角形であり、再生中の音符に向かって左から右に移動する 1 ピクセルのビューがあります。

問題は、これら 2 つのことを同時に行う方法がわからないことです。サンプル レンダリング関数からメッセージを送信できません。これは、速度が遅くなり、オーディオ再生に不具合が生じる可能性があるためです。再生されているものを反映するように UI を更新する方法を提案する人はいますか?

私の音楽再生コードはこの例に基づいており、RenderTone メソッドは別のスレッドで実行されていると思います。1000 個のサンプルが再生されるたびに 1 ピクセルのビューを 1 ピクセル移動したいのですが (一例にすぎませんが、もっと少なくすることもできます)、UI にメッセージを送信し、サンプル数の更新を送信する方法がわかりません。再生されました。

したがって、以下のコードのバリエーションが実行されている間に、何らかの方法で UI を更新する必要があります。

OSStatus RenderTone(
    void *inRefCon, 
    AudioUnitRenderActionFlags *ioActionFlags, 
    const AudioTimeStamp *inTimeStamp, 
    UInt32 inBusNumber, 
    UInt32 inNumberFrames, 
    AudioBufferList *ioData)

{
    // Fixed amplitude is good enough for our purposes
    const double amplitude = 0.25;

    // Get the tone parameters out of the view controller
    ToneGeneratorViewController *viewController =
        (ToneGeneratorViewController *)inRefCon;
    double theta = viewController->theta;
    double theta_increment =
        2.0 * M_PI * viewController->frequency / viewController->sampleRate;

    // This is a mono tone generator so we only need the first buffer
    const int channel = 0;
    Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;

    // Generate the samples
    for (UInt32 frame = 0; frame < inNumberFrames; frame++) 
    {
        buffer[frame] = sin(theta) * amplitude;

        theta += theta_increment;
        if (theta > 2.0 * M_PI)
        {
            theta -= 2.0 * M_PI;
        }
    }

    // Store the updated theta back in the view controller
    viewController->theta = theta;

    return noErr;
}
4

2 に答える 2

1

iOSデバイスでは、UIはディスプレイの60Hzのリフレッシュレートに関してのみ更新できます。したがって、ディスプレイのリフレッシュレートでのポーリングは合理的な代替手段であり、オーディオユニットのコールバックスレッド内のリアルタイムの制約に違反する不適切な処理(メモリ管理を伴う可能性のあるObj Cメッセージングなど)を行うリスクはありません。

オーディオセッションのバッファ期間を1/60秒以下にするように要求できます。次に、オーディオユニットバッファコールバックを設定するか、オーディオサンプル位置カウンタをインクリメントします(この書き込みがアトミックになるように、1整列されたlong int変数にします)。

次に、UI実行ループで、必要なUIの応答性に応じて、このオーディオ位置カウンターを1秒あたり60回(フレーム同期)以下の速度でポーリングします。オーディオサンプルの位置から音楽の位置を計算し、音楽の位置が新しいノートが再生されている、または再生されようとしていることを示している場合は、UIを更新します。

于 2012-08-11T22:27:52.423 に答える
1

このコードのさまざまな場面で、メイン スレッドに戻る単純なブロックを使用することをお勧めします。

dispatch_async(dispatch_get_main_queue(), ^{ someViewController makeSomeChange:withParam; } );

それらをまれに送信できます。RenderTone コードを highPriority キューで実行できるため、重要な作業がない場合にのみ mainQueue が実行されます。

于 2012-08-03T13:23:21.787 に答える