我正在开发一个 midi 程序,并希望用户可以选择使用哪个 midi 音序器,如果他们有很多而不是使用MidiSystem.getSequencer()
.
编辑
我的代码看起来像这样。
public class Demo {
public static void main(String[] args) {
Sequencer sequencer;
//Gets default sequencer if only one argument given
try {
sequencer = MidiSystem.getSequencer();
} catch (MidiUnavailableException e) {
e.printStackTrace();
return;
}
if (args.length == 0) {
return;
}
File file = new File(args[0]);
boolean select = args.length > 1;
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
List<String> sequencers = new ArrayList<>();
MidiDevice device;
//Populates sequencers lists with potential values and prints
for (int i = 0; i < infos.length; i++) {
try {
device = MidiSystem.getMidiDevice(infos[i]);
if (device instanceof Sequencer) {
System.out.println(sequencers.size() + ": " + device.getDeviceInfo().getName());
sequencers.add(device.getDeviceInfo().getName());
}
} catch (MidiUnavailableException e) {
System.out.println(e.getMessage());
}
}
String name;
//If multiple arguments are given select a new sequencer from the list
if (select) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the number of the sequencer you wish to use");
name = sequencers.get(scanner.nextInt());
for (int i = 0; i < infos.length; i++) {
try {
device = MidiSystem.getMidiDevice(infos[i]);
if (device.getDeviceInfo().getName().equals(name)) {
//TODO: This line does not create a valid sequencer
sequencer = (Sequencer) device;
System.out.println("Sequencer changed to " + device.getDeviceInfo().getName());
}
} catch (MidiUnavailableException e) {
System.out.println("Cannot locate device " + name);
}
}
}
//Attempt to play midi data from a file into selected sequencer
if (sequencer != null) {
if (!sequencer.isOpen()) {
try {
sequencer.open();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}
try {
sequencer.setSequence(MidiSystem.getSequence(file));
} catch (InvalidMidiDataException | IOException e) {
e.printStackTrace();
return;
}
System.out.println("Attempting to play Midi");
sequencer.start();
}
}
}
如果您使用一个指向 midi 文件的参数运行程序,它会播放它,但如果您有 2 个参数并且它要求您选择一个音序器,它是无声的。定序器肯定会在打印语句发生时设置,并且程序不会立即退出,就好像还在播放 midi,但没有噪音出现。
基于 GUI 的 MRE
此 MRE 将命令行应用程序转换为 GUI,以便于使用。
要测试此代码:
- 启动图形用户界面
- 确保文本字段(顶部)指向有效的 MIDI 文件
- 在下面的列表中选择一个音序器
- 单击文本字段以使其获得焦点
- 激活添加到该字段的操作侦听器(在 Windows 上,这意味着“按回车”)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.*;
import javax.sound.midi.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class MidiSequencers {
private JComponent ui = null;
Vector<Sequencer> sequencers = new Vector<>();
public static String URLString = "https://bitmidi.com/uploads/18908.mid";
// Used on my local system, given the hot-link had problems
//"file:/C:/Users/Andrew/Downloads/Queen%20-%20Bohemian%20Rhapsody.mid";
URL url;
JList sequencerList;
MidiSequencers() {
try {
initUI();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public final void initUI() throws Exception {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
populateSequencers();
sequencerList = new JList(sequencers);
ui.add(new JScrollPane(sequencerList));
JTextField textField = new JTextField(URLString, 10);
ui.add(textField,BorderLayout.PAGE_START);
ActionListener playListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Sequencer sequencer = (Sequencer)sequencerList.getSelectedValue();
playSequence(sequencer);
}
};
textField.addActionListener(playListener);
}
private void populateSequencers() throws Exception {
Sequencer sequencer;
//Gets default sequencer if only one argument given
sequencer = MidiSystem.getSequencer();
sequencers.add(sequencer);
url = new URL(URLString);
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
MidiDevice device;
// Populates sequencers list with available sequencers
for (int i = 0; i < infos.length; i++) {
try {
device = MidiSystem.getMidiDevice(infos[i]);
if (device instanceof Sequencer) {
System.out.println(sequencers.size() + ": " + device.getDeviceInfo().getName());
sequencers.add((Sequencer) device);
}
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}
}
private void playSequence(Sequencer sequencer) {
if (!sequencer.isOpen()) {
try {
sequencer.open();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}
try {
sequencer.setSequence(MidiSystem.getSequence(url));
} catch (Exception e) {
e.printStackTrace();
return;
}
System.out.println("Attempting to play Midi");
sequencer.start();
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
MidiSequencers o = new MidiSequencers();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}