私は midi プログラムに取り組んでおり、使用する代わりに多数の 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 ファイルを指す引数を 1 つ指定してプログラムを実行すると、プログラムは再生されますが、引数が 2 つあり、シーケンサーを選択するように求められた場合は、何も表示されません。print ステートメントが発生すると、シーケンサーは確実に設定され、プログラムは midi がまだ再生されているかのようにすぐには終了しませんが、ノイズは発生しません。
GUI ベースの MRE
この MRE は、コマンド ライン アプリを GUI に変換して、操作しやすくしました。
このコードをテストするには:
- GUI を起動する
- テキスト フィールド (上部) が有効な MIDI ファイルを指していることを確認します。
- 以下のリストからシーケンサーを 1 つ選択してください
- テキストフィールドをクリックしてフォーカスします
- フィールドに追加されたアクション リスナーをアクティブにします (Windows では「Enter キーを押す」ことを意味します)。
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);
}
}