1 package camidion.chordhelper.mididevice;
4 import java.util.Vector;
6 import javax.sound.midi.MidiDevice;
7 import javax.sound.midi.MidiEvent;
8 import javax.sound.midi.MidiUnavailableException;
9 import javax.sound.midi.Receiver;
10 import javax.sound.midi.Sequencer;
11 import javax.sound.midi.Transmitter;
12 import javax.swing.AbstractListModel;
15 * 1個の MIDI デバイスに属する Transmitter/Receiver のリストモデル
17 public class MidiConnecterListModel extends AbstractListModel<AutoCloseable> {
18 protected MidiDevice device;
19 private List<MidiConnecterListModel> modelList;
21 * 実体のない新規Transmitterを表すインターフェース
23 public interface NewTransmitter extends Transmitter {};
24 public NewTransmitter newTransmitter;
26 * 指定のMIDIデバイスに属する {@link Transmitter}/{@link Receiver} のリストモデルを構築します。
28 * @param device 対象MIDIデバイス
29 * @param modelList リストモデルを格納している親リスト
31 public MidiConnecterListModel(MidiDevice device, List<MidiConnecterListModel> modelList) {
33 this.modelList = modelList;
35 newTransmitter = new NewTransmitter() {
37 public void setReceiver(Receiver receiver) { }
39 public Receiver getReceiver() { return null; }
41 public void close() { }
49 public MidiDevice getMidiDevice() { return device; }
54 public String toString() { return device.getDeviceInfo().toString(); }
56 public AutoCloseable getElementAt(int index) {
57 List<Receiver> rxList = device.getReceivers();
58 int rxSize = rxList.size();
59 if( index < rxSize ) return rxList.get(index);
61 List<Transmitter> txList = device.getTransmitters();
62 int txSize = txList.size();
63 if( index < txSize ) return txList.get(index);
64 if( index == txSize ) return newTransmitter;
68 public int getSize() {
69 int txSize = txSupported() ? device.getTransmitters().size() + 1 : 0;
70 return device.getReceivers().size() + txSize;
73 * 指定の要素がこのリストモデルで最初に見つかった位置を返します。
75 * @param element 探したい要素
76 * @return 位置のインデックス(先頭が 0、見つからないとき -1)
78 public int indexOf(AutoCloseable element) {
80 List<Receiver> rxList = device.getReceivers();
81 if( (index = rxList.indexOf(element)) >= 0 ) return index;
82 List<Transmitter> txList = device.getTransmitters();
83 if( (index = txList.indexOf(element)) >= 0 ) return rxList.size() + index;
84 if( element.equals(newTransmitter) ) return rxList.size() + txList.size();
88 * このリストが {@link Transmitter} をサポートしているか調べます。
89 * @return {@link Transmitter} をサポートしていたら true
91 public boolean txSupported() { return device.getMaxTransmitters() != 0; }
93 * このリストが {@link Receiver} をサポートしているか調べます。
94 * @return {@link Receiver} をサポートしていたら true
96 public boolean rxSupported() { return device.getMaxReceivers() != 0; }
98 * このリストのMIDIデバイスの入出力タイプを返します。
99 * @return このリストのMIDIデバイスの入出力タイプ
101 * <li>MIDI_OUT: {@link Receiver}から受けた{@link MidiEvent}を音源や画面に出力するデバイス</li>
102 * <li>MIDI_IN: キーボードやシーケンサから入力した{@link MidiEvent}を{@link Transmitter}から{@link Receiver}へ転送するデバイス</li>
103 * <li>MIDI_IN_OUT: 上記両方の機能をサポートしたデバイス</li>
104 * <li>MIDI_NONE: 上記両方ともサポートしていないデバイス</li>
107 public MidiDeviceInOutType getMidiDeviceInOutType() {
108 if( rxSupported() ) {
110 return MidiDeviceInOutType.MIDI_IN_OUT;
112 return MidiDeviceInOutType.MIDI_OUT;
116 return MidiDeviceInOutType.MIDI_IN;
118 return MidiDeviceInOutType.MIDI_NONE;
122 * 引数で指定されたトランスミッタをレシーバを接続します。
125 * @return 接続されたレシーバ(このリストにないレシーバが指定された場合はnull)
127 public Receiver ConnectToReceiver(Transmitter tx, Receiver rx) {
128 if( ! device.getReceivers().contains(rx) ) return null;
130 fireContentsChanged(this,0,getSize());
135 * 引数で指定されたリストモデルの最初のレシーバに接続します。
136 * @param anotherModel 接続先レシーバを持つリストモデル
138 public void connectToReceiverOf(MidiConnecterListModel anotherModel) {
139 if( ! txSupported() || anotherModel == null || ! anotherModel.rxSupported() ) return;
140 List<Receiver> rxList = anotherModel.device.getReceivers();
141 if( rxList.isEmpty() ) return;
142 openTransmitter().setReceiver(rxList.get(0));
145 * レシーバに未接続の最初のトランスミッタを返します。
146 * ない場合は {@link MidiDevice#getTransmitter} で新たに取得して返します。
148 * @return 未接続のトランスミッタ
150 public Transmitter openTransmitter() {
151 if( ! txSupported() ) return null;
152 List<Transmitter> txList = device.getTransmitters();
153 for( Transmitter tx : txList ) if( tx.getReceiver() == null ) return tx;
156 tx = device.getTransmitter();
157 } catch( MidiUnavailableException e ) {
161 fireIntervalAdded(this,0,getSize());
166 * このリストモデルにないトランスミッタが指定された場合、無視されます。
167 * @param txToClose 閉じたいトランスミッタ
169 public void closeTransmitter(Transmitter txToClose) {
170 if( ! device.getTransmitters().contains(txToClose) ) return;
172 fireIntervalRemoved(this,0,getSize());
176 * @throws MidiUnavailableException デバイスを開くことができない場合
178 public void openDevice() throws MidiUnavailableException {
180 if( rxSupported() && device.getReceivers().isEmpty() ) device.getReceiver();
184 * 対象MIDIデバイスの{@link Receiver}を設定した他デバイスの{@link Transmitter}があれば、
187 public void closeDevice() {
188 if( rxSupported() ) {
189 Receiver rx = device.getReceivers().get(0);
190 for( MidiConnecterListModel m : modelList ) {
191 if( m == this || ! m.txSupported() ) continue;
192 for( int i=0; i<m.getSize(); i++ ) {
193 AutoCloseable ac = m.getElementAt(i);
194 if( ! (ac instanceof Transmitter) ) continue;
195 Transmitter tx = ((Transmitter)ac);
196 if( tx.getReceiver() == rx ) m.closeTransmitter(tx);
204 * <p>マイクロ秒位置はMIDIデバイスを開いてからの時間で表されます。
205 * このメソッドではMIDIデバイスをいったん閉じて再び開くことによって
207 * 接続相手のデバイスがあった場合、元通りに接続を復元します。
209 * <p>MIDIデバイスからリアルタイムレコーディングを開始するときは、
210 * 必ずマイクロ秒位置をリセットする必要があります。
211 * (リセットされていないマイクロ秒位置がそのままシーケンサに記録されると、
212 * 大幅に後ろのほうにずれて記録されてしまいます)
215 public void resetMicrosecondPosition() {
216 if( ! txSupported() || device instanceof Sequencer ) return;
218 // デバイスを閉じる前に接続相手の情報を保存
219 List<Transmitter> txList = device.getTransmitters();
220 List<Receiver> peerRxList = new Vector<Receiver>();
221 for( Transmitter tx : txList ) {
222 Receiver rx = tx.getReceiver();
223 if( rx != null ) peerRxList.add(rx);
225 List<Transmitter> peerTxList = null;
227 if( rxSupported() ) {
228 rx = device.getReceivers().get(0);
229 peerTxList = new Vector<Transmitter>();
230 for( MidiConnecterListModel m : modelList ) {
231 if( m == this || ! m.txSupported() ) continue;
232 for( int i=0; i<m.getSize(); i++ ) {
233 Object obj = m.getElementAt(i);
234 if( ! (obj instanceof Transmitter) ) continue;
235 Transmitter tx = ((Transmitter)obj);
236 if( tx.getReceiver() == rx ) peerTxList.add(tx);
240 // いったん閉じて開く(ここでマイクロ秒位置がリセットされる)
244 } catch( MidiUnavailableException e ) {
248 for( Receiver peerRx : peerRxList ) {
249 Transmitter tx = openTransmitter();
250 if( tx != null ) tx.setReceiver(peerRx);
252 if( peerTxList != null ) {
253 rx = device.getReceivers().get(0);
254 for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rx);