4

AUFilePlayerを使用してコアオーディオを操作して、いくつかのmp3をミキサーユニットにロードしています。すべてがうまく再生されますが、音楽を一時停止したり、音楽を最初に巻き戻したりすることはできません。AudioGraphを起動して停止しようとしましたが、再生を停止すると再起動できません。また、AudioUnitSetPropertyを使用して、ファイルの再生を0に設定してみました

つまり、これらの線に沿った何か:

        ScheduledAudioFileRegion rgn;
        memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
        rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
        rgn.mTimeStamp.mSampleTime = 0;
        rgn.mCompletionProc = NULL;
        rgn.mCompletionProcUserData = NULL;
        rgn.mAudioFile = inputFile;
        rgn.mLoopCount = 1;
        rgn.mStartFrame = 0;

        rgn.mFramesToPlay = nPackets * inputFormat.mFramesPerPacket;

        AudioUnitSetProperty(fileUnit, kAudioUnitProperty_ScheduledFileRegion, 
                             kAudioUnitScope_Global, 0,&rgn, sizeof(rgn));

助言がありますか?

4

2 に答える 2

6

他の誰かが同様の問題に取り組んでいて、グーグルで検索するのに数時間かかる場合に備えて、再生ヘッドを具体的に取得して設定する方法について私が発見したものは次のとおりです。

AUFilePlayerユニットから再生ヘッドを取得するには:

AudioTimeStamp timestamp;
UInt32 size = sizeof(timestamp);
err = AudioUnitGetProperty(unit, kAudioUnitProperty_CurrentPlayTime, kAudioUnitScope_Global, 0, &timestamp, &size);

これtimestamp.mSampleTimeは、そのファイルの現在の再生ヘッドです。floatまたはdoubleにキャストmSampleTimeし、ファイルのサンプルレートで割って、秒に変換します。

AUFilePlayerの再生ヘッドを再起動するために、複数のAUFilePlayerがミキサーを通過し、さまざまな時間、複数回、さまざまなループカウントでスケジュールできる、より複雑なシナリオがありました。これは実際のシナリオであり、すべてを正しい時間に再起動するには、少しのコードが必要でした。

各AUFilePlayerには4つのシナリオがあり、そのスケジュールは次のとおりです。

  1. 再生ヘッドは最初にあるので、通常どおりにスケジュールできます。

  2. 再生ヘッドはアイテムの期間を過ぎており、スケジュールする必要はまったくありません。

  3. 再生ヘッドはアイテムが開始する前にあるため、開始時間を上に移動できます。

  4. 再生ヘッドはアイテムの再生中にあるため、ファイル内で再生する領域を調整する必要があり、残りのループは個別にスケジュールする必要があります(完全に再生されるように)。

これを示すいくつかのコードがあります(いくつかの外部構造は私自身のコードからのものであり、Core Audioではありませんが、メカニズムは明確である必要があります):

// Add each region
for(int iItem = 0; iItem < schedule.items.count; iItem++) {
    AEFileScheduleItem *scheduleItem = [schedule.items objectAtIndex:iItem];

    // Setup the region
    ScheduledAudioFileRegion region;
    [file setRegion:&region schedule:scheduleItem];

    // Compute where we are at in it
    float playheadTime = schedule.playhead / file.sampleRate;
    float endOfItem = scheduleItem.startTime + (file.duration*(1+scheduleItem.loopCount));

    // There are four scenarios:

    // 1. The playhead is -1
    //    In this case, we're all done
    if(schedule.playhead == -1) {
    }

    // 2. The playhead is past the item start time and duration*loopCount
    //    In this case, just ignore it and move on
    else if(playheadTime > endOfItem) {
        continue;
    }

    // 3. The playhead is less than or equal to the start time
    //    In this case, simply subtract the playhead from the start time
    else if(playheadTime <= scheduleItem.startTime) {
        region.mTimeStamp.mSampleTime -= schedule.playhead;
    }

    // 4. The playhead is in the middle of the file duration*loopCount
    //    In this case, set the start time to zero, adjust the loopCount
    //    startFrame and framesToPlay
    else {

        // First remove the start time
        region.mStartFrame = 0;
        double offsetTime = playheadTime - scheduleItem.startTime;

        // Next, take out any expired loops
        int loopsExpired = floor(offsetTime/file.duration);
        int fullLoops = region.mLoopCount - loopsExpired;
        region.mLoopCount = 0;
        offsetTime -= (loopsExpired * file.duration);

        // Then, adjust this segment of a loop accordingly
        region.mStartFrame = offsetTime * file.sampleRate;
        region.mFramesToPlay = region.mFramesToPlay - region.mStartFrame;

        // Finally, schedule any remaining loops separately
        if(fullLoops > 0) {
            ScheduledAudioFileRegion loops;
            [file setRegion:&loops schedule:scheduleItem];
            loops.mStartFrame = region.mFramesToPlay;
            loops.mLoopCount = fullLoops-1;
            if(![super.errors check:AudioUnitSetProperty(unit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &region, sizeof(region))
                           location:@"AudioUnitSetProperty(ScheduledFileRegion)"])
                return false;
        }
    }

    // Set the region
    if(![super.errors check:AudioUnitSetProperty(unit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &region, sizeof(region))
                   location:@"AudioUnitSetProperty(ScheduledFileRegion)"])
        return false;
}
于 2013-04-28T10:12:07.637 に答える
3

私はそれを考え出した。誰かが同じ問題に遭遇した場合に備えて、ここに私の解決策があります:

  1. 起動時に、ファイルプレーヤーオーディオユニットの配列を使用してAUGraphを初期化します。ファイルプレーヤーのオーディオユニット配列の各トラックの再生ヘッドをゼロに設定しました。

  2. 「一時停止」で、最初にAuGraphを停止します。次に、ファイルプレーヤーオーディオユニットの配列をループして、現在の再生ヘッドの位置をキャプチャします。一時停止ボタンを押すたびに、新しい現在の再生ヘッドの位置を古い再生ヘッドの位置に追加して、実際の位置を取得します。

  3. ユーザーが再生を押すと、アプリを初めて起動したときと同じようにAuGraphを再初期化します。ユーザーが「一時停止」を押したときに保存した番号に、再生を指示するのではなく、再生ヘッドを設定するだけです。ファイルの開始。

  4. ユーザーが[停止]をクリックした場合、保存されている再生ヘッドの位置をゼロに設定してから、AuGraphを停止します。

于 2012-08-02T16:39:02.957 に答える