1

ユーザーがオーディオユニットを使用してビートを記録できるアプリを持っています。これを実現するために、Apple の MixerHost サンプル コードから Mixer クラスを変更しました。

現在、サウンド ファイルがループしており、これを停止したいと考えています。サウンド ファイルが完成したら、ユーザーがミックスを保存できるようにしたいと思います。

ループの理由は、関数for loopの次のセクションの最後の行にあります。inputrendercallback

for (UInt32 frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber) {

        outSamplesChannelLeft[frameNumber]                 = dataInLeft[sampleNumber];
        if (isStereo) outSamplesChannelRight[frameNumber]  = dataInRight[sampleNumber];

        sampleNumber++;

        // After reaching the end of the sound stored in memory--that is, after
        //    (frameTotalForSound / inNumberFrames) invocations of this callback--loop back to the 
        //    start of the sound so playback resumes from there.
        if (sampleNumber >= frameTotalForSound) sampleNumber = 0;
    }

サンプルが使い果たされたら、コールバックにサンプルの要求を停止するように指示するために変更する必要があることは理解してif (sampleNumber >= frameTotalForSound) sampleNumber = 0;いますが、この C-Struct を操作するよりも、Objective C でメソッドを呼び出す方がはるかに快適です。

これを行う方法について誰かアイデアがありますか?

ありがとう。

4

3 に答える 3

2

MixerHost は、Apple が提供する貴重な数少ない Core Audio の例の 1 つであるため、多くの人がこのオーディオ ファイル ループの問題に遭遇したに違いないと想像できます。

NSNotificationCenter を使用してこの問題を解決しました。C 関数内での Objective C の使用を非難する前に、MixerHost の例自体で Apple のコードの他の部分を模倣することで、この解決策を見つけたことを認識しておいてください。たとえば、プログラムを一時停止して、ヘッドフォンが取り外されたこと、またはデバイスがドック コネクタから取り外されたことを示すために、Apple は MixerHostAudio クラスの通知センターを使用しましたaudioRouteChangeListenerCallback

 if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {

            NSLog (@"Audio output device was removed; stopping audio playback.");
            NSString *MixerObjectPlaybackStateDidChangeNotification = @"MixerObjectPlaybackStateDidChangeNotification";
            [[NSNotificationCenter defaultCenter] postNotificationName: MixerObjectPlaybackStateDidChangeNotification object: audioObject]; 

inputrendercallback関数内からの通知も投稿することにしました。

for (UInt32 frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber) {

        if (sampleNumber == frameTotalForSound) {

            NSString *AudioFileFinishedPlaying = @"AudioFileFinishedPlaying";
            [[NSNotificationCenter defaultCenter] postNotificationName: AudioFileFinishedPlaying object: nil];
        }

        outSamplesChannelLeft[frameNumber]                 = dataInLeft[sampleNumber];
        if (isStereo) outSamplesChannelRight[frameNumber]  = dataInRight[sampleNumber];

        sampleNumber++;

...

次に addObserver:selector:name:object:、プログラムの別の部分でメソッドを使用して、ループを停止し、アプリに関連する他のタスクを実行しました。

これがお役に立てば幸いです。誰かがより良い解決策を持っているなら、私はそれを受け入れる用意があります. ありがとう。

于 2012-04-21T13:28:15.480 に答える
1

オーディオ処理またはバッファ コールバックの内部ループでは、Objective C メッセージングを使用しないでください。理由もなくサイクル オーバーヘッドが多すぎます。C 構造体では、組み込みの C 型を使用することに固執します。フラグ変数の設定はOKです。必要なオブジェクト メッセージングは​​、後でコールバックと内側のオーディオ サンプル ループの外で行います。

于 2012-04-21T07:05:00.033 に答える
0

ソリューションを投稿していただきありがとうございます。それは機能し、Apple が他の通知を宣言した方法と矛盾していません。いくつかのメモ:

  1. 複数のファイルを混合している場合、これにより、最も短いファイルが最後に到達したときにプレーヤーが停止します。

  2. 私は次のコードを試しました(残りのinputrendercallback関数は変更されていないと仮定します):

    if (sampleNumber >= frameTotalForSound) { NSLog(@"終わりました!"); THIS.stopAUGraph; サンプル番号 = 0; // もう一度プレイしたい場合 }

于 2012-11-21T05:23:19.530 に答える