[英]Using MIDI in Java
我正在尝试编写一个使用 MIDI 的 Java 程序,因此该程序必须排列:音符(包含我想要播放的所有音符)和另一个数组时间(指定何时播放音符)音符和时间一次分组三个,所以我可以有多个和弦,问题是程序只播放一个非常简短的音符然后停止,我做错了什么? 波纹管是代码,我使用的是 Java 16。
package application;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.ShortMessage;
public class App {
public static void main(String[] args)
throws MidiUnavailableException, InvalidMidiDataException, InterruptedException {
var receiver = MidiSystem.getReceiver();
int[] notes = { 60, 64, 67, 60, 65, 67, 55, 59, 62, 55, 60, 62, 53, 57, 60, 53, 58, 60 };
int[] times = { 0, 0, 0, 1000, 1000, 1000, 2000, 2000, 2000, 3000, 3000, 3000, 4000, 4000, 4000, 5000, 5000,
5000 };
for (int i = 0; i < notes.length; i++) {
int note = notes[i];
int time = times[i];
System.out.println(note + ":" + time);
receiver.send(new ShortMessage(ShortMessage.NOTE_ON, 0, note, 127), time * 1000);
receiver.send(new ShortMessage(ShortMessage.NOTE_OFF, 0, note, 127), (time + 1000) * 1000);
}
Thread.sleep(7000);
}
}
我认为它与 ShortMessage.NOTE_OFF 有关,但我不确定,我无法弄清楚。
问题很可能与您的times
数组有关。
如前所述,该程序可以在它发送到设备接收器的每条 MIDI 消息中包含一个时间戳。 但是,此类时间戳仅用于微调时序,以校正处理延迟。 调用者一般不能设置任意时间戳; 传递给 Receiver.send 的时间值必须接近当前时间,否则接收设备可能无法正确安排消息。 这意味着如果应用程序想要提前为整首音乐创建一个 MIDI 消息队列(而不是创建每个消息以响应实时事件),则必须非常小心地安排每个消息在几乎正确的时间调用 Receiver.send。
幸运的是,大多数应用程序不必关心这样的调度。 程序可以使用 Sequencer 对象来管理 MIDI 消息队列,而不是调用 Receiver.send 本身。
您盲目地假设数字(1000、2000、3000 等)是毫秒,但在 api 中定义为ticks
。
就像在任何音乐中一样,您需要定义细分和每滴答脉冲 (PPQ),例如四分音符、16 分音符等。
在 java 中,这通常是通过定义一个音序器和这些设置来完成的,然后在所述音序器上创建一个音轨,然后在该音轨上播放音符。
这是我在互联网上找到的一个例子。
public class MyMidiPlayer {
public static void main(String[] args) {
System.out.println("Enter the number of notes to be played: ");
Scanner in = new Scanner(System.in);
int numOfNotes = in.nextInt();
MyMidiPlayer player = new MyMidiPlayer();
player.setUpPlayer(numOfNotes);
}
public void setUpPlayer(int numOfNotes) {
try {
// A static method of MidiSystem that returns
// a sequencer instance.
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
// Creating a sequence.
Sequence sequence = new Sequence(Sequence.PPQ, 4);
// PPQ(Pulse per ticks) is used to specify timing
// type and 4 is the timing resolution.
// Creating a track on our sequence upon which
// MIDI events would be placed
Track track = sequence.createTrack();
// Adding some events to the track
for (int i = 5; i < (4 * numOfNotes) + 5; i += 4){
// Add Note On event
track.add(makeEvent(144, 1, i, 100, i));
// Add Note Off event
track.add(makeEvent(128, 1, i, 100, i + 2));
}
// Setting our sequence so that the sequencer can
// run it on synthesizer
sequencer.setSequence(sequence);
// Specifies the beat rate in beats per minute.
sequencer.setTempoInBPM(220);
// Sequencer starts to play notes
sequencer.start();
while (true) {
// Exit the program when sequencer has stopped playing.
if (!sequencer.isRunning()) {
sequencer.close();
System.exit(1);
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
public MidiEvent makeEvent(int command, int channel,
int note, int velocity, int tick) {
MidiEvent event = null;
try {
// ShortMessage stores a note as command type, channel,
// instrument it has to be played on and its speed.
ShortMessage a = new ShortMessage();
a.setMessage(command, channel, note, velocity);
// A midi event is comprised of a short message(representing
// a note) and the tick at which that note has to be played
event = new MidiEvent(a, tick);
}
catch (Exception ex) {
ex.printStackTrace();
}
return event;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.