* Copyright (C) 2004-2013 @きよし - Akiyoshi Kamide\r
* http://www.yk.rim.or.jp/~kamide/music/chordhelper/\r
*/\r
-public class ChordHelperApplet extends JApplet implements MetaEventListener {\r
+public class ChordHelperApplet extends JApplet {\r
/////////////////////////////////////////////////////////////////////\r
//\r
// JavaScript などからの呼び出しインターフェース\r
*/\r
public static class VersionInfo {\r
public static final String NAME = "MIDI Chord Helper";\r
- public static final String VERSION = "Ver.20131113.1";\r
+ public static final String VERSION = "Ver.20131114.1";\r
public static final String COPYRIGHT = "Copyright (C) 2004-2013";\r
public static final String AUTHER = "@きよし - Akiyoshi Kamide";\r
public static final String URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";\r
//\r
// MIDI parts\r
//\r
- deviceModelList.sequencerModel.getSequencer().addMetaEventListener(this);\r
+ deviceModelList.sequencerModel.getSequencer().addMetaEventListener(\r
+ new MetaEventListener() {\r
+ @Override\r
+ public void meta(MetaMessage msg) {\r
+ switch(msg.getType()) {\r
+ case 0x01: // Text(任意のテキスト:コメントなど)\r
+ case 0x02: // Copyright(著作権表示)\r
+ case 0x05: // Lyrics(歌詞)\r
+ case 0x06: // Marker\r
+ case 0x03: // Sequence Name / Track Name(曲名またはトラック名)\r
+ lyricDisplay.addLyric(msg.getData());\r
+ break;\r
+ case 0x51: // Tempo (3 bytes) - テンポ\r
+ tempoSelecter.setTempo(msg.getData());\r
+ break;\r
+ case 0x58: // Time signature (4 bytes) - 拍子\r
+ timesigSelecter.setValue(msg.getData());\r
+ break;\r
+ case 0x59: // Key signature (2 bytes) : 調号\r
+ Music.Key key = new Music.Key(msg.getData());\r
+ keysigLabel.setKeySignature(key);\r
+ chordMatrix.setKeySignature(key);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ );\r
deviceModelList.sequencerModel.addChangeListener(\r
new ChangeListener() {\r
+ @Override\r
public void stateChanged(ChangeEvent e) {\r
MidiSequenceTableModel sequenceTableModel = deviceModelList.sequencerModel.getSequenceTableModel();\r
- int i = editorDialog.sequenceListTableModel.getLoadedIndex();\r
+ int loadedSequenceIndex = editorDialog.sequenceListTableModel.getLoadedIndex();\r
songTitleLabel.setText(\r
"<html>"+(\r
- i < 0 ? "[No MIDI file loaded]" :\r
- "MIDI file " + i + ": " + (\r
- sequenceTableModel == null ||\r
- sequenceTableModel.toString() == null ||\r
- sequenceTableModel.toString().isEmpty() ?\r
+ loadedSequenceIndex < 0 ? "[No MIDI file loaded]" :\r
+ "MIDI file " + loadedSequenceIndex + ": " + (\r
+ sequenceTableModel == null ||\r
+ sequenceTableModel.toString() == null ||\r
+ sequenceTableModel.toString().isEmpty() ?\r
"[Untitled]" :\r
"<font color=maroon>"+sequenceTableModel+"</font>"\r
)\r
)+"</html>"\r
);\r
chordMatrix.setPlaying(deviceModelList.sequencerModel.isRunning());\r
- long currentTickPosition = deviceModelList.sequencerModel.getSequencer().getTickPosition();\r
+ long tickPos = deviceModelList.sequencerModel.getSequencer().getTickPosition();\r
SequenceTickIndex tickIndex = null;\r
if( sequenceTableModel != null ) {\r
tickIndex = sequenceTableModel.getSequenceTickIndex();\r
- tickIndex.tickToMeasure(currentTickPosition);\r
- chordMatrix.setBeat(\r
- (byte)(tickIndex.lastBeat), tickIndex.timesigUpper\r
- );\r
+ tickIndex.tickToMeasure(tickPos);\r
+ chordMatrix.setBeat(tickIndex);\r
if(\r
deviceModelList.sequencerModel.getValueIsAdjusting()\r
|| (\r
! deviceModelList.sequencerModel.getSequencer().isRecording()\r
)\r
) {\r
- MetaMessage msg = tickIndex.lastMetaMessageAt(\r
- SequenceTickIndex.TIME_SIGNATURE, currentTickPosition\r
- );\r
- if( msg == null ) timesigSelecter.clear(); else meta(msg);\r
- msg = tickIndex.lastMetaMessageAt(\r
- SequenceTickIndex.TEMPO, currentTickPosition\r
- );\r
- if( msg == null ) tempoSelecter.clear(); else meta(msg);\r
- msg = tickIndex.lastMetaMessageAt(\r
- SequenceTickIndex.KEY_SIGNATURE, currentTickPosition\r
- );\r
- if( msg == null ) keysigLabel.clear(); else meta(msg);\r
+ MetaMessage msg;\r
+ msg = tickIndex.lastMetaMessageAt(SequenceTickIndex.TIME_SIGNATURE, tickPos);\r
+ timesigSelecter.setValue(msg==null ? null : msg.getData());\r
+ msg = tickIndex.lastMetaMessageAt(SequenceTickIndex.TEMPO, tickPos);\r
+ tempoSelecter.setTempo(msg==null ? null : msg.getData());\r
+ msg = tickIndex.lastMetaMessageAt(SequenceTickIndex.KEY_SIGNATURE, tickPos);\r
+ if( msg == null )\r
+ keysigLabel.clear();\r
+ else {\r
+ Music.Key key = new Music.Key(msg.getData());\r
+ keysigLabel.setKeySignature(key);\r
+ chordMatrix.setKeySignature(key);\r
+ }\r
}\r
}\r
}\r
deviceModelList.sequencerModel.stop(); // MIDI再生を強制終了\r
System.gc();\r
}\r
- /////////////////////////////////////////\r
- //\r
- // MetaEventListener\r
- //\r
- public void meta(MetaMessage msg) {\r
- int msgtype = msg.getType();\r
- switch( msgtype ) {\r
-\r
- case 0x01: // Text(任意のテキスト:コメントなど)\r
- case 0x02: // Copyright(著作権表示)\r
- case 0x05: // Lyrics(歌詞)\r
- case 0x06: // Marker\r
- case 0x03: // Sequence Name / Track Name(曲名またはトラック名)\r
- lyricDisplay.addLyric(msg.getData());\r
- break;\r
-\r
- case 0x51: // Tempo (3 bytes) - テンポ\r
- tempoSelecter.setTempo(msg.getData());\r
- break;\r
- case 0x58: // Time signature (4 bytes) - 拍子\r
- timesigSelecter.setValue(msg.getData());\r
- break;\r
- case 0x59: // Key signature (2 bytes) : 調号\r
- keysigLabel.setKeySignature( new Music.Key(msg.getData()) );\r
- chordMatrix.setKeySignature( new Music.Key(msg.getData()) );\r
- break;\r
-\r
- }\r
- }\r
private void innerSetDarkMode(boolean is_dark) {\r
Color col = is_dark ? Color.black : null;\r
// Color fgcol = is_dark ? Color.pink : null;\r
\r
private byte currentBeat = 0;\r
private byte timesigUpper = 4;\r
- public void setBeat(byte beat, byte tsu) {\r
+ public void setBeat(SequenceTickIndex sequenceTickIndex) {\r
+ byte beat = (byte)(sequenceTickIndex.lastBeat);\r
+ byte tsu = sequenceTickIndex.timesigUpper;\r
if( currentBeat == beat && timesigUpper == tsu )\r
return;\r
timesigUpper = tsu;\r
* このモデルのMIDIシーケンサが開始されているか調べます。\r
* @return 開始されていたらtrue\r
*/\r
- public boolean isRunning() { return timeRangeUpdater.isRunning(); }\r
+ public boolean isRunning() {\r
+ // return timeRangeUpdater.isRunning();\r
+ return getSequencer().isRunning();\r
+ }\r
/**\r
* このモデルのMIDIシーケンサを開始します。\r
*/\r
listenerList.remove(ChangeListener.class, listener);\r
}\r
/**\r
- * 状態が変わったことをリスナーに通知します。\r
+ * 状態の変化をリスナーに通知します。\r
+ * <p>登録中のすべての {@link ChangeListener} について\r
+ * {@link ChangeListener#stateChanged(ChangeEvent)}\r
+ * を呼び出すことによって通知します。\r
+ * </p>\r
*/\r
public void fireStateChanged() {\r
Object[] listeners = listenerList.getListenerList();\r
}\r
else if( status == 0xFF ) {\r
switch( data1 ) { // Data type -> Selecter\r
- case 0x51: dataText.setValue( tempoSelecter.getTempoByteArray() ); break;\r
- case 0x58: dataText.setValue( timesigSelecter.getByteArray() ); break;\r
- case 0x59: dataText.setValue( keysigSelecter.getKey().getBytes() ); break;\r
+ case 0x51: dataText.setValue(tempoSelecter.getTempoByteArray()); break;\r
+ case 0x58: dataText.setValue(timesigSelecter.getByteArray()); break;\r
+ case 0x59: dataText.setValue(keysigSelecter.getKey().getBytes()); break;\r
default: break;\r
}\r
}\r
*/\r
class TempoSelecter extends JPanel implements MouseListener {\r
static final int DEFAULT_QPM = 120;\r
- JSpinner tempo_spinner;\r
+ JSpinner tempoSpinner;\r
SpinnerNumberModel tempoSpinnerModel;\r
- JLabel tempo_label, tempo_value_label;\r
+ JLabel tempoLabel, tempoValueLabel;\r
private boolean editable;\r
- private long prev_beat_us_pos = 0;\r
+ private long prevBeatMicrosecondPosition = 0;\r
\r
public TempoSelecter() {\r
- String tool_tip = "Tempo in quatrers per minute - テンポ(1分あたりの四分音符の数)";\r
- tempo_label = new JLabel(\r
+ String tooltip = "Tempo in quatrers per minute - テンポ(1分あたりの四分音符の数)";\r
+ tempoLabel = new JLabel(\r
"=",\r
- new ButtonIcon( ButtonIcon.QUARTER_NOTE_ICON ),\r
+ new ButtonIcon(ButtonIcon.QUARTER_NOTE_ICON),\r
JLabel.CENTER\r
);\r
- tempo_label.setVerticalAlignment( JLabel.CENTER );\r
+ tempoLabel.setVerticalAlignment(JLabel.CENTER);\r
tempoSpinnerModel = new SpinnerNumberModel(DEFAULT_QPM, 1, 999, 1);\r
- tempo_spinner = new JSpinner( tempoSpinnerModel );\r
- tempo_spinner.setToolTipText( tool_tip );\r
- tempo_value_label = new JLabel( ""+DEFAULT_QPM );\r
- tempo_value_label.setToolTipText( tool_tip );\r
- setLayout( new BoxLayout(this,BoxLayout.X_AXIS) );\r
- add( tempo_label );\r
+ tempoSpinner = new JSpinner(tempoSpinnerModel);\r
+ tempoSpinner.setToolTipText(tooltip);\r
+ tempoValueLabel = new JLabel(""+DEFAULT_QPM);\r
+ tempoValueLabel.setToolTipText(tooltip);\r
+ setLayout(new BoxLayout(this,BoxLayout.X_AXIS));\r
+ add( tempoLabel );\r
add( Box.createHorizontalStrut(5) );\r
- add( tempo_spinner );\r
- add( tempo_value_label );\r
+ add( tempoSpinner );\r
+ add( tempoValueLabel );\r
setEditable(true);\r
- tempo_label.addMouseListener(this);\r
+ tempoLabel.addMouseListener(this);\r
}\r
+ @Override\r
public void mousePressed(MouseEvent e) {\r
Component obj = e.getComponent();\r
- if( obj == tempo_label && isEditable() ) {\r
+ if(obj == tempoLabel && isEditable()) {\r
//\r
// Adjust tempo by interval time between two clicks\r
//\r
- long current_us = System.nanoTime()/1000;\r
+ long currentMicrosecond = System.nanoTime()/1000;\r
// midi_ch_selecter.noteOn( 9, 37, 100 );\r
- long interval_us = current_us - prev_beat_us_pos;\r
- prev_beat_us_pos = current_us;\r
+ long interval_us = currentMicrosecond - prevBeatMicrosecondPosition;\r
+ prevBeatMicrosecondPosition = currentMicrosecond;\r
if( interval_us < 2000000L /* Shorter than 2 sec only */ ) {\r
int tempo_in_bpm = (int)(240000000L / interval_us) >> 2; // n/4拍子の場合のみを想定\r
int old_tempo_in_bpm = getTempoInQpm();\r
public void mouseEntered(MouseEvent e) { }\r
public void mouseExited(MouseEvent e) { }\r
public void mouseClicked(MouseEvent e) { }\r
+ /**\r
+ * 編集可能かどうかを返します。\r
+ * @return 編集可能ならtrue\r
+ */\r
public boolean isEditable() { return editable; }\r
+ /**\r
+ * 編集可能かどうかを設定します。\r
+ * @param editable 編集可能ならtrue\r
+ */\r
public void setEditable( boolean editable ) {\r
this.editable = editable;\r
- tempo_spinner.setVisible( editable );\r
- tempo_value_label.setVisible( !editable );\r
+ tempoSpinner.setVisible( editable );\r
+ tempoValueLabel.setVisible( !editable );\r
if( !editable ) {\r
// Copy spinner's value to label\r
- tempo_value_label.setText(\r
+ tempoValueLabel.setText(\r
""+tempoSpinnerModel.getNumber().intValue()\r
);\r
}\r
- tempo_label.setToolTipText(\r
+ tempoLabel.setToolTipText(\r
editable ?\r
"Click rhythmically to adjust tempo - ここをクリックしてリズムをとるとテンポを合わせられます"\r
: null\r
);\r
}\r
+ /**\r
+ * テンポを返します。\r
+ * @return テンポ [BPM](QPM)\r
+ */\r
public int getTempoInQpm() {\r
return tempoSpinnerModel.getNumber().intValue();\r
}\r
+ /**\r
+ * テンポをMIDIメタメッセージのバイト列として返します。\r
+ * @return MIDIメタメッセージのバイト列\r
+ */\r
public byte[] getTempoByteArray() {\r
- return MIDISpec.qpmTempoToByteArray( getTempoInQpm() );\r
+ return MIDISpec.qpmTempoToByteArray(getTempoInQpm());\r
}\r
- public void setTempo( int qpm ) {\r
+ /**\r
+ * テンポを設定します。\r
+ * @param qpm BPM(QPM)の値\r
+ */\r
+ public void setTempo(int qpm) {\r
tempoSpinnerModel.setValue(new Integer(qpm));\r
- tempo_value_label.setText(""+qpm);\r
+ tempoValueLabel.setText(""+qpm);\r
}\r
- public void setTempo( byte msgdata[] ) {\r
- setTempo( MIDISpec.byteArrayToQpmTempo( msgdata ) );\r
+ /**\r
+ * MIDIメタメッセージのバイト列からテンポを設定します。\r
+ * @param msgdata MIDIメタメッセージのバイト列(null を指定した場合はデフォルトに戻る)\r
+ */\r
+ public void setTempo(byte msgdata[]) {\r
+ setTempo(msgdata==null ? DEFAULT_QPM: MIDISpec.byteArrayToQpmTempo(msgdata));\r
}\r
- public void clear() { setTempo( DEFAULT_QPM ); }\r
}\r
\r
/**\r
data[3] = 8;\r
return data;\r
}\r
- public void setValue( byte upper, byte lower_index ) {\r
+ public void setValue(byte upper, byte lowerIndex) {\r
upperTimesigSpinnerModel.setValue( upper );\r
- lowerTimesigCombobox.setSelectedIndex( lower_index );\r
- timesigValueLabel.setTimeSignature( upper, lower_index );\r
+ lowerTimesigCombobox.setSelectedIndex( lowerIndex );\r
+ timesigValueLabel.setTimeSignature( upper, lowerIndex );\r
}\r
- public void setValue( byte[] data ) {\r
- setValue( data[0], data[1] );\r
+ public void setValue(byte[] data) {\r
+ if(data == null)\r
+ clear();\r
+ else\r
+ setValue(data[0], data[1]);\r
}\r
public boolean isEditable() { return editable; }\r
public void setEditable( boolean editable ) {\r
}\r
public Sequence getMidiSequence() {\r
Music.FirstTrackSpec first_track_spec = new Music.FirstTrackSpec(\r
- seq_name_text.getText(),\r
- tempo_selecter.getTempoByteArray(),\r
- timesig_selecter.getByteArray()\r
- );\r
+ seq_name_text.getText(),\r
+ tempo_selecter.getTempoByteArray(),\r
+ timesig_selecter.getByteArray()\r
+ );\r
return getChordProgression().toMidiSequence(\r
- ppq_combo_box.getPPQ(),\r
- measure_selecter.getStartMeasurePosition(),\r
- measure_selecter.getEndMeasurePosition(),\r
- first_track_spec,\r
- track_spec_panel.getTrackSpecs()\r
- );\r
+ ppq_combo_box.getPPQ(),\r
+ measure_selecter.getStartMeasurePosition(),\r
+ measure_selecter.getEndMeasurePosition(),\r
+ first_track_spec,\r
+ track_spec_panel.getTrackSpecs()\r
+ );\r
}\r
- public void setChordProgression( Music.ChordProgression cp ) {\r
- chord_text.setText( cp.toString() );\r
+ public void setChordProgression(Music.ChordProgression cp) {\r
+ chord_text.setText(cp.toString());\r
}\r
- public void setRandomChordProgression( int measure_length ) {\r
+ public void setRandomChordProgression(int measureLength) {\r
//\r
// テンポ・拍子・コード進行をランダムに設定\r
//\r
int timesig_upper = 4;\r
int timesig_lower_index = 2;\r
switch( (int)(Math.random() * 10) ) {\r
- case 0: timesig_upper = 3; break; // 3/4\r
+ case 0: timesig_upper = 3; break; // 3/4\r
}\r
- timesig_selecter.setValue(\r
- (byte)timesig_upper,\r
- (byte)timesig_lower_index\r
- );\r
- setChordProgression(\r
- new Music.ChordProgression( measure_length, timesig_upper )\r
- );\r
+ timesig_selecter.setValue((byte)timesig_upper, (byte)timesig_lower_index);\r
+ setChordProgression(new Music.ChordProgression(measureLength, timesig_upper));\r
}\r
public void transpose(int chromatic_offset) {\r
Music.ChordProgression cp = getChordProgression();\r
//\r
// 音色(プログラム)設定\r
pg_family_selecter = new MidiProgramFamilySelecter(\r
- pg_selecter = new MidiProgramSelecter()\r
- );\r
+ pg_selecter = new MidiProgramSelecter()\r
+ );\r
pg_selecter.setFamilySelecter(\r
- pg_family_selecter\r
- );\r
+ pg_family_selecter\r
+ );\r
// 音域指定\r
//\r
keyboard_panel = new PianoKeyboardPanel();\r
JPanel track_selecter_panel = new JPanel();\r
track_selecter_panel.add( new JLabel("Track select:") );\r
track_selecter_panel.add(\r
- trackSelecter = new JComboBox<Music.AbstractNoteTrackSpec>()\r
- );\r
+ trackSelecter = new JComboBox<Music.AbstractNoteTrackSpec>()\r
+ );\r
add( track_selecter_panel );\r
\r
add( track_type_label = new JLabel() );\r