OSDN Git Service

9795671fbd0e488bd0b7e533913ce5bcda9805b6
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / mididevice / MidiDeviceModelList.java
1 package camidion.chordhelper.mididevice;
2
3 import java.util.List;
4 import java.util.Vector;
5
6 import javax.sound.midi.MidiDevice;
7 import javax.sound.midi.MidiSystem;
8 import javax.sound.midi.MidiUnavailableException;
9 import javax.sound.midi.Sequencer;
10 import javax.sound.midi.Synthesizer;
11
12 import camidion.chordhelper.ChordHelperApplet;
13 import camidion.chordhelper.midieditor.MidiSequenceEditor;
14
15 /**
16  * MIDIデバイスモデルリスト
17  */
18 public class MidiDeviceModelList extends Vector<MidiConnecterListModel> {
19         /**
20          * MIDIエディタ
21          */
22         public MidiSequenceEditor editorDialog;
23         /**
24          * MIDIエディタモデル
25          */
26         private MidiConnecterListModel editorDialogModel;
27         /**
28          * MIDIシンセサイザーモデル
29          */
30         private MidiConnecterListModel synthModel;
31         /**
32          * 最初のMIDI出力
33          */
34         private MidiConnecterListModel firstMidiOutModel;
35         /**
36          * MIDIデバイスモデルリストを生成します。
37          * @param guiVirtualDeviceList GUI仮想MIDIデバイスのリスト
38          */
39         public MidiDeviceModelList(List<VirtualMidiDevice> guiVirtualDeviceList) {
40                 MidiDevice.Info[] deviceInfos = MidiSystem.getMidiDeviceInfo();
41                 MidiConnecterListModel guiModels[] = new MidiConnecterListModel[guiVirtualDeviceList.size()];
42                 MidiConnecterListModel firstMidiInModel = null;
43                 //
44                 // GUI仮想MIDIデバイスリストの構築
45                 for( int i=0; i<guiVirtualDeviceList.size(); i++ )
46                         guiModels[i] = addMidiDevice(guiVirtualDeviceList.get(i));
47                 //
48                 // シーケンサの取得
49                 Sequencer sequencer;
50                 try {
51                         sequencer = MidiSystem.getSequencer(false);
52                         sequencerModel = (MidiSequencerModel)addMidiDevice(sequencer);
53                 } catch( MidiUnavailableException e ) {
54                         System.out.println(ChordHelperApplet.VersionInfo.NAME +" : MIDI sequencer unavailable");
55                         e.printStackTrace();
56                 }
57                 // MIDIエディタの生成
58                 editorDialog = new MidiSequenceEditor(sequencerModel);
59                 editorDialogModel = addMidiDevice(editorDialog.getVirtualMidiDevice());
60                 for( MidiDevice.Info info : deviceInfos ) {
61                         // MIDIデバイスの取得
62                         MidiDevice device;
63                         try {
64                                 device = MidiSystem.getMidiDevice(info);
65                         } catch( MidiUnavailableException e ) {
66                                 e.printStackTrace(); continue;
67                         }
68                         // シーケンサの場合はすでに取得済みなのでスキップ
69                         if( device instanceof Sequencer ) continue;
70                         //
71                         // Java内蔵シンセサイザ
72                         if( device instanceof Synthesizer ) {
73                                 try {
74                                         synthModel = addMidiDevice(MidiSystem.getSynthesizer());
75                                 } catch( MidiUnavailableException e ) {
76                                         System.out.println(ChordHelperApplet.VersionInfo.NAME +
77                                                         " : Java internal MIDI synthesizer unavailable");
78                                         e.printStackTrace();
79                                 }
80                                 continue;
81                         }
82                         // MIDIデバイスを追加し、最初のエントリを覚えておく
83                         MidiConnecterListModel m = addMidiDevice(device);
84                         if( m.rxSupported() && firstMidiOutModel == null ) firstMidiOutModel = m;
85                         if( m.txSupported() && firstMidiInModel == null ) firstMidiInModel = m;
86                 }
87                 // MIDIデバイスを開く。
88                 //   NOTE: 必ず MIDI OUT Rx デバイスを先に開くこと。
89                 //
90                 //   そうすれば、後から開いた MIDI IN Tx デバイスからの
91                 //   タイムスタンプのほうが「若く」なる。これにより、
92                 //   先に開かれ「少し歳を食った」Rx デバイスは
93                 //   「信号が遅れてやってきた」と認識するので、
94                 //   遅れを取り戻そうとして即座に音を出してくれる。
95                 //
96                 //   開く順序が逆になると「進みすぎるから遅らせよう」として
97                 //   無用なレイテンシーが発生する原因になる。
98                 try {
99                         MidiConnecterListModel openModels[] = {
100                                 synthModel,
101                                 firstMidiOutModel,
102                                 sequencerModel,
103                                 firstMidiInModel,
104                                 editorDialogModel,
105                         };
106                         for( MidiConnecterListModel m : openModels ) if( m != null ) m.openDevice();
107                         for( MidiConnecterListModel m : guiModels ) m.openDevice();
108                 } catch( MidiUnavailableException ex ) {
109                         ex.printStackTrace();
110                 }
111                 // 初期接続
112                 //
113                 for( MidiConnecterListModel mtx : guiModels ) {
114                         for( MidiConnecterListModel mrx : guiModels ) mtx.connectToReceiverOf(mrx);
115                         mtx.connectToReceiverOf(sequencerModel);
116                         mtx.connectToReceiverOf(synthModel);
117                         mtx.connectToReceiverOf(firstMidiOutModel);
118                 }
119                 if( firstMidiInModel != null ) {
120                         for( MidiConnecterListModel m : guiModels ) firstMidiInModel.connectToReceiverOf(m);
121                         firstMidiInModel.connectToReceiverOf(sequencerModel);
122                         firstMidiInModel.connectToReceiverOf(synthModel);
123                         firstMidiInModel.connectToReceiverOf(firstMidiOutModel);
124                 }
125                 if( sequencerModel != null ) {
126                         for( MidiConnecterListModel m : guiModels ) sequencerModel.connectToReceiverOf(m);
127                         sequencerModel.connectToReceiverOf(synthModel);
128                         sequencerModel.connectToReceiverOf(firstMidiOutModel);
129                 }
130                 if( editorDialogModel != null ) {
131                         editorDialogModel.connectToReceiverOf(synthModel);
132                         editorDialogModel.connectToReceiverOf(firstMidiOutModel);
133                 }
134         }
135         /**
136          * このデバイスモデルリストに登録されたMIDIシーケンサーモデルを返します。
137          * @return MIDIシーケンサーモデル
138          */
139         public MidiSequencerModel getSequencerModel() { return sequencerModel; }
140         private MidiSequencerModel sequencerModel;
141         /**
142          * 指定のMIDIデバイスからMIDIデバイスモデルを生成して追加します。
143          * @param device MIDIデバイス
144          * @return 生成されたMIDIデバイスモデル
145          */
146         private MidiConnecterListModel addMidiDevice(MidiDevice device) {
147                 MidiConnecterListModel m;
148                 if( device instanceof Sequencer )
149                         m = new MidiSequencerModel(this,(Sequencer)device,this);
150                 else
151                         m = new MidiConnecterListModel(device,this);
152                 addElement(m);
153                 return m;
154         }
155 }