OSDN Git Service

eVocaloid対応歌詞の配列で添字上限チェックが抜けていたのを修正
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / midieditor / TempoSelecter.java
1 package camidion.chordhelper.midieditor;\r
2 \r
3 import java.awt.Component;\r
4 import java.awt.event.MouseEvent;\r
5 import java.awt.event.MouseListener;\r
6 \r
7 import javax.sound.midi.MetaEventListener;\r
8 import javax.sound.midi.MetaMessage;\r
9 import javax.swing.Box;\r
10 import javax.swing.BoxLayout;\r
11 import javax.swing.JLabel;\r
12 import javax.swing.JPanel;\r
13 import javax.swing.JSpinner;\r
14 import javax.swing.SpinnerNumberModel;\r
15 import javax.swing.SwingUtilities;\r
16 \r
17 import camidion.chordhelper.ButtonIcon;\r
18 import camidion.chordhelper.music.MIDISpec;\r
19 \r
20 /**\r
21  * テンポ選択(QPM: Quarter Per Minute)\r
22  */\r
23 public class TempoSelecter extends JPanel implements MouseListener, MetaEventListener {\r
24         static final int DEFAULT_QPM = 120;\r
25         protected SpinnerNumberModel tempoSpinnerModel =\r
26                 new SpinnerNumberModel(DEFAULT_QPM, 1, 999, 1);\r
27         private JLabel tempoLabel = new JLabel(\r
28                 "=", new ButtonIcon(ButtonIcon.QUARTER_NOTE_ICON), JLabel.CENTER\r
29         ) {{\r
30                 setVerticalAlignment(JLabel.CENTER);\r
31         }};\r
32         private JLabel tempoValueLabel = new JLabel(""+DEFAULT_QPM);\r
33         private JSpinner tempoSpinner = new JSpinner(tempoSpinnerModel);\r
34         public TempoSelecter() {\r
35                 String tooltip = "Tempo in quatrers per minute - テンポ(1分あたりの四分音符の数)";\r
36                 tempoSpinner.setToolTipText(tooltip);\r
37                 tempoValueLabel.setToolTipText(tooltip);\r
38                 setLayout(new BoxLayout(this,BoxLayout.X_AXIS));\r
39                 add(tempoLabel);\r
40                 add(Box.createHorizontalStrut(5));\r
41                 add(tempoSpinner);\r
42                 add(tempoValueLabel);\r
43                 setEditable(true);\r
44                 tempoLabel.addMouseListener(this);\r
45         }\r
46         private long prevBeatMicrosecondPosition = 0;\r
47         private class SetTempoRunnable implements Runnable {\r
48                 byte[] qpm;\r
49                 public SetTempoRunnable(byte[] qpm) { this.qpm = qpm; }\r
50                 @Override\r
51                 public void run() { setTempo(qpm);}\r
52         }\r
53         @Override\r
54         public void meta(MetaMessage msg) {\r
55                 switch(msg.getType()) {\r
56                 case 0x51: // Tempo (3 bytes) - テンポ\r
57                         if( ! SwingUtilities.isEventDispatchThread() ) {\r
58                                 SwingUtilities.invokeLater(new SetTempoRunnable(msg.getData()));\r
59                                 break;\r
60                         }\r
61                         setTempo(msg.getData());\r
62                         break;\r
63                 }\r
64         }\r
65         @Override\r
66         public void mousePressed(MouseEvent e) {\r
67                 Component obj = e.getComponent();\r
68                 if(obj == tempoLabel && isEditable()) {\r
69                         //\r
70                         // Adjust tempo by interval time between two clicks\r
71                         //\r
72                         long currentMicrosecond = System.nanoTime()/1000;\r
73                         // midi_ch_selecter.noteOn( 9, 37, 100 );\r
74                         long interval_us = currentMicrosecond - prevBeatMicrosecondPosition;\r
75                         prevBeatMicrosecondPosition = currentMicrosecond;\r
76                         if( interval_us < 2000000L /* Shorter than 2 sec only */ ) {\r
77                                 int tempo_in_bpm = (int)(240000000L / interval_us) >> 2; //  n/4拍子の場合のみを想定\r
78                         int old_tempo_in_bpm = getTempoInQpm();\r
79                         setTempo( ( tempo_in_bpm + old_tempo_in_bpm * 2 ) / 3 );\r
80                         }\r
81                 }\r
82         }\r
83         public void mouseReleased(MouseEvent e) { }\r
84         public void mouseEntered(MouseEvent e) { }\r
85         public void mouseExited(MouseEvent e) { }\r
86         public void mouseClicked(MouseEvent e) { }\r
87         private boolean editable;\r
88         /**\r
89          * 編集可能かどうかを返します。\r
90          * @return 編集可能ならtrue\r
91          */\r
92         public boolean isEditable() { return editable; }\r
93         /**\r
94          * 編集可能かどうかを設定します。\r
95          * @param editable 編集可能ならtrue\r
96          */\r
97         public void setEditable( boolean editable ) {\r
98                 this.editable = editable;\r
99                 tempoSpinner.setVisible( editable );\r
100                 tempoValueLabel.setVisible( !editable );\r
101                 if( !editable ) {\r
102                         // Copy spinner's value to label\r
103                         tempoValueLabel.setText(\r
104                                 ""+tempoSpinnerModel.getNumber().intValue()\r
105                         );\r
106                 }\r
107                 tempoLabel.setToolTipText(\r
108                         editable ?\r
109                         "Click rhythmically to adjust tempo - ここをクリックしてリズムをとるとテンポを合わせられます"\r
110                         : null\r
111                 );\r
112         }\r
113         /**\r
114          * テンポを返します。\r
115          * @return テンポ [BPM](QPM)\r
116          */\r
117         public int getTempoInQpm() {\r
118                 return tempoSpinnerModel.getNumber().intValue();\r
119         }\r
120         /**\r
121          * テンポをMIDIメタメッセージのバイト列として返します。\r
122          * @return MIDIメタメッセージのバイト列\r
123          */\r
124         public byte[] getTempoByteArray() {\r
125                 return MIDISpec.qpmTempoToByteArray(getTempoInQpm());\r
126         }\r
127         /**\r
128          * テンポを設定します。\r
129          * @param qpm BPM(QPM)の値\r
130          */\r
131         public void setTempo(int qpm) {\r
132                 tempoSpinnerModel.setValue(new Integer(qpm));\r
133                 tempoValueLabel.setText(""+qpm);\r
134         }\r
135         /**\r
136          * MIDIメタメッセージのバイト列からテンポを設定します。\r
137          * @param msgdata MIDIメタメッセージのバイト列(null を指定した場合はデフォルトに戻る)\r
138          */\r
139         public void setTempo(byte msgdata[]) {\r
140                 setTempo(msgdata==null ? DEFAULT_QPM: MIDISpec.byteArrayToQpmTempo(msgdata));\r
141         }\r
142 }