From: Akiyoshi Kamide Date: Sun, 19 Jun 2016 16:29:40 +0000 (+0900) Subject: ・Java8 VM 環境対応 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f6358cf1f64d55e56032663ef821caf0b0bd1c8b;p=midichordhelper%2FMIDIChordHelper.git ・Java8 VM 環境対応 ・MIDIデバイス周りのリファクタリング(入れ子クラスの外出しなど) --- diff --git a/.classpath b/.classpath index 5c26a12..70858d0 100644 --- a/.classpath +++ b/.classpath @@ -1,7 +1,7 @@ - - - - - - - + + + + + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 838bd9d..0c68a61 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,11 +1,7 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/camidion/chordhelper/ChordHelperApplet.java b/src/camidion/chordhelper/ChordHelperApplet.java index d567cbd..fcda283 100644 --- a/src/camidion/chordhelper/ChordHelperApplet.java +++ b/src/camidion/chordhelper/ChordHelperApplet.java @@ -285,7 +285,7 @@ public class ChordHelperApplet extends JApplet { */ public static class VersionInfo { public static final String NAME = "MIDI Chord Helper"; - public static final String VERSION = "Ver.20160619.1"; + public static final String VERSION = "Ver.20160619.2"; 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/"; diff --git a/src/camidion/chordhelper/mididevice/DummyTransmitter.java b/src/camidion/chordhelper/mididevice/DummyTransmitter.java new file mode 100644 index 0000000..0f84d14 --- /dev/null +++ b/src/camidion/chordhelper/mididevice/DummyTransmitter.java @@ -0,0 +1,17 @@ +package camidion.chordhelper.mididevice; + +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +/** + * 実体のない新規{@link Transmitter} + */ +public class DummyTransmitter implements Transmitter { + private Receiver receiver; + @Override + public void setReceiver(Receiver receiver) { this.receiver = receiver; } + @Override + public Receiver getReceiver() { return receiver; } + @Override + public void close() { } +} diff --git a/src/camidion/chordhelper/mididevice/MidiCablePane.java b/src/camidion/chordhelper/mididevice/MidiCablePane.java index 5788ee9..e4f4b03 100644 --- a/src/camidion/chordhelper/mididevice/MidiCablePane.java +++ b/src/camidion/chordhelper/mididevice/MidiCablePane.java @@ -154,7 +154,7 @@ public class MidiCablePane extends JComponent implements DragSourceMotionListene g2.drawLine(rxBounds.x, rxBounds.y, draggingPoint.x, draggingPoint.y); } // Transmitterを全部スキャン - MidiDeviceModel.TransmitterListModel txListModel = fromDeviceModel.getTransmitterListModel(); + TransmitterListModel txListModel = fromDeviceModel.getTransmitterListModel(); int ntx = txListModel == null ? 0 : txListModel.getSize(); for( int index=0 ; index < ntx; index++ ) { Transmitter tx = txListModel.getElementAt(index); diff --git a/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java b/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java index 8399c9a..90785e8 100644 --- a/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java +++ b/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java @@ -23,8 +23,8 @@ import javax.swing.Timer; */ public class MidiDeviceFrame extends JInternalFrame { private MidiDeviceModel deviceModel; - private MidiTransmitterListView transmitterListView; - private MidiReceiverListView receiverListView; + private TransmitterListView transmitterListView; + private ReceiverListView receiverListView; private JScrollPane scrollPane; private JPanel trxPanel, txPanel, rxPanel; private Timer timer; @@ -37,12 +37,12 @@ public class MidiDeviceFrame extends JInternalFrame { * このデバイスフレームに貼り付けられたMIDIトランスミッタリストビューを取得します。 * @return MIDIトランスミッタリストビュー */ - public MidiTransmitterListView getMidiTransmitterListView() { return transmitterListView; } + public TransmitterListView getMidiTransmitterListView() { return transmitterListView; } /** * このデバイスフレームに貼り付けられたMIDIトランシーバリストビューを取得します。 * @return MIDIトランシーバリストビュー */ - public MidiReceiverListView getMidiReceiverListView() { return receiverListView; } + public ReceiverListView getMidiReceiverListView() { return receiverListView; } /** * ダイアログウィンドウがアクティブなときだけタイムスタンプ更新を有効にするためのリスナー */ @@ -78,18 +78,18 @@ public class MidiDeviceFrame extends JInternalFrame { }}, BorderLayout.SOUTH); add(scrollPane = new JScrollPane(trxPanel = new JPanel() {{ setLayout(new BorderLayout()); - MidiDeviceModel.ReceiverListModel rxListModel = getMidiDeviceModel().getReceiverListModel(); + ReceiverListModel rxListModel = getMidiDeviceModel().getReceiverListModel(); if( rxListModel != null ) { - receiverListView = new MidiReceiverListView(rxListModel, cablePane); + receiverListView = new ReceiverListView(rxListModel, cablePane); add(rxPanel = new JPanel() {{ setLayout(new BorderLayout()); add(new JLabel("Rx") {{ setVerticalAlignment(TOP); }}, BorderLayout.WEST); add(receiverListView); }}, BorderLayout.NORTH); } - MidiDeviceModel.TransmitterListModel txListModel = getMidiDeviceModel().getTransmitterListModel(); + TransmitterListModel txListModel = getMidiDeviceModel().getTransmitterListModel(); if( txListModel != null ) { - transmitterListView = new MidiTransmitterListView(txListModel, cablePane); + transmitterListView = new TransmitterListView(txListModel, cablePane); add(txPanel = new JPanel() {{ setLayout(new BorderLayout()); add(new JLabel("Tx") {{ setVerticalAlignment(TOP); }}, BorderLayout.WEST); diff --git a/src/camidion/chordhelper/mididevice/MidiDeviceModel.java b/src/camidion/chordhelper/mididevice/MidiDeviceModel.java index 43c39ac..71160d6 100644 --- a/src/camidion/chordhelper/mididevice/MidiDeviceModel.java +++ b/src/camidion/chordhelper/mididevice/MidiDeviceModel.java @@ -1,212 +1,27 @@ package camidion.chordhelper.mididevice; -import java.util.List; -import java.util.Vector; - import javax.sound.midi.MidiDevice; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Receiver; -import javax.sound.midi.Sequencer; import javax.sound.midi.Transmitter; -import javax.swing.AbstractListModel; import javax.swing.tree.TreePath; /** * 1個の{@link MidiDevice}を表すモデル */ public class MidiDeviceModel { - - /** - * {@link Receiver} のリストを表す {@link javax.swing.ListModel} - */ - public class ReceiverListModel extends AbstractListModel { - @Override - public Receiver getElementAt(int index) { return device.getReceivers().get(index); } - @Override - public int getSize() { return device.getReceivers().size(); } - /** - * 指定の要素がこのリストモデルで最初に見つかった位置を返します。 - * - * @param element 探したい要素 - * @return 位置のインデックス(先頭が 0、見つからないとき -1) - */ - public int indexOf(Object element) { return device.getReceivers().indexOf(element); } - /** - * {@link MidiDevice#getReceiver()} でレシーバを1個開きます。 - * すでに1個開いている場合は無視されます。 - * - * @throws MidiUnavailableException リソースの制約のためにレシーバを使用できない場合にスローされる - */ - public void openReceiver() throws MidiUnavailableException { - if( device.getReceivers().isEmpty() ) device.getReceiver(); - } - /** - * このリストモデルの{@link Receiver}に接続された他デバイスの{@link Transmitter}を全て閉じます。 - */ - public void closePeerTransmitters() { - List rxList = device.getReceivers(); - for( Receiver rx : rxList ) { - for( MidiDeviceModel m : deviceModelList ) { - if( m == MidiDeviceModel.this || m.txListModel == null ) continue; - m.txListModel.closePeerTransmitterOf(rx); - } - } - } - } - - /** - * 実体のない新規{@link Transmitter}を表すインターフェース - */ - interface NewTransmitter extends Transmitter {}; /** - * {@link Transmitter} のリストを表す {@link javax.swing.ListModel} + * {@link javax.swing.JTree}で使用するツリー表示のパスを返します。 + * @return ツリーパス */ - public class TransmitterListModel extends AbstractListModel { - private NewTransmitter newTransmitter = new NewTransmitter() { - private Receiver receiver; - @Override - public void setReceiver(Receiver receiver) { this.receiver = receiver; } - @Override - public Receiver getReceiver() { return receiver; } - @Override - public void close() { } - }; - @Override - public Transmitter getElementAt(int index) { - List txList = device.getTransmitters(); - int length = txList.size(); - if( index == length ) return newTransmitter; - if( index > length || index < 0 ) return null; - return txList.get(index); - } - @Override - public int getSize() { return device.getTransmitters().size() + 1; } - /** - * 指定の要素がこのリストモデルで最初に見つかった位置(先頭が 0)を返します。 - * 見つからなかった場合は -1 を返します。 - * - * @param element 探したい要素 - * @return 位置 - */ - public int indexOf(Object element) { - List txList = device.getTransmitters(); - return element.equals(newTransmitter) ? txList.size() : txList.indexOf(element); - } - /** - * レシーバに未接続の最初の{@link Transmitter}を返します。 - * ない場合は{@link MidiDevice#getTransmitter}で新たに取得して返します。 - * - * @return 未接続の{@link Transmitter} - * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる - */ - public Transmitter getUnconnectedTransmitter() throws MidiUnavailableException { - List txList = device.getTransmitters(); - for( Transmitter tx : txList ) if( tx.getReceiver() == null ) return tx; - Transmitter tx; - tx = device.getTransmitter(); - fireIntervalAdded(this, 0, getSize()); - return tx; - } - /** - * このリストモデルの{@link #getUnconnectedTransmitter()}が返した{@link Transmitter}を、 - * 相手のMIDIデバイスが持つ最初の{@link Receiver}に接続します。 - * - * @param anotherDeviceModel 接続相手のMIDIデバイス - * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる - */ - public void connectToFirstReceiverOfDevice(MidiDeviceModel anotherDeviceModel) throws MidiUnavailableException { - List rxList = anotherDeviceModel.device.getReceivers(); - if( ! rxList.isEmpty() ) txListModel.getUnconnectedTransmitter().setReceiver(rxList.get(0)); - } - /** - * 指定の{@link Transmitter}がリストにあれば、それを閉じます。 - * 閉じるとリストから自動的に削除されるので、表示の更新も行います。 - * - * @param tx このリストモデルで開いている{@link Transmitter} - */ - public void close(Transmitter tx) { - if( ! device.getTransmitters().contains(tx) ) return; - tx.close(); - fireIntervalRemoved(this, 0, getSize()); - } - /** - * このリストモデルにある{@link Transmitter}のうち、 - * 引数で指定された{@link Receiver}へデータを送信しているものを全て閉じます。 - * 閉じるとリストから自動的に削除されるので、表示の更新も行います。 - */ - private void closePeerTransmitterOf(Receiver rx) { - List originalTxList = device.getTransmitters(); - List closingTxList = new Vector(); - for( Transmitter tx : originalTxList ) if( tx.getReceiver() == rx ) closingTxList.add(tx); - if( closingTxList.isEmpty() ) return; - int length = getSize(); - for( Transmitter tx : closingTxList ) tx.close(); - fireIntervalRemoved(this, 0, length); - } - /** - * マイクロ秒位置をリセットします。 - *

マイクロ秒位置はMIDIデバイスを開いてからの時間で表されます。 - * このメソッドではMIDIデバイスをいったん閉じて再び開くことによって - * 時間位置をリセットします。 - * 接続相手のデバイスがあった場合、元通りに接続を復元します。 - *

- *

MIDIデバイスからリアルタイムレコーディングを開始するときは、 - * 必ずマイクロ秒位置をリセットする必要があります。 - * (リセットされていないマイクロ秒位置がそのままシーケンサに記録されると、 - * 大幅に後ろのほうにずれて記録されてしまいます) - *

- */ - public void resetMicrosecondPosition() { - // - // シーケンサはこのメソッドでのリセット対象外 - if( device instanceof Sequencer ) return; - // - // デバイスを閉じる前に接続状態を把握 - List myTxList = device.getTransmitters(); - List peerRxList = new Vector(); - for( Transmitter tx : myTxList ) { - Receiver rx = tx.getReceiver(); - if( rx != null ) peerRxList.add(rx); - } - List myRxList = device.getReceivers(); - List peerTxList = new Vector(); - for( Receiver rx : myRxList ) { - for( MidiDeviceModel m : deviceModelList ) { - if( m == MidiDeviceModel.this ) continue; - List peerSourceTxList = m.getMidiDevice().getTransmitters(); - for( Transmitter tx : peerSourceTxList ) if( tx.getReceiver() == rx ) peerTxList.add(tx); - } - } - // いったん閉じて開く(ここでマイクロ秒位置がリセットされる) - // その後、元通りに接続し直す - device.close(); - try { - device.open(); - for( Receiver peerRx : peerRxList ) getUnconnectedTransmitter().setReceiver(peerRx); - if( ! myRxList.isEmpty() ) { - Receiver rx = myRxList.get(0); - for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rx); - } - } catch( MidiUnavailableException e ) { - e.printStackTrace(); - } - } - } - + public TreePath getTreePath() { return treePath; } + private TreePath treePath; /** * このリストのMIDIデバイスの入出力タイプを返します。 * @return このリストのMIDIデバイスの入出力タイプ */ public MidiDeviceInOutType getMidiDeviceInOutType() { return ioType; } private MidiDeviceInOutType ioType; - - /** - * {@link javax.swing.JTree}で使用するツリー表示のパスを返します。 - * @return ツリーパス - */ - public TreePath getTreePath() { return treePath; } - private TreePath treePath; - /** * 対象MIDIデバイスを返します。 * @return 対象MIDIデバイス @@ -219,17 +34,6 @@ public class MidiDeviceModel { @Override public String toString() { return device.getDeviceInfo().toString(); } /** - * このデバイスモデルが {@link Transmitter} をサポートしているか調べます。 - * @return {@link Transmitter} をサポートしていたら true - */ - public boolean txSupported() { return device.getMaxTransmitters() != 0; } - /** - * このデバイスモデルが {@link Receiver} をサポートしているか調べます。 - * @return {@link Receiver} をサポートしていたら true - */ - public boolean rxSupported() { return device.getMaxReceivers() != 0; } - - /** * {@link Transmitter} のリストモデルを返します。サポートしていない場合はnullを返します。 * @return リストモデルまたはnull */ @@ -241,26 +45,27 @@ public class MidiDeviceModel { */ public ReceiverListModel getReceiverListModel() { return rxListModel; } private ReceiverListModel rxListModel; - + /** + * このMIDIデバイスモデルを収容しているリストを返します。 + */ + public MidiDeviceModelList getDeviceModelList() { return deviceModelList; } protected MidiDeviceModelList deviceModelList; /** * MIDIデバイスモデルを構築します。 * * @param device 対象MIDIデバイス - * @param deviceModelList 接続相手となりうるMIDIデバイスのリスト + * @param deviceModelList このMIDIデバイスモデルを収容しているリスト(接続相手となりうるMIDIデバイス) */ public MidiDeviceModel(MidiDevice device, MidiDeviceModelList deviceModelList) { this.device = device; this.deviceModelList = deviceModelList; - if( txSupported() ) { - txListModel = new TransmitterListModel(); - } - if( rxSupported() ) { - ioType = txSupported() ? MidiDeviceInOutType.MIDI_IN_OUT :MidiDeviceInOutType.MIDI_OUT; - rxListModel = new ReceiverListModel(); + 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 = txSupported() ? MidiDeviceInOutType.MIDI_IN :MidiDeviceInOutType.MIDI_NONE; + ioType = txListModel != null ? MidiDeviceInOutType.MIDI_IN :MidiDeviceInOutType.MIDI_NONE; } treePath = new TreePath(new Object[] {deviceModelList, ioType ,this}); } @@ -274,7 +79,7 @@ public class MidiDeviceModel { */ public void open() throws MidiUnavailableException { device.open(); - if( rxListModel != null ) rxListModel.openReceiver(); + if( rxListModel != null ) rxListModel.openSingleReceiver(); } /** * このMIDIデバイスを {@link MidiDevice#close()} で閉じます。 diff --git a/src/camidion/chordhelper/mididevice/MidiDeviceModelList.java b/src/camidion/chordhelper/mididevice/MidiDeviceModelList.java index 22f21dd..6fcbbd9 100644 --- a/src/camidion/chordhelper/mididevice/MidiDeviceModelList.java +++ b/src/camidion/chordhelper/mididevice/MidiDeviceModelList.java @@ -67,8 +67,8 @@ public class MidiDeviceModelList extends Vector { // その他のMIDIデバイス MidiDeviceModel m; addElement(m = new MidiDeviceModel(device, this)); - if( m.rxSupported() && firstMidiOutModel == null ) firstMidiOutModel = m; - if( m.txSupported() && firstMidiInModel == null ) firstMidiInModel = m; + if( firstMidiOutModel == null && m.getReceiverListModel() != null ) firstMidiOutModel = m; + if( firstMidiInModel == null && m.getTransmitterListModel() != null ) firstMidiInModel = m; } // MIDIデバイスを開く。 // NOTE: 必ず MIDI OUT Rx デバイスを先に開くこと。 @@ -92,7 +92,7 @@ public class MidiDeviceModelList extends Vector { for( MidiDeviceModel m : guiModels ) m.open(); // // 初期接続 - MidiDeviceModel.TransmitterListModel txListModel; + TransmitterListModel txListModel; for( MidiDeviceModel mtx : guiModels ) { if( (txListModel = mtx.getTransmitterListModel() ) != null) { for( MidiDeviceModel m : guiModels ) txListModel.connectToFirstReceiverOfDevice(m); @@ -122,7 +122,7 @@ public class MidiDeviceModelList extends Vector { */ public void resetMicrosecondPosition() { for(MidiDeviceModel m : this) { - MidiDeviceModel.TransmitterListModel txListModel = m.getTransmitterListModel(); + TransmitterListModel txListModel = m.getTransmitterListModel(); if( txListModel != null ) txListModel.resetMicrosecondPosition(); } } diff --git a/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java b/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java index deb6bbc..1234078 100644 --- a/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java +++ b/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java @@ -157,13 +157,13 @@ public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelection modelToFrame.put(deviceModel, frame); // // トランスミッタリストモデルが変化したときにMIDIケーブルを再描画 - if( deviceModel.txSupported() ) { - deviceModel.getTransmitterListModel().addListDataListener(cablePane.midiConnecterListDataListener); - } + TransmitterListModel txListModel = deviceModel.getTransmitterListModel(); + if( txListModel != null ) txListModel.addListDataListener(cablePane.midiConnecterListDataListener); + // // レシーバリストモデルが変化したときにMIDIケーブルを再描画 - if( deviceModel.rxSupported() ) { - deviceModel.getReceiverListModel().addListDataListener(cablePane.midiConnecterListDataListener); - } + ReceiverListModel rxListModel = deviceModel.getReceiverListModel(); + if( rxListModel != null ) rxListModel.addListDataListener(cablePane.midiConnecterListDataListener); + // // デバイスフレームが開閉したときの動作 frame.addInternalFrameListener(cablePane.midiDeviceFrameListener); frame.addInternalFrameListener(deviceTreeView.midiDeviceFrameListener); diff --git a/src/camidion/chordhelper/mididevice/ReceiverListModel.java b/src/camidion/chordhelper/mididevice/ReceiverListModel.java new file mode 100644 index 0000000..4af7c69 --- /dev/null +++ b/src/camidion/chordhelper/mididevice/ReceiverListModel.java @@ -0,0 +1,53 @@ +package camidion.chordhelper.mididevice; + +import java.util.List; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; +import javax.swing.AbstractListModel; + +/** + * {@link Receiver} のリストを表す {@link javax.swing.ListModel} + */ +public class ReceiverListModel extends AbstractListModel { + protected MidiDeviceModel deviceModel; + public ReceiverListModel(MidiDeviceModel deviceModel) { + this.deviceModel = deviceModel; + } + @Override + public Receiver getElementAt(int index) { + return deviceModel.getMidiDevice().getReceivers().get(index); + } + @Override + public int getSize() { + return deviceModel.getMidiDevice().getReceivers().size(); + } + public int indexOf(Object element) { + return deviceModel.getMidiDevice().getReceivers().indexOf(element); + } + /** + * {@link Receiver}を最大1個開きます。 + * @throws MidiUnavailableException リソースの制約のためにレシーバを使用できない場合にスローされる + */ + public void openSingleReceiver() throws MidiUnavailableException { + MidiDevice device = deviceModel.getMidiDevice(); + if( device.getReceivers().isEmpty() ) device.getReceiver(); + } + /** + * このリストモデルの{@link Receiver}に接続された他デバイスの{@link Transmitter}を全て閉じます。 + */ + public void closePeerTransmitters() { + List rxList = deviceModel.getMidiDevice().getReceivers(); + MidiDeviceModelList deviceModelList = deviceModel.getDeviceModelList(); + for( Receiver rx : rxList ) { + for( MidiDeviceModel m : deviceModelList ) { + if( m == deviceModel ) continue; + TransmitterListModel txListModel = m.getTransmitterListModel(); + if( txListModel == null ) continue; + txListModel.closePeerTransmitterOf(rx); + } + } + } +} diff --git a/src/camidion/chordhelper/mididevice/MidiReceiverListView.java b/src/camidion/chordhelper/mididevice/ReceiverListView.java similarity index 92% rename from src/camidion/chordhelper/mididevice/MidiReceiverListView.java rename to src/camidion/chordhelper/mididevice/ReceiverListView.java index 6f4403c..780fb33 100644 --- a/src/camidion/chordhelper/mididevice/MidiReceiverListView.java +++ b/src/camidion/chordhelper/mididevice/ReceiverListView.java @@ -23,9 +23,9 @@ import javax.swing.ListSelectionModel; /** * MIDIレシーバ({@link Receiver})のリストビューです。 * レシーバをこのビューからドラッグし、 - * {@link MidiTransmitterListView} のトランスミッタにドロップして接続できます。 + * {@link TransmitterListView} のトランスミッタにドロップして接続できます。 */ -public class MidiReceiverListView extends JList { +public class ReceiverListView extends JList { /** * レシーバを描画するクラス */ @@ -62,15 +62,15 @@ public class MidiReceiverListView extends JList { * @return 表示される{@link Receiver}のリストを提供するデータモデル */ @Override - public MidiDeviceModel.ReceiverListModel getModel() { - return (MidiDeviceModel.ReceiverListModel) super.getModel(); + public ReceiverListModel getModel() { + return (ReceiverListModel) super.getModel(); } /** * 仮想MIDI端子リストビューを生成します。 * @param model このビューから参照されるデータモデル * @param cablePane MIDIケーブル描画面 */ - public MidiReceiverListView(MidiDeviceModel.ReceiverListModel model, final MidiCablePane cablePane) { + public ReceiverListView(ReceiverListModel model, final MidiCablePane cablePane) { super(model); setCellRenderer(new CellRenderer()); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); diff --git a/src/camidion/chordhelper/mididevice/TransmitterListModel.java b/src/camidion/chordhelper/mididevice/TransmitterListModel.java new file mode 100644 index 0000000..37dbecb --- /dev/null +++ b/src/camidion/chordhelper/mididevice/TransmitterListModel.java @@ -0,0 +1,141 @@ +package camidion.chordhelper.mididevice; + +import java.util.List; +import java.util.Vector; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Transmitter; +import javax.swing.AbstractListModel; + +/** + * {@link Transmitter} のリストを表す {@link javax.swing.ListModel} + */ +public class TransmitterListModel extends AbstractListModel { + protected Transmitter dummyTransmitter = new DummyTransmitter(); + protected MidiDeviceModel deviceModel; + public TransmitterListModel(MidiDeviceModel deviceModel) { + this.deviceModel = deviceModel; + } + @Override + public Transmitter getElementAt(int index) { + List txList = deviceModel.getMidiDevice().getTransmitters(); + int length = txList.size(); + if( index == length ) return dummyTransmitter; + if( index > length || index < 0 ) return null; + return txList.get(index); + } + @Override + public int getSize() { + return deviceModel.getMidiDevice().getTransmitters().size() + 1; + } + public int indexOf(Object element) { + List txList = deviceModel.getMidiDevice().getTransmitters(); + return dummyTransmitter.equals(element) ? txList.size() : txList.indexOf(element); + } + /** + * レシーバに未接続の最初の{@link Transmitter}を返します。 + * ない場合は{@link MidiDevice#getTransmitter}で新たに取得して返します。 + * + * @return 未接続の{@link Transmitter} + * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる + */ + public Transmitter getUnconnectedTransmitter() throws MidiUnavailableException { + MidiDevice device = deviceModel.getMidiDevice(); + List txList = device.getTransmitters(); + for( Transmitter tx : txList ) if( tx.getReceiver() == null ) return tx; + Transmitter tx; + tx = device.getTransmitter(); + fireIntervalAdded(this, 0, getSize()); + return tx; + } + /** + * このリストモデルの{@link #getUnconnectedTransmitter()}が返した{@link Transmitter}を、 + * 相手のMIDIデバイスが持つ最初の{@link Receiver}に接続します。 + * + * @param anotherDeviceModel 接続相手のMIDIデバイス + * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる + */ + public void connectToFirstReceiverOfDevice(MidiDeviceModel anotherDeviceModel) throws MidiUnavailableException { + List rxList = anotherDeviceModel.getMidiDevice().getReceivers(); + if( ! rxList.isEmpty() ) + deviceModel.getTransmitterListModel().getUnconnectedTransmitter().setReceiver(rxList.get(0)); + } + /** + * 指定の{@link Transmitter}がリストにあれば、それを閉じます。 + * 閉じるとリストから自動的に削除されるので、表示の更新も行います。 + * + * @param tx このリストモデルで開いている{@link Transmitter} + */ + public void close(Transmitter tx) { + if( ! deviceModel.getMidiDevice().getTransmitters().contains(tx) ) return; + tx.close(); + fireIntervalRemoved(this, 0, getSize()); + } + /** + * このリストモデルにある{@link Transmitter}のうち、 + * 引数で指定された{@link Receiver}へデータを送信しているものを全て閉じます。 + * 閉じるとリストから自動的に削除されるので、表示の更新も行います。 + */ + public void closePeerTransmitterOf(Receiver rx) { + List closingTxList = new Vector(); + List txList = deviceModel.getMidiDevice().getTransmitters(); + for( Transmitter tx : txList ) if( tx.getReceiver() == rx ) closingTxList.add(tx); + if( closingTxList.isEmpty() ) return; + int length = getSize(); + for( Transmitter tx : closingTxList ) tx.close(); + fireIntervalRemoved(this, 0, length); + } + /** + * マイクロ秒位置をリセットします。 + *

マイクロ秒位置はMIDIデバイスを開いてからの時間で表されます。 + * このメソッドではMIDIデバイスをいったん閉じて再び開くことによって + * 時間位置をリセットします。 + * 接続相手のデバイスがあった場合、元通りに接続を復元します。 + *

+ *

MIDIデバイスからリアルタイムレコーディングを開始するときは、 + * 必ずマイクロ秒位置をリセットする必要があります。 + * (リセットされていないマイクロ秒位置がそのままシーケンサに記録されると、 + * 大幅に後ろのほうにずれて記録されてしまいます) + *

+ */ + public void resetMicrosecondPosition() { + MidiDevice device = deviceModel.getMidiDevice(); + // + // シーケンサはこのメソッドでのリセット対象外 + if( device instanceof Sequencer ) return; + // + // デバイスを閉じる前に接続状態を把握 + List peerRxList = new Vector(); + List txList = device.getTransmitters(); + for( Transmitter tx : txList ) { + Receiver rx = tx.getReceiver(); + if( rx != null ) peerRxList.add(rx); + } + List myRxList = device.getReceivers(); + List peerTxList = new Vector(); + MidiDeviceModelList deviceModelList = deviceModel.getDeviceModelList(); + for( Receiver rx : myRxList ) { + for( MidiDeviceModel m : deviceModelList ) { + if( m == deviceModel ) continue; + List peerSourceTxList = m.getMidiDevice().getTransmitters(); + for( Transmitter tx : peerSourceTxList ) if( tx.getReceiver() == rx ) peerTxList.add(tx); + } + } + // いったん閉じて開く(ここでマイクロ秒位置がリセットされる) + // その後、元通りに接続し直す + device.close(); + try { + device.open(); + for( Receiver peerRx : peerRxList ) getUnconnectedTransmitter().setReceiver(peerRx); + if( ! myRxList.isEmpty() ) { + Receiver rx = myRxList.get(0); + for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rx); + } + } catch( MidiUnavailableException e ) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/camidion/chordhelper/mididevice/MidiTransmitterListView.java b/src/camidion/chordhelper/mididevice/TransmitterListView.java similarity index 89% rename from src/camidion/chordhelper/mididevice/MidiTransmitterListView.java rename to src/camidion/chordhelper/mididevice/TransmitterListView.java index 9f6aef8..6c15c91 100644 --- a/src/camidion/chordhelper/mididevice/MidiTransmitterListView.java +++ b/src/camidion/chordhelper/mididevice/TransmitterListView.java @@ -22,14 +22,12 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; -import camidion.chordhelper.mididevice.MidiDeviceModel.NewTransmitter; - /** * MIDIトランスミッタ({@link Transmitter})のリストビューです。 * トランスミッタをこのビューからドラッグし、 - * {@link MidiReceiverListView} のレシーバにドロップして接続できます。 + * {@link ReceiverListView} のレシーバにドロップして接続できます。 */ -public class MidiTransmitterListView extends JList { +public class TransmitterListView extends JList { /** * トランスミッタを描画するクラス */ @@ -48,7 +46,7 @@ public class MidiTransmitterListView extends JList { setForeground(list.getForeground()); } setIcon(MidiDeviceDialog.MIDI_CONNECTER_ICON); - if( value instanceof MidiDeviceModel.NewTransmitter ) { + if( value instanceof DummyTransmitter ) { setToolTipText("未接続の送信端子(Tx):ドラッグ&ドロップしてRxに接続できます。"); } else { setToolTipText("接続済の送信端子(Tx):ドラッグ&ドロップして接続先Rxを変更、または切断できます。"); @@ -70,15 +68,15 @@ public class MidiTransmitterListView extends JList { * @return 表示される{@link Transmitter}のリストを提供するデータモデル */ @Override - public MidiDeviceModel.TransmitterListModel getModel() { - return (MidiDeviceModel.TransmitterListModel) super.getModel(); + public TransmitterListModel getModel() { + return (TransmitterListModel) super.getModel(); } /** * 仮想MIDI端子リストビューを生成します。 * @param model このビューから参照されるデータモデル * @param cablePane MIDIケーブル描画面 */ - public MidiTransmitterListView(MidiDeviceModel.TransmitterListModel model, final MidiCablePane cablePane) { + public TransmitterListView(TransmitterListModel model, final MidiCablePane cablePane) { super(model); setCellRenderer(new CellRenderer()); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -99,7 +97,7 @@ public class MidiTransmitterListView extends JList { if( ! event.getDropSuccess() ) { // 所定の場所にドロップされなかったトランスミッタを閉じる getModel().close(droppedTx); - } else if( droppedTx instanceof MidiDeviceModel.NewTransmitter ) { + } else if( droppedTx instanceof DummyTransmitter ) { // ドロップされたダミートランスミッタに接続されたレシーバを // 新しい本物のトランスミッタに付け替える try { @@ -143,7 +141,7 @@ public class MidiTransmitterListView extends JList { Object sourceRx = t.getTransferData(DraggingTransceiver.receiverFlavor); if( sourceRx != null ) { Transmitter tx = getModel().getElementAt(locationToIndex(event.getLocation())); - if( tx instanceof NewTransmitter ) tx = getModel().getUnconnectedTransmitter(); + if( tx instanceof DummyTransmitter ) tx = getModel().getUnconnectedTransmitter(); tx.setReceiver((Receiver)sourceRx); event.dropComplete(true); return;