-1

編集:これは自己完結型の例です:

MidiLatte midiLatte = new MidiLatte();

for (int i = 60; i <= 72; i++) {
    midiLatte.addNote(i, 4);
}
midiLatte.playAndRemove();

try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

try {
    Field f = MidiLatte.class.getDeclaredField("player");
    f.setAccessible(true);
    Sequencer s = (Sequencer) f.get(midiLatte);
    s.stop();
} catch (NoSuchFieldException | IllegalAccessException e) {
    e.printStackTrace();
}

for (int i = 48; i <= 60; i++) {
    midiLatte.addNote(i, 4);
}
midiLatte.playAndRemove();

MidiLatte hereのソースコードを見つけることができました。対処して申し訳ありません。クラスで使用する必要があります。(それが私に任されていれば、javax.sound.midi直接使用します...) これが行うことになっているのは、12 音符のシーケンスの再生を開始し (最初のforループ)、3000 ミリ秒後に停止して、別のシーケンスを再生できるようにすることです (2 番目のforループ) )。ただし、最終的には、2 番目のシーケンスの再生が開始されたときに、最初から再生が開始されるわけではありません。でいくつかの音符を開始します。


javax.sound.midiAPIを使用する Java GUI アプリケーションを作成しています。具体的には、ユーザーが音符を入力して順番に再生できるシーケンサーです。私が抱えている問題は、MIDI メッセージを送信した後、他の何かを演奏できるようにそれらを停止する方法が必要だということです。たとえば、ユーザーが再生ボタンを押したとします。次に、明らかに、プログラムがノートを再生します。私が望んでいるのは、シーケンスの再生中にユーザーが再生を押すと、現在の再生が停止して最初からやり直すことです。

MIDI を Swing で動作させる方法は (イベント キューを台無しにせずにそうするのは簡単なことではありません) Thread、MIDI を処理する別のものを用意することです。前の段落で提示した問題は別として、これは問題なく動作します。私の実装run方法は次のとおりです。Thread

@Override
public void run() {
    midiLatte = new MidiLatte();
    //This loop waits for tasks to become available
    while (true) {
        try {
            tasks.take().accept(midiLatte);
        } catch (InterruptedException e) {
            System.out.println("MPThread interrupted");
        }
    }
}

MidiLatteは、MIDI メッセージの送信を容易にし、Sequencer. 基本的に、これが機能する方法tasksは、のLinkedBlockingQueueですConsumer<MidiLatte>。これでできることは、キューに a を追加する外部クラス ( MPThread、 my customThreadは内部クラス) にメソッドを持つことです。Consumer<MidiLatte>これにより、次のような MIDI タスクを簡単にスケジュールできます。

midiPlayer.addAction(midiLatte -> {
    // do midi stuff
});

ただし、前述のように、これらのタスクをキャンセルして、送信済みの MIDI 再生を停止できるようにする必要があります。前者は簡単です。キューをクリアするだけです。

tasks.clear();

ただし、後者は、MIDI タスクが既に送信されており、MIDI API の管理下にあるため、困難です。使用しsequencer.stop()てみましたが、次の例に示すように、奇妙な結果が得られます。

player.addAction(midiLatte -> {
    //midi stuff
});
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
player.cancelPending();
player.addAction(midiLatte -> {
    //Midi stuff
});

どこでキューをcancelPending()呼び出しsequencer.stop()てクリアします。最終的に何が起こるかは次のとおりです(ユーザーがバグを不明確に説明すると迷惑で混乱する可能性があることを経験から知っているので、順を追って説明します。それでもわからない場合は教えてください):

  • 最初のシーケンスが正しく再生されます。
  • 3000 (多かれ少なかれ) ミリ秒後、最初のシーケンスが停止します。
  • 2 番目のシーケンスはすぐに再生を開始しますが、最初から開始しません。むしろ、ずっと再生されていたかのように再生を開始します。

A B C D E F G Aこれを説明するために、最初のシーケンスの音符がで、2 番目のシーケンスの音符が であると想像してください1 2 3 4 5 6 7 8。3000 ミルがCD最初のシーケンスの間にある場合、全体の再生はA B C 1 2 3 4 5 6 7 8. しかし、実際に起こることはA B C 4 5 6 7 8.

希望する動作を実現するにはどうすればよいですか? 同時実行の設定方法に固有の問題がある場合は、教えてください。私が望む動作を繰り返しますが、ここにあります。再生ボタンを押すと、MIDI シーケンスが再生されます。シーケンスの再生中にもう一度押すと、最初の再生が停止し、シーケンスが最初から再生されます。不明な点があれば教えてください。ありがとうございました!

4

1 に答える 1