import camidion.chordhelper.chordmatrix.ChordMatrix;
import camidion.chordhelper.chordmatrix.ChordMatrixListener;
import camidion.chordhelper.mididevice.MidiDeviceDialog;
-import camidion.chordhelper.mididevice.MidiDeviceModelManager;
+import camidion.chordhelper.mididevice.MidiDeviceTreeModel;
import camidion.chordhelper.mididevice.MidiSequencerModel;
import camidion.chordhelper.mididevice.SequencerMeasureView;
import camidion.chordhelper.mididevice.SequencerTimeView;
*/
public static class VersionInfo {
public static final String NAME = "MIDI Chord Helper";
- public static final String VERSION = "Ver.20161005.1";
+ public static final String VERSION = "Ver.20161010.1";
public static final String COPYRIGHT = "Copyright (C) 2004-2016";
public static final String AUTHER = "@きよし - Akiyoshi Kamide";
public static final String URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";
private KeySignatureLabel keysigLabel;
private AnoGakkiPane anoGakkiPane;
private JToggleButton anoGakkiToggleButton;
- private MidiDeviceModelManager deviceModelManager;
+ private MidiDeviceTreeModel deviceTreeModel;
public void init() {
loadIconImage();
}};
VirtualMidiDevice guiMidiDevice = keyboardPanel.keyboardCenterPanel.keyboard.midiDevice;
//
- // MIDIデバイスマネージャを構築
- deviceModelManager = new MidiDeviceModelManager(guiMidiDevice);
- MidiDeviceDialog midiDeviceDialog = new MidiDeviceDialog(deviceModelManager);
- midiDeviceDialog.setIconImage(iconImage);
+ // MIDIデバイスツリーモデルを構築
+ deviceTreeModel = new MidiDeviceTreeModel(guiMidiDevice);
+ //
+ // MIDIシーケンサと連携するプレイリストモデルを構築
+ playlistModel = new PlaylistTableModel(sequencerModel = deviceTreeModel.getSequencerModel());
//
- // MIDIデバイス一覧のシーケンサと連携するプレイリストを構築
- playlistModel = new PlaylistTableModel(sequencerModel = deviceModelManager.getSequencerModel());
+ // MIDIデバイスダイアログの構築
+ MidiDeviceDialog midiDeviceDialog = new MidiDeviceDialog(deviceTreeModel);
+ midiDeviceDialog.setIconImage(iconImage);
//
// MIDIエディタダイアログの構築
(midiEditor = new MidiSequenceEditorDialog(playlistModel, guiMidiDevice)).setIconImage(iconImage);
}
@Override
public void destroy() {
- deviceModelManager.close();
+ deviceTreeModel.closeAllDevices();
super.destroy();
}
@Override
});
// デバイスツリーが変更されたときの更新処理を予約
MidiDeviceTreeModel deviceTreeModel = deviceTreeView.getModel();
- List<MidiDeviceModel> deviceModelList = deviceTreeModel.getDeviceModelList();
TreeModelListener treeModelListener = new TreeModelListener() {
@Override
public void treeNodesChanged(TreeModelEvent e) { }
public void treeStructureChanged(TreeModelEvent e) {
//
// 削除されたデバイスモデルに対するデバイスフレームをマップから外す
- List<MidiDeviceModel> removingDeviceModels = new ArrayList<>();
+ List<MidiDeviceModel> deviceModelsToRemove = new ArrayList<>();
for( MidiDeviceModel m : frameMap.keySet() ) {
- if( ! deviceModelList.contains(m) ) removingDeviceModels.add(m);
+ if( ! deviceTreeModel.contains(m) ) deviceModelsToRemove.add(m);
}
- for( MidiDeviceModel m : removingDeviceModels ) {
+ for( MidiDeviceModel m : deviceModelsToRemove ) {
MidiDeviceFrame frame = frameMap.remove(m);
if( frame != null ) remove(frame);
}
- removingDeviceModels.clear();
//
// 新しいデバイスモデルに対するデバイスフレームを生成してマップに登録
- for( MidiDeviceModel deviceModel : deviceModelList ) {
+ for( MidiDeviceModel deviceModel : deviceTreeModel ) {
if( frameMap.containsKey(deviceModel) ) continue;
MidiDeviceFrame frame = new MidiDeviceFrame(deviceModel, cablePane);
frameMap.put(deviceModel, frame);
// 表示したデバイスフレームを整列
int toX = 10;
int toY = 10;
- for( MidiDeviceModel deviceModel : deviceModelList ) {
+ for( MidiDeviceModel deviceModel : deviceTreeModel ) {
if( ! deviceModel.getMidiDevice().isOpen() ) continue;
frameMap.get(deviceModel).setLocation(toX, toY);
toX = (toX == 10 ? 270 : 10);
- toY += 50;
+ toY += 70;
}
deviceTreeView.expandAll();
//
*/
public class MidiDeviceDialog extends JDialog {
public static final Icon MIDI_CONNECTER_ICON = new ButtonIcon(ButtonIcon.MIDI_CONNECTOR_ICON);
- public static final String MSGS = "Microsoft GS Wavetable Synth";
/**
* MIDIデバイスダイアログを開くアクション
*/
};
/**
* MIDIデバイスダイアログを構築します。
- * @param deviceModelManager デバイスモデルマネージャ
+ * @param deviceTreeModel デバイスツリーモデル
*/
- public MidiDeviceDialog(final MidiDeviceModelManager deviceModelManager) {
+ public MidiDeviceDialog(MidiDeviceTreeModel deviceTreeModel) {
setTitle(openAction.getValue(Action.NAME).toString());
setBounds( 300, 300, 820, 540 );
- MidiDeviceTreeView deviceTreeView = new MidiDeviceTreeView(deviceModelManager.getTreeModel());
+ MidiDeviceTreeView deviceTreeView = new MidiDeviceTreeView(deviceTreeModel);
final MidiDeviceInfoPane deviceInfoPane = new MidiDeviceInfoPane();
deviceTreeView.addTreeSelectionListener(deviceInfoPane);
MidiDeviceDesktopPane desktopPane = new MidiDeviceDesktopPane(deviceTreeView, deviceInfoPane, this);
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- deviceModelManager.updateMidiDeviceList();
+ deviceTreeModel.updateMidiDeviceList();
deviceTreeView.expandAll();
}
});
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- deviceModelManager.resetMicrosecondPosition();
+ deviceTreeModel.resetMicrosecondPosition();
}
});
}});
*/
public MidiDeviceModel getMidiDeviceModel() { return deviceModel; }
/**
- * このデバイスフレームに貼り付けられたMIDIトランスミッタリストビューを取得します。
- * @return MIDIトランスミッタリストビュー
- */
- public TransmitterListView getMidiTransmitterListView() { return transmitterListView; }
- /**
- * このデバイスフレームに貼り付けられたMIDIトランシーバリストビューを取得します。
- * @return MIDIトランシーバリストビュー
- */
- public ReceiverListView getMidiReceiverListView() { return receiverListView; }
- /**
* MIDIデバイスモデルからフレームビューを構築します。
*/
public MidiDeviceFrame(MidiDeviceModel deviceModel, MidiCablePane cablePane) {
setLayout(new BorderLayout());
ReceiverListModel rxListModel = getMidiDeviceModel().getReceiverListModel();
if( rxListModel != null ) {
- receiverListView = new ReceiverListView(rxListModel, cablePane);
add(rxPanel = new JPanel() {{
setLayout(new BorderLayout());
add(new JLabel("Rx") {{ setVerticalAlignment(TOP); }}, BorderLayout.WEST);
- add(receiverListView);
+ add(receiverListView = new ReceiverListView(rxListModel, cablePane));
}}, BorderLayout.NORTH);
}
TransmitterListModel txListModel = getMidiDeviceModel().getTransmitterListModel();
if( txListModel != null ) {
- transmitterListView = new TransmitterListView(txListModel, cablePane);
add(txPanel = new JPanel() {{
setLayout(new BorderLayout());
add(new JLabel("Tx") {{ setVerticalAlignment(TOP); }}, BorderLayout.WEST);
- add(transmitterListView);
+ add(transmitterListView = new TransmitterListView(txListModel, cablePane));
}}, rxListModel == null ? BorderLayout.NORTH : BorderLayout.SOUTH);
}
}}));
* {@link #MIDI_IN}と{@link #MIDI_OUT}の両方をサポートしたデバイスを表します。
*/
MIDI_IN_OUT("MIDI input/output devices (MIDI sequencer etc.)", "I/O");
- private String description;
- private String shortName;
+
private MidiDeviceInOutType(String description, String shortName) {
this.description = description;
this.shortName = shortName;
}
+ public static MidiDeviceInOutType getValueFor(TransmitterListModel txListModel, ReceiverListModel rxListModel) {
+ // tx:IN rx:OUT
+ return rxListModel == null ?
+ (txListModel == null ? MIDI_NONE : MIDI_IN) :
+ (txListModel == null ? MIDI_OUT : MIDI_IN_OUT);
+ }
public String getDescription() { return description; }
+ private String description;
public String getShortName() { return shortName; }
+ private String shortName;
+
}
package camidion.chordhelper.mididevice;
import javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Transmitter;
* @return このリストのMIDIデバイスの入出力タイプ
*/
public MidiDeviceInOutType getInOutType() { return ioType; }
- private MidiDeviceInOutType ioType = MidiDeviceInOutType.MIDI_NONE;
+ private MidiDeviceInOutType ioType;
/**
* 対象MIDIデバイスを返します。
* @return 対象MIDIデバイス
* 対象MIDIデバイスの名前を返します。
*/
@Override
- public String toString() {
- return device.getDeviceInfo().toString();
- }
+ public String toString() { return device.getDeviceInfo().toString(); }
/**
* {@link Transmitter} のリストモデルを返します。サポートしていない場合はnullを返します。
* @return リストモデルまたはnull
public ReceiverListModel getReceiverListModel() { return rxListModel; }
private ReceiverListModel rxListModel;
/**
- * ã\81\93ã\81®MIDIã\83\87ã\83\90ã\82¤ã\82¹ã\83¢ã\83\87ã\83«ã\82\92å\8f\8e容ã\81\97ã\81¦ã\81\84ã\82\8bã\83ªã\82¹ã\83\88を返します。
+ * ã\81\93ã\81®MIDIã\83\87ã\83\90ã\82¤ã\82¹ã\83¢ã\83\87ã\83«ã\82\92å\8f\8e容ã\81\97ã\81¦ã\81\84ã\82\8bã\83\84ã\83ªã\83¼ã\83¢ã\83\87ã\83«を返します。
*/
- public MidiDeviceModelManager getDeviceModelManager() { return deviceModelManager; }
- protected MidiDeviceModelManager deviceModelManager;
+ public MidiDeviceTreeModel getDeviceTreeModel() { return deviceTreeModel; }
+ protected MidiDeviceTreeModel deviceTreeModel;
+ /**
+ * MIDIデバイス情報からMIDIデバイスモデルを構築します。
+ *
+ * @param deviceInfo 対象MIDIデバイス情報
+ * @param deviceTreeModel 収容先のMIDIデバイスツリーモデル
+ * @throws MidiUnavailableException {@link MidiSystem#getMidiDevice(MidiDevice.Info)}からの例外
+ */
+ public MidiDeviceModel(MidiDevice.Info deviceInfo, MidiDeviceTreeModel deviceTreeModel) throws MidiUnavailableException {
+ this(MidiSystem.getMidiDevice(deviceInfo), deviceTreeModel);
+ }
/**
- * MIDIデバイスモデルを構築します。
+ * MIDIã\83\87ã\83\90ã\82¤ã\82¹ã\81\8bã\82\89ã\83¢ã\83\87ã\83«ã\82\92æ§\8bç¯\89ã\81\97ã\81¾ã\81\99ã\80\82
*
* @param device 対象MIDIデバイス
- * @param deviceModelManager このMIDIデバイスモデルのマネージャー(接続相手となりうるMIDIデバイス)
+ * @param deviceTreeModel このMIDIデバイスモデルのマネージャー(接続相手となりうるMIDIデバイス)
*/
- public MidiDeviceModel(MidiDevice device, MidiDeviceModelManager deviceModelManager) {
- this.deviceModelManager = deviceModelManager;
+ public MidiDeviceModel(MidiDevice device, MidiDeviceTreeModel deviceTreeModel) {
+ this.deviceTreeModel = deviceTreeModel;
this.device = device;
- if( device.getMaxTransmitters() != 0 ) {
- txListModel = new TransmitterListModel(this);
- }
- if( device.getMaxReceivers() != 0 ) {
- rxListModel = new ReceiverListModel(this);
- ioType = txListModel != null ? MidiDeviceInOutType.MIDI_IN_OUT :MidiDeviceInOutType.MIDI_OUT;
- }
- else {
- ioType = txListModel != null ? MidiDeviceInOutType.MIDI_IN :MidiDeviceInOutType.MIDI_NONE;
- }
- treePath = new TreePath(new Object[] {deviceModelManager, ioType ,this});
+ if( device.getMaxTransmitters() != 0 ) txListModel = new TransmitterListModel(this);
+ if( device.getMaxReceivers() != 0 ) rxListModel = new ReceiverListModel(this);
+ ioType = MidiDeviceInOutType.getValueFor(txListModel, rxListModel);
+ treePath = new TreePath(new Object[] {deviceTreeModel, ioType ,this});
}
/**
* このMIDIデバイスを開きます。
* それらも全て閉じます。
*/
public void close() {
- if( rxListModel != null ) rxListModel.closePeerTransmitters();
+ if( rxListModel != null ) rxListModel.closeTransmitters();
device.close();
}
}
+++ /dev/null
-package camidion.chordhelper.mididevice;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.MidiUnavailableException;
-import javax.sound.midi.Receiver;
-import javax.sound.midi.Sequencer;
-import javax.sound.midi.Synthesizer;
-import javax.sound.midi.Transmitter;
-
-import camidion.chordhelper.ChordHelperApplet;
-
-/**
- * 仮想MIDIデバイスを含めたすべてのMIDIデバイスモデル {@link MidiDeviceModel} を管理するオブジェクト
- */
-public class MidiDeviceModelManager {
-
- private List<MidiDeviceModel> deviceModelList = new Vector<>();
- public List<MidiDeviceModel> getDeviceModelList() { return deviceModelList; }
-
- private MidiSequencerModel sequencerModel;
- public MidiSequencerModel getSequencerModel() { return sequencerModel; }
-
- private MidiDeviceTreeModel treeModel;
- public MidiDeviceTreeModel getTreeModel() { return treeModel; }
- public void setTreeModel(MidiDeviceTreeModel treeModel) { this.treeModel = treeModel; }
-
- public MidiDeviceModelManager(VirtualMidiDevice guiVirtualDevice) {
- List<MidiDevice.Info> deviceInfos = Arrays.asList(MidiSystem.getMidiDeviceInfo());
- //
- // GUI仮想MIDIデバイス
- MidiDeviceModel guiModel = new MidiDeviceModel(guiVirtualDevice, this);
- deviceModelList.add(guiModel);
- //
- // シーケンサ
- Sequencer sequencer = null;
- try {
- sequencer = MidiSystem.getSequencer(false);
- deviceModelList.add(sequencerModel = new MidiSequencerModel(sequencer, this));
- } catch( MidiUnavailableException e ) {
- System.out.println(ChordHelperApplet.VersionInfo.NAME +" : MIDI sequencer unavailable");
- e.printStackTrace();
- }
- // その他のリアルMIDIデバイス
- MidiDeviceModel synthModel = null;
- MidiDeviceModel firstMidiInModel = null;
- MidiDeviceModel firstMidiOutModel = null;
- for( MidiDevice.Info info : deviceInfos ) {
- MidiDevice device;
- try {
- device = MidiSystem.getMidiDevice(info);
- } catch( MidiUnavailableException e ) {
- e.printStackTrace();
- continue;
- }
- // シーケンサはすでに取得済みなのでスキップ
- if( device instanceof Sequencer ) continue;
- //
- // Java内蔵シンセサイザ
- if( device instanceof Synthesizer ) {
- try {
- device = MidiSystem.getSynthesizer();
- deviceModelList.add(synthModel = new MidiDeviceModel(device, this));
- } catch( MidiUnavailableException e ) {
- System.out.println(ChordHelperApplet.VersionInfo.NAME +
- " : Java internal MIDI synthesizer unavailable");
- e.printStackTrace();
- }
- continue;
- }
- // その他のMIDIデバイス
- MidiDeviceModel m;
- deviceModelList.add(m = new MidiDeviceModel(device, this));
- //
- // 最初の MIDI OUT(Windowsの場合は通常、内蔵音源 Microsoft GS Wavetable SW Synth)
- if( firstMidiOutModel == null && m.getReceiverListModel() != null ) firstMidiOutModel = m;
- //
- // 最初の MIDI IN(USB MIDI インターフェースにつながったMIDIキーボードなど)
- if( firstMidiInModel == null && m.getTransmitterListModel() != null ) firstMidiInModel = m;
- }
- // MIDIデバイスを開く。
- // NOTE: 必ず MIDI OUT Rx デバイスを先に開くこと。
- //
- // そうすれば、後から開いた MIDI IN Tx デバイスからのタイムスタンプのほうが「若く」なるので、
- // 相手の MIDI OUT Rx デバイスは「信号が遅れてやってきた」と認識、遅れを取り戻そうとして
- // 即座に音を出してくれる。
- //
- // 開く順序が逆になると「進みすぎるから遅らせよう」として無用なレイテンシーが発生する原因になる。
- try {
- // デバイスを開く
- MidiDeviceModel modelsToOpen[] = {synthModel, firstMidiOutModel, sequencerModel, firstMidiInModel};
- for( MidiDeviceModel m : modelsToOpen ) if( m != null ) m.open();
- guiModel.open();
- //
- // 初期接続
- // GUI → GUI、各音源、シーケンサ
- TransmitterListModel txListModel;
- if( (txListModel = guiModel.getTransmitterListModel() ) != null) {
- txListModel.connectToFirstReceiverOfDevices(guiModel,sequencerModel,synthModel,firstMidiOutModel);
- }
- // MIDI IN → GUI、各音源、シーケンサ
- if( firstMidiInModel != null && (txListModel = firstMidiInModel.getTransmitterListModel()) != null) {
- txListModel.connectToFirstReceiverOfDevices(guiModel,sequencerModel,synthModel,firstMidiOutModel);
- }
- // シーケンサ → GUI、各音源
- if( sequencerModel != null && (txListModel = sequencerModel.getTransmitterListModel()) != null) {
- txListModel.connectToFirstReceiverOfDevices(guiModel,synthModel,firstMidiOutModel);
- }
- } catch( MidiUnavailableException ex ) {
- ex.printStackTrace();
- }
- treeModel = new MidiDeviceTreeModel(deviceModelList);
- }
- /**
- * MIDIデバイスリストを最新の状態に更新します。USB-MIDIデバイスの着脱後に使います。
- */
- public void updateMidiDeviceList() {
- //
- // USBから抜いたMIDIデバイスを相手のMIDIデバイスに接続したまま
- // MidiSystem.getMidiDeviceInfo()を呼ぶと、Java VM が落ちることがある。
- //
- // それを回避するため、接続を一旦全部閉じる。
- //
- // 各Receiverごとに相手のTransmitterを閉じ、デバイスモデル同士の接続を覚えておく。
- Map<MidiDeviceModel, Set<MidiDeviceModel>> rxToTxConnections = new HashMap<>();
- for(MidiDeviceModel m : deviceModelList) {
- ReceiverListModel rxListModel = m.getReceiverListModel();
- if( rxListModel == null ) continue;
- Set<MidiDeviceModel> txDeviceModels = rxListModel.closePeerTransmitters();
- if( txDeviceModels.isEmpty() ) continue;
- rxToTxConnections.put(m, txDeviceModels);
- }
- // 最新のMIDIデバイス情報を取得
- MidiDevice.Info[] infoArray = MidiSystem.getMidiDeviceInfo();
- //
- // 追加されたデバイスの情報
- List<MidiDevice.Info> additionalDeviceInfos = new Vector<>(Arrays.asList(infoArray));
- //
- // 取り外されたデバイスのモデル
- List<MidiDeviceModel> removingDeviceModels = new Vector<>();
- //
- // 既存デバイスをスキャン
- for(MidiDeviceModel m : deviceModelList) {
- MidiDevice device = m.getMidiDevice();
- if( device instanceof VirtualMidiDevice ) continue;
- if( ! additionalDeviceInfos.remove(device.getDeviceInfo()) ) {
- // 最新のMIDIデバイス情報リストから除去しようとして、すでに存在していなかった場合、
- // そのデバイスはすでに取り外されている
- m.close();
- removingDeviceModels.add(m);
- }
- }
- // 取り外されたデバイスのモデルを除去
- deviceModelList.removeAll(removingDeviceModels);
- //
- // 追加されたデバイスをモデル化してデバイスモデルリストに追加
- for( MidiDevice.Info info : additionalDeviceInfos ) {
- try {
- MidiDevice device = MidiSystem.getMidiDevice(info);
- MidiDeviceModel m = new MidiDeviceModel(device, this);
- deviceModelList.add(m);
- } catch( MidiUnavailableException e ) {
- e.printStackTrace();
- }
- }
- // デバイスモデル同士の接続を復元
- Set<MidiDeviceModel> rxDeviceModels = rxToTxConnections.keySet();
- for( MidiDeviceModel rxm : rxDeviceModels ) {
- if( ! deviceModelList.contains(rxm) ) continue;
- List<Receiver> rxList = rxm.getReceiverListModel().getTransceivers();
- for( Receiver rx : rxList ) {
- Set<MidiDeviceModel> txDeviceModels = rxToTxConnections.get(rxm);
- for( MidiDeviceModel txm : txDeviceModels ) {
- try {
- txm.getTransmitterListModel().openTransmitter().setReceiver(rx);
- } catch( MidiUnavailableException e ) {
- e.printStackTrace();
- }
- }
- }
- }
- // デバイスツリーの更新を通知
- treeModel.setDeviceModelList(deviceModelList);
- }
- /**
- * {@link Transmitter}を持つすべてのデバイス(例:MIDIキーボードなど)について、
- * {@link MidiDeviceModel#resetMicrosecondPosition()}でマイクロ秒位置をリセットします。
- */
- public void resetMicrosecondPosition() {
- for(MidiDeviceModel m : deviceModelList) {
- TransmitterListModel txListModel = m.getTransmitterListModel();
- if( txListModel != null ) txListModel.resetMicrosecondPosition();
- }
- }
- /**
- * すべてのMIDIデバイスを閉じます。
- */
- public void close() {
- for(MidiDeviceModel m : deviceModelList) m.getMidiDevice().close();
- deviceModelList.clear();
- treeModel = null;
- }
-}
package camidion.chordhelper.mididevice;
+import java.util.AbstractList;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.EnumMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+import javax.sound.midi.MidiDevice;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.Receiver;
+import javax.sound.midi.Sequencer;
+import javax.sound.midi.Synthesizer;
+import javax.sound.midi.Transmitter;
import javax.swing.event.EventListenerList;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
+import camidion.chordhelper.ChordHelperApplet;
+
/**
- * MIDIデバイスを{@link MidiDeviceInOutType}で分類して参照できるようにするツリーモデル
+ * 仮想MIDIデバイスを含めたすべてのMIDIデバイスモデル{@link MidiDeviceModel}をツリー構造で管理するモデル。
+ * 読み取り専用のMIDIデバイスリストとしても、
+ * I/Oタイプで分類されたMIDIデバイスツリーモデルとしても参照できます。
*/
-public class MidiDeviceTreeModel implements TreeModel {
+public class MidiDeviceTreeModel extends AbstractList<MidiDeviceModel> implements TreeModel {
+ @Override
+ public String toString() { return "MIDI devices"; }
- private List<MidiDeviceModel> deviceModelList;
- public List<MidiDeviceModel> getDeviceModelList() { return deviceModelList; }
- public void setDeviceModelList(List<MidiDeviceModel> deviceModelList) {
- group.clear();
- this.deviceModelList = deviceModelList;
- createGroup();
- fireTreeStructureChanged(this, null, null, null);
+ // MIDIデバイスモデルリストとツリー
+ protected List<MidiDeviceModel> deviceModelList = new Vector<>();
+ protected Map<MidiDeviceInOutType, List<MidiDeviceModel>> deviceModelTree; {
+ deviceModelTree = new EnumMap<>(MidiDeviceInOutType.class);
+ deviceModelTree.put(MidiDeviceInOutType.MIDI_OUT, new ArrayList<>());
+ deviceModelTree.put(MidiDeviceInOutType.MIDI_IN, new ArrayList<>());
+ deviceModelTree.put(MidiDeviceInOutType.MIDI_IN_OUT, new ArrayList<>());
+ };
+ /**
+ * MIDIデバイスモデルを追加します。
+ *
+ * @param dm 追加するMIDIデバイスモデル
+ * @return 呼出しの結果としてこのリストが変更された場合はtrue
+ */
+ protected boolean addDeviceModel(MidiDeviceModel dm) {
+ if( ! deviceModelList.add(dm) ) return false;
+ deviceModelTree.get(dm.getInOutType()).add(dm); return true;
}
-
- private Map<MidiDeviceInOutType, List<MidiDeviceModel>> group = new EnumMap<>(MidiDeviceInOutType.class);
- private void createGroup() {
- for(MidiDeviceInOutType ioType : MidiDeviceInOutType.values()) {
- if( ioType != MidiDeviceInOutType.MIDI_NONE ) group.put(ioType, new ArrayList<>());
- }
- for( MidiDeviceModel m : deviceModelList ) group.get(m.getInOutType()).add(m);
+ /**
+ * MIDIデバイス情報をモデルとして追加します。
+ *
+ * @param info 追加するMIDIデバイス情報({@link MidiDevice.Info})
+ * @return 呼出しの結果としてこのリストが変更された場合はtrue
+ * @throws MidiUnavailableException {@link MidiDeviceModel#MidiDeviceModel(MidiDevice.Info, MidiDeviceTreeModel) MidiDeviceModelコンストラクタ}からの例外
+ */
+ protected boolean addDeviceModel(MidiDevice.Info info) throws MidiUnavailableException {
+ return addDeviceModel(new MidiDeviceModel(info, this));
}
- public Map<MidiDeviceInOutType, List<MidiDeviceModel>> getGroup() { return group; }
-
- public MidiDeviceTreeModel(List<MidiDeviceModel> deviceModelList) {
- this.deviceModelList = deviceModelList;
- createGroup();
+ /**
+ * リストとツリーモデルから、指定されたMIDIデバイスモデル(複数指定可)を除去します。
+ *
+ * @param deviceModelsToRemove 除去したいMIDIデバイスモデル
+ * @return 指定されたMIDIデバイスモデルがこのリストに含まれていた場合はtrue
+ */
+ protected boolean removeDeviceModels(Collection<MidiDeviceModel> deviceModelsToRemove) {
+ if( ! deviceModelList.removeAll(deviceModelsToRemove) ) return false;
+ for( MidiDeviceModel dm : deviceModelsToRemove )
+ deviceModelTree.get(dm.getInOutType()).remove(dm);
+ return true;
+ }
+ /**
+ * リスト、ツリーモデル、接続マップから、指定されたMIDIデバイスモデル(複数指定可)を除去します。
+ *
+ * @param deviceModelsToRemove 除去したいMIDIデバイスモデル
+ * @param rxToTxConnections MIDIデバイスモデル接続マップ({@link #disconnectAllDevices()}の戻り値)
+ * @return 指定されたMIDIデバイスモデルがこのリストに含まれていた場合はtrue
+ */
+ protected boolean removeDeviceModels(
+ Collection<MidiDeviceModel> deviceModelsToRemove,
+ Map<MidiDeviceModel, Collection<MidiDeviceModel>> rxToTxConnections) {
+ if( ! removeDeviceModels(deviceModelsToRemove) ) return false;
+ Set<MidiDeviceModel> rxModels = rxToTxConnections.keySet();
+ rxModels.removeAll(deviceModelsToRemove);
+ for( MidiDeviceModel m : rxModels )
+ rxToTxConnections.get(m).removeAll(deviceModelsToRemove);
+ return true;
}
+ /**
+ * このMIDIデバイスツリーモデルに登録されているMIDIシーケンサーモデルを返します。
+ * @return MIDIシーケンサーモデル
+ */
+ public MidiSequencerModel getSequencerModel() { return sequencerModel; }
+ protected MidiSequencerModel sequencerModel;
+ //
+ // リスト用インターフェース
@Override
- public String toString() { return "MIDI devices"; }
+ public MidiDeviceModel get(int index) { return deviceModelList.get(index); }
+ @Override
+ public int size() { return deviceModelList.size(); }
+ //
+ // ツリーモデル用インターフェース
@Override
public Object getRoot() { return this; }
@Override
public int getChildCount(Object parent) {
if( parent == getRoot() ) return MidiDeviceInOutType.values().length - 1;
- if( parent instanceof MidiDeviceInOutType ) return group.get(parent).size();
+ if( parent instanceof MidiDeviceInOutType ) return deviceModelTree.get(parent).size();
return 0;
}
@Override
public Object getChild(Object parent, int index) {
if( parent == getRoot() ) return MidiDeviceInOutType.values()[index + 1];
- if( parent instanceof MidiDeviceInOutType ) return group.get(parent).get(index);
+ if( parent instanceof MidiDeviceInOutType ) return deviceModelTree.get(parent).get(index);
return null;
}
@Override
public int getIndexOfChild(Object parent, Object child) {
- if( parent == getRoot() ) return ((MidiDeviceInOutType)child).ordinal() - 1;
- if( parent instanceof MidiDeviceInOutType ) return group.get(parent).indexOf(child);
+ if( parent == getRoot() && child instanceof MidiDeviceInOutType ) {
+ return ((MidiDeviceInOutType)child).ordinal() - 1;
+ }
+ if( parent instanceof MidiDeviceInOutType ) return deviceModelTree.get(parent).indexOf(child);
return -1;
}
@Override
public boolean isLeaf(Object node) { return node instanceof MidiDeviceModel; }
@Override
public void valueForPathChanged(TreePath path, Object newValue) {}
- //
- private EventListenerList listenerList = new EventListenerList();
@Override
public void addTreeModelListener(TreeModelListener listener) {
listenerList.add(TreeModelListener.class, listener);
public void removeTreeModelListener(TreeModelListener listener) {
listenerList.remove(TreeModelListener.class, listener);
}
+ protected EventListenerList listenerList = new EventListenerList();
protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
}
}
}
+
+ /**
+ * {@link MidiSystem#getMidiDeviceInfo()} の結果を、不変の {@link List} として返します。
+ *
+ * <p>注意点:MIDIデバイスをUSBから抜いて、他のデバイスとの接続を切断せずに
+ * {@link MidiSystem#getMidiDeviceInfo()}を呼び出すと
+ * (少なくとも Windows 10 で)Java VM がクラッシュすることがあります。
+ * </p>
+ * @return インストールされているMIDIデバイスの情報のリスト
+ */
+ public static List<MidiDevice.Info> getMidiDeviceInfo() {
+ return Arrays.asList(MidiSystem.getMidiDeviceInfo());
+ }
+
+ /**
+ * 指定されたMIDIデバイスモデルをまとめて開きます。
+ *
+ * @param toOpenList 開きたいMIDIデバイスモデルのコレクション
+ */
+ public void openDevices(Collection<MidiDeviceModel> toOpenList) {
+ for( MidiDeviceModel toOpen : toOpenList ) {
+ try {
+ toOpen.open();
+ } catch( MidiUnavailableException ex ) {
+ System.out.println("Cannot open MIDI device " + toOpen);
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * 引数で与えられたGUI仮想MIDIデバイスと、{@link #getMidiDeviceInfo()}から取得したMIDIデバイス情報から、
+ * MIDIデバイスツリーモデルを初期構築します。
+ *
+ * @param guiVirtualDevice 管理対象に含めるGUI仮想MIDIデバイス
+ */
+ public MidiDeviceTreeModel(VirtualMidiDevice guiVirtualDevice) {
+ MidiDeviceModel guiModel = new MidiDeviceModel(guiVirtualDevice, this);
+ addDeviceModel(guiModel);
+ try {
+ addDeviceModel(sequencerModel = new MidiSequencerModel(MidiSystem.getSequencer(false), this));
+ } catch( MidiUnavailableException e ) {
+ System.out.println(ChordHelperApplet.VersionInfo.NAME +" : MIDI sequencer unavailable");
+ e.printStackTrace();
+ }
+ MidiDeviceModel synthModel = null;
+ MidiDeviceModel firstMidiInModel = null;
+ MidiDeviceModel firstMidiOutModel = null;
+ for( MidiDevice.Info info : getMidiDeviceInfo() ) {
+ MidiDevice device;
+ try {
+ device = MidiSystem.getMidiDevice(info);
+ } catch( MidiUnavailableException e ) {
+ e.printStackTrace();
+ continue;
+ }
+ if( device instanceof Sequencer ) continue; // シーケンサはすでに取得済み
+ if( device instanceof Synthesizer ) { // Java内蔵シンセサイザ
+ try {
+ addDeviceModel(synthModel = new MidiDeviceModel(MidiSystem.getSynthesizer(), this));
+ } catch( MidiUnavailableException e ) {
+ System.out.println(ChordHelperApplet.VersionInfo.NAME +
+ " : Java internal MIDI synthesizer unavailable");
+ e.printStackTrace();
+ }
+ continue;
+ }
+ MidiDeviceModel m = new MidiDeviceModel(device, this);
+ //
+ // 最初の MIDI OUT(Windowsの場合は通常、内蔵音源 Microsoft GS Wavetable SW Synth)
+ if( firstMidiOutModel == null && m.getReceiverListModel() != null ) firstMidiOutModel = m;
+ //
+ // 最初の MIDI IN(USB MIDI インターフェースにつながったMIDIキーボードなど)
+ if( firstMidiInModel == null && m.getTransmitterListModel() != null ) firstMidiInModel = m;
+ //
+ addDeviceModel(m);
+ }
+ // 開くMIDIデバイスモデルの一覧を作成
+ //
+ // NOTE: 必ず MIDI OUT Rx デバイスを先に開くこと。
+ //
+ // そうすれば、後から開いた MIDI IN Tx デバイスからのタイムスタンプのほうが「若く」なるので、
+ // 相手の MIDI OUT Rx デバイスは「信号が遅れてやってきた」と認識、遅れを取り戻そうとして
+ // 即座に音を出してくれる。
+ //
+ // 開く順序が逆になると「進みすぎるから遅らせよう」として無用なレイテンシーが発生する原因になる。
+ //
+ List<MidiDeviceModel> toOpenList = new ArrayList<>();
+ for( MidiDeviceModel toOpen : Arrays.asList(
+ synthModel, firstMidiOutModel, sequencerModel, guiModel, firstMidiInModel) ) {
+ if( toOpen != null ) toOpenList.add(toOpen);
+ }
+ // MIDIデバイスモデルを開く
+ openDevices(toOpenList);
+ //
+ // 初期接続マップを作成(開いたデバイスを相互に接続する)
+ Map<MidiDeviceModel, Collection<MidiDeviceModel>> initialConnection = new LinkedHashMap<>();
+ for( MidiDeviceModel rxm : toOpenList ) {
+ if( rxm.getReceiverListModel() == null ) continue;
+ List<MidiDeviceModel> txmList;
+ initialConnection.put(rxm, txmList = new ArrayList<>());
+ for( MidiDeviceModel txm : toOpenList ) {
+ if( txm.getTransmitterListModel() == null ) continue;
+ //
+ // Tx/Rx両方を持つデバイスでは
+ // ・シーケンサーモデルは自分自身には接続しない
+ // ・GUIデバイスモデルでは自分自身にも接続する
+ if( txm == sequencerModel && txm == rxm ) continue;
+ //
+ txmList.add(txm);
+ }
+ }
+ // 初期接続を実行
+ connectDevices(initialConnection);
+ }
+ /**
+ * すべてのMIDIデバイスを閉じます。
+ */
+ public void closeAllDevices() {
+ for(MidiDeviceModel m : deviceModelList) m.getMidiDevice().close();
+ }
+ /**
+ * デバイス間の接続をすべて切断します。
+ * 各{@link Receiver}ごとに相手デバイスの{@link Transmitter}を閉じ、
+ * その時どのように接続されていたかを示すマップを返します。
+ *
+ * @return MIDIデバイスモデル接続マップ(再接続時に{@link #connectDevices(Map)}に指定可)
+ * <ul>
+ * <li>キー:各{@link Receiver}を持つMIDIデバイスモデル</li>
+ * <li>値:接続相手だった{@link Transmitter}を持つMIDIデバイスモデルのコレクション</li>
+ * </ul>
+ */
+ public Map<MidiDeviceModel, Collection<MidiDeviceModel>> disconnectAllDevices() {
+ Map<MidiDeviceModel, Collection<MidiDeviceModel>> rxToTxConnections = new LinkedHashMap<>();
+ for(MidiDeviceModel m : deviceModelList) {
+ ReceiverListModel rxListModel = m.getReceiverListModel();
+ if( rxListModel == null ) continue;
+ Collection<MidiDeviceModel> txDeviceModels = rxListModel.closeTransmitters();
+ if( txDeviceModels.isEmpty() ) continue;
+ rxToTxConnections.put(m, txDeviceModels);
+ }
+ return rxToTxConnections;
+ }
+ /**
+ * デバイス間の接続を復元します。
+ *
+ * @param rxToTxConnections {@link #disconnectAllDevices()}が返したMIDIデバイスモデル接続マップ
+ * <ul>
+ * <li>キー:{@link Receiver}側デバイスモデル</li>
+ * <li>値:{@link Transmitter}側デバイスモデルのコレクション</li>
+ * </ul>
+ */
+ public void connectDevices(Map<MidiDeviceModel, Collection<MidiDeviceModel>> rxToTxConnections) {
+ for( MidiDeviceModel rxm : rxToTxConnections.keySet() ) {
+ if( rxm == null ) continue;
+ Receiver rx = rxm.getReceiverListModel().getTransceivers().get(0);
+ for( MidiDeviceModel txm : rxToTxConnections.get(rxm) ) {
+ if( txm == null ) continue;
+ try {
+ txm.getTransmitterListModel().openTransmitter().setReceiver(rx);
+ } catch( MidiUnavailableException e ) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ /**
+ * USB-MIDIデバイスの着脱後、MIDIデバイスリストを最新の状態に更新します。
+ *
+ * <p>USBからMIDIデバイスを抜いた場合に {@link #getMidiDeviceInfo()} で
+ * Java VM クラッシュが発生する現象を回避するため、更新前に全デバイスの接続を一時切断し、
+ * 更新完了後に接続を復元します。
+ * </p>
+ */
+ public void updateMidiDeviceList() {
+ // 一時切断
+ Map<MidiDeviceModel, Collection<MidiDeviceModel>> rxToTxConnections = disconnectAllDevices();
+ //
+ // 追加・削除されたMIDIデバイスを特定
+ List<MidiDevice.Info> toAdd = new Vector<>(getMidiDeviceInfo());
+ List<MidiDeviceModel> toRemove = new Vector<>();
+ for(MidiDeviceModel m : deviceModelList) {
+ MidiDevice d = m.getMidiDevice();
+ if( d instanceof VirtualMidiDevice || toAdd.remove(d.getDeviceInfo()) ) continue;
+ d.close();
+ toRemove.add(m);
+ }
+ // 削除されたデバイスのモデルを除去
+ removeDeviceModels(toRemove, rxToTxConnections);
+ //
+ // 追加されたデバイスのモデルを登録
+ for( MidiDevice.Info info : toAdd ) {
+ try {
+ addDeviceModel(info);
+ } catch( MidiUnavailableException e ) {
+ e.printStackTrace();
+ }
+ }
+ // 再接続
+ connectDevices(rxToTxConnections);
+ //
+ // リスナーに通知してツリー表示を更新してもらう
+ fireTreeStructureChanged(this, null, null, null);
+ }
+ /**
+ * {@link Transmitter}を持つすべてのデバイス(例:MIDIキーボードなど)について、
+ * {@link MidiDeviceModel#resetMicrosecondPosition()}でマイクロ秒位置をリセットします。
+ */
+ public void resetMicrosecondPosition() {
+ for(MidiDeviceModel m : deviceModelList) {
+ TransmitterListModel txListModel = m.getTransmitterListModel();
+ if( txListModel != null ) txListModel.resetMicrosecondPosition();
+ }
+ }
+
}
/**
* MIDIシーケンサモデルを構築します。
* @param sequencer シーケンサーMIDIデバイス
- * @param deviceModelList 親のMIDIデバイスモデルリスト
+ * @param deviceModelTree 親のMIDIデバイスツリーモデル
*/
- public MidiSequencerModel(Sequencer sequencer, MidiDeviceModelManager deviceModelList) {
- super(sequencer, deviceModelList);
+ public MidiSequencerModel(Sequencer sequencer, MidiDeviceTreeModel deviceModelTree) {
+ super(sequencer, deviceModelTree);
}
/**
* このシーケンサーの再生スピード調整モデル
timeRangeUpdater.start();
SequenceTrackListTableModel sequenceTableModel = getSequenceTrackListTableModel();
if( sequenceTableModel != null && sequenceTableModel.hasRecordChannel() ) {
- deviceModelManager.resetMicrosecondPosition();
+ deviceTreeModel.resetMicrosecondPosition();
System.gc();
sequencer.startRecording();
}
package camidion.chordhelper.mididevice;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
if( device.getReceivers().isEmpty() ) device.getReceiver();
}
/**
- * このリストモデルの{@link Receiver}に接続された{@link Transmitter}を全て閉じます。
+ * このリストモデルの{@link Receiver}に接続された{@link Transmitter}を全て閉じ、
+ * 接続相手だったMIDIデバイスモデルのユニークな集合を返します。
*
* @return 閉じた{@link Transmitter}の{@link MidiDeviceModel}の集合
*/
- public Set<MidiDeviceModel> closePeerTransmitters() {
- List<Receiver> rxList = deviceModel.getMidiDevice().getReceivers();
- List<MidiDeviceModel> deviceModelList = deviceModel.getDeviceModelManager().getDeviceModelList();
- Set<MidiDeviceModel> peedDeviceModels = new HashSet<>();
- for( Receiver rx : rxList ) {
- for( MidiDeviceModel peedDeviceModel : deviceModelList ) {
- if( peedDeviceModel == deviceModel ) continue;
- TransmitterListModel txListModel = peedDeviceModel.getTransmitterListModel();
- if( txListModel == null || txListModel.closeTransmittersConnectedTo(rx).isEmpty() ) continue;
- peedDeviceModels.add(peedDeviceModel);
+ public Set<MidiDeviceModel> closeTransmitters() {
+ Set<MidiDeviceModel> peerDeviceModelSet = new LinkedHashSet<>();
+ List<Receiver> rxList = getTransceivers();
+ if( ! rxList.isEmpty() ) {
+ for( MidiDeviceModel peerDeviceModel : deviceModel.getDeviceTreeModel() ) {
+ if( peerDeviceModel == deviceModel ) continue;
+ TransmitterListModel txListModel = peerDeviceModel.getTransmitterListModel();
+ if( txListModel == null ) continue;
+ for( Receiver rx : rxList )
+ if( ! txListModel.closeTransmittersFor(rx).isEmpty() )
+ peerDeviceModelSet.add(peerDeviceModel);
}
}
- return peedDeviceModels;
+ return peerDeviceModelSet;
}
}
package camidion.chordhelper.mididevice;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
-import java.util.Vector;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiUnavailableException;
return tx;
}
/**
- * 相手のMIDIデバイスが持つ最初の{@link Receiver}を、
- * このリストモデルの新規{@link Transmitter}に接続します。
- *
- * @param anotherDeviceModels 接続相手のMIDIデバイス(複数指定可)
- * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる
- */
- public void connectToFirstReceiverOfDevices(MidiDeviceModel... anotherDeviceModels) throws MidiUnavailableException {
- for( MidiDeviceModel anotherDeviceModel : anotherDeviceModels ) {
- List<Receiver> rxList = anotherDeviceModel.getMidiDevice().getReceivers();
- if( ! rxList.isEmpty() ) deviceModel.getTransmitterListModel().openTransmitter().setReceiver(rxList.get(0));
- }
- }
- /**
- * 指定の{@link Transmitter}を閉じ、要素数が1個減ったことをこのモデルを参照しているビューへ通知します。
+ * 指定された{@link Transmitter}を閉じ、要素数が1個減ったことをこのモデルを参照しているビューへ通知します。
*
* @param tx このリストモデルで開いている{@link Transmitter}
*/
fireIntervalRemoved(this, index, index);
}
/**
+ * 指定された複数の{@link Transmitter}を閉じ、要素数が大きく減ったことをこのモデルを参照しているビューへ通知します。
+ *
+ * @param txc このリストモデルで開いている{@link Transmitter}のコレクション
+ */
+ public void closeTransmitters(Collection<Transmitter> txc) {
+ if( txc.isEmpty() ) return;
+ int length = getSize();
+ for( Transmitter tx : txc ) tx.close();
+ fireIntervalRemoved(this, 0, length);
+ }
+ /**
* このリストモデルにある{@link Transmitter}のうち、
- * 引数で指定された{@link Receiver}へデータを送信しているものを全て閉じます。
- * 閉じるとリストから自動的に削除されるので、表示の更新も行います。
+ * 引数で指定された{@link Receiver}へデータを送信しているものを探し、
+ * それらを{@link #closeTransmitters(Collection)}で閉じます。
+ *
* @return 閉じた{@link Transmitter}のリスト
*/
- public List<Transmitter> closeTransmittersConnectedTo(Receiver rx) {
- List<Transmitter> closeTxList = new Vector<Transmitter>();
- List<Transmitter> txList = getTransceivers();
- for( Transmitter tx : txList ) if( tx.getReceiver() == rx ) closeTxList.add(tx);
- if( ! closeTxList.isEmpty() ) {
- int length = getSize();
- for( Transmitter tx : closeTxList ) tx.close();
- fireIntervalRemoved(this, 0, length);
- }
- return closeTxList;
+ public List<Transmitter> closeTransmittersFor(Receiver rx) {
+ List<Transmitter> txToClose = new ArrayList<Transmitter>();
+ for( Transmitter tx : getTransceivers() ) if( tx.getReceiver() == rx ) txToClose.add(tx);
+ closeTransmitters(txToClose);
+ return txToClose;
}
/**
* マイクロ秒位置をリセットします。
MidiDevice device = deviceModel.getMidiDevice();
if( device instanceof Sequencer || ! device.isOpen() ) return;
//
- // デバイスを閉じる前に接続状態を把握
- List<Receiver> peerRxList = new Vector<Receiver>();
- List<Transmitter> txList = device.getTransmitters();
- for( Transmitter tx : txList ) {
+ // 接続状態を保存
+ // 自分Tx → 相手Rx
+ List<Receiver> peerRxList = new ArrayList<Receiver>();
+ for( Transmitter tx : device.getTransmitters() ) {
Receiver rx = tx.getReceiver();
if( rx != null ) peerRxList.add(rx);
}
- List<Transmitter> peerTxList = new Vector<Transmitter>();
- List<MidiDeviceModel> deviceModelList = deviceModel.getDeviceModelManager().getDeviceModelList();
+ // 自分Rx ← 相手Tx
+ List<Transmitter> peerTxList = new ArrayList<Transmitter>();
List<Receiver> rxList = device.getReceivers();
- for( Receiver rx : rxList ) {
- for( MidiDeviceModel m : deviceModelList ) {
- if( m == deviceModel ) continue;
+ if( ! rxList.isEmpty() ) {
+ for( MidiDeviceModel m : deviceModel.getDeviceTreeModel() ) {
+ if( m == deviceModel ) continue; // 「自分Rx ← 自分Tx」は重複するのでスキップ
List<Transmitter> peerSourceTxList = m.getMidiDevice().getTransmitters();
- for( Transmitter tx : peerSourceTxList ) if( tx.getReceiver() == rx ) peerTxList.add(tx);
+ for( Transmitter tx : peerSourceTxList ) {
+ for( Receiver rx : rxList ) if( tx.getReceiver() == rx ) peerTxList.add(tx);
+ }
}
}
- // いったん閉じて開く(ここでマイクロ秒位置がリセットされる)
- // その後、元通りに接続し直す
- device.close();
+ device.close(); // 一旦閉じる
try {
- device.open();
+ device.open(); // 再び開くことでマイクロ秒位置がリセットされる
+ //
+ // 接続を復元
+ // 自分Tx → 相手Rx
for( Receiver peerRx : peerRxList ) openTransmitter().setReceiver(peerRx);
+ // 自分Rx ← 相手Tx
if( ! rxList.isEmpty() ) {
- Receiver rx = rxList.get(0);
- for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rx);
+ for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rxList.get(0));
}
} catch( MidiUnavailableException e ) {
e.printStackTrace();
}
}
-}
\ No newline at end of file
+}