編輯:這是一個自包含的例子:停止MIDI音序器,這樣我可以打別的
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的源代碼。對不起,處理它;我需要將它用於我的課程。 (如果它是由我決定的,我會直接使用3210 ...)這個應該做的是開始播放一個12個音符的序列(第一個for
循環),但在3000毫秒後停止,這樣它可以播放不同的序列(第二個for
循環)。然而,最終發生的事情是,當第二個序列開始播放時,它從一開始就不這樣做;它在開始的幾個音符。
我正在使用的3210 API一個Java GUI應用程序。具體來說,它是一個音序器,允許用戶輸入音符並按順序播放。我遇到的問題是,我需要一種方法,在發送完MIDI消息後,停止它們以便我可以播放其他內容。例如,讓我們說用戶點擊播放。然後,顯然,該程序播放音符。我想要發生的是,如果用戶在序列播放過程中按下播放鍵,它會停止當前播放並重新開始。
我已經獲得MIDI與Swing一起工作的方式 - 在不破壞事件隊列的情況下這麼做並不重要),而是通過獨立的Thread
來處理MIDI內容。除了我在前一段中提出的問題,這工作正常。這是我Thread
實施run
方法:
@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
是Consumer<MidiLatte>
的LinkedBlockingQueue
s。這可以讓我做的是在外部類中有一個方法(MPThread
,我的自定義Thread
是一個內部類),它將一個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()
並清除隊列。最終發生的事情如下(我從經驗中知道,當用戶不清楚地描述他們的bug時,它可能會令人討厭和困惑,所以我要逐步展示它。請告訴我,如果你仍然不明白什麼發生。):
- 第一個序列開始正確播放。
- 經過3000(或多或少)毫秒後,第一個序列停止。
- 第二個序列立即開始播放,但不從頭開始;而是開始玩,就好像它一直在玩。
爲了說明這一點,設想第一個序列的音符是A B C D E F G A
,第二個序列是1 2 3 4 5 6 7 8
。應該發生的是,如果第一個序列中的3000密爾落在C
和D
之間,則整個回放爲A B C 1 2 3 4 5 6 7 8
。但是,實際發生的是A B C 4 5 6 7 8
。
我該如何實現我想要的行爲?如果我設置併發的方式存在固有的問題,請告訴我。只是重申我想要的行爲,就是這樣。 當按下播放按鈕時,MIDI序列播放。如果在序列仍在播放的過程中再次按下該按鈕,則第一個播放會停止,並且序列會從頭開始再次播放。如果我不清楚,請告訴我。謝謝!
爲了更好的幫助,一個[MCVE]或[簡短,獨立,正確的例子](http://www.sscce.org/)。 –
我與@AndrewThompson--讓我們理解你的代碼和你的問題的最好方法是創建你的[MCVE](http://stackoverflow.com/help/mcve)和/或[SSCCE] (http://www.sscce.org/)並將其與您的問題一起發佈,但這不是一件容易的事情,因爲您將不得不嘲笑我們沒有訪問的庫至。 –
我不確定這與Swing有什麼關係,所以你可能只是能夠從你的自定義播放器中生成一個例子 – MadProgrammer