1

MIDIファイルからロードしたMIDIシーケンスMusicPlayerを再生していて、再生中にシーケンスを別のシーケンスに変更したい。私がこれを試すとき:

 MusicPlayerSetSequence(_player, sequence);
 MusicSequenceSetAUGraph(sequence, _processingGraph);

再生を停止します。だから私はそれをもう一度始めて時間を設定します

MusicPlayerSetTime(_player, currentTime);

そのため、前のシーケンスが停止した場所で再び再生されますが、少し遅延があります。に時間間隔を追加しようとしましたcurrentTime。これは、停止する前と再開した後の時間を取得することで得られたものです。しかし、まだ遅れがあります。

停止->シーケンスの変更->再開する代わりの方法があるかどうか疑問に思いました。

4

2 に答える 2

2

トラックを追加および削除したり、シーケンスを切り替えたりする場合は、必ずAUSamplerを管理する必要があります。AUSamplerを廃棄し、新しいトラックごとに新しいものを作成する方がおそらくクリーンですが、AUSamplerを「リサイクル」することも可能ですが、それはそれらを追跡する必要があることを意味します。

AUSamplersの管理とは、インスタンスを使用しなくなった場合(たとえば、MusicTrackを削除または置換した場合)、AUMixerインスタンスから切断し、AUGraphインスタンスから削除してから、AUGraphを更新する必要があることを意味します。

これらすべてを処理する方法はたくさんあります。AUSamplerインスタンスのバス番号、ロードされたサウンドフォントなどを追跡するのに便利SamplerAudioUnitなように、必要なすべてのプロパティとメソッドを含む名前のNSObjectのサブクラスを使用します。MusicTracksについても同じです-私はTrackクラスを持っています-しかし、これはあなたのプロジェクトでは必要ないかもしれません。

ただし、要点は、パフォーマンスとメモリのためにAUSamplerを管理する必要があるということです。インスタンスが使用されなくなった場合は、インスタンスを削除して、AUMixerバス入力を解放する必要があります。

ところで-私はドキュメントをチェックし、ミキサーバスの数に技術的な制限はないようです-しかし、数を指定する必要があります。

// this is not cut and paste code - just an example of managing the AUSampler instance

- (OSStatus)deleteTrack:(Track*) trackObj
{
    OSStatus result = noErr;

    // turn off MP if playing
    BOOL MPstate = [self isPlaying];
    if (MPstate){
        MusicPlayerStop(player);
    }

    //-disconnect node from mixer + update list of mixer buses
    SamplerAudioUnit * samplerObj = trackObj.sampler;
    UInt32 busNumber = samplerObj.busNumber;

    result = AUGraphDisconnectNodeInput(graph, mixerNode, busNumber);
    if (result) {[self printErrorMessage: @"AUGraphDisconnectNodeInput" withStatus: result];}

     [self clearMixerBusState: busNumber]; // routine that keeps track of available busses

    result = MusicSequenceDisposeTrack(sequence, trackObj.track);
    if (result) {[self printErrorMessage: @"MusicSequenceDisposeTrack" withStatus: result];}

    // remove AUSampler node
    result = AUGraphRemoveNode(graph, samplerObj.samplerNode);
    if (result) {[self printErrorMessage: @"AUGraphRemoveNode" withStatus: result];}

    result = AUGraphUpdate(graph, NULL);
    if (result) {[self printErrorMessage: @"AUGraphUpdate" withStatus: result];}
    samplerObj = nil;
    trackObj = nil;

    if (MPstate){
        MusicPlayerStart(player);
    }

    //    CAShow(graph);
    //    CAShow(sequence);

    return result;
}
于 2012-08-12T00:10:29.403 に答える
1

なぜなら

MusicPlayerSetSequence(_player, sequence);
MusicSequenceSetAUGraph(sequence, _processingGraph);

それでもプレーヤーは停止しますが、少し休憩を聞くことは可能です。したがって、を更新する代わりに、musicSequence先に進んでトラックのコンテンツを変更しました。これにより、中断は発生しません。

MusicTrack currentTrack;
MusicTrack currentTrack2;
MusicSequenceGetIndTrack(musicSequence, 0, &currentTrack);
MusicSequenceGetIndTrack(musicSequence, 1, &currentTrack2);
MusicTrackClear(currentTrack, 0, _trackLen);
MusicTrackClear(currentTrack2, 0, _trackLen);

MusicSequence tmpSequence;
switch (number) {
    case 0:
        tmpSequence = musicSequence1;
        break;
    case 1:
        tmpSequence = musicSequence2;
        break;
    case 2:
        tmpSequence = musicSequence3;
        break;
    case 3:
        tmpSequence = musicSequence4;
        break;

    default:
        tmpSequence = musicSequence1;
        break;
}

MusicTrack tmpTrack;
MusicTrack tmpTrack2;
MusicSequenceGetIndTrack(tmpSequence, 0, &tmpTrack);
MusicSequenceGetIndTrack(tmpSequence, 1, &tmpTrack2);
MusicTimeStamp trackLen = 0;
UInt32 trackLenLenLen = sizeof(trackLen);
MusicTrackGetProperty(tmpTrack, kSequenceTrackProperty_TrackLength, &trackLen, &trackLenLenLen);
_trackLen = trackLen;
MusicTrackCopyInsert(tmpTrack, 0, _trackLen, currentTrack, 0);
MusicTrackCopyInsert(tmpTrack2, 0, _trackLen, currentTrack2, 0);

ノードの切断、グラフの更新、プレーヤーの停止はありません。

于 2012-08-15T00:20:39.907 に答える