OSDN Git Service

MIDIイベントテーブル、MIDIシーケンス自動生成時の
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / ChordTextField.java
1 package camidion.chordhelper;
2
3 import java.io.UnsupportedEncodingException;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import javax.sound.midi.MetaEventListener;
8 import javax.sound.midi.MetaMessage;
9 import javax.swing.JTextField;
10 import javax.swing.SwingUtilities;
11
12 import camidion.chordhelper.mididevice.MidiSequencerModel;
13 import camidion.chordhelper.midieditor.SequenceTrackListTableModel;
14 import camidion.chordhelper.music.Chord;
15
16 public class ChordTextField extends JTextField implements MetaEventListener {
17         private MidiSequencerModel sequencerModel;
18         public ChordTextField(MidiSequencerModel sequencerModel) {
19                 super(80);
20                 //
21                 // JTextField は、サイズ設定をしないとリサイズ時に縦に伸び過ぎてしまう。
22                 // 1行しか入力できないので、縦に伸びすぎるのはスペースがもったいない。
23                 // そこで、このような現象を防止するために、最大サイズを明示的に
24                 // 画面サイズと同じに設定する。
25                 //
26                 // To reduce resized height, set maximum size to screen size.
27                 //
28                 setMaximumSize(
29                         java.awt.Toolkit.getDefaultToolkit().getScreenSize()
30                 );
31                 this.sequencerModel = sequencerModel;
32                 sequencerModel.getSequencer().addMetaEventListener(this);
33         }
34         @Override
35         public void meta(MetaMessage msg) {
36                 int t = msg.getType();
37                 switch(t) {
38                 case 0x01: // Text(任意のテキスト:コメントなど)
39                 case 0x05: // Lyrics(歌詞)
40                 case 0x02: // Copyright(著作権表示)
41                 case 0x03: // Sequence Name / Track Name(曲名またはトラック名)
42                 case 0x06: // Marker
43                         byte[] d = msg.getData();
44                         if( ! SwingUtilities.isEventDispatchThread() ) {
45                                 // MIDIシーケンサの EDT から呼ばれた場合、
46                                 // 表示処理を Swing の EDT に振り直す。
47                                 SwingUtilities.invokeLater(new AddTextJob(t,d));
48                                 return;
49                         }
50                         addText(t,d);
51                         break;
52                 default:
53                         return;
54                 }
55         }
56         /**
57          * 歌詞を追加するジョブ
58          */
59         public class AddTextJob implements Runnable {
60                 private int type;
61                 private byte[] data;
62                 public AddTextJob(int type, byte[] data) {
63                         this.type = type;
64                         this.data = data;
65                 }
66                 @Override
67                 public void run() { addText(type, data); }
68         }
69         /**
70          * 前回のタイムスタンプ
71          */
72         private long lastArrivedTime = System.nanoTime();
73         /**
74          * スキップするテキスト
75          */
76         private Map<Integer,String> skippingTextMap = new HashMap<>();
77         /**
78          * テキストを追加し、カーソルを末尾に移動します。
79          * @param data テキストの元データ
80          */
81         private void addText(int type, byte[] data) {
82                 // 頻繁に来たかどうかだけとりあえずチェック
83                 long arrivedTime = System.nanoTime();
84                 boolean isSoon = (arrivedTime - lastArrivedTime < 1000000000L /* 1sec */);
85                 lastArrivedTime = arrivedTime;
86                 //
87                 // 文字コード確認用シーケンス
88                 SequenceTrackListTableModel m = sequencerModel.getSequenceTrackListTableModel();
89                 //
90                 // 追加するデータを適切な文字コードで文字列に変換
91                 String additionalText;
92                 if( m != null ) {
93                         additionalText = new String(data,m.charset);
94                 }
95                 else try {
96                         additionalText = new String(data,"JISAutoDetect");
97                 }
98                 catch( UnsupportedEncodingException e ) {
99                         additionalText = new String(data);
100                 }
101                 additionalText = additionalText.trim();
102                 String lastAdditionalText = skippingTextMap.remove(type);
103                 // 歌詞とテキストで同じもの同士がすぐに来た場合は追加しない
104                 if( ! (isSoon && additionalText.equals(lastAdditionalText)) ) {
105                         // テキストと歌詞が同じかどうかチェックするための比較対象を記録
106                         switch(type) {
107                         case 0x01: skippingTextMap.put(0x05,additionalText);
108                         case 0x05: skippingTextMap.put(0x01,additionalText);
109                         }
110                         // 既存の歌詞
111                         String currentText = getText();
112                         if(
113                                 currentText != null && ! currentText.isEmpty()
114                                 && (
115                                         isSoon ||
116                                         ! additionalText.isEmpty() && additionalText.length() <= 8
117                                 )
118                         ) {
119                                 // 既存歌詞がある場合、頻繁に来たか短い歌詞だったら追加
120                                 currentText += " " + additionalText;
121                         }
122                         else {
123                                 // それ以外の場合は上書き
124                                 currentText = additionalText;
125                         }
126                         setText(currentText);
127                 }
128                 // 入力カーソル(キャレット)をテキストの末尾へ
129                 setCaretPosition(getText().length());
130         }
131         /**
132          * 現在のコード
133          */
134         private Chord currentChord = null;
135         /**
136          * コードを追加します。
137          * @param chord コード
138          */
139         public void appendChord(Chord chord) {
140                 if( currentChord == null && chord == null )
141                         return;
142                 if( currentChord != null && chord != null && chord.equals(currentChord) )
143                         return;
144                 String delimiter = ""; // was "\n"
145                 setText( getText() + (chord == null ? delimiter : chord + " ") );
146                 currentChord = ( chord == null ? null : chord.clone() );
147         }
148 }