* @return 追加先のインデックス値(0から始まる)。追加できなかったときは -1\r
*/\r
public int addRandomSongToPlaylist(int measureLength) {\r
- editorDialog.new_seq_dialog.setRandomChordProgression(measureLength);\r
+ editorDialog.newSequenceDialog.setRandomChordProgression(measureLength);\r
return editorDialog.addSequence();\r
}\r
/**\r
* @return MIDIファイル名(設定されていないときは空文字列)\r
*/\r
public String getMidiFilename() {\r
- MidiSequenceModel seq_model = deviceManager.timeRangeModel.getSequenceModel();\r
+ MidiSequenceTableModel seq_model = deviceManager.timeRangeModel.getSequenceTableModel();\r
if( seq_model == null ) return null;\r
String fn = seq_model.getFilename();\r
return fn == null ? "" : fn ;\r
* @param isVisible 表示するときtrue\r
*/\r
public void setChordDiagramVisible(boolean isVisible) {\r
- keyboard_split_pane.resetToPreferredSizes();\r
+ keyboardSplitPane.resetToPreferredSizes();\r
if( ! isVisible )\r
- keyboard_split_pane.setDividerLocation((double)1.0);\r
+ keyboardSplitPane.setDividerLocation((double)1.0);\r
}\r
/**\r
* コードダイヤグラムをギターモードに変更します。\r
* @param isDark ダークモードのときtrue、明るい表示のときfalse(デフォルト)\r
*/\r
public void setDarkMode(boolean isDark) {\r
- dark_mode_toggle_button.setSelected(isDark);\r
+ darkModeToggleButton.setSelected(isDark);\r
}\r
/**\r
* バージョン情報\r
*/\r
public static class VersionInfo {\r
public static final String NAME = "MIDI Chord Helper";\r
- public static final String VERSION = "Ver.20131031.1";\r
+ public static final String VERSION = "Ver.20131110.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
public String getAppletInfo() {\r
return VersionInfo.getInfo();\r
}\r
- class AboutMessagePane extends JEditorPane {\r
+ private class AboutMessagePane extends JEditorPane implements ActionListener {\r
URI uri = null;\r
public AboutMessagePane() { this(true); }\r
public AboutMessagePane(boolean link_enabled) {\r
}\r
});\r
}\r
- // バージョン情報を表示\r
- public void showMessage() {\r
- JOptionPane.showMessageDialog( null, this, "Version info",\r
- JOptionPane.INFORMATION_MESSAGE,\r
- imageIcon\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ JOptionPane.showMessageDialog(\r
+ null, this, "Version info",\r
+ JOptionPane.INFORMATION_MESSAGE, imageIcon\r
);\r
}\r
}\r
// アプリケーションのアイコンイメージ\r
public ImageIcon imageIcon;\r
// ボタンの余白を詰めたいときは setMargin() の引数にこれを指定する\r
- Insets zero_insets = new Insets(0,0,0,0);\r
+ public static final Insets ZERO_INSETS = new Insets(0,0,0,0);\r
//\r
- JPanel\r
- keyboard_sequencer_panel,\r
- chord_guide,\r
- sequencer_panel,\r
- sequencer_upper_panel,\r
- sequencer_lower_panel,\r
- midi_io_panel;\r
- Color\r
- root_pane_default_bgcolor,\r
- lyric_display_default_bgcolor;\r
- Border\r
- lyric_display_default_border,\r
- dark_mode_toggle_border;\r
- AboutMessagePane aboutMessagePane = new AboutMessagePane();\r
- //\r
- JSplitPane main_split_pane, keyboard_split_pane;\r
- ChordTextField lyric_display;\r
- MidiKeyboardPanel keyboardPanel;\r
- ChordMatrix chordMatrix;\r
- ChordButtonLabel enterButtonLabel;\r
- InversionAndOmissionLabel inversionOmissionButton;\r
- JToggleButton dark_mode_toggle_button;\r
- MidiDeviceManager deviceManager;\r
- MidiDeviceDialog midiConnectionDialog;\r
- MidiEditor editorDialog;\r
- ChordDiagram chordDiagram;\r
- //\r
- // Tempo, Time signature, Key signature\r
- //\r
- TempoSelecter tempo_selecter = new TempoSelecter();\r
- TimeSignatureSelecter timesig_selecter = new TimeSignatureSelecter();\r
- KeySignatureLabel keysig_label = new KeySignatureLabel();\r
- JLabel song_title_label = new JLabel();\r
+ private JPanel keyboardSequencerPanel;\r
+ private JPanel chordGuide;\r
+ private Color rootPaneDefaultBgcolor;\r
+ private Color lyricDisplayDefaultBgcolor;\r
+ private Border lyricDisplayDefaultBorder;\r
+ private JSplitPane mainSplitPane;\r
+ private JSplitPane keyboardSplitPane;\r
+ private ChordButtonLabel enterButtonLabel;\r
+ private ChordTextField lyricDisplay;\r
+ private MidiKeyboardPanel keyboardPanel;\r
+ ChordMatrix chordMatrix;\r
+ private InversionAndOmissionLabel inversionOmissionButton;\r
+ private JToggleButton darkModeToggleButton;\r
+ MidiDeviceModelList deviceManager;\r
+ MidiDeviceDialog midiConnectionDialog;\r
+ MidiEditor editorDialog;\r
+ ChordDiagram chordDiagram;\r
+ TempoSelecter tempoSelecter = new TempoSelecter() {\r
+ { setEditable(false); }\r
+ };\r
+ TimeSignatureSelecter timesigSelecter = new TimeSignatureSelecter() {\r
+ { setEditable(false); }\r
+ };\r
+ KeySignatureLabel keysigLabel = new KeySignatureLabel() {\r
+ {\r
+ addMouseListener(new MouseAdapter() {\r
+ public void mousePressed(MouseEvent e) {\r
+ chordMatrix.setKeySignature(keysigLabel.getKey());\r
+ }\r
+ });\r
+ }\r
+ };\r
+ JLabel songTitleLabel = new JLabel();\r
//\r
// あの楽器\r
AnoGakkiLayeredPane anoGakkiLayeredPane;\r
- JToggleButton ano_gakki_toggle_button;\r
+ JToggleButton anoGakkiToggleButton;\r
\r
public void init() {\r
String imageIconPath = "images/midichordhelper.png";\r
else {\r
imageIcon = new ImageIcon(imageIconUrl);\r
}\r
- root_pane_default_bgcolor = getContentPane().getBackground();\r
- //\r
- // About\r
- JButton aboutButton = new JButton("Version info");\r
- aboutButton.setToolTipText( VersionInfo.NAME + " " + VersionInfo.VERSION );\r
- aboutButton.addActionListener( new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- aboutMessagePane.showMessage();\r
- }\r
- });\r
- //\r
- // Chord matrix\r
- //\r
- chordMatrix = new ChordMatrix();\r
- chordMatrix.addChordMatrixListener(new ChordMatrixListener(){\r
- public void keySignatureChanged() {\r
- Music.Key capo_key = chordMatrix.getKeySignatureCapo();\r
- keyboardPanel.keySelecter.setKey(capo_key);\r
- keyboardPanel.keyboardCenterPanel.keyboard.setKeySignature(capo_key);\r
- }\r
- public void chordChanged() { chordOn(); }\r
- });\r
- enterButtonLabel = new ChordButtonLabel("Enter",chordMatrix);\r
- enterButtonLabel.addMouseListener(new MouseAdapter() {\r
- public void mousePressed(MouseEvent e) {\r
- if( (e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) // RightClicked\r
- chordMatrix.setSelectedChord( (Music.Chord)null );\r
- else\r
- chordMatrix.setSelectedChord( lyric_display.getText() );\r
- }\r
- });\r
+ Image iconImage = (imageIcon == null) ? null : imageIcon.getImage();\r
+ rootPaneDefaultBgcolor = getContentPane().getBackground();\r
+ chordMatrix = new ChordMatrix() {{\r
+ addChordMatrixListener(new ChordMatrixListener(){\r
+ public void keySignatureChanged() {\r
+ Music.Key capoKey = getKeySignatureCapo();\r
+ keyboardPanel.keySelecter.setKey(capoKey);\r
+ keyboardPanel.keyboardCenterPanel.keyboard.setKeySignature(capoKey);\r
+ }\r
+ public void chordChanged() { chordOn(); }\r
+ });\r
+ }};\r
chordMatrix.capoSelecter.checkbox.addItemListener(\r
new ItemListener() {\r
public void itemStateChanged(ItemEvent e) {\r
}\r
}\r
);\r
- // Piano keyboard\r
- //\r
- keyboardPanel = new MidiKeyboardPanel(chordMatrix);\r
- keyboardPanel.keyboardCenterPanel.keyboard.addPianoKeyboardListener(\r
- new PianoKeyboardAdapter() {\r
- public void pianoKeyPressed(int n, InputEvent e) {\r
- chordDiagram.clear();\r
+ keyboardPanel = new MidiKeyboardPanel(chordMatrix) {{\r
+ keyboardCenterPanel.keyboard.addPianoKeyboardListener(\r
+ new PianoKeyboardAdapter() {\r
+ public void pianoKeyPressed(int n, InputEvent e) {\r
+ chordDiagram.clear();\r
+ }\r
}\r
- }\r
- );\r
- keyboardPanel.keySelecter.keysigCombobox.addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- Music.Key key = keyboardPanel.keySelecter.getKey();\r
- key.transpose( - chordMatrix.capoSelecter.getCapo() );\r
- chordMatrix.setKeySignature(key);\r
+ );\r
+ keySelecter.keysigCombobox.addActionListener(\r
+ new ActionListener() {\r
+ public void actionPerformed(ActionEvent e) {\r
+ Music.Key key = keySelecter.getKey();\r
+ key.transpose( - chordMatrix.capoSelecter.getCapo() );\r
+ chordMatrix.setKeySignature(key);\r
+ }\r
+ }\r
+ );\r
+ keyboardCenterPanel.keyboard.setPreferredSize(new Dimension(571, 80));\r
+ }};\r
+ deviceManager = new MidiDeviceModelList(\r
+ new Vector<VirtualMidiDevice>() {\r
+ {\r
+ add(keyboardPanel.keyboardCenterPanel.keyboard.midiDevice);\r
}\r
}\r
);\r
- keyboardPanel.keyboardCenterPanel.keyboard.setPreferredSize(\r
- new Dimension( 571, 80 )\r
- );\r
- // MIDI connection and MIDI editor\r
- //\r
- Vector<VirtualMidiDevice> vmdList = new Vector<VirtualMidiDevice>();\r
- vmdList.add(keyboardPanel.keyboardCenterPanel.keyboard.midiDevice);\r
- deviceManager = new MidiDeviceManager(vmdList);\r
editorDialog = new MidiEditor(deviceManager);\r
- Image iconImage = imageIcon == null ? null : imageIcon.getImage();\r
editorDialog.setIconImage(iconImage);\r
- JButton editButton = new JButton(\r
- "Edit/Playlist/Speed", new ButtonIcon(ButtonIcon.EDIT_ICON)\r
- );\r
- editButton.setMargin(zero_insets);\r
- editButton.addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- editorDialog.setVisible(true);\r
- }\r
- }\r
- );\r
- new DropTarget(\r
- this, DnDConstants.ACTION_COPY_OR_MOVE, editorDialog, true\r
- );\r
+ new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, editorDialog, true);\r
deviceManager.setMidiEditor(editorDialog);\r
keyboardPanel.eventDialog = editorDialog.eventDialog;\r
- //\r
midiConnectionDialog = new MidiDeviceDialog(deviceManager);\r
midiConnectionDialog.setIconImage(iconImage);\r
- JButton midiConnectionButton = new JButton(\r
- "MIDI device connection",\r
- new ButtonIcon( ButtonIcon.MIDI_CONNECTOR_ICON )\r
- );\r
- midiConnectionButton.addActionListener(new ActionListener() {\r
- public void actionPerformed( ActionEvent event ) {\r
- midiConnectionDialog.setVisible(true);\r
- }\r
- });\r
- //\r
- // Displays\r
- //\r
- lyric_display = new ChordTextField();\r
- lyric_display.addActionListener( new ActionListener() {\r
- public void actionPerformed(ActionEvent event) {\r
- chordMatrix.setSelectedChord(\r
- event.getActionCommand().trim().split("[ \t\r\n]")[0]\r
- );\r
- }\r
- });\r
- lyric_display_default_border = lyric_display.getBorder();\r
- lyric_display_default_bgcolor = lyric_display.getBackground();\r
- //\r
- // Dark mode\r
- //\r
- dark_mode_toggle_button = new JToggleButton(\r
- new ButtonIcon(ButtonIcon.DARK_MODE_ICON)\r
- );\r
- dark_mode_toggle_button.setMargin(zero_insets);\r
- dark_mode_toggle_button.addItemListener(new ItemListener() {\r
- public void itemStateChanged(ItemEvent e) {\r
- innerSetDarkMode(dark_mode_toggle_button.isSelected());\r
- }\r
- });\r
- dark_mode_toggle_button.setToolTipText("Light / Dark - 明かりを点灯/消灯");\r
- dark_mode_toggle_border = dark_mode_toggle_button.getBorder();\r
- dark_mode_toggle_button.setBorder( null );\r
- //\r
- // Inversion/Omission(転回・省略音)\r
- //\r
- inversionOmissionButton = new InversionAndOmissionLabel();\r
- //\r
- // あの楽器 切り替えボタン\r
- //\r
- ano_gakki_toggle_button = new JToggleButton(\r
- new ButtonIcon(ButtonIcon.ANO_GAKKI_ICON)\r
- );\r
- ano_gakki_toggle_button.setOpaque(false);\r
- ano_gakki_toggle_button.setMargin(zero_insets);\r
- ano_gakki_toggle_button.setBorder( null );\r
- ano_gakki_toggle_button.setToolTipText("あの楽器");\r
- ano_gakki_toggle_button.addItemListener(\r
- new ItemListener() {\r
- public void itemStateChanged(ItemEvent e) {\r
- keyboardPanel.keyboardCenterPanel.keyboard.anoGakkiLayeredPane\r
- = ano_gakki_toggle_button.isSelected() ? anoGakkiLayeredPane : null ;\r
+ lyricDisplay = new ChordTextField() {{\r
+ addActionListener(new ActionListener() {\r
+ public void actionPerformed(ActionEvent event) {\r
+ chordMatrix.setSelectedChord(\r
+ event.getActionCommand().trim().split("[ \t\r\n]")[0]\r
+ );\r
}\r
- }\r
- );\r
+ });\r
+ }};\r
+ lyricDisplayDefaultBorder = lyricDisplay.getBorder();\r
+ lyricDisplayDefaultBgcolor = lyricDisplay.getBackground();\r
//\r
// Chord diagram\r
//\r
//\r
// MIDI parts\r
//\r
- tempo_selecter.setEditable(false);\r
- timesig_selecter.setEditable(false);\r
- keysig_label.addMouseListener(new MouseAdapter() {\r
- public void mousePressed(MouseEvent e) {\r
- chordMatrix.setKeySignature( keysig_label.getKey() );\r
- }\r
- });\r
deviceManager.getSequencer().addMetaEventListener(this);\r
deviceManager.timeRangeModel.addChangeListener(\r
new ChangeListener() {\r
public void stateChanged(ChangeEvent e) {\r
- MidiSequenceModel seq_model = deviceManager.timeRangeModel.getSequenceModel();\r
- SequenceListModel seq_list_model = editorDialog.seqListModel;\r
- int i = seq_list_model.getLoadedIndex();\r
- song_title_label.setText(\r
+ MidiSequenceTableModel sequenceTableModel = deviceManager.timeRangeModel.getSequenceTableModel();\r
+ int i = editorDialog.seqListModel.getLoadedIndex();\r
+ songTitleLabel.setText(\r
"<html>"+(\r
i < 0 ? "[No MIDI file loaded]" :\r
"MIDI file " + i + ": " + (\r
- seq_model == null ||\r
- seq_model.toString() == null ||\r
- seq_model.toString().isEmpty() ?\r
+ sequenceTableModel == null ||\r
+ sequenceTableModel.toString() == null ||\r
+ sequenceTableModel.toString().isEmpty() ?\r
"[Untitled]" :\r
- "<font color=maroon>"+seq_model+"</font>"\r
+ "<font color=maroon>"+sequenceTableModel+"</font>"\r
)\r
)+"</html>"\r
);\r
chordMatrix.setPlaying(deviceManager.timeRangeModel.timer.isRunning());\r
- long current_tick_position = deviceManager.getSequencer().getTickPosition();\r
- SequenceIndex seq_index = null;\r
- if( seq_model != null ) {\r
- seq_index = seq_model.getSequenceIndex();\r
- seq_index.tickToMeasure( current_tick_position );\r
+ long currentTickPosition = deviceManager.getSequencer().getTickPosition();\r
+ SequenceTickIndex tickIndex = null;\r
+ if( sequenceTableModel != null ) {\r
+ tickIndex = sequenceTableModel.getSequenceTickIndex();\r
+ tickIndex.tickToMeasure(currentTickPosition);\r
chordMatrix.setBeat(\r
- (byte)(seq_index.last_beat), seq_index.timesig_upper\r
+ (byte)(tickIndex.lastBeat), tickIndex.timesigUpper\r
);\r
if(\r
deviceManager.timeRangeModel.getValueIsAdjusting()\r
! deviceManager.getSequencer().isRecording()\r
)\r
) {\r
- MetaMessage msg = seq_index.lastTimeSignatureAt( current_tick_position );\r
- if( msg == null ) timesig_selecter.clear(); else meta(msg);\r
- msg = seq_index.lastTempoAt( current_tick_position );\r
- if( msg == null ) tempo_selecter.clear(); else meta(msg);\r
- msg = seq_index.lastKeySignatureAt( current_tick_position );\r
- if( msg == null ) keysig_label.clear(); else meta(msg);\r
+ MetaMessage msg = tickIndex.lastMetaMessageAt(\r
+ SequenceTickIndex.TIME_SIGNATURE, currentTickPosition\r
+ );\r
+ if( msg == null )\r
+ timesigSelecter.clear();\r
+ else\r
+ meta(msg);\r
+ msg = tickIndex.lastMetaMessageAt(\r
+ SequenceTickIndex.TEMPO, currentTickPosition\r
+ );\r
+ if( msg == null )\r
+ tempoSelecter.clear();\r
+ else\r
+ meta(msg);\r
+ msg = tickIndex.lastMetaMessageAt(\r
+ SequenceTickIndex.KEY_SIGNATURE, currentTickPosition\r
+ );\r
+ if( msg == null )\r
+ keysigLabel.clear();\r
+ else\r
+ meta(msg);\r
}\r
}\r
}\r
}\r
);\r
deviceManager.timeRangeModel.fireStateChanged();\r
- //\r
- // Construct tree of panels\r
- //\r
- chord_guide = new JPanel();\r
- chord_guide.setLayout(new BoxLayout( chord_guide, BoxLayout.X_AXIS ));\r
- chord_guide.add( Box.createHorizontalStrut(2) );\r
- chord_guide.add( chordMatrix.chordGuide );\r
- chord_guide.add( Box.createHorizontalStrut(2) );\r
- chord_guide.add( lyric_display );\r
- chord_guide.add( Box.createHorizontalStrut(2) );\r
- chord_guide.add( enterButtonLabel );\r
- chord_guide.add( Box.createHorizontalStrut(5) );\r
- chord_guide.add( chordMatrix.chordDisplay );\r
- chord_guide.add( Box.createHorizontalStrut(5) );\r
- chord_guide.add( dark_mode_toggle_button );\r
- chord_guide.add( Box.createHorizontalStrut(5) );\r
- chord_guide.add( ano_gakki_toggle_button );\r
- chord_guide.add( Box.createHorizontalStrut(5) );\r
- chord_guide.add( inversionOmissionButton );\r
- chord_guide.add( Box.createHorizontalStrut(5) );\r
- chord_guide.add( chordMatrix.capoSelecter );\r
- chord_guide.add( Box.createHorizontalStrut(2) );\r
- //\r
- sequencer_upper_panel = new JPanel();\r
- sequencer_upper_panel.setLayout(\r
- new BoxLayout( sequencer_upper_panel, BoxLayout.X_AXIS )\r
- );\r
- sequencer_upper_panel.add( Box.createHorizontalStrut(12) );\r
- sequencer_upper_panel.add( keysig_label );\r
- sequencer_upper_panel.add( Box.createHorizontalStrut(12) );\r
- sequencer_upper_panel.add( timesig_selecter );\r
- sequencer_upper_panel.add( Box.createHorizontalStrut(12) );\r
- sequencer_upper_panel.add( tempo_selecter );\r
- sequencer_upper_panel.add( Box.createHorizontalStrut(12) );\r
- sequencer_upper_panel.add(\r
- new MeasureIndicator(deviceManager.timeRangeModel)\r
- );\r
- sequencer_upper_panel.add( Box.createHorizontalStrut(12) );\r
- sequencer_upper_panel.add( song_title_label );\r
- sequencer_upper_panel.add( Box.createHorizontalStrut(12) );\r
- sequencer_upper_panel.add( editButton );\r
- //\r
- JButton top_button, bottom_button, backward_button, forward_button;\r
- JToggleButton repeat_button;\r
- sequencer_lower_panel = new JPanel();\r
- sequencer_lower_panel.setLayout(\r
- new BoxLayout( sequencer_lower_panel, BoxLayout.X_AXIS )\r
- );\r
- sequencer_lower_panel.add( Box.createHorizontalStrut(10) );\r
- sequencer_lower_panel.add(\r
- new JSlider(deviceManager.timeRangeModel)\r
- );\r
- sequencer_lower_panel.add(\r
- new TimeIndicator(deviceManager.timeRangeModel)\r
- );\r
- sequencer_lower_panel.add( Box.createHorizontalStrut(5) );\r
- sequencer_lower_panel.add(\r
- top_button = new JButton(editorDialog.move_to_top_action)\r
- );\r
- sequencer_lower_panel.add(\r
- backward_button = new JButton(\r
- deviceManager.timeRangeModel.move_backward_action\r
- )\r
- );\r
- sequencer_lower_panel.add(\r
- new JToggleButton(deviceManager.timeRangeModel.startStopAction)\r
- );\r
- sequencer_lower_panel.add(\r
- forward_button = new JButton(\r
- deviceManager.timeRangeModel.move_forward_action\r
- )\r
- );\r
- sequencer_lower_panel.add(\r
- bottom_button = new JButton(\r
- editorDialog.move_to_bottom_action\r
- )\r
- );\r
- sequencer_lower_panel.add(\r
- repeat_button = new JToggleButton(\r
- deviceManager.timeRangeModel.toggle_repeat_action\r
- )\r
- );\r
- sequencer_lower_panel.add( Box.createHorizontalStrut(10) );\r
- top_button.setMargin(zero_insets);\r
- bottom_button.setMargin(zero_insets);\r
- backward_button.setMargin(zero_insets);\r
- forward_button.setMargin(zero_insets);\r
- repeat_button.setMargin(zero_insets);\r
- //\r
- midi_io_panel = new JPanel();\r
- midi_io_panel.add( midiConnectionButton );\r
- midi_io_panel.add( aboutButton );\r
- //\r
- sequencer_panel = new JPanel();\r
- sequencer_panel.setLayout(\r
- new BoxLayout( sequencer_panel, BoxLayout.Y_AXIS )\r
- );\r
- sequencer_panel.add( sequencer_upper_panel );\r
- sequencer_panel.add( sequencer_lower_panel );\r
- sequencer_panel.add( midi_io_panel );\r
- //\r
- keyboard_split_pane = new JSplitPane(\r
- JSplitPane.HORIZONTAL_SPLIT, keyboardPanel, chordDiagram\r
- );\r
- keyboard_split_pane.setOneTouchExpandable(true);\r
- keyboard_split_pane.setResizeWeight(1.0);\r
- keyboard_split_pane.setAlignmentX((float)0.5);\r
- //\r
- keyboard_sequencer_panel = new JPanel();\r
- keyboard_sequencer_panel.setLayout(\r
- new BoxLayout( keyboard_sequencer_panel, BoxLayout.Y_AXIS )\r
- );\r
- keyboard_sequencer_panel.add(chord_guide);\r
- keyboard_sequencer_panel.add(Box.createVerticalStrut(5));\r
- keyboard_sequencer_panel.add(keyboard_split_pane);\r
- keyboard_sequencer_panel.add(Box.createVerticalStrut(5));\r
- keyboard_sequencer_panel.add(sequencer_panel);\r
- //\r
- main_split_pane = new JSplitPane(\r
- JSplitPane.VERTICAL_SPLIT,\r
- chordMatrix, keyboard_sequencer_panel\r
- );\r
- main_split_pane.setResizeWeight(0.5);\r
- main_split_pane.setAlignmentX((float)0.5);\r
- main_split_pane.setDividerSize(5);\r
- //\r
- anoGakkiLayeredPane = new AnoGakkiLayeredPane();\r
- anoGakkiLayeredPane.add(main_split_pane);\r
+ chordGuide = new JPanel() {\r
+ {\r
+ setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
+ add( Box.createHorizontalStrut(2) );\r
+ add( chordMatrix.chordGuide );\r
+ add( Box.createHorizontalStrut(2) );\r
+ add( lyricDisplay );\r
+ add( Box.createHorizontalStrut(2) );\r
+ add( enterButtonLabel = new ChordButtonLabel("Enter",chordMatrix) {{\r
+ addMouseListener(new MouseAdapter() {\r
+ public void mousePressed(MouseEvent e) {\r
+ if( (e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) // RightClicked\r
+ chordMatrix.setSelectedChord( (Music.Chord)null );\r
+ else\r
+ chordMatrix.setSelectedChord( lyricDisplay.getText() );\r
+ }\r
+ });\r
+ }});\r
+ add( Box.createHorizontalStrut(5) );\r
+ add( chordMatrix.chordDisplay );\r
+ add( Box.createHorizontalStrut(5) );\r
+ add( darkModeToggleButton = new JToggleButton(new ButtonIcon(ButtonIcon.DARK_MODE_ICON)) {{\r
+ setMargin(ZERO_INSETS);\r
+ addItemListener(new ItemListener() {\r
+ public void itemStateChanged(ItemEvent e) {\r
+ innerSetDarkMode(darkModeToggleButton.isSelected());\r
+ }\r
+ });\r
+ setToolTipText("Light / Dark - 明かりを点灯/消灯");\r
+ setBorder(null);\r
+ }});\r
+ add( Box.createHorizontalStrut(5) );\r
+ add( anoGakkiToggleButton = new JToggleButton(\r
+ new ButtonIcon(ButtonIcon.ANO_GAKKI_ICON)\r
+ ) {{\r
+ setOpaque(false);\r
+ setMargin(ZERO_INSETS);\r
+ setBorder( null );\r
+ setToolTipText("あの楽器");\r
+ addItemListener(\r
+ new ItemListener() {\r
+ public void itemStateChanged(ItemEvent e) {\r
+ keyboardPanel.keyboardCenterPanel.keyboard.anoGakkiLayeredPane\r
+ = anoGakkiToggleButton.isSelected() ? anoGakkiLayeredPane : null ;\r
+ }\r
+ }\r
+ );\r
+ }} );\r
+ add( Box.createHorizontalStrut(5) );\r
+ add( inversionOmissionButton = new InversionAndOmissionLabel() );\r
+ add( Box.createHorizontalStrut(5) );\r
+ add( chordMatrix.capoSelecter );\r
+ add( Box.createHorizontalStrut(2) );\r
+ }\r
+ };\r
+ keyboardSequencerPanel = new JPanel() {{\r
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
+ add(chordGuide);\r
+ add(Box.createVerticalStrut(5));\r
+ add(keyboardSplitPane = new JSplitPane(\r
+ JSplitPane.HORIZONTAL_SPLIT, keyboardPanel, chordDiagram\r
+ ) {{\r
+ setOneTouchExpandable(true);\r
+ setResizeWeight(1.0);\r
+ setAlignmentX((float)0.5);\r
+ }});\r
+ add(Box.createVerticalStrut(5));\r
+ add(new JPanel() {{\r
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
+ add(new JPanel() {{\r
+ setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
+ add( Box.createHorizontalStrut(12) );\r
+ add( keysigLabel );\r
+ add( Box.createHorizontalStrut(12) );\r
+ add( timesigSelecter );\r
+ add( Box.createHorizontalStrut(12) );\r
+ add( tempoSelecter );\r
+ add( Box.createHorizontalStrut(12) );\r
+ add( new MeasureIndicator(deviceManager.timeRangeModel) );\r
+ add( Box.createHorizontalStrut(12) );\r
+ add( songTitleLabel );\r
+ add( Box.createHorizontalStrut(12) );\r
+ add( new JButton("Edit/Playlist/Speed", new ButtonIcon(ButtonIcon.EDIT_ICON)) {{\r
+ setMargin(ZERO_INSETS);\r
+ addActionListener(editorDialog);\r
+ }});\r
+ }});\r
+ add(new JPanel() {{\r
+ setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
+ add( Box.createHorizontalStrut(10) );\r
+ add( new JSlider(deviceManager.timeRangeModel));\r
+ add( new TimeIndicator(deviceManager.timeRangeModel) );\r
+ add( Box.createHorizontalStrut(5) );\r
+ add( new JButton(editorDialog.move_to_top_action) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add(new JButton(deviceManager.timeRangeModel.moveBackwardAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add(new JToggleButton(deviceManager.timeRangeModel.startStopAction));\r
+ add(new JButton(deviceManager.timeRangeModel.moveForwardAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add(new JButton(editorDialog.move_to_bottom_action) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add(new JToggleButton(deviceManager.timeRangeModel.toggleRepeatAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add( Box.createHorizontalStrut(10) );\r
+ }});\r
+ add(new JPanel() {{\r
+ add(new JButton(\r
+ "MIDI device connection",\r
+ new ButtonIcon( ButtonIcon.MIDI_CONNECTOR_ICON )\r
+ ) {{\r
+ addActionListener(midiConnectionDialog);\r
+ }});\r
+ add(new JButton("Version info") {{\r
+ setToolTipText(VersionInfo.NAME + " " + VersionInfo.VERSION);\r
+ addActionListener(new AboutMessagePane());\r
+ }});\r
+ }});\r
+ }});\r
+ }};\r
+ mainSplitPane = new JSplitPane(\r
+ JSplitPane.VERTICAL_SPLIT, chordMatrix, keyboardSequencerPanel\r
+ ) {{\r
+ setResizeWeight(0.5);\r
+ setAlignmentX((float)0.5);\r
+ setDividerSize(5);\r
+ }};\r
+ anoGakkiLayeredPane = new AnoGakkiLayeredPane() {{ add(mainSplitPane); }};\r
setContentPane(anoGakkiLayeredPane);\r
- setPreferredSize( new Dimension(750,470) );\r
+ setPreferredSize(new Dimension(750,470));\r
}\r
/////////////////////////////////////////\r
//\r
case 0x05: // Lyrics(歌詞)\r
case 0x06: // Marker\r
case 0x03: // Sequence Name / Track Name(曲名またはトラック名)\r
- lyric_display.addLyric(msg.getData());\r
+ lyricDisplay.addLyric(msg.getData());\r
break;\r
\r
case 0x51: // Tempo (3 bytes) - テンポ\r
- tempo_selecter.setTempo(msg.getData());\r
+ tempoSelecter.setTempo(msg.getData());\r
break;\r
case 0x58: // Time signature (4 bytes) - 拍子\r
- timesig_selecter.setValue(msg.getData());\r
+ timesigSelecter.setValue(msg.getData());\r
break;\r
case 0x59: // Key signature (2 bytes) : 調号\r
- keysig_label.setKeySignature( new Music.Key(msg.getData()) );\r
+ keysigLabel.setKeySignature( new Music.Key(msg.getData()) );\r
chordMatrix.setKeySignature( new Music.Key(msg.getData()) );\r
break;\r
\r
}\r
}\r
- //\r
- ///////////////////////////////////////////////////////////////\r
- //\r
- // Methods\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
getContentPane().setBackground(\r
- is_dark ? Color.black : root_pane_default_bgcolor\r
- );\r
- main_split_pane.setBackground( col );\r
- keyboard_split_pane.setBackground( col );\r
+ is_dark ? Color.black : rootPaneDefaultBgcolor\r
+ );\r
+ mainSplitPane.setBackground( col );\r
+ keyboardSplitPane.setBackground( col );\r
enterButtonLabel.setDarkMode( is_dark );\r
- chord_guide.setBackground( col );\r
- lyric_display.setBorder( is_dark ? null : lyric_display_default_border );\r
- lyric_display.setBackground( is_dark ?\r
- chordMatrix.darkModeColorset.backgrounds[2] : lyric_display_default_bgcolor\r
- );\r
- lyric_display.setForeground( is_dark ? Color.white : null );\r
+ chordGuide.setBackground( col );\r
+ lyricDisplay.setBorder( is_dark ? null : lyricDisplayDefaultBorder );\r
+ lyricDisplay.setBackground( is_dark ?\r
+ chordMatrix.darkModeColorset.backgrounds[2] : lyricDisplayDefaultBgcolor\r
+ );\r
+ lyricDisplay.setForeground( is_dark ? Color.white : null );\r
inversionOmissionButton.setBackground( col );\r
- ano_gakki_toggle_button.setBackground( col );\r
- keyboard_sequencer_panel.setBackground( col );\r
+ anoGakkiToggleButton.setBackground( col );\r
+ keyboardSequencerPanel.setBackground( col );\r
chordDiagram.setBackground( col );\r
chordDiagram.titleLabel.setDarkMode( is_dark );\r
chordMatrix.setDarkMode( is_dark );\r
keyboardPanel.setDarkMode( is_dark );\r
}\r
- /////////////////////////////////////////////////////////////////\r
- //\r
- // 発音(和音)\r
- //\r
- // 注:この関数を直接呼ぶとアルペジオが効かないので、\r
- // chord_matrix.setSelectedChord() を使うことを推奨\r
- //\r
- int[] chordOnNotes = null;\r
+\r
+ private int[] chordOnNotes = null;\r
+ /**\r
+ * 和音を発音します。\r
+ * <p>この関数を直接呼ぶとアルペジオが効かないので、\r
+ * chord_matrix.setSelectedChord() を使うことを推奨\r
+ * </p>\r
+ */\r
public void chordOn() {\r
Music.Chord playChord = chordMatrix.getSelectedChord();\r
if(\r
}\r
if( playChord == null ) {\r
// もう鳴らさないので、歌詞表示に通知して終了\r
- if( lyric_display != null )\r
- lyric_display.currentChord = null;\r
+ if( lyricDisplay != null )\r
+ lyricDisplay.currentChord = null;\r
return;\r
}\r
// あの楽器っぽい表示\r
);\r
chordDiagram.setChord(diagramChord);\r
if( chordDiagram.recordTextButton.isSelected() )\r
- lyric_display.appendChord(diagramChord);\r
+ lyricDisplay.appendChord(diagramChord);\r
}\r
}\r
\r
}\r
}\r
\r
-// Inversion and Omission menu button\r
-//\r
+/**\r
+ * 転回・省略音メニューボタン\r
+ */\r
class InversionAndOmissionLabel extends JLabel\r
-implements MouseListener, PopupMenuListener\r
+ implements MouseListener, PopupMenuListener\r
{\r
JPopupMenu popup_menu;\r
ButtonGroup omission_group = new ButtonGroup();\r
import java.security.AccessControlException;\r
import java.util.ArrayList;\r
import java.util.EventObject;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
import java.util.Vector;\r
\r
import javax.sound.midi.InvalidMidiDataException;\r
* Copyright (C) 2006-2013 Akiyoshi Kamide\r
* http://www.yk.rim.or.jp/~kamide/music/chordhelper/\r
*/\r
-class MidiEditor extends JDialog implements DropTargetListener, ListSelectionListener {\r
- Insets zero_insets = new Insets(0,0,0,0);\r
+class MidiEditor extends JDialog\r
+ implements DropTargetListener, ListSelectionListener, ActionListener\r
+{\r
+ public static final Insets ZERO_INSETS = new Insets(0,0,0,0);\r
\r
- MidiDeviceManager deviceManager;\r
+ MidiDeviceModelList deviceManager;\r
\r
- SequenceListModel seqListModel;\r
- JFileChooser file_chooser = null;\r
- Base64Dialog base64_dialog = null;\r
- NewSequenceDialog new_seq_dialog;\r
+ SequenceListTableModel seqListModel;\r
+ private JFileChooser fileChooser = null;\r
+ private Base64Dialog base64Dialog = new Base64Dialog(this);\r
+ NewSequenceDialog newSequenceDialog;\r
MidiEventDialog eventDialog = new MidiEventDialog();\r
\r
MidiEvent copied_events[] = null;\r
int copied_events_PPQ = 0;\r
\r
- ListSelectionModel\r
- seq_selection_model,\r
- track_selection_model,\r
- event_selection_model;\r
+ ListSelectionModel seqSelectionModel;\r
+ ListSelectionModel track_selection_model;\r
+ ListSelectionModel event_selection_model;\r
\r
- JTable\r
- sequence_table_view,\r
- track_table_view,\r
- event_table_view;\r
+ JTable sequence_table_view;\r
+ JTable track_table_view;\r
+ JTable event_table_view;\r
\r
- JScrollPane\r
- scrollable_sequence_table,\r
- scrollable_track_table_view,\r
- scrollable_event_table_view;\r
+ JScrollPane scrollable_sequence_table;\r
+ JScrollPane scrollable_track_table_view;\r
+ JScrollPane scrollable_event_table_view;\r
\r
- JLabel\r
- total_time_label,\r
- tracks_label,\r
- midi_events_label;\r
+ JLabel totalTimeLabel;\r
+ JLabel tracks_label;\r
+ JLabel midi_events_label;\r
\r
JButton\r
add_new_sequence_button, delete_sequence_button,\r
\r
JCheckBox pair_note_checkbox;\r
\r
- JButton forward_button, backward_button;\r
+ JButton forward_button;\r
+ JButton backward_button;\r
JToggleButton play_pause_button;\r
\r
- JSplitPane\r
- sequence_split_pane, track_split_pane;\r
+ JSplitPane sequence_split_pane;\r
+ JSplitPane track_split_pane;\r
\r
- VirtualMidiDevice midiDevice = new AbstractVirtualMidiDevice() {\r
+ VirtualMidiDevice virtualMidiDevice = new AbstractVirtualMidiDevice() {\r
{\r
info = new MyInfo();\r
setMaxReceivers(0);\r
\r
class MidiEventCellEditor extends AbstractCellEditor implements TableCellEditor {\r
MidiEvent[] midi_events_to_be_removed; // 削除対象にする変更前イベント(null可)\r
- MidiTrackModel midi_track_model; // 対象トラック\r
- MidiSequenceModel seq_model; // 対象シーケンス\r
+ MidiTrackTableModel midi_track_model; // 対象トラック\r
+ MidiSequenceTableModel seq_model; // 対象シーケンス\r
MidiEvent sel_midi_evt = null; // 選択されたイベント\r
int sel_index = -1; // 選択されたイベントの場所\r
long current_tick = 0; // 選択されたイベントのtick位置\r
};\r
\r
private void setSelectedEvent() {\r
- seq_model = seqListModel.getSequenceModel(seq_selection_model);\r
+ seq_model = seqListModel.getSequenceModel(seqSelectionModel);\r
eventDialog.midiMessageForm.durationForm.setPPQ(\r
- seq_model.getSequence().getResolution()\r
- );\r
- tick_position_model.setSequenceIndex(\r
- seq_model.getSequenceIndex()\r
- );\r
+ seq_model.getSequence().getResolution()\r
+ );\r
+ tick_position_model.setSequenceIndex(seq_model.getSequenceTickIndex());\r
sel_index = -1;\r
current_tick = 0;\r
sel_midi_evt = null;\r
- midi_track_model = (MidiTrackModel)event_table_view.getModel();\r
+ midi_track_model = (MidiTrackTableModel)event_table_view.getModel();\r
if( ! event_selection_model.isSelectionEmpty() ) {\r
sel_index = event_selection_model.getMinSelectionIndex();\r
sel_midi_evt = midi_track_model.getMidiEvent(sel_index);\r
Action jump_event_action = new AbstractAction() {\r
{ putValue(NAME,"Jump"); }\r
public void actionPerformed(ActionEvent e) {\r
- scrollToEventAt(\r
- tick_position_model.getTickPosition()\r
- );\r
+ scrollToEventAt(tick_position_model.getTickPosition());\r
eventDialog.setVisible(false);\r
}\r
};\r
{ putValue(NAME,"Paste"); }\r
public void actionPerformed(ActionEvent e) {\r
long tick = tick_position_model.getTickPosition();\r
- ((MidiTrackModel)event_table_view.getModel()).addMidiEvents(\r
+ ((MidiTrackTableModel)event_table_view.getModel()).addMidiEvents(\r
copied_events, tick, copied_events_PPQ\r
);\r
scrollToEventAt( tick );\r
- seqListModel.fireSequenceChanged(seq_selection_model);\r
+ seqListModel.fireSequenceChanged(seqSelectionModel);\r
eventDialog.setVisible(false);\r
}\r
};\r
public MidiEventCellEditor() {\r
edit_event_button.setHorizontalAlignment(JButton.LEFT);\r
eventDialog.cancel_button.setAction(cancel_action);\r
- eventDialog.midiMessageForm.setOutputMidiChannels(\r
- midiDevice.getChannels()\r
- );\r
+ eventDialog.midiMessageForm.setOutputMidiChannels(virtualMidiDevice.getChannels());\r
eventDialog.tick_position_form.setModel(tick_position_model);\r
edit_event_button.addActionListener(\r
new ActionListener() {\r
pair_note_on_off_model.addItemListener(new ItemListener() {\r
public void itemStateChanged(ItemEvent e) {\r
eventDialog.midiMessageForm.durationForm.setEnabled(\r
- pair_note_on_off_model.isSelected()\r
- );\r
+ pair_note_on_off_model.isSelected()\r
+ );\r
}\r
});\r
pair_note_on_off_model.setSelected(true);\r
return "";\r
}\r
public Component getTableCellEditorComponent(\r
- JTable table, Object value, boolean isSelected,\r
- int row, int column\r
- ) {\r
+ JTable table, Object value, boolean isSelected,\r
+ int row, int column\r
+ ) {\r
edit_event_button.setText((String)value);\r
return edit_event_button;\r
}\r
public Action move_to_top_action = new AbstractAction() {\r
{\r
putValue( SHORT_DESCRIPTION,\r
- "Move to top or previous song - 曲の先頭または前の曲へ戻る"\r
- );\r
+ "Move to top or previous song - 曲の先頭または前の曲へ戻る"\r
+ );\r
putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.TOP_ICON) );\r
}\r
public void actionPerformed( ActionEvent event ) {\r
//\r
// Constructor\r
//\r
- public MidiEditor(MidiDeviceManager deviceManager) {\r
+ public MidiEditor(MidiDeviceModelList deviceManager) {\r
this.deviceManager = deviceManager;\r
setTitle("MIDI Editor/Playlist - MIDI Chord Helper");\r
setBounds( 150, 200, 850, 500 );\r
setLayout(new FlowLayout());\r
Icon delete_icon = new ButtonIcon(ButtonIcon.X_ICON);\r
- new DropTarget(\r
- this, DnDConstants.ACTION_COPY_OR_MOVE, this, true\r
- );\r
- total_time_label = new JLabel();\r
+ new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this, true);\r
+ totalTimeLabel = new JLabel();\r
//\r
// Buttons (Sequence)\r
//\r
add_new_sequence_button = new JButton("New");\r
add_new_sequence_button.setToolTipText("Generate new song - 新しい曲を生成");\r
- add_new_sequence_button.setMargin(zero_insets);\r
+ add_new_sequence_button.setMargin(ZERO_INSETS);\r
add_new_sequence_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
- new_seq_dialog.setVisible(true);\r
+ newSequenceDialog.setVisible(true);\r
}\r
}\r
);\r
add_midi_file_button = new JButton("Open");\r
- add_midi_file_button.setMargin(zero_insets);\r
+ add_midi_file_button.setMargin(ZERO_INSETS);\r
add_midi_file_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
if(\r
- file_chooser == null ||\r
- file_chooser.showOpenDialog(MidiEditor.this) != JFileChooser.APPROVE_OPTION\r
- ) return;\r
- addSequenceFromMidiFile(file_chooser.getSelectedFile());\r
+ fileChooser == null ||\r
+ fileChooser.showOpenDialog(MidiEditor.this) != JFileChooser.APPROVE_OPTION\r
+ ) return;\r
+ addSequenceFromMidiFile(fileChooser.getSelectedFile());\r
}\r
}\r
);\r
//\r
- play_pause_button = new JToggleButton(\r
- deviceManager.timeRangeModel.startStopAction\r
- );\r
+ play_pause_button = new JToggleButton(deviceManager.timeRangeModel.startStopAction);\r
backward_button = new JButton(move_to_top_action);\r
- backward_button.setMargin(zero_insets);\r
+ backward_button.setMargin(ZERO_INSETS);\r
forward_button = new JButton(move_to_bottom_action);\r
- forward_button.setMargin(zero_insets);\r
+ forward_button.setMargin(ZERO_INSETS);\r
//\r
jump_sequence_button = new JButton("Jump");\r
jump_sequence_button.setToolTipText("Move to selected song - 選択した曲へ進む");\r
- jump_sequence_button.setMargin(zero_insets);\r
+ jump_sequence_button.setMargin(ZERO_INSETS);\r
jump_sequence_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
- load( seq_selection_model.getMinSelectionIndex() );\r
+ load( seqSelectionModel.getMinSelectionIndex() );\r
}\r
}\r
);\r
save_midi_file_button = new JButton("Save");\r
- save_midi_file_button.setMargin(zero_insets);\r
+ save_midi_file_button.setMargin(ZERO_INSETS);\r
save_midi_file_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
- if( file_chooser == null ) return;\r
+ if( fileChooser == null ) return;\r
File midi_file;\r
- MidiSequenceModel seq_model =\r
- seqListModel.getSequenceModel(seq_selection_model);\r
+ MidiSequenceTableModel seq_model =\r
+ seqListModel.getSequenceModel(seqSelectionModel);\r
String filename = seq_model.getFilename();\r
if( filename != null && ! filename.isEmpty() ) {\r
midi_file = new File(filename);\r
- file_chooser.setSelectedFile(midi_file);\r
+ fileChooser.setSelectedFile(midi_file);\r
}\r
- if( file_chooser.showSaveDialog(MidiEditor.this) != JFileChooser.APPROVE_OPTION ) {\r
+ if( fileChooser.showSaveDialog(MidiEditor.this) != JFileChooser.APPROVE_OPTION ) {\r
return;\r
}\r
- midi_file = file_chooser.getSelectedFile();\r
+ midi_file = fileChooser.getSelectedFile();\r
if( midi_file.exists() && ! confirm(\r
"Overwrite " + midi_file.getName() + " ?\n"\r
+ midi_file.getName() + " を上書きしてよろしいですか?"\r
}\r
);\r
delete_sequence_button = new JButton("Delete", delete_icon);\r
- delete_sequence_button.setMargin(zero_insets);\r
+ delete_sequence_button.setMargin(ZERO_INSETS);\r
delete_sequence_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
if(\r
- file_chooser != null &&\r
- seqListModel.getSequenceModel(seq_selection_model).isModified() &&\r
- ! confirm(\r
- "Selected MIDI sequence not saved - delete it ?\n" +\r
- "選択したMIDIシーケンスは保存されていませんが、削除しますか?"\r
- )\r
- ) return;\r
- seqListModel.removeSequence(seq_selection_model);\r
- total_time_label.setText( seqListModel.getTotalLength() );\r
+ fileChooser != null &&\r
+ seqListModel.getSequenceModel(seqSelectionModel).isModified() &&\r
+ ! confirm(\r
+ "Selected MIDI sequence not saved - delete it ?\n" +\r
+ "選択したMIDIシーケンスは保存されていませんが、削除しますか?"\r
+ )\r
+ ) return;\r
+ seqListModel.removeSequence(seqSelectionModel);\r
+ totalTimeLabel.setText( seqListModel.getTotalLength() );\r
}\r
}\r
);\r
//\r
tracks_label = new JLabel("Tracks");\r
add_track_button = new JButton("New");\r
- add_track_button.setMargin(zero_insets);\r
+ add_track_button.setMargin(ZERO_INSETS);\r
add_track_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
- seqListModel.getSequenceModel(seq_selection_model).createTrack();\r
- int n_tracks = seqListModel.getSequenceModel(seq_selection_model).getRowCount();\r
+ seqListModel.getSequenceModel(seqSelectionModel).createTrack();\r
+ int n_tracks = seqListModel.getSequenceModel(seqSelectionModel).getRowCount();\r
if( n_tracks > 0 ) {\r
// Select a created track\r
track_selection_model.setSelectionInterval(\r
n_tracks - 1, n_tracks - 1\r
);\r
}\r
- seqListModel.fireSequenceChanged(seq_selection_model);\r
+ seqListModel.fireSequenceChanged(seqSelectionModel);\r
}\r
}\r
);\r
remove_track_button = new JButton("Delete", delete_icon);\r
- remove_track_button.setMargin(zero_insets);\r
+ remove_track_button.setMargin(ZERO_INSETS);\r
remove_track_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
"Do you want to delete selected track ?\n選択したトラックを削除しますか?"\r
)) return;\r
seqListModel.getSequenceModel(\r
- seq_selection_model\r
+ seqSelectionModel\r
).deleteTracks( track_selection_model );\r
- seqListModel.fireSequenceChanged(seq_selection_model);\r
+ seqListModel.fireSequenceChanged(seqSelectionModel);\r
}\r
}\r
);\r
//\r
event_cell_editor = new MidiEventCellEditor();\r
add_event_button = new JButton(event_cell_editor.query_add_event_action);\r
- add_event_button.setMargin(zero_insets);\r
+ add_event_button.setMargin(ZERO_INSETS);\r
jump_event_button = new JButton(event_cell_editor.query_jump_event_action);\r
- jump_event_button.setMargin(zero_insets);\r
+ jump_event_button.setMargin(ZERO_INSETS);\r
paste_event_button = new JButton(event_cell_editor.query_paste_event_action);\r
- paste_event_button.setMargin(zero_insets);\r
+ paste_event_button.setMargin(ZERO_INSETS);\r
remove_event_button = new JButton("Delete", delete_icon);\r
- remove_event_button.setMargin(zero_insets);\r
+ remove_event_button.setMargin(ZERO_INSETS);\r
remove_event_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
if( ! confirm(\r
"Do you want to delete selected event ?\n選択したMIDIイベントを削除しますか?"\r
)) return;\r
- ((MidiTrackModel)event_table_view.getModel()).removeMidiEvents( event_selection_model );\r
- seqListModel.fireSequenceChanged(seq_selection_model);\r
+ ((MidiTrackTableModel)event_table_view.getModel()).removeMidiEvents( event_selection_model );\r
+ seqListModel.fireSequenceChanged(seqSelectionModel);\r
}\r
}\r
);\r
cut_event_button = new JButton("Cut");\r
- cut_event_button.setMargin(zero_insets);\r
+ cut_event_button.setMargin(ZERO_INSETS);\r
cut_event_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
if( ! confirm(\r
"Do you want to cut selected event ?\n選択したMIDIイベントを切り取りますか?"\r
)) return;\r
- MidiTrackModel track_model = (MidiTrackModel)event_table_view.getModel();\r
+ MidiTrackTableModel track_model = (MidiTrackTableModel)event_table_view.getModel();\r
copied_events = track_model.getMidiEvents( event_selection_model );\r
copied_events_PPQ = seqListModel.getSequenceModel(\r
- seq_selection_model\r
+ seqSelectionModel\r
).getSequence().getResolution();\r
track_model.removeMidiEvents( copied_events );\r
- seqListModel.fireSequenceChanged(seq_selection_model);\r
+ seqListModel.fireSequenceChanged(seqSelectionModel);\r
}\r
}\r
);\r
copy_event_button = new JButton("Copy");\r
- copy_event_button.setMargin(zero_insets);\r
+ copy_event_button.setMargin(ZERO_INSETS);\r
copy_event_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
- copied_events = ((MidiTrackModel)event_table_view.getModel()).getMidiEvents(\r
+ copied_events = ((MidiTrackTableModel)event_table_view.getModel()).getMidiEvents(\r
event_selection_model\r
);\r
copied_events_PPQ = seqListModel.getSequenceModel(\r
- seq_selection_model\r
+ seqSelectionModel\r
).getSequence().getResolution();\r
updateButtonStatus();\r
}\r
//\r
// Tables\r
//\r
- MidiSequenceModel empty_track_table_model = new MidiSequenceModel(\r
- seqListModel = new SequenceListModel(deviceManager)\r
+ MidiSequenceTableModel empty_track_table_model = new MidiSequenceTableModel(\r
+ seqListModel = new SequenceListTableModel(deviceManager)\r
);\r
sequence_table_view = new JTable( seqListModel );\r
track_table_view = new JTable( empty_track_table_model );\r
- event_table_view = new JTable( new MidiTrackModel() );\r
+ event_table_view = new JTable( new MidiTrackTableModel() );\r
//\r
seqListModel.sizeColumnWidthToFit( sequence_table_view );\r
//\r
TableColumnModel track_column_model = track_table_view.getColumnModel();\r
empty_track_table_model.sizeColumnWidthToFit(track_column_model);\r
//\r
- seq_selection_model = sequence_table_view.getSelectionModel();\r
- seq_selection_model.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );\r
- seq_selection_model.addListSelectionListener(\r
+ seqSelectionModel = sequence_table_view.getSelectionModel();\r
+ seqSelectionModel.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );\r
+ seqSelectionModel.addListSelectionListener(\r
new ListSelectionListener() {\r
public void valueChanged(ListSelectionEvent e) {\r
if( e.getValueIsAdjusting() ) return;\r
scrollable_event_table_view\r
= new JScrollPane(event_table_view);\r
\r
- base64_dialog = new Base64Dialog(this);\r
- if( base64_dialog.isBase64Available() ) {\r
+ if( base64Dialog.isBase64Available() ) {\r
base64_encode_button = new JButton( "Base64 Encode" );\r
- base64_encode_button.setMargin(zero_insets);\r
+ base64_encode_button.setMargin(ZERO_INSETS);\r
base64_encode_button.addActionListener(\r
new ActionListener() {\r
public void actionPerformed(ActionEvent e) {\r
- MidiSequenceModel seq_model =\r
- seqListModel.getSequenceModel(seq_selection_model);\r
- base64_dialog.setMIDIData(\r
- seq_model.getMIDIdata(), seq_model.getFilename()\r
- );\r
- base64_dialog.setVisible(true);\r
+ MidiSequenceTableModel seq_model =\r
+ seqListModel.getSequenceModel(seqSelectionModel);\r
+ base64Dialog.setMIDIData(\r
+ seq_model.getMIDIdata(), seq_model.getFilename()\r
+ );\r
+ base64Dialog.setVisible(true);\r
}\r
}\r
);\r
}\r
- new_seq_dialog = new NewSequenceDialog(this);\r
- new_seq_dialog.setChannels( midiDevice.getChannels() );\r
+ newSequenceDialog = new NewSequenceDialog(this);\r
+ newSequenceDialog.setChannels(virtualMidiDevice.getChannels());\r
\r
JPanel button_panel = new JPanel();\r
button_panel.setLayout( new BoxLayout( button_panel, BoxLayout.LINE_AXIS ) );\r
- button_panel.add( total_time_label );\r
+ button_panel.add( totalTimeLabel );\r
button_panel.add( Box.createRigidArea(new Dimension(10, 0)) );\r
button_panel.add( add_new_sequence_button );\r
button_panel.add( Box.createRigidArea(new Dimension(5, 0)) );\r
playlist_panel.add( Box.createRigidArea(new Dimension(0, 10)) );\r
\r
sequenceSelectionChanged();\r
- total_time_label.setText( seqListModel.getTotalLength() );\r
+ totalTimeLabel.setText( seqListModel.getTotalLength() );\r
\r
try {\r
- file_chooser = new JFileChooser();\r
+ fileChooser = new JFileChooser();\r
FileNameExtensionFilter filter = new FileNameExtensionFilter(\r
- "MIDI sequence (*.mid)", "mid"\r
- );\r
- file_chooser.setFileFilter(filter);\r
+ "MIDI sequence (*.mid)", "mid"\r
+ );\r
+ fileChooser.setFileFilter(filter);\r
}\r
catch( ExceptionInInitializerError e ) {\r
- file_chooser = null;\r
+ fileChooser = null;\r
}\r
catch( NoClassDefFoundError e ) {\r
- file_chooser = null;\r
+ fileChooser = null;\r
}\r
catch( AccessControlException e ) {\r
- file_chooser = null;\r
+ fileChooser = null;\r
}\r
- if( file_chooser == null ) {\r
+ if( fileChooser == null ) {\r
// Applet cannot access local files\r
add_midi_file_button.setVisible(false);\r
save_midi_file_button.setVisible(false);\r
cp.add(Box.createVerticalStrut(2));\r
cp.add(sequence_split_pane);\r
//\r
- seq_selection_model.setSelectionInterval(0,0);\r
+ seqSelectionModel.setSelectionInterval(0,0);\r
updateButtonStatus();\r
}\r
public void dragEnter(DropTargetDragEvent event) {\r
Object src = e.getSource();\r
if( src == track_selection_model ) {\r
if(\r
- seqListModel.getSequenceModel(seq_selection_model) == null\r
+ seqListModel.getSequenceModel(seqSelectionModel) == null\r
||\r
track_selection_model.isSelectionEmpty()\r
) {\r
midi_events_label.setText("MIDI Events (No track selected)");\r
- event_table_view.setModel(new MidiTrackModel());\r
+ event_table_view.setModel(new MidiTrackTableModel());\r
}\r
else {\r
int sel_index = track_selection_model.getMinSelectionIndex();\r
- MidiTrackModel track_model\r
- = seqListModel.getSequenceModel(seq_selection_model).getTrackModel(sel_index);\r
+ MidiTrackTableModel track_model\r
+ = seqListModel.getSequenceModel(seqSelectionModel).getTrackModel(sel_index);\r
if( track_model == null ) {\r
midi_events_label.setText("MIDI Events (No track selected)");\r
- event_table_view.setModel(new MidiTrackModel());\r
+ event_table_view.setModel(new MidiTrackTableModel());\r
}\r
else {\r
midi_events_label.setText(\r
event_table_view.setModel(track_model);\r
TableColumnModel tcm = event_table_view.getColumnModel();\r
track_model.sizeColumnWidthToFit(tcm);\r
- tcm.getColumn( MidiTrackModel.COLUMN_MESSAGE ).setCellEditor(event_cell_editor);\r
+ tcm.getColumn( MidiTrackTableModel.COLUMN_MESSAGE ).setCellEditor(event_cell_editor);\r
}\r
}\r
updateButtonStatus();\r
}\r
else if( src == event_selection_model ) {\r
if( ! event_selection_model.isSelectionEmpty() ) {\r
- MidiTrackModel track_model\r
- = (MidiTrackModel)event_table_view.getModel();\r
+ MidiTrackTableModel track_model\r
+ = (MidiTrackTableModel)event_table_view.getModel();\r
int min_index = event_selection_model.getMinSelectionIndex();\r
if( track_model.hasTrack() ) {\r
MidiEvent midi_event = track_model.getMidiEvent(min_index);\r
int cmd = sm.getCommand();\r
if( cmd == 0x80 || cmd == 0x90 || cmd == 0xA0 ) {\r
// ノート番号を持つ場合、音を鳴らす。\r
- MidiChannel out_midi_channels[] = midiDevice.getChannels();\r
+ MidiChannel out_midi_channels[] = virtualMidiDevice.getChannels();\r
int ch = sm.getChannel();\r
int note = sm.getData1();\r
int vel = sm.getData2();\r
JOptionPane.WARNING_MESSAGE\r
) == JOptionPane.YES_OPTION ;\r
}\r
- public void setVisible(boolean is_to_visible) {\r
- if( is_to_visible && isVisible() ) toFront();\r
- else super.setVisible(is_to_visible);\r
+ @Override\r
+ public void setVisible(boolean isToVisible) {\r
+ if( isToVisible && isVisible() )\r
+ toFront();\r
+ else\r
+ super.setVisible(isToVisible);\r
+ }\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ setVisible(true);\r
}\r
public void sequenceSelectionChanged() {\r
- MidiSequenceModel seq_model\r
- = seqListModel.getSequenceModel(seq_selection_model);\r
+ MidiSequenceTableModel seq_model\r
+ = seqListModel.getSequenceModel(seqSelectionModel);\r
jump_sequence_button.setEnabled( seq_model != null );\r
save_midi_file_button.setEnabled( seq_model != null );\r
add_track_button.setEnabled( seq_model != null );\r
base64_encode_button.setEnabled( seq_model != null );\r
\r
if( seq_model != null ) {\r
- int sel_index = seq_selection_model.getMinSelectionIndex();\r
+ int sel_index = seqSelectionModel.getMinSelectionIndex();\r
delete_sequence_button.setEnabled(true);\r
track_table_view.setModel(seq_model);\r
TableColumnModel tcm = track_table_view.getColumnModel();\r
seq_model.sizeColumnWidthToFit(tcm);\r
- tcm.getColumn(MidiSequenceModel.COLUMN_RECORD_CHANNEL).setCellEditor(\r
+ tcm.getColumn(MidiSequenceTableModel.COLUMN_RECORD_CHANNEL).setCellEditor(\r
seq_model.new RecordChannelCellEditor()\r
);\r
track_selection_model.setSelectionInterval(0,0);\r
}\r
else {\r
delete_sequence_button.setEnabled(false);\r
- track_table_view.setModel(new MidiSequenceModel(seqListModel));\r
+ track_table_view.setModel(new MidiSequenceTableModel(seqListModel));\r
tracks_label.setText("Tracks (No MIDI file selected)");\r
}\r
updateButtonStatus();\r
boolean is_track_selected = (\r
! track_selection_model.isSelectionEmpty()\r
&&\r
- seqListModel.getSequenceModel(seq_selection_model) != null\r
+ seqListModel.getSequenceModel(seqSelectionModel) != null\r
&&\r
- seqListModel.getSequenceModel(seq_selection_model).getRowCount() > 0\r
+ seqListModel.getSequenceModel(seqSelectionModel).getRowCount() > 0\r
);\r
//\r
// Track list\r
remove_track_button.setEnabled( is_track_selected );\r
//\r
TableModel tm = event_table_view.getModel();\r
- if( ! (tm instanceof MidiTrackModel) ) return;\r
+ if( ! (tm instanceof MidiTrackTableModel) ) return;\r
//\r
- MidiTrackModel track_model = (MidiTrackModel)tm;\r
+ MidiTrackTableModel track_model = (MidiTrackTableModel)tm;\r
jump_sequence_button.setEnabled(\r
track_model != null && track_model.getRowCount() > 0\r
);\r
);\r
}\r
public String getMIDIdataBase64() {\r
- base64_dialog.setMIDIData(\r
- deviceManager.timeRangeModel.getSequenceModel().getMIDIdata()\r
- );\r
- return base64_dialog.getBase64Data();\r
+ base64Dialog.setMIDIData(\r
+ deviceManager.timeRangeModel.getSequenceTableModel().getMIDIdata()\r
+ );\r
+ return base64Dialog.getBase64Data();\r
}\r
public int addSequence() {\r
- return addSequence(new_seq_dialog.getMidiSequence());\r
+ return addSequence(newSequenceDialog.getMidiSequence());\r
}\r
public int addSequence(Sequence seq) {\r
- int last_index = seqListModel.addSequence(seq);\r
- total_time_label.setText( seqListModel.getTotalLength() );\r
+ int lastIndex = seqListModel.addSequence(seq);\r
+ totalTimeLabel.setText( seqListModel.getTotalLength() );\r
if( ! deviceManager.getSequencer().isRunning() ) {\r
- loadAndPlay(last_index);\r
+ loadAndPlay(lastIndex);\r
}\r
- return last_index;\r
+ return lastIndex;\r
}\r
public int addSequenceFromBase64Text(String base64_encoded_text, String filename) {\r
- base64_dialog.setBase64Data( base64_encoded_text );\r
- return addSequenceFromMidiData( base64_dialog.getMIDIData(), filename );\r
+ base64Dialog.setBase64Data( base64_encoded_text );\r
+ return addSequenceFromMidiData( base64Dialog.getMIDIData(), filename );\r
}\r
public int addSequenceFromBase64Text() {\r
- return addSequenceFromMidiData( base64_dialog.getMIDIData(), null );\r
+ return addSequenceFromMidiData( base64Dialog.getMIDIData(), null );\r
}\r
public int addSequenceFromMidiData(byte[] data, String filename) {\r
int last_index;\r
showWarning("MIDI data invalid");\r
return -1;\r
}\r
- total_time_label.setText( seqListModel.getTotalLength() );\r
+ totalTimeLabel.setText( seqListModel.getTotalLength() );\r
return last_index;\r
}\r
public int addSequenceFromMidiFile(File midi_file) {\r
e.printStackTrace();\r
return -1;\r
}\r
- total_time_label.setText( seqListModel.getTotalLength() );\r
+ totalTimeLabel.setText( seqListModel.getTotalLength() );\r
return last_index;\r
}\r
public int addSequenceFromURL(String midi_file_url) {\r
e.printStackTrace();\r
return -1;\r
}\r
- total_time_label.setText( seqListModel.getTotalLength() );\r
+ totalTimeLabel.setText( seqListModel.getTotalLength() );\r
return last_index;\r
}\r
public void load(int index) {\r
deviceManager.timeRangeModel.start();\r
}\r
public void loadAndPlay() {\r
- loadAndPlay( seq_selection_model.getMinSelectionIndex() );\r
+ loadAndPlay( seqSelectionModel.getMinSelectionIndex() );\r
}\r
public void loadAndPlay( java.util.List<File> fileList ) {\r
int lastIndex = -1;\r
return seqListModel.isModified();\r
}\r
public boolean isRecordable() {\r
- MidiSequenceModel seq_model =\r
- seqListModel.getSequenceModel(seq_selection_model);\r
+ MidiSequenceTableModel seq_model =\r
+ seqListModel.getSequenceModel(seqSelectionModel);\r
return seq_model == null ? false : seq_model.isRecordable();\r
}\r
public void scrollToEventAt( long tick ) {\r
- MidiTrackModel track_model = (MidiTrackModel)event_table_view.getModel();\r
+ MidiTrackTableModel track_model = (MidiTrackTableModel)event_table_view.getModel();\r
scrollToEventAt( track_model.tickToIndex(tick) );\r
}\r
public void scrollToEventAt( int index ) {\r
}\r
}\r
\r
-/////////////////////////////////////////////////////////////\r
-//\r
-// プレイリスト\r
-//\r
-class SequenceListModel extends AbstractTableModel\r
-{\r
+/**\r
+ * プレイリスト(MIDIシーケンスリスト)のテーブルモデル\r
+ */\r
+class SequenceListTableModel extends AbstractTableModel implements ChangeListener {\r
public static final int COLUMN_SEQ_NUMBER = 0;\r
public static final int COLUMN_MODIFIED = 1;\r
public static final int COLUMN_DIVISION_TYPE = 2;\r
public static final int COLUMN_SEQ_LENGTH = 6;\r
public static final int COLUMN_FILENAME = 7;\r
public static final int COLUMN_SEQ_NAME = 8;\r
- static String column_titles[] = {\r
+ private static final String COLUMN_TITLES[] = {\r
"No.",\r
"Modified",\r
"DivType",\r
"Filename",\r
"Sequence name",\r
};\r
- static int column_width_ratios[] = {\r
+ private static final int COLUMN_WIDTH_RATIOS[] = {\r
2, 6, 6, 6, 6, 6, 6, 16, 40,\r
};\r
-\r
- private ArrayList<MidiSequenceModel>\r
- sequences = new ArrayList<MidiSequenceModel>();\r
-\r
- MidiDeviceManager device_manager;\r
- int second_position = 0;\r
-\r
- public SequenceListModel( MidiDeviceManager device_manager ) {\r
- (this.device_manager = device_manager).timeRangeModel.addChangeListener(\r
- new ChangeListener() {\r
- public void stateChanged(ChangeEvent e) {\r
- int sec_pos = SequenceListModel.this.device_manager.timeRangeModel.getValue() / 1000;\r
- if( second_position == sec_pos ) return;\r
- second_position = sec_pos;\r
- fireTableCellUpdated( getLoadedIndex(), COLUMN_SEQ_POSITION );\r
- }\r
- }\r
- );\r
- }\r
-\r
- // TableModel\r
- //\r
- public int getRowCount() { return sequences.size(); }\r
- public int getColumnCount() { return column_titles.length; }\r
- public String getColumnName(int column) {\r
- return column_titles[column];\r
+ private List<MidiSequenceTableModel> sequenceList = new ArrayList<>();\r
+ MidiDeviceModelList deviceManager;\r
+ /**\r
+ * 新しいプレイリストのテーブルモデルを構築します。\r
+ * @param deviceManager MIDIデバイスマネージャ\r
+ */\r
+ public SequenceListTableModel(MidiDeviceModelList deviceManager) {\r
+ (this.deviceManager = deviceManager).timeRangeModel.addChangeListener(this);\r
+ }\r
+ private int secondPosition = 0;\r
+ @Override\r
+ public void stateChanged(ChangeEvent e) {\r
+ int sec = deviceManager.timeRangeModel.getValue() / 1000;\r
+ if( secondPosition == sec )\r
+ return;\r
+ secondPosition = sec;\r
+ fireTableCellUpdated(getLoadedIndex(), COLUMN_SEQ_POSITION);\r
}\r
+ public int getRowCount() { return sequenceList.size(); }\r
+ public int getColumnCount() { return COLUMN_TITLES.length; }\r
+ public String getColumnName(int column) { return COLUMN_TITLES[column]; }\r
public Class<?> getColumnClass(int column) {\r
switch(column) {\r
case COLUMN_MODIFIED: return Boolean.class;\r
public Object getValueAt(int row, int column) {\r
switch(column) {\r
case COLUMN_SEQ_NUMBER: return row;\r
- case COLUMN_MODIFIED: return sequences.get(row).isModified();\r
+ case COLUMN_MODIFIED: return sequenceList.get(row).isModified();\r
case COLUMN_DIVISION_TYPE: {\r
- float div_type = sequences.get(row).getSequence().getDivisionType();\r
+ float div_type = sequenceList.get(row).getSequence().getDivisionType();\r
if( div_type == Sequence.PPQ ) return "PPQ";\r
else if( div_type == Sequence.SMPTE_24 ) return "SMPTE_24";\r
else if( div_type == Sequence.SMPTE_25 ) return "SMPTE_25";\r
else if( div_type == Sequence.SMPTE_30DROP ) return "SMPTE_30DROP";\r
else return "[Unknown]";\r
}\r
- case COLUMN_RESOLUTION: return sequences.get(row).getSequence().getResolution();\r
- case COLUMN_TRACKS: return sequences.get(row).getSequence().getTracks().length;\r
+ case COLUMN_RESOLUTION: return sequenceList.get(row).getSequence().getResolution();\r
+ case COLUMN_TRACKS: return sequenceList.get(row).getSequence().getTracks().length;\r
case COLUMN_SEQ_POSITION: {\r
- Sequence loaded_seq = device_manager.getSequencer().getSequence();\r
- if( loaded_seq != null && loaded_seq == sequences.get(row).getSequence() )\r
- return String.format( "%02d:%02d", second_position/60, second_position%60 );\r
+ Sequence loaded_seq = deviceManager.getSequencer().getSequence();\r
+ if( loaded_seq != null && loaded_seq == sequenceList.get(row).getSequence() )\r
+ return String.format("%02d:%02d", secondPosition/60, secondPosition%60);\r
else\r
return "";\r
}\r
case COLUMN_SEQ_LENGTH: {\r
- long usec = sequences.get(row).getSequence().getMicrosecondLength();\r
+ long usec = sequenceList.get(row).getSequence().getMicrosecondLength();\r
int sec = (int)( (usec < 0 ? usec += 0x100000000L : usec) / 1000L / 1000L );\r
return String.format( "%02d:%02d", sec/60, sec%60 );\r
}\r
case COLUMN_FILENAME: {\r
- String filename = sequences.get(row).getFilename();\r
+ String filename = sequenceList.get(row).getFilename();\r
return filename == null ? "" : filename;\r
}\r
case COLUMN_SEQ_NAME: {\r
- String seq_name = sequences.get(row).toString();\r
+ String seq_name = sequenceList.get(row).toString();\r
return seq_name == null ? "" : seq_name;\r
}\r
default: return "";\r
case COLUMN_FILENAME:\r
// ファイル名の変更\r
String filename = (String)val;\r
- sequences.get(row).setFilename(filename);\r
+ sequenceList.get(row).setFilename(filename);\r
fireTableCellUpdated(row, COLUMN_FILENAME);\r
break;\r
case COLUMN_SEQ_NAME:\r
// シーケンス名の設定または変更\r
- if( sequences.get(row).setName((String)val) )\r
+ if( sequenceList.get(row).setName((String)val) )\r
fireTableCellUpdated(row, COLUMN_MODIFIED);\r
break;\r
}\r
TableColumnModel column_model = table_view.getColumnModel();\r
int total_width = column_model.getTotalColumnWidth();\r
int i, total_width_ratio;\r
- for( i=0, total_width_ratio = 0; i<column_width_ratios.length; i++ ) {\r
- total_width_ratio += column_width_ratios[i];\r
+ for( i=0, total_width_ratio = 0; i<COLUMN_WIDTH_RATIOS.length; i++ ) {\r
+ total_width_ratio += COLUMN_WIDTH_RATIOS[i];\r
}\r
- for( i=0; i<column_width_ratios.length; i++ ) {\r
+ for( i=0; i<COLUMN_WIDTH_RATIOS.length; i++ ) {\r
column_model.getColumn(i).setPreferredWidth(\r
- total_width * column_width_ratios[i] / total_width_ratio\r
+ total_width * COLUMN_WIDTH_RATIOS[i] / total_width_ratio\r
);\r
}\r
}\r
public boolean isModified() {\r
- for( MidiSequenceModel seq_model : sequences ) {\r
+ for( MidiSequenceTableModel seq_model : sequenceList ) {\r
if( seq_model.isModified() ) return true;\r
}\r
return false;\r
int max_index = sel_model.getMaxSelectionIndex();\r
for( int i = min_index; i <= max_index; i++ ) {\r
if( sel_model.isSelectedIndex(i) ) {\r
- sequences.get(i).setModified(is_modified);\r
+ sequenceList.get(i).setModified(is_modified);\r
fireTableCellUpdated(i, COLUMN_MODIFIED);\r
}\r
}\r
}\r
- public MidiSequenceModel getSequenceModel(ListSelectionModel sel_model) {\r
+ public MidiSequenceTableModel getSequenceModel(ListSelectionModel sel_model) {\r
if( sel_model.isSelectionEmpty() ) return null;\r
int sel_index = sel_model.getMinSelectionIndex();\r
- if( sel_index >= sequences.size() ) return null;\r
- return sequences.get(sel_index);\r
+ if( sel_index >= sequenceList.size() ) return null;\r
+ return sequenceList.get(sel_index);\r
}\r
public void fireSequenceChanged( ListSelectionModel sel_model ) {\r
if( sel_model.isSelectionEmpty() ) return;\r
sel_model.getMaxSelectionIndex()\r
);\r
}\r
- public void fireSequenceChanged( MidiSequenceModel seq_model ) {\r
- for( int index=0; index<sequences.size(); index++ )\r
- if( sequences.get(index) == seq_model )\r
+ public void fireSequenceChanged( MidiSequenceTableModel seq_model ) {\r
+ for( int index=0; index<sequenceList.size(); index++ )\r
+ if( sequenceList.get(index) == seq_model )\r
fireSequenceChanged(index,index);\r
}\r
public void fireSequenceChanged( int min_index, int max_index ) {\r
for( int index = min_index; index <= max_index; index++ ) {\r
- MidiSequenceModel seq_model = sequences.get(index);\r
+ MidiSequenceTableModel seq_model = sequenceList.get(index);\r
seq_model.setModified(true);\r
- if( device_manager.getSequencer().getSequence() == seq_model.getSequence() ) {\r
+ if( deviceManager.getSequencer().getSequence() == seq_model.getSequence() ) {\r
// シーケンサーに対して、同じシーケンスを再度セットする。\r
// (これをやらないと更新が反映されないため)\r
- device_manager.timeRangeModel.setSequenceModel(seq_model);\r
+ deviceManager.timeRangeModel.setSequenceModel(seq_model);\r
}\r
}\r
fireTableRowsUpdated( min_index, max_index );\r
Sequence seq = (new Music.ChordProgression()).toMidiSequence();\r
return seq == null ? -1 : addSequence(seq,null);\r
}\r
- public int addSequence( Sequence seq ) {\r
- return addSequence( seq, "" );\r
- }\r
- public int addSequence( Sequence seq, String filename ) {\r
- MidiSequenceModel seq_model = new MidiSequenceModel(this);\r
- seq_model.setSequence(seq);\r
- seq_model.setFilename(filename);\r
- sequences.add(seq_model);\r
- int last_index = sequences.size() - 1;\r
- fireTableRowsInserted( last_index, last_index );\r
- return last_index;\r
- }\r
- public int addSequence( byte[] midiData, String filename )\r
- throws InvalidMidiDataException\r
- {\r
- return ( midiData == null ) ?\r
- addSequence() :\r
- addSequence( new ByteArrayInputStream(midiData), filename ) ;\r
- }\r
- public int addSequence( File midi_file )\r
- throws InvalidMidiDataException, FileNotFoundException\r
- {\r
- FileInputStream fis = new FileInputStream(midi_file);\r
- int retval = addSequence( fis, midi_file.getName() );\r
+ public int addSequence(Sequence seq) {\r
+ return addSequence(seq, "");\r
+ }\r
+ public int addSequence(Sequence seq, String filename) {\r
+ MidiSequenceTableModel seqModel = new MidiSequenceTableModel(this);\r
+ seqModel.setSequence(seq);\r
+ seqModel.setFilename(filename);\r
+ sequenceList.add(seqModel);\r
+ int lastIndex = sequenceList.size() - 1;\r
+ fireTableRowsInserted(lastIndex, lastIndex);\r
+ return lastIndex;\r
+ }\r
+ public int addSequence(byte[] midiData, String filename) throws InvalidMidiDataException {\r
+ return (midiData == null) ? addSequence() : addSequence(new ByteArrayInputStream(midiData), filename);\r
+ }\r
+ public int addSequence(File midiFile) throws InvalidMidiDataException, FileNotFoundException {\r
+ FileInputStream fis = new FileInputStream(midiFile);\r
+ int retval = addSequence(fis, midiFile.getName());\r
try {\r
fis.close();\r
} catch( IOException ex ) {\r
ex.printStackTrace();\r
}\r
return retval;\r
- }\r
- public int addSequence( InputStream in, String filename )\r
- throws InvalidMidiDataException\r
- {\r
- if( in == null ) return addSequence();\r
+ }\r
+ public int addSequence(InputStream in, String filename) throws InvalidMidiDataException {\r
+ if(in == null) return addSequence();\r
Sequence seq;\r
try {\r
seq = MidiSystem.getSequence(in);\r
return -1;\r
}\r
return addSequence( seq, filename );\r
- }\r
- public int addSequence( String midi_file_url )\r
- throws InvalidMidiDataException, AccessControlException\r
- {\r
- URL url = toURL( midi_file_url );\r
+ }\r
+ public int addSequence(String midiFileUrl) throws InvalidMidiDataException, AccessControlException {\r
+ URL url = toURL(midiFileUrl);\r
if( url == null ) {\r
return -1;\r
}\r
} catch( AccessControlException e ) {\r
throw e;\r
}\r
- return addSequence( seq, url.getFile().replaceFirst("^.*/","") );\r
- }\r
+ return addSequence(seq, url.getFile().replaceFirst("^.*/",""));\r
+ }\r
public void removeSequence( ListSelectionModel sel_model ) {\r
if( sel_model.isSelectionEmpty() ) return;\r
int sel_index = sel_model.getMinSelectionIndex();\r
- if( sequences.get(sel_index) == device_manager.timeRangeModel.getSequenceModel() )\r
- device_manager.timeRangeModel.setSequenceModel(null);\r
- sequences.remove(sel_index);\r
+ if( sequenceList.get(sel_index) == deviceManager.timeRangeModel.getSequenceTableModel() )\r
+ deviceManager.timeRangeModel.setSequenceModel(null);\r
+ sequenceList.remove(sel_index);\r
fireTableRowsDeleted( sel_index, sel_index );\r
}\r
public void loadToSequencer( int index ) {\r
int loaded_index = getLoadedIndex();\r
if( loaded_index == index ) return;\r
- MidiSequenceModel seq_model = sequences.get(index);\r
- device_manager.timeRangeModel.setSequenceModel(seq_model);\r
+ MidiSequenceTableModel seq_model = sequenceList.get(index);\r
+ deviceManager.timeRangeModel.setSequenceModel(seq_model);\r
seq_model.fireTableDataChanged();\r
fireTableCellUpdated( loaded_index, COLUMN_SEQ_POSITION );\r
fireTableCellUpdated( index, COLUMN_SEQ_POSITION );\r
}\r
public int getLoadedIndex() {\r
- MidiSequenceModel seq_model = device_manager.timeRangeModel.getSequenceModel();\r
- for( int i=0; i<sequences.size(); i++ )\r
- if( sequences.get(i) == seq_model ) return i;\r
+ MidiSequenceTableModel seq_model = deviceManager.timeRangeModel.getSequenceTableModel();\r
+ for( int i=0; i<sequenceList.size(); i++ )\r
+ if( sequenceList.get(i) == seq_model ) return i;\r
return -1;\r
}\r
public boolean loadNext( int offset ) {\r
int loaded_index = getLoadedIndex();\r
int index = (loaded_index < 0 ? 0 : loaded_index + offset);\r
- if( index < 0 || index >= sequences.size() ) return false;\r
+ if( index < 0 || index >= sequenceList.size() ) return false;\r
loadToSequencer( index );\r
return true;\r
}\r
public int getTotalSeconds() {\r
int total_sec = 0;\r
long usec;\r
- for( MidiSequenceModel seq_model : sequences ) {\r
+ for( MidiSequenceTableModel seq_model : sequenceList ) {\r
usec = seq_model.getSequence().getMicrosecondLength();\r
total_sec += (int)( (usec < 0 ? usec += 0x100000000L : usec) / 1000L / 1000L );\r
}\r
int sec = getTotalSeconds();\r
return String.format( "MIDI file playlist - Total length = %02d:%02d", sec/60, sec%60 );\r
}\r
- //\r
- // 文字列を URL オブジェクトに変換\r
- //\r
- public URL toURL( String url_string ) {\r
- if( url_string == null || url_string.isEmpty() ) {\r
+ /**\r
+ * 文字列をURLオブジェクトに変換\r
+ * @param urlString URL文字列\r
+ * @return URLオブジェクト\r
+ */\r
+ private URL toURL(String urlString) {\r
+ if( urlString == null || urlString.isEmpty() ) {\r
return null;\r
}\r
URI uri = null;\r
URL url = null;\r
try {\r
- uri = new URI(url_string);\r
+ uri = new URI(urlString);\r
url = uri.toURL();\r
} catch( URISyntaxException e ) {\r
e.printStackTrace();\r
}\r
}\r
\r
-//////////////////////////////////////////////////////////\r
-//\r
-// Track List (MIDI Sequence) Model\r
-//\r
-//////////////////////////////////////////////////////////\r
-class MidiSequenceModel extends AbstractTableModel\r
+/**\r
+ * MIDIシーケンス(トラックリスト)を表すテーブルモデル\r
+ */\r
+class MidiSequenceTableModel extends AbstractTableModel\r
{\r
public static final int COLUMN_TRACK_NUMBER = 0;\r
public static final int COLUMN_EVENTS = 1;\r
public static final int COLUMN_RECORD_CHANNEL = 4;\r
public static final int COLUMN_CHANNEL = 5;\r
public static final int COLUMN_TRACK_NAME = 6;\r
- public static final String column_titles[] = {\r
+ public static final String columnTitles[] = {\r
"No.", "Events", "Mute", "Solo", "RecCh", "Ch", "Track name"\r
};\r
- public static final int column_width_ratios[] = {\r
+ public static final int columnWidthRatios[] = {\r
30, 60, 40, 40, 60, 40, 200\r
};\r
- private SequenceListModel seq_list_model;\r
- private Sequence seq;\r
- private SequenceIndex seq_index;\r
+ private SequenceListTableModel sequenceListTableModel;\r
+ private Sequence sequence;\r
+ private SequenceTickIndex seqIndex;\r
private String filename = "";\r
- private boolean is_modified = false;\r
- private ArrayList<MidiTrackModel> track_models\r
- = new ArrayList<MidiTrackModel>();\r
+ private List<MidiTrackTableModel> trackModelList = new ArrayList<>();\r
\r
+ /**\r
+ * 記録するMIDIチャンネル\r
+ */\r
class RecordChannelCellEditor extends DefaultCellEditor {\r
public RecordChannelCellEditor() {\r
- super(new JComboBox<String>() {\r
- {\r
- addItem("OFF");\r
- for( int i=1; i <= MIDISpec.MAX_CHANNELS; i++ )\r
- addItem( String.format( "%d", i ) );\r
- addItem("ALL");\r
+ super(\r
+ new JComboBox<String>() {\r
+ {\r
+ addItem("OFF");\r
+ for( int i=1; i <= MIDISpec.MAX_CHANNELS; i++ )\r
+ addItem( String.format("%d", i) );\r
+ addItem("ALL");\r
+ }\r
}\r
- });\r
+ );\r
}\r
}\r
\r
- public MidiSequenceModel( SequenceListModel slm ) {\r
- seq_list_model = slm;\r
- }\r
- //\r
- // TableModel interface\r
- //\r
+ /**\r
+ * 新しい {@link MidiSequenceTableModel} を構築します。\r
+ * @param sequenceListTableModel プレイリスト\r
+ */\r
+ public MidiSequenceTableModel(SequenceListTableModel sequenceListTableModel) {\r
+ this.sequenceListTableModel = sequenceListTableModel;\r
+ }\r
+ @Override\r
public int getRowCount() {\r
- return seq == null ? 0 : seq.getTracks().length;\r
- }\r
- public int getColumnCount() {\r
- return column_titles.length;\r
- }\r
- public String getColumnName(int column) {\r
- return column_titles[column];\r
- }\r
+ return sequence == null ? 0 : sequence.getTracks().length;\r
+ }\r
+ @Override\r
+ public int getColumnCount() { return columnTitles.length; }\r
+ /**\r
+ * 列名を返します。\r
+ * @return 列名\r
+ */\r
+ @Override\r
+ public String getColumnName(int column) { return columnTitles[column]; }\r
+ /**\r
+ * 指定された列の型を返します。\r
+ * @return 指定された列の型\r
+ */\r
+ @Override\r
public Class<?> getColumnClass(int column) {\r
switch(column) {\r
case COLUMN_TRACK_NUMBER:\r
return Integer.class;\r
case COLUMN_MUTE:\r
case COLUMN_SOLO:\r
- return\r
- (seq == getSequencer().getSequence()) ?\r
- Boolean.class : String.class;\r
+ return (sequence == getSequencer().getSequence()) ? Boolean.class : String.class;\r
case COLUMN_RECORD_CHANNEL:\r
case COLUMN_CHANNEL:\r
case COLUMN_TRACK_NAME:\r
return String.class;\r
- default: return super.getColumnClass(column);\r
+ default:\r
+ return super.getColumnClass(column);\r
}\r
}\r
+ @Override\r
public Object getValueAt(int row, int column) {\r
switch(column) {\r
case COLUMN_TRACK_NUMBER: return row;\r
case COLUMN_EVENTS:\r
- return seq.getTracks()[row].size();\r
+ return sequence.getTracks()[row].size();\r
case COLUMN_MUTE:\r
- return (seq == getSequencer().getSequence()) ?\r
+ return (sequence == getSequencer().getSequence()) ?\r
getSequencer().getTrackMute(row) : "";\r
case COLUMN_SOLO:\r
- return (seq == getSequencer().getSequence()) ?\r
+ return (sequence == getSequencer().getSequence()) ?\r
getSequencer().getTrackSolo(row) : "";\r
case COLUMN_RECORD_CHANNEL:\r
- return (seq == getSequencer().getSequence()) ?\r
- track_models.get(row).getRecordingChannel() : "";\r
+ return (sequence == getSequencer().getSequence()) ?\r
+ trackModelList.get(row).getRecordingChannel() : "";\r
case COLUMN_CHANNEL: {\r
- int ch = track_models.get(row).getChannel();\r
+ int ch = trackModelList.get(row).getChannel();\r
return ch < 0 ? "" : ch + 1 ;\r
}\r
case COLUMN_TRACK_NAME:\r
- return track_models.get(row).toString();\r
+ return trackModelList.get(row).toString();\r
default: return "";\r
}\r
}\r
+ /**\r
+ * セルが編集可能かどうかを返します。\r
+ */\r
+ @Override\r
public boolean isCellEditable( int row, int column ) {\r
switch(column) {\r
case COLUMN_MUTE:\r
case COLUMN_SOLO:\r
case COLUMN_RECORD_CHANNEL:\r
- return seq == getSequencer().getSequence();\r
+ return sequence == getSequencer().getSequence();\r
case COLUMN_CHANNEL:\r
case COLUMN_TRACK_NAME:\r
return true;\r
return false;\r
}\r
}\r
+ /**\r
+ * 列の値を設定します。\r
+ */\r
+ @Override\r
public void setValueAt(Object val, int row, int column) {\r
switch(column) {\r
case COLUMN_MUTE:\r
getSequencer().setTrackSolo( row, ((Boolean)val).booleanValue() );\r
break;\r
case COLUMN_RECORD_CHANNEL:\r
- track_models.get(row).setRecordingChannel((String)val);\r
+ trackModelList.get(row).setRecordingChannel((String)val);\r
break;\r
case COLUMN_CHANNEL: {\r
Integer ch;\r
}\r
if( --ch <= 0 || ch > MIDISpec.MAX_CHANNELS )\r
break;\r
- MidiTrackModel track_model = track_models.get(row);\r
+ MidiTrackTableModel track_model = trackModelList.get(row);\r
int old_ch = track_model.getChannel();\r
if( ch == old_ch ) break;\r
track_model.setChannel(ch);\r
break;\r
}\r
case COLUMN_TRACK_NAME:\r
- track_models.get(row).setString((String)val);\r
+ trackModelList.get(row).setString((String)val);\r
break;\r
}\r
fireTableCellUpdated(row,column);\r
}\r
- // Methods (Table view)\r
- //\r
- public void sizeColumnWidthToFit( TableColumnModel column_model ) {\r
- int total_width = column_model.getTotalColumnWidth();\r
- int i, total_width_ratio = 0;\r
- for( i=0; i<column_width_ratios.length; i++ ) {\r
- total_width_ratio += column_width_ratios[i];\r
- }\r
- for( i=0; i<column_width_ratios.length; i++ ) {\r
- column_model.getColumn(i).setPreferredWidth(\r
- total_width * column_width_ratios[i] / total_width_ratio\r
- );\r
+ /**\r
+ * 列に合わせて幅を調整します。\r
+ * @param columnModel テーブル列モデル\r
+ */\r
+ public void sizeColumnWidthToFit(TableColumnModel columnModel) {\r
+ int totalWidth = columnModel.getTotalColumnWidth();\r
+ int totalWidthRatio = 0;\r
+ for( int i=0; i<columnWidthRatios.length; i++ ) {\r
+ totalWidthRatio += columnWidthRatios[i];\r
+ }\r
+ for( int i=0; i<columnWidthRatios.length; i++ ) {\r
+ columnModel.getColumn(i).setPreferredWidth(\r
+ totalWidth * columnWidthRatios[i] / totalWidthRatio\r
+ );\r
}\r
}\r
- // Methods (sequence)\r
- //\r
- public Sequence getSequence() { return this.seq; }\r
- public void setSequence( Sequence seq ) {\r
- //\r
+ /**\r
+ * MIDIシーケンスを返します。\r
+ * @return MIDIシーケンス\r
+ */\r
+ public Sequence getSequence() { return sequence; }\r
+ /**\r
+ * MIDIシーケンスを設定します。\r
+ * @param sequence MIDIシーケンス\r
+ */\r
+ public void setSequence(Sequence sequence) {\r
getSequencer().recordDisable(null); // The "null" means all tracks\r
- //\r
- this.seq = seq;\r
- int old_size = track_models.size();\r
- if( old_size > 0 ) {\r
- track_models.clear();\r
- fireTableRowsDeleted(0, old_size-1);\r
+ this.sequence = sequence;\r
+ int oldSize = trackModelList.size();\r
+ if( oldSize > 0 ) {\r
+ trackModelList.clear();\r
+ fireTableRowsDeleted(0, oldSize-1);\r
}\r
- if( seq == null ) {\r
- seq_index = null;\r
+ if( sequence == null ) {\r
+ seqIndex = null;\r
}\r
else {\r
- seq_index = new SequenceIndex( seq );\r
- Track tklist[] = seq.getTracks();\r
+ seqIndex = new SequenceTickIndex(sequence);\r
+ Track tklist[] = sequence.getTracks();\r
for( Track tk : tklist )\r
- track_models.add( new MidiTrackModel( tk, this ) );\r
+ trackModelList.add( new MidiTrackTableModel( tk, this ) );\r
fireTableRowsInserted(0, tklist.length-1);\r
}\r
}\r
- public SequenceIndex getSequenceIndex() {\r
- return this.seq_index;\r
- }\r
- public void setModified(boolean is_modified) {\r
- this.is_modified = is_modified;\r
- }\r
- public boolean isModified() { return is_modified; }\r
- public void setFilename(String filename) {\r
- this.filename = filename;\r
- }\r
+ /**\r
+ * シーケンスtickインデックスを返します。\r
+ * @return シーケンスtickインデックス\r
+ */\r
+ public SequenceTickIndex getSequenceTickIndex() { return this.seqIndex; }\r
+ private boolean isModified = false;\r
+ /**\r
+ * 変更されたかどうかを設定します。\r
+ * @param isModified 変更されたときtrue\r
+ */\r
+ public void setModified(boolean isModified) {\r
+ this.isModified = isModified;\r
+ }\r
+ /**\r
+ * 変更されたかどうかを返します。\r
+ * @return 変更済みのときtrue\r
+ */\r
+ public boolean isModified() { return isModified; }\r
+ /**\r
+ * ファイル名を設定します。\r
+ * @param filename ファイル名\r
+ */\r
+ public void setFilename(String filename) { this.filename = filename; }\r
+ /**\r
+ * ファイル名を返します。\r
+ * @return ファイル名\r
+ */\r
public String getFilename() { return filename; }\r
+ @Override\r
public String toString() {\r
- return MIDISpec.getNameOf(seq);\r
+ return MIDISpec.getNameOf(sequence);\r
}\r
public boolean setName( String name ) {\r
if( name.equals(toString()) )\r
return false;\r
- if( ! MIDISpec.setNameOf(seq,name) )\r
+ if( ! MIDISpec.setNameOf(sequence,name) )\r
return false;\r
setModified(true);\r
fireTableDataChanged();\r
return true;\r
}\r
public byte[] getMIDIdata() {\r
- if( seq == null || seq.getTracks().length == 0 ) {\r
+ if( sequence == null || sequence.getTracks().length == 0 ) {\r
return null;\r
}\r
/*\r
*/\r
ByteArrayOutputStream out = new ByteArrayOutputStream();\r
try {\r
- MidiSystem.write(seq, 1, out);\r
+ MidiSystem.write(sequence, 1, out);\r
return out.toByteArray();\r
} catch ( IOException e ) {\r
e.printStackTrace();\r
}\r
}\r
public void fireTimeSignatureChanged() {\r
- seq_index = new SequenceIndex( seq );\r
+ seqIndex = new SequenceTickIndex( sequence );\r
}\r
public void fireTrackChanged( Track tk ) {\r
int row = getTrackRow(tk);\r
fireSequenceChanged();\r
}\r
public void fireSequenceChanged() {\r
- seq_list_model.fireSequenceChanged(this);\r
+ sequenceListTableModel.fireSequenceChanged(this);\r
}\r
- public MidiTrackModel getTrackModel( int index ) {\r
- Track tracks[] = seq.getTracks();\r
+ public MidiTrackTableModel getTrackModel( int index ) {\r
+ Track tracks[] = sequence.getTracks();\r
if( tracks.length == 0 ) return null;\r
Track tk = tracks[index];\r
- for( MidiTrackModel model : track_models )\r
+ for( MidiTrackTableModel model : trackModelList )\r
if( model.getTrack() == tk )\r
return model;\r
return null;\r
}\r
- public int getTrackRow( Track tk ) {\r
- Track tracks[] = seq.getTracks();\r
+ public int getTrackRow(Track tk) {\r
+ Track tracks[] = sequence.getTracks();\r
for( int i=0; i<tracks.length; i++ )\r
if( tracks[i] == tk )\r
return i;\r
return -1;\r
}\r
public void createTrack() {\r
- Track tk = seq.createTrack();\r
- track_models.add( new MidiTrackModel( tk, this ) );\r
- int last_row = seq.getTracks().length - 1;\r
+ Track tk = sequence.createTrack();\r
+ trackModelList.add( new MidiTrackTableModel( tk, this ) );\r
+ int last_row = sequence.getTracks().length - 1;\r
fireTableRowsInserted( last_row, last_row );\r
}\r
public void deleteTracks( ListSelectionModel selection_model ) {\r
return;\r
int min_sel_index = selection_model.getMinSelectionIndex();\r
int max_sel_index = selection_model.getMaxSelectionIndex();\r
- Track tklist[] = seq.getTracks();\r
+ Track tklist[] = sequence.getTracks();\r
for( int i = max_sel_index; i >= min_sel_index; i-- ) {\r
if( ! selection_model.isSelectedIndex(i) )\r
continue;\r
- seq.deleteTrack( tklist[i] );\r
- track_models.remove(i);\r
+ sequence.deleteTrack( tklist[i] );\r
+ trackModelList.remove(i);\r
}\r
fireTableRowsDeleted( min_sel_index, max_sel_index );\r
}\r
- //\r
- // Methods (sequencer)\r
- //\r
+ /**\r
+ * MIDIシーケンサを返します。\r
+ * @return MIDIシーケンサ\r
+ */\r
public Sequencer getSequencer() {\r
- return seq_list_model.device_manager.getSequencer();\r
+ return sequenceListTableModel.deviceManager.getSequencer();\r
}\r
+ /**\r
+ * 録音可能かどうかを返します。\r
+ * @return 録音可能であればtrue\r
+ */\r
public boolean isRecordable() {\r
- if( seq != getSequencer().getSequence() ) return false;\r
- int num_row = getRowCount();\r
- String s;\r
- for( int row=0; row<num_row; row++ ) {\r
- s = (String)getValueAt(\r
- row, COLUMN_RECORD_CHANNEL\r
- );\r
- if( s.equals("OFF") ) continue;\r
+ if( sequence != getSequencer().getSequence() )\r
+ return false;\r
+ int rowCount = getRowCount();\r
+ for( int row=0; row < rowCount; row++ ) {\r
+ if("OFF".equals(getValueAt(row, COLUMN_RECORD_CHANNEL)))\r
+ continue;\r
return true;\r
}\r
return false;\r
}\r
}\r
\r
-////////////////////////////////////////////////////////\r
-//\r
-// Event List (Track) Model\r
-//\r
-////////////////////////////////////////////////////////\r
-class MidiTrackModel extends AbstractTableModel\r
+/**\r
+ * MIDIトラック(MIDIイベントリスト)テーブルモデル\r
+ */\r
+class MidiTrackTableModel extends AbstractTableModel\r
{\r
public static final int COLUMN_EVENT_NUMBER = 0;\r
public static final int COLUMN_TICK_POSITION = 1;\r
public static final int COLUMN_BEAT_POSITION = 3;\r
public static final int COLUMN_EXTRA_TICK_POSITION = 4;\r
public static final int COLUMN_MESSAGE = 5;\r
- public static final String column_titles[] = {\r
+ public static final String COLUMN_TITLES[] = {\r
"No.", "TickPos.", "Measure", "Beat", "ExTick", "MIDI Message",\r
};\r
public static final int column_width_ratios[] = {\r
30, 40, 20,20,20, 280,\r
};\r
private Track track;\r
- private MidiSequenceModel parent_model;\r
- //\r
- // Constructor\r
- //\r
- public MidiTrackModel() { } // To create empty model\r
- public MidiTrackModel( MidiSequenceModel parent_model ) {\r
- this.parent_model = parent_model;\r
- }\r
- public MidiTrackModel( Track tk, MidiSequenceModel parent_model ) {\r
- this.track = tk;\r
- this.parent_model = parent_model;\r
- }\r
- // TableModel interface\r
- //\r
- public int getRowCount() {\r
- return track == null ? 0 : track.size();\r
- }\r
- public int getColumnCount() {\r
- return column_titles.length;\r
- }\r
- public String getColumnName(int column) {\r
- return column_titles[column];\r
- }\r
+ private MidiSequenceTableModel parent;\r
+ public MidiTrackTableModel() { } // To create empty model\r
+ public MidiTrackTableModel(MidiSequenceTableModel parent) {\r
+ this.parent = parent;\r
+ }\r
+ public MidiTrackTableModel(Track track, MidiSequenceTableModel parent) {\r
+ this.track = track;\r
+ this.parent = parent;\r
+ }\r
+ public int getRowCount() { return track == null ? 0 : track.size(); }\r
+ public int getColumnCount() { return COLUMN_TITLES.length; }\r
+ public String getColumnName(int column) { return COLUMN_TITLES[column]; }\r
public Class<?> getColumnClass(int column) {\r
switch(column) {\r
case COLUMN_EVENT_NUMBER:\r
return track.get(row).getTick();\r
\r
case COLUMN_MEASURE_POSITION:\r
- return parent_model.getSequenceIndex().tickToMeasure(\r
- track.get(row).getTick()\r
- ) + 1;\r
+ return parent.getSequenceTickIndex().tickToMeasure(track.get(row).getTick()) + 1;\r
\r
case COLUMN_BEAT_POSITION:\r
- parent_model.getSequenceIndex().tickToMeasure(\r
- track.get(row).getTick()\r
- );\r
- return parent_model.getSequenceIndex().last_beat + 1;\r
+ parent.getSequenceTickIndex().tickToMeasure(track.get(row).getTick());\r
+ return parent.getSequenceTickIndex().lastBeat + 1;\r
\r
case COLUMN_EXTRA_TICK_POSITION:\r
- parent_model.getSequenceIndex().tickToMeasure(\r
- track.get(row).getTick()\r
- );\r
- return parent_model.getSequenceIndex().last_extra_tick;\r
+ parent.getSequenceTickIndex().tickToMeasure(track.get(row).getTick());\r
+ return parent.getSequenceTickIndex().lastExtraTick;\r
\r
case COLUMN_MESSAGE:\r
- return msgToString(\r
- track.get(row).getMessage()\r
- );\r
+ return msgToString(track.get(row).getMessage());\r
+\r
default: return "";\r
}\r
}\r
tick = (Long)value;\r
break;\r
case COLUMN_MEASURE_POSITION:\r
- tick = parent_model.getSequenceIndex().measureToTick(\r
- (Integer)value - 1,\r
- (Integer)getValueAt( row, COLUMN_BEAT_POSITION ) - 1,\r
- (Integer)getValueAt( row, COLUMN_EXTRA_TICK_POSITION )\r
- );\r
+ tick = parent.getSequenceTickIndex().measureToTick(\r
+ (Integer)value - 1,\r
+ (Integer)getValueAt( row, COLUMN_BEAT_POSITION ) - 1,\r
+ (Integer)getValueAt( row, COLUMN_EXTRA_TICK_POSITION )\r
+ );\r
break;\r
case COLUMN_BEAT_POSITION:\r
- tick = parent_model.getSequenceIndex().measureToTick(\r
- (Integer)getValueAt( row, COLUMN_MEASURE_POSITION ) - 1,\r
- (Integer)value - 1,\r
- (Integer)getValueAt( row, COLUMN_EXTRA_TICK_POSITION )\r
- );\r
+ tick = parent.getSequenceTickIndex().measureToTick(\r
+ (Integer)getValueAt( row, COLUMN_MEASURE_POSITION ) - 1,\r
+ (Integer)value - 1,\r
+ (Integer)getValueAt( row, COLUMN_EXTRA_TICK_POSITION )\r
+ );\r
break;\r
case COLUMN_EXTRA_TICK_POSITION:\r
- tick = parent_model.getSequenceIndex().measureToTick(\r
- (Integer)getValueAt( row, COLUMN_MEASURE_POSITION ) - 1,\r
- (Integer)getValueAt( row, COLUMN_BEAT_POSITION ) - 1,\r
- (Integer)value\r
- );\r
+ tick = parent.getSequenceTickIndex().measureToTick(\r
+ (Integer)getValueAt( row, COLUMN_MEASURE_POSITION ) - 1,\r
+ (Integer)getValueAt( row, COLUMN_BEAT_POSITION ) - 1,\r
+ (Integer)value\r
+ );\r
break;\r
case COLUMN_MESSAGE:\r
return;\r
}\r
changeEventTick(row,tick);\r
}\r
-\r
- // Methods (Table view)\r
- //\r
public void sizeColumnWidthToFit( TableColumnModel column_model ) {\r
int total_width = column_model.getTotalColumnWidth();\r
int i, total_width_ratio = 0;\r
}\r
for( i=0; i<column_width_ratios.length; i++ ) {\r
column_model.getColumn(i).setPreferredWidth(\r
- total_width * column_width_ratios[i] / total_width_ratio\r
- );\r
+ total_width * column_width_ratios[i] / total_width_ratio\r
+ );\r
}\r
}\r
- // Methods\r
- //\r
- private boolean isRhythmPart(int ch) {\r
- return (ch == 9);\r
- }\r
- // トラックオブジェクトの取得\r
+ /**\r
+ * MIDIトラックを返します。\r
+ * @return MIDIトラック\r
+ */\r
public Track getTrack() { return track; }\r
- //\r
- // 文字列としてトラック名を返す\r
- public String toString() {\r
- return MIDISpec.getNameOf(track);\r
- }\r
- // トラック名をセットする\r
- public boolean setString( String name ) {\r
- if(\r
- name.equals(toString())\r
- ||\r
- ! MIDISpec.setNameOf( track, name )\r
- )\r
+ /**\r
+ * 文字列としてトラック名を返します。\r
+ */\r
+ @Override\r
+ public String toString() { return MIDISpec.getNameOf(track); }\r
+ /**\r
+ * トラック名を設定します。\r
+ * @param name トラック名\r
+ * @return 設定が行われたらtrue\r
+ */\r
+ public boolean setString(String name) {\r
+ if(name.equals(toString()) || ! MIDISpec.setNameOf(track, name))\r
return false;\r
- parent_model.setModified(true);\r
- parent_model.fireSequenceChanged();\r
+ parent.setModified(true);\r
+ parent.fireSequenceChanged();\r
fireTableDataChanged();\r
return true;\r
}\r
- //\r
- // 録音中の MIDI チャンネル\r
private String rec_ch = "OFF";\r
- public String getRecordingChannel() {\r
- return rec_ch;\r
- }\r
+ /**\r
+ * 録音中のMIDIチャンネルを返します。\r
+ * @return 録音中のMIDIチャンネル\r
+ */\r
+ public String getRecordingChannel() { return rec_ch; }\r
+ /**\r
+ * 録音中のMIDIチャンネルを設定します。\r
+ * @param ch_str 録音中のMIDIチャンネル\r
+ */\r
public void setRecordingChannel(String ch_str) {\r
- Sequencer sequencer = parent_model.getSequencer();\r
+ Sequencer sequencer = parent.getSequencer();\r
if( ch_str.equals("OFF") ) {\r
sequencer.recordDisable( track );\r
}\r
public void setChannel(int ch) {\r
// すべてのチャンネルメッセージに対して\r
// 同一のMIDIチャンネルをセットする\r
- MidiMessage msg;\r
- ShortMessage smsg;\r
- int index, track_size = track.size();\r
- for( index=0; index < track_size; index++ ) {\r
- msg = track.get(index).getMessage();\r
- if(\r
- ! (msg instanceof ShortMessage)\r
- ||\r
- ! MIDISpec.isChannelMessage(smsg = (ShortMessage)msg)\r
- ||\r
- smsg.getChannel() == ch\r
- )\r
+ int track_size = track.size();\r
+ for( int index=0; index < track_size; index++ ) {\r
+ MidiMessage msg = track.get(index).getMessage();\r
+ if( ! (msg instanceof ShortMessage) )\r
+ continue;\r
+ ShortMessage smsg = (ShortMessage)msg;\r
+ if( ! MIDISpec.isChannelMessage(smsg) )\r
+ continue;\r
+ if( smsg.getChannel() == ch )\r
continue;\r
try {\r
smsg.setMessage(\r
- smsg.getCommand(), ch,\r
- smsg.getData1(), smsg.getData2()\r
- );\r
+ smsg.getCommand(), ch,\r
+ smsg.getData1(), smsg.getData2()\r
+ );\r
}\r
catch( InvalidMidiDataException e ) {\r
e.printStackTrace();\r
}\r
- parent_model.setModified(true);\r
+ parent.setModified(true);\r
}\r
- parent_model.fireTrackChanged( track );\r
- parent_model.fireSequenceChanged();\r
+ parent.fireTrackChanged( track );\r
+ parent.fireSequenceChanged();\r
fireTableDataChanged();\r
}\r
- //\r
- // MIDI イベントの tick 位置変更\r
+ /**\r
+ * MIDIイベントのtick位置を変更します。\r
+ * @param row 行インデックス\r
+ * @param new_tick 新しいtick位置\r
+ */\r
public void changeEventTick(int row, long new_tick) {\r
MidiEvent old_midi_event = track.get(row);\r
if( old_midi_event.getTick() == new_tick ) {\r
track.remove(old_midi_event);\r
track.add(new_midi_event);\r
fireTableDataChanged();\r
- //\r
if( MIDISpec.isEOT(msg) ) {\r
// EOTの場所が変わると曲の長さが変わるので、親モデルへ通知する。\r
- parent_model.fireSequenceChanged();\r
+ parent.fireSequenceChanged();\r
}\r
}\r
- //\r
- // MIDI tick から位置を取得(バイナリーサーチ)\r
+ /**\r
+ * MIDI tick を行インデックスに変換します。\r
+ * 検索はバイナリーサーチで行われます。\r
+ * @param tick MIDI tick\r
+ * @return 行インデックス\r
+ */\r
public int tickToIndex( long tick ) {\r
- if( track == null ) return 0;\r
+ if( track == null )\r
+ return 0;\r
int min_index = 0;\r
int max_index = track.size() - 1;\r
long current_tick;\r
}\r
return (min_index + max_index) / 2;\r
}\r
- // NoteOn/NoteOff ペアの一方のインデックスから、\r
- // その相手を返す\r
+ /**\r
+ * NoteOn/NoteOff ペアの一方の行インデックスから、\r
+ * もう一方(ペアの相手)の行インデックスを返します。\r
+ * @param index 行インデックス\r
+ * @return ペアを構成する相手の行インデックス(ない場合は -1)\r
+ */\r
public int getIndexOfPartnerFor( int index ) {\r
- if( track == null || index >= track.size() ) return -1;\r
+ if( track == null || index >= track.size() )\r
+ return -1;\r
MidiMessage msg = track.get(index).getMessage();\r
if( ! (msg instanceof ShortMessage) ) return -1;\r
ShortMessage sm = (ShortMessage)msg;\r
// Not found\r
return -1;\r
}\r
- //\r
+ /**\r
+ * 指定のMIDIメッセージが拍子記号かどうか調べます。\r
+ * @param msg MIDIメッセージ\r
+ * @return 拍子記号のときtrue\r
+ */\r
public boolean isTimeSignature( MidiMessage msg ) {\r
- // 拍子記号のとき True を返す\r
- return\r
- (msg instanceof MetaMessage)\r
- &&\r
- ((MetaMessage)msg).getType() == 0x58;\r
- }\r
- public boolean isNote( int index ) { // Note On または Note Off のとき True を返す\r
+ return (msg instanceof MetaMessage) && ((MetaMessage)msg).getType() == 0x58;\r
+ }\r
+ /**\r
+ * ノートメッセージかどうか調べます。\r
+ * @param index 行インデックス\r
+ * @return Note On または Note Off のとき true\r
+ */\r
+ public boolean isNote(int index) {\r
MidiEvent midi_evt = getMidiEvent(index);\r
MidiMessage msg = midi_evt.getMessage();\r
if( ! (msg instanceof ShortMessage) ) return false;\r
return cmd == ShortMessage.NOTE_ON || cmd == ShortMessage.NOTE_OFF ;\r
}\r
public boolean hasTrack() { return track != null; }\r
- //\r
- // イベントの取得\r
- //\r
- public MidiEvent getMidiEvent( int index ) {\r
- return track.get(index);\r
- }\r
- public MidiEvent[] getMidiEvents( ListSelectionModel sel_model ) {\r
+ /**\r
+ * 指定の行インデックスのMIDIイベントを返します。\r
+ * @param index 行インデックス\r
+ * @return MIDIイベント\r
+ */\r
+ public MidiEvent getMidiEvent(int index) { return track.get(index); }\r
+ /**\r
+ * 選択されているMIDIイベントを返します。\r
+ * @param selectionModel 選択状態モデル\r
+ * @return 選択されているMIDIイベント\r
+ */\r
+ public MidiEvent[] getMidiEvents(ListSelectionModel selectionModel) {\r
Vector<MidiEvent> events = new Vector<MidiEvent>();\r
- if( ! sel_model.isSelectionEmpty() ) {\r
- int min_sel_index = sel_model.getMinSelectionIndex();\r
- int max_sel_index = sel_model.getMaxSelectionIndex();\r
- for( int i = min_sel_index; i <= max_sel_index; i++ )\r
- if( sel_model.isSelectedIndex(i) )\r
+ if( ! selectionModel.isSelectionEmpty() ) {\r
+ int i = selectionModel.getMinSelectionIndex();\r
+ int max_sel_index = selectionModel.getMaxSelectionIndex();\r
+ for( ; i <= max_sel_index; i++ )\r
+ if( selectionModel.isSelectedIndex(i) )\r
events.add(track.get(i));\r
}\r
return events.toArray(new MidiEvent[1]);\r
}\r
- //\r
- // イベントの追加\r
- //\r
+ /**\r
+ * MIDIイベントを追加します。\r
+ * @param midi_event 追加するMIDIイベント\r
+ * @return 追加できたらtrue\r
+ */\r
public boolean addMidiEvent( MidiEvent midi_event ) {\r
if( !(track.add(midi_event)) )\r
return false;\r
if( isTimeSignature(midi_event.getMessage()) )\r
- parent_model.fireTimeSignatureChanged();\r
- parent_model.fireTrackChanged( track );\r
+ parent.fireTimeSignatureChanged();\r
+ parent.fireTrackChanged( track );\r
int last_index = track.size() - 1;\r
fireTableRowsInserted( last_index-1, last_index-1 );\r
return true;\r
}\r
+ /**\r
+ * MIDIイベントを追加します。\r
+ * @param midi_events 追加するMIDIイベント\r
+ * @param destination_tick 追加先tick\r
+ * @param midi_events_ppq PPQ値(タイミング解像度)\r
+ * @return 追加できたらtrue\r
+ */\r
public boolean addMidiEvents(\r
- MidiEvent midi_events[],\r
- long destination_tick,\r
- int midi_events_ppq\r
- ) {\r
- int dest_ppq = parent_model.getSequence().getResolution();\r
- boolean done = false, has_time_signature = false;\r
+ MidiEvent midi_events[], long destination_tick, int midi_events_ppq\r
+ ) {\r
+ int dest_ppq = parent.getSequence().getResolution();\r
+ boolean done = false;\r
+ boolean has_time_signature = false;\r
long event_tick = 0;\r
long first_event_tick = -1;\r
MidiEvent new_midi_event;\r
msg = midi_event.getMessage();\r
if( first_event_tick < 0 ) {\r
first_event_tick = event_tick;\r
- new_midi_event = new MidiEvent(\r
- msg, destination_tick\r
- );\r
+ new_midi_event = new MidiEvent(msg, destination_tick);\r
}\r
else {\r
new_midi_event = new MidiEvent(\r
- msg,\r
- destination_tick + (event_tick - first_event_tick) * dest_ppq / midi_events_ppq\r
- );\r
+ msg,\r
+ destination_tick + (event_tick - first_event_tick) * dest_ppq / midi_events_ppq\r
+ );\r
}\r
- if( ! track.add(new_midi_event) ) continue;\r
+ if( ! track.add(new_midi_event) )\r
+ continue;\r
done = true;\r
- if( isTimeSignature(msg) ) has_time_signature = true;\r
+ if( isTimeSignature(msg) )\r
+ has_time_signature = true;\r
}\r
if( done ) {\r
if( has_time_signature )\r
- parent_model.fireTimeSignatureChanged();\r
- parent_model.fireTrackChanged( track );\r
+ parent.fireTimeSignatureChanged();\r
+ parent.fireTrackChanged( track );\r
int last_index = track.size() - 1;\r
int old_last_index = last_index - midi_events.length;\r
fireTableRowsInserted( old_last_index, last_index );\r
}\r
return done;\r
}\r
- //\r
- // イベントの削除\r
- //\r
- public void removeMidiEvents( MidiEvent midi_events[] ) {\r
+ /**\r
+ * MIDIイベントを除去します。\r
+ * @param midi_events 除去するMIDIイベント\r
+ */\r
+ public void removeMidiEvents(MidiEvent midi_events[]) {\r
boolean had_time_signature = false;\r
for( MidiEvent midi_event : midi_events ) {\r
if( isTimeSignature(midi_event.getMessage()) )\r
track.remove(midi_event);\r
}\r
if( had_time_signature )\r
- parent_model.fireTimeSignatureChanged();\r
- parent_model.fireTrackChanged( track );\r
+ parent.fireTimeSignatureChanged();\r
+ parent.fireTrackChanged( track );\r
int last_index = track.size() - 1;\r
int old_last_index = last_index + midi_events.length;\r
if( last_index < 0 ) last_index = 0;\r
fireTableRowsDeleted( old_last_index, last_index );\r
}\r
- public void removeMidiEvents( ListSelectionModel sel_model ) {\r
- removeMidiEvents( getMidiEvents(sel_model) );\r
- }\r
- //\r
- // イベントの表示\r
- //\r
+ /**\r
+ * 引数の選択内容が示すMIDIイベントを除去します。\r
+ * @param sel_model 選択内容\r
+ */\r
+ public void removeMidiEvents(ListSelectionModel sel_model) {\r
+ removeMidiEvents(getMidiEvents(sel_model));\r
+ }\r
+ private boolean isRhythmPart(int ch) { return (ch == 9); }\r
+ /**\r
+ * MIDIメッセージの内容を文字列で返します。\r
+ * @param msg MIDIメッセージ\r
+ * @return MIDIメッセージの内容を表す文字列\r
+ */\r
public String msgToString(MidiMessage msg) {\r
String str = "";\r
if( msg instanceof ShortMessage ) {\r
break;\r
case ShortMessage.PITCH_BEND:\r
{\r
- int val = (\r
- (data1 & 0x7F) | ( (data2 & 0x7F) << 7 )\r
- );\r
+ int val = ((data1 & 0x7F) | ((data2 & 0x7F) << 7));\r
str += ch_prefix + status_prefix + ( (val-8192) * 100 / 8191) + "% (" + val + ")";\r
}\r
break;\r
case 0x00: // Sequence Number (for MIDI Format 2)\r
if( msgdata.length == 2 ) {\r
str += String.format(\r
- ": %04X",\r
- ((msgdata[0] & 0xFF) << 8) | (msgdata[1] & 0xFF)\r
- );\r
+ ": %04X",\r
+ ((msgdata[0] & 0xFF) << 8) | (msgdata[1] & 0xFF)\r
+ );\r
break;\r
}\r
str += ": Size not 2 byte : data=(";\r
case 0x54: // SMPTE Offset\r
if( msgdata.length == 5 ) {\r
str += ": "\r
- + (msgdata[0] & 0xFF) + ":"\r
- + (msgdata[1] & 0xFF) + ":"\r
- + (msgdata[2] & 0xFF) + "."\r
- + (msgdata[3] & 0xFF) + "."\r
- + (msgdata[4] & 0xFF);\r
+ + (msgdata[0] & 0xFF) + ":"\r
+ + (msgdata[1] & 0xFF) + ":"\r
+ + (msgdata[2] & 0xFF) + "."\r
+ + (msgdata[3] & 0xFF) + "."\r
+ + (msgdata[4] & 0xFF);\r
break;\r
}\r
str += ": Size not 5 byte : data=(";\r
int manufacturer_id = (int)(msgdata[0] & 0xFF );\r
int device_id = (int)(msgdata[1] & 0xFF);\r
int model_id = (int)(msgdata[2] & 0xFF);\r
- String manufacturer_name\r
- = MIDISpec.getSysExManufacturerName(manufacturer_id);\r
+ String manufacturer_name = MIDISpec.getSysExManufacturerName(manufacturer_id);\r
if( manufacturer_name == null ) {\r
manufacturer_name = String.format( "[Manufacturer code %02X]", msgdata[0] );\r
}\r
}\r
}\r
\r
-///////////////////////////////////////////////////////////////////////////\r
-//\r
-// MIDI シーケンスデータのインデックス\r
-//\r
-// 拍子、テンポ、調だけを抜き出したトラックを保持するためのインデックス。\r
-//\r
-// 指定の MIDI tick の位置におけるテンポ、調、拍子を取得したり、\r
-// 拍子情報から MIDI tick と小節位置との間の変換を行うために使います。\r
-//\r
-class SequenceIndex {\r
-\r
- private Track timesig_positions;\r
- private Track tempo_positions;\r
- private Track keysig_positions;\r
- private Sequence tmp_seq;\r
-\r
- public int ticks_per_whole_note;\r
-\r
- public SequenceIndex( Sequence source_seq ) {\r
+/**\r
+ * MIDI シーケンスデータのtickインデックス\r
+ * <p>拍子、テンポ、調だけを抜き出したトラックを保持するためのインデックスです。\r
+ * 指定の MIDI tick の位置におけるテンポ、調、拍子を取得したり、\r
+ * 拍子情報から MIDI tick と小節位置との間の変換を行うために使います。\r
+ * </p>\r
+ */\r
+class SequenceTickIndex {\r
+ /**\r
+ * メタメッセージの種類:テンポ\r
+ */\r
+ public static final int TEMPO = 0;\r
+ /**\r
+ * メタメッセージの種類:拍子\r
+ */\r
+ public static final int TIME_SIGNATURE = 1;\r
+ /**\r
+ * メタメッセージの種類:調号\r
+ */\r
+ public static final int KEY_SIGNATURE = 2;\r
+ /**\r
+ * メタメッセージタイプ → メタメッセージの種類 変換マップ\r
+ */\r
+ private static final Map<Integer,Integer> INDEX_META_TO_TRACK =\r
+ new HashMap<Integer,Integer>() {\r
+ {\r
+ put(0x51, TEMPO);\r
+ put(0x58, TIME_SIGNATURE);\r
+ put(0x59, KEY_SIGNATURE);\r
+ }\r
+ };\r
+ /**\r
+ * 新しいMIDIシーケンスデータのインデックスを構築します。\r
+ * @param sourceSequence 元のMIDIシーケンス\r
+ */\r
+ public SequenceTickIndex(Sequence sourceSequence) {\r
try {\r
- int ppq = source_seq.getResolution();\r
- ticks_per_whole_note = ppq * 4;\r
- tmp_seq = new Sequence(Sequence.PPQ, ppq, 3);\r
- Track[] tmp_tracks = tmp_seq.getTracks();\r
- timesig_positions = tmp_tracks[0];\r
- tempo_positions = tmp_tracks[1];\r
- keysig_positions = tmp_tracks[2];\r
- Track[] tracks = source_seq.getTracks();\r
- for( Track tk : tracks ) {\r
+ int ppq = sourceSequence.getResolution();\r
+ wholeNoteTickLength = ppq * 4;\r
+ tmpSequence = new Sequence(Sequence.PPQ, ppq, 3);\r
+ tracks = tmpSequence.getTracks();\r
+ Track[] sourceTracks = sourceSequence.getTracks();\r
+ for( Track tk : sourceTracks ) {\r
for( int i_evt = 0 ; i_evt < tk.size(); i_evt++ ) {\r
MidiEvent evt = tk.get(i_evt);\r
MidiMessage msg = evt.getMessage();\r
- if( ! (msg instanceof MetaMessage) ) continue;\r
- switch( ((MetaMessage)msg).getType() ) {\r
- case 0x51: tempo_positions.add(evt); break;\r
- case 0x58: timesig_positions.add(evt); break;\r
- case 0x59: keysig_positions.add(evt); break;\r
- default: break;\r
- }\r
+ if( ! (msg instanceof MetaMessage) )\r
+ continue;\r
+ MetaMessage metaMsg = (MetaMessage)msg;\r
+ int metaType = metaMsg.getType();\r
+ Integer metaIndex = INDEX_META_TO_TRACK.get(metaType);\r
+ if( metaIndex != null ) tracks[metaIndex].add(evt);\r
}\r
}\r
}\r
e.printStackTrace();\r
}\r
}\r
-\r
- private MetaMessage lastMessageAt( Track tk, long tick_position ) {\r
- if( tk == null ) return null;\r
- MidiEvent evt;\r
- MetaMessage msg;\r
- for( int i_evt = tk.size() - 1 ; i_evt >= 0; i_evt-- ) {\r
- evt = tk.get(i_evt);\r
- if( evt.getTick() > tick_position ) continue;\r
- msg = (MetaMessage)( evt.getMessage() );\r
- if( msg.getType() != 0x2F /* EOT */ ) return msg;\r
+ private Sequence tmpSequence;\r
+ /**\r
+ * このtickインデックスのタイミング解像度を返します。\r
+ * @return このtickインデックスのタイミング解像度\r
+ */\r
+ public int getResolution() {\r
+ return tmpSequence.getResolution();\r
+ }\r
+ private Track[] tracks;\r
+ /**\r
+ * 指定されたtick位置以前の最後のメタメッセージを返します。\r
+ * @param trackIndex メタメッセージの種類()\r
+ * @param tickPosition\r
+ * @return\r
+ */\r
+ public MetaMessage lastMetaMessageAt(int trackIndex, long tickPosition) {\r
+ Track track = tracks[trackIndex];\r
+ for(int eventIndex = track.size()-1 ; eventIndex >= 0; eventIndex--) {\r
+ MidiEvent event = track.get(eventIndex);\r
+ if( event.getTick() > tickPosition )\r
+ continue;\r
+ MetaMessage metaMessage = (MetaMessage)(event.getMessage());\r
+ if( metaMessage.getType() == 0x2F /* skip EOT (last event) */ )\r
+ continue;\r
+ return metaMessage;\r
}\r
return null;\r
}\r
- public MetaMessage lastTimeSignatureAt( long tick_position ) {\r
- return lastMessageAt( timesig_positions, tick_position );\r
- }\r
- public MetaMessage lastKeySignatureAt( long tick_position ) {\r
- return lastMessageAt( keysig_positions, tick_position );\r
- }\r
- public MetaMessage lastTempoAt( long tick_position ) {\r
- return lastMessageAt( tempo_positions, tick_position );\r
- }\r
- public int getResolution() { return tmp_seq.getResolution(); }\r
\r
- // MIDI tick を小節位置に変換\r
- public int last_measure;\r
- public int last_beat;\r
- public int last_extra_tick;\r
- public int ticks_per_beat;\r
- public byte timesig_upper;\r
- public byte timesig_lower_index;\r
- int tickToMeasure(long tick_position) {\r
- byte extra_beats = 0;\r
- MidiEvent evt = null;\r
- MidiMessage msg = null;\r
+ private int wholeNoteTickLength;\r
+ public int lastBeat;\r
+ public int lastExtraTick;\r
+ public byte timesigUpper;\r
+ public byte timesigLowerIndex;\r
+ /**\r
+ * tick位置を小節位置に変換します。\r
+ * @param tickPosition tick位置\r
+ * @return 小節位置\r
+ */\r
+ int tickToMeasure(long tickPosition) {\r
+ byte extraBeats = 0;\r
+ MidiEvent event = null;\r
+ MidiMessage message = null;\r
byte[] data = null;\r
- long current_tick = 0L;\r
- long next_timesig_tick = 0L;\r
- long prev_tick = 0L;\r
+ long currentTick = 0L;\r
+ long nextTimesigTick = 0L;\r
+ long prevTick = 0L;\r
long duration = 0L;\r
- last_measure = 0;\r
- int measures, beats;\r
- int i_evt = 0;\r
- timesig_upper = 4;\r
- timesig_lower_index = 2; // =log2(4)\r
- if( timesig_positions != null ) {\r
- do {\r
- // Check current time-signature event\r
- if( i_evt < timesig_positions.size() ) {\r
- msg = (evt = timesig_positions.get(i_evt)).getMessage();\r
- current_tick = next_timesig_tick = evt.getTick();\r
- if(\r
- current_tick > tick_position || (\r
- msg.getStatus() == 0xFF && ((MetaMessage)msg).getType() == 0x2F /* EOT */\r
- )\r
- ) {\r
- current_tick = tick_position;\r
- }\r
- }\r
- else { // No event\r
- current_tick = next_timesig_tick = tick_position;\r
- }\r
- // Add measure from last event\r
- //\r
- ticks_per_beat = ticks_per_whole_note >> timesig_lower_index;\r
- duration = current_tick - prev_tick;\r
- beats = (int)( duration / ticks_per_beat );\r
- last_extra_tick = (int)(duration % ticks_per_beat);\r
- measures = beats / timesig_upper;\r
- extra_beats = (byte)(beats % timesig_upper);\r
- last_measure += measures;\r
- if( next_timesig_tick > tick_position ) break; // Not reached to next time signature\r
- //\r
- // Reached to the next time signature, so get it.\r
- if( ( data = ((MetaMessage)msg).getData() ).length > 0 ) { // To skip EOT, check the data length.\r
- timesig_upper = data[0];\r
- timesig_lower_index = data[1];\r
- }\r
- if( current_tick == tick_position ) break; // Calculation complete\r
- //\r
- // Calculation incomplete, so prepare for next\r
- //\r
- if( extra_beats > 0 ) {\r
+ int lastMeasure = 0;\r
+ int eventIndex = 0;\r
+ timesigUpper = 4;\r
+ timesigLowerIndex = 2; // =log2(4)\r
+ if( tracks[TIME_SIGNATURE] != null ) {\r
+ do {\r
+ // Check current time-signature event\r
+ if( eventIndex < tracks[TIME_SIGNATURE].size() ) {\r
+ message = (event = tracks[TIME_SIGNATURE].get(eventIndex)).getMessage();\r
+ currentTick = nextTimesigTick = event.getTick();\r
+ if(currentTick > tickPosition || (message.getStatus() == 0xFF && ((MetaMessage)message).getType() == 0x2F /* EOT */)) {\r
+ currentTick = tickPosition;\r
+ }\r
+ }\r
+ else { // No event\r
+ currentTick = nextTimesigTick = tickPosition;\r
+ }\r
+ // Add measure from last event\r
//\r
- // Extra beats are treated as 1 measure\r
- last_measure++;\r
- }\r
- prev_tick = current_tick;\r
- i_evt++;\r
- } while( true );\r
+ int beatTickLength = wholeNoteTickLength >> timesigLowerIndex;\r
+ duration = currentTick - prevTick;\r
+ int beats = (int)( duration / beatTickLength );\r
+ lastExtraTick = (int)(duration % beatTickLength);\r
+ int measures = beats / timesigUpper;\r
+ extraBeats = (byte)(beats % timesigUpper);\r
+ lastMeasure += measures;\r
+ if( nextTimesigTick > tickPosition ) break; // Not reached to next time signature\r
+ //\r
+ // Reached to the next time signature, so get it.\r
+ if( ( data = ((MetaMessage)message).getData() ).length > 0 ) { // To skip EOT, check the data length.\r
+ timesigUpper = data[0];\r
+ timesigLowerIndex = data[1];\r
}\r
- last_beat = extra_beats;\r
- return last_measure;\r
- }\r
-\r
- // 小節位置を MIDI tick に変換\r
- public long measureToTick( int measure ) {\r
- return measureToTick( measure, 0, 0 );\r
- }\r
- public long measureToTick( int measure, int beat, int extra_tick ) {\r
+ if( currentTick == tickPosition ) break; // Calculation complete\r
+ //\r
+ // Calculation incomplete, so prepare for next\r
+ //\r
+ if( extraBeats > 0 ) {\r
+ //\r
+ // Extra beats are treated as 1 measure\r
+ lastMeasure++;\r
+ }\r
+ prevTick = currentTick;\r
+ eventIndex++;\r
+ } while( true );\r
+ }\r
+ lastBeat = extraBeats;\r
+ return lastMeasure;\r
+ }\r
+ /**\r
+ * 小節位置を MIDI tick に変換します。\r
+ * @param measure 小節位置\r
+ * @return MIDI tick\r
+ */\r
+ public long measureToTick(int measure) {\r
+ return measureToTick(measure, 0, 0);\r
+ }\r
+ /**\r
+ * 指定の小節位置、拍、拍内tickを、そのシーケンス全体の MIDI tick に変換します。\r
+ * @param measure 小節位置\r
+ * @param beat 拍\r
+ * @param extraTick 拍内tick\r
+ * @return そのシーケンス全体の MIDI tick\r
+ */\r
+ public long measureToTick(int measure, int beat, int extraTick) {\r
MidiEvent evt = null;\r
MidiMessage msg = null;\r
byte[] data = null;\r
long estimated_ticks;\r
int ticks_per_beat;\r
int i_evt = 0;\r
- timesig_upper = 4;\r
- timesig_lower_index = 2; // =log2(4)\r
- do {\r
- ticks_per_beat = ticks_per_whole_note >> timesig_lower_index;\r
- estimated_ticks = ((measure * timesig_upper) + beat) * ticks_per_beat + extra_tick;\r
- if( timesig_positions == null || i_evt > timesig_positions.size() ) {\r
- return duration_sum + estimated_ticks;\r
- }\r
- msg = (evt = timesig_positions.get(i_evt)).getMessage();\r
- if( msg.getStatus() == 0xFF && ((MetaMessage)msg).getType() == 0x2F /* EOT */ ) {\r
- return duration_sum + estimated_ticks;\r
- }\r
- duration = (tick = evt.getTick()) - prev_tick;\r
- if( duration >= estimated_ticks ) {\r
- return duration_sum + estimated_ticks;\r
- }\r
- // Re-calculate measure (ignore extra beats/ticks)\r
- measure -= ( duration / (ticks_per_beat * timesig_upper) );\r
- duration_sum += duration;\r
- //\r
- // Get next time-signature\r
- data = ( (MetaMessage)msg ).getData();\r
- timesig_upper = data[0];\r
- timesig_lower_index = data[1];\r
- prev_tick = tick;\r
- i_evt++;\r
- } while( true );\r
+ timesigUpper = 4;\r
+ timesigLowerIndex = 2; // =log2(4)\r
+ do {\r
+ ticks_per_beat = wholeNoteTickLength >> timesigLowerIndex;\r
+ estimated_ticks = ((measure * timesigUpper) + beat) * ticks_per_beat + extraTick;\r
+ if( tracks[TIME_SIGNATURE] == null || i_evt > tracks[TIME_SIGNATURE].size() ) {\r
+ return duration_sum + estimated_ticks;\r
+ }\r
+ msg = (evt = tracks[TIME_SIGNATURE].get(i_evt)).getMessage();\r
+ if( msg.getStatus() == 0xFF && ((MetaMessage)msg).getType() == 0x2F /* EOT */ ) {\r
+ return duration_sum + estimated_ticks;\r
+ }\r
+ duration = (tick = evt.getTick()) - prev_tick;\r
+ if( duration >= estimated_ticks ) {\r
+ return duration_sum + estimated_ticks;\r
+ }\r
+ // Re-calculate measure (ignore extra beats/ticks)\r
+ measure -= ( duration / (ticks_per_beat * timesigUpper) );\r
+ duration_sum += duration;\r
+ //\r
+ // Get next time-signature\r
+ data = ( (MetaMessage)msg ).getData();\r
+ timesigUpper = data[0];\r
+ timesigLowerIndex = data[1];\r
+ prev_tick = tick;\r
+ i_evt++;\r
+ } while( true );\r
}\r
}\r
import java.awt.Color;\r
import java.awt.event.ActionEvent;\r
import java.awt.event.ActionListener;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
\r
import javax.sound.midi.InvalidMidiDataException;\r
import javax.sound.midi.MetaEventListener;\r
/**\r
* シーケンサの現在位置(分:秒)を表示するビュー\r
*/\r
-class TimeIndicator extends JPanel {\r
- private TimeLabel timePositionLabel;\r
- private TimeLabel timeLengthLabel;\r
+class TimeIndicator extends JPanel implements ChangeListener {\r
+ /**\r
+ * 時間(分:秒)表示ラベル\r
+ */\r
+ private static class TimeLabel extends JLabel {\r
+ /**\r
+ * 時間表示の形式\r
+ */\r
+ private TimeLabelFormat formatType;\r
+ /**\r
+ * 時間の値(秒)\r
+ */\r
+ private int valueInSec;\r
+ /**\r
+ * 時間表示ラベルを構築します。\r
+ * @param formatType 表示形式\r
+ */\r
+ public TimeLabel(TimeLabelFormat formatType) {\r
+ super();\r
+ if( (this.formatType = formatType) == TimeLabelFormat.POSITION ) {\r
+ setFont( getFont().deriveFont(getFont().getSize2D() + 4) );\r
+ setForeground( new Color(0x80,0x00,0x00) );\r
+ setToolTipText("Time position - 現在位置(分:秒)");\r
+ }\r
+ else {\r
+ setToolTipText("Time length - 曲の長さ(分:秒)");\r
+ }\r
+ setText(formatType.toTimeString(valueInSec));\r
+ }\r
+ /**\r
+ * 時間の値を秒単位で設定します。\r
+ * @param sec 秒単位の時間\r
+ */\r
+ public void setTimeInSecond(int sec) {\r
+ if( valueInSec == sec )\r
+ return;\r
+ setText(formatType.toTimeString(sec));\r
+ }\r
+ }\r
+ private TimeLabel timePositionLabel = new TimeLabel(TimeLabelFormat.POSITION);\r
+ private TimeLabel timeLengthLabel = new TimeLabel(TimeLabelFormat.LENGTH);\r
private SequencerTimeRangeModel model;\r
- public TimeIndicator() {\r
- timePositionLabel = new TimeLabel(TimeLabelFormat.POSITION);\r
- timeLengthLabel = new TimeLabel(TimeLabelFormat.LENGTH);\r
+ /**\r
+ * シーケンサの現在位置(分:秒)を表示するビューを構築します。\r
+ * @param model スライダー用の時間範囲データモデル\r
+ */\r
+ public TimeIndicator(SequencerTimeRangeModel model) {\r
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
add(timePositionLabel);\r
add(timeLengthLabel);\r
+ (this.model = model).addChangeListener(this);\r
}\r
- public TimeIndicator(SequencerTimeRangeModel model) {\r
- this();\r
- (this.model = model).addChangeListener(\r
- new ChangeListener() {\r
- public void stateChanged(ChangeEvent e) {\r
- SequencerTimeRangeModel model = TimeIndicator.this.model;\r
- timeLengthLabel.setTimeInSecond(model.getMaximum()/1000);\r
- timePositionLabel.setTimeInSecond(model.getValue()/1000);\r
- }\r
- }\r
- );\r
+ public void stateChanged(ChangeEvent e) {\r
+ timeLengthLabel.setTimeInSecond(model.getMaximum()/1000);\r
+ timePositionLabel.setTimeInSecond(model.getValue()/1000);\r
}\r
}\r
\r
/**\r
- * 時間(分:秒)表示ラベル\r
+ * 小節表示ビュー\r
*/\r
-class TimeLabel extends JLabel {\r
+class MeasureIndicator extends JPanel implements ChangeListener {\r
/**\r
- * 時間表示の形式\r
+ * 小節表示ラベル\r
*/\r
- private TimeLabelFormat formatType;\r
- /**\r
- * 時間の値(秒)\r
- */\r
- private int valueInSec = -1;\r
- /**\r
- * 時間表示ラベルを構築します。\r
- * @param formatType 表示形式\r
- */\r
- public TimeLabel(TimeLabelFormat formatType) {\r
- super();\r
- if( (this.formatType = formatType) == TimeLabelFormat.POSITION ) {\r
- float largePointSize = getFont().getSize2D() + 4;\r
- setFont( getFont().deriveFont(largePointSize) );\r
- setForeground( new Color(0x80,0x00,0x00) );\r
- setToolTipText("Time position - 現在位置(分:秒)");\r
+ private static class MeasureLabel extends JLabel {\r
+ private TimeLabelFormat formatType;\r
+ private int measure = -1;\r
+ private int beat = 0;\r
+ public MeasureLabel(TimeLabelFormat formatType) {\r
+ if( (this.formatType = formatType) == TimeLabelFormat.POSITION ) {\r
+ setFont( getFont().deriveFont(getFont().getSize2D() + 4) );\r
+ setForeground( new Color(0x80,0x00,0x00) );\r
+ setText( "0001:01" );\r
+ setToolTipText("Measure:beat position - 何小節目:何拍目");\r
+ }\r
+ else {\r
+ setText( "/0000" );\r
+ setToolTipText("Measure length - 小節の数");\r
+ }\r
}\r
- else {\r
- setToolTipText("Time length - 曲の長さ(分:秒)");\r
+ public void setMeasure(int measure) {\r
+ setMeasure(measure,0);\r
+ }\r
+ public void setMeasure(int measure, int beat) {\r
+ if( this.measure == measure && this.beat == beat ) {\r
+ return;\r
+ }\r
+ this.beat = beat;\r
+ this.measure = measure;\r
+ if( formatType == TimeLabelFormat.LENGTH )\r
+ setText(String.format("/%04d", measure));\r
+ else\r
+ setText(String.format("%04d:%02d", measure+1, beat+1));\r
}\r
- setText(formatType.toTimeString(0));\r
- }\r
- /**\r
- * 時間の値をマイクロ秒単位で設定します。\r
- * @param us マイクロ秒単位の時間\r
- */\r
- public void setTimeInMicrosecond(long us) {\r
- setTimeInSecond( (int)(us/1000000) );\r
}\r
+ private MeasureLabel measurePositionLabel = new MeasureLabel(TimeLabelFormat.POSITION);\r
+ private MeasureLabel measureLengthLabel = new MeasureLabel(TimeLabelFormat.LENGTH);\r
+ private SequencerTimeRangeModel model;\r
/**\r
- * 時間の値を秒単位で設定します。\r
- * @param sec 秒単位の時間\r
+ * シーケンサの現在の小節位置を表示するビューを構築します。\r
+ * @param model スライダー用の時間範囲データモデル\r
*/\r
- public void setTimeInSecond(int sec) {\r
- if( valueInSec == sec )\r
- return;\r
- if( (valueInSec = sec) < 0 )\r
- setText(null);\r
- else\r
- setText(formatType.toTimeString(sec));\r
- }\r
-}\r
-\r
-/**\r
- * 小節表示ビュー\r
- */\r
-class MeasureIndicator extends JPanel {\r
- private SequencerTimeRangeModel model;\r
- private MeasureLabel measurePositionLabel;\r
- private MeasureLabel measureLengthLabel;\r
- public MeasureIndicator() {\r
- measurePositionLabel = new MeasureLabel(TimeLabelFormat.POSITION);\r
- measureLengthLabel = new MeasureLabel(TimeLabelFormat.LENGTH);\r
- setLayout( new BoxLayout( this, BoxLayout.X_AXIS ) );\r
- add( measurePositionLabel );\r
- add( measureLengthLabel );\r
- }\r
public MeasureIndicator(SequencerTimeRangeModel model) {\r
- this();\r
- (this.model = model).addChangeListener(new ChangeListener() {\r
- @Override\r
- public void stateChanged(ChangeEvent e) {\r
- SequencerTimeRangeModel model = MeasureIndicator.this.model;\r
- Sequencer sequencer = model.deviceManager.getSequencer();\r
- MidiSequenceModel seqModel =\r
- model.deviceManager.timeRangeModel.getSequenceModel();\r
- SequenceIndex seqIndex = (\r
- seqModel == null ? null : seqModel.getSequenceIndex()\r
- );\r
- if( ! sequencer.isRunning() || sequencer.isRecording() ) {\r
- measureLengthLabel.setMeasure(\r
- seqIndex == null ? 0 : seqIndex.tickToMeasure(\r
- sequencer.getTickLength()\r
- )\r
- );\r
- }\r
- if( seqIndex == null ) {\r
- measurePositionLabel.setMeasure( 0, 0 );\r
- }\r
- else {\r
- int measurePosition = seqIndex.tickToMeasure(\r
- sequencer.getTickPosition()\r
- );\r
- measurePositionLabel.setMeasure(\r
- measurePosition, seqIndex.last_beat\r
- );\r
- }\r
- }\r
- });\r
+ setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
+ add(measurePositionLabel);\r
+ add(measureLengthLabel);\r
+ (this.model = model).addChangeListener(this);\r
}\r
-}\r
-/**\r
- * 小節表示ラベル\r
- */\r
-class MeasureLabel extends JLabel {\r
- private TimeLabelFormat formatType;\r
- private int measure = -1;\r
- private int beat = 0;\r
- public MeasureLabel(TimeLabelFormat formatType) {\r
- if( (this.formatType = formatType) == TimeLabelFormat.POSITION ) {\r
- float large_point_size = getFont().getSize2D() + 4;\r
- setFont( getFont().deriveFont(large_point_size) );\r
- setForeground( new Color(0x80,0x00,0x00) );\r
- setText( "0001:01" );\r
- setToolTipText("Measure:beat position - 何小節目:何拍目");\r
+ @Override\r
+ public void stateChanged(ChangeEvent e) {\r
+ Sequencer sequencer = model.deviceModelList.getSequencer();\r
+ MidiSequenceTableModel seqModel =\r
+ model.deviceModelList.timeRangeModel.getSequenceTableModel();\r
+ SequenceTickIndex seqIndex = (\r
+ seqModel == null ? null : seqModel.getSequenceTickIndex()\r
+ );\r
+ if( ! sequencer.isRunning() || sequencer.isRecording() ) {\r
+ measureLengthLabel.setMeasure(\r
+ seqIndex == null ? 0 : seqIndex.tickToMeasure(\r
+ sequencer.getTickLength()\r
+ )\r
+ );\r
}\r
- else {\r
- setText( "/0000" );\r
- setToolTipText("Measure length - 小節の数");\r
+ if( seqIndex == null ) {\r
+ measurePositionLabel.setMeasure( 0, 0 );\r
}\r
- }\r
- public void setMeasure(int measure) {\r
- setMeasure(measure,0);\r
- }\r
- public void setMeasure(int measure, int beat) {\r
- if( this.measure == measure && this.beat == beat ) {\r
- return;\r
+ else {\r
+ int measurePosition = seqIndex.tickToMeasure(\r
+ sequencer.getTickPosition()\r
+ );\r
+ measurePositionLabel.setMeasure(\r
+ measurePosition, seqIndex.lastBeat\r
+ );\r
}\r
- this.beat = beat;\r
- if( (this.measure = measure) < 0 )\r
- setText( null );\r
- else if( formatType == TimeLabelFormat.LENGTH )\r
- setText( String.format("/%04d", measure) );\r
- else\r
- setText( String.format("%04d:%02d", measure+1, beat+1) );\r
}\r
}\r
\r
}\r
\r
/**\r
- * 時間範囲データモデル\r
+ * スライダー用の時間範囲データモデル\r
*/\r
-class SequencerTimeRangeModel implements BoundedRangeModel {\r
- static final int INTERVAL_MS = 20;\r
- MidiDeviceManager deviceManager;\r
+class SequencerTimeRangeModel\r
+ implements BoundedRangeModel, MetaEventListener, ActionListener\r
+{\r
+ /**\r
+ * 更新インターバル [ミリ秒]\r
+ */\r
+ private static final int INTERVAL_MS = 20;\r
+ /**\r
+ * MIDIデバイスモデルリスト\r
+ */\r
+ MidiDeviceModelList deviceModelList;\r
+ /**\r
+ * シーケンサ\r
+ */\r
private Sequencer sequencer;\r
- javax.swing.Timer timer;\r
- private boolean valueIsAdjusting = false;\r
- private EventListenerList listenerList = new EventListenerList();\r
+ /**\r
+ * このデータモデルをシーケンサに同期させるためのサンプリングタイマー\r
+ */\r
+ javax.swing.Timer timer = new javax.swing.Timer(INTERVAL_MS, this);\r
+ /**\r
+ * 開始終了アクション\r
+ */\r
public StartStopAction startStopAction = new StartStopAction();\r
- class StartStopAction extends AbstractAction {\r
- Icon play_icon = new ButtonIcon(ButtonIcon.PLAY_ICON);\r
- Icon pause_icon = new ButtonIcon(ButtonIcon.PAUSE_ICON);\r
+ /**\r
+ * 開始終了アクション\r
+ */\r
+ private class StartStopAction extends AbstractAction {\r
+ private Map<Boolean,Icon> iconMap = new HashMap<Boolean,Icon>() {\r
+ {\r
+ put(Boolean.FALSE, new ButtonIcon(ButtonIcon.PLAY_ICON));\r
+ put(Boolean.TRUE, new ButtonIcon(ButtonIcon.PAUSE_ICON));\r
+ }\r
+ };\r
{\r
putValue(\r
SHORT_DESCRIPTION,\r
"Start/Stop recording or playing - 録音または再生の開始/停止"\r
);\r
- putValue( LARGE_ICON_KEY, play_icon );\r
- putValue( SELECTED_KEY, false );\r
+ setRunning(false);\r
}\r
+ @Override\r
public void actionPerformed(ActionEvent event) {\r
- if( timer.isRunning() ) stop(); else start();\r
+ if(timer.isRunning()) stop(); else start();\r
}\r
- public void setRunning(boolean is_running) {\r
- putValue( LARGE_ICON_KEY, is_running ? pause_icon : play_icon );\r
- putValue( SELECTED_KEY, is_running );\r
+ /**\r
+ * 開始されているかどうかを設定します。\r
+ * @param isRunning 開始されていたらtrue\r
+ */\r
+ public void setRunning(boolean isRunning) {\r
+ putValue(LARGE_ICON_KEY, iconMap.get(isRunning));\r
+ putValue(SELECTED_KEY, isRunning);\r
}\r
}\r
- public Action move_backward_action = new AbstractAction() {\r
+ /**\r
+ * 1小節戻るアクション\r
+ */\r
+ public Action moveBackwardAction = new AbstractAction() {\r
{\r
- putValue( SHORT_DESCRIPTION, "Move backward 1 measure - 1小節戻る" );\r
- putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.BACKWARD_ICON) );\r
- }\r
- public void actionPerformed( ActionEvent event ) {\r
- moveMeasure(-1);\r
+ putValue(SHORT_DESCRIPTION, "Move backward 1 measure - 1小節戻る");\r
+ putValue(LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.BACKWARD_ICON));\r
}\r
+ @Override\r
+ public void actionPerformed(ActionEvent event) { moveMeasure(-1); }\r
};\r
- public Action move_forward_action = new AbstractAction() {\r
+ /**\r
+ *1小節進むアクション\r
+ */\r
+ public Action moveForwardAction = new AbstractAction() {\r
{\r
- putValue( SHORT_DESCRIPTION, "Move forward 1 measure - 1小節進む" );\r
- putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.FORWARD_ICON) );\r
- }\r
- public void actionPerformed( ActionEvent event ) {\r
- moveMeasure(1);\r
+ putValue(SHORT_DESCRIPTION, "Move forward 1 measure - 1小節進む");\r
+ putValue(LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.FORWARD_ICON));\r
}\r
+ @Override\r
+ public void actionPerformed(ActionEvent event) { moveMeasure(1); }\r
};\r
- public Action toggle_repeat_action = new AbstractAction() {\r
+ /**\r
+ * 小節位置を移動します。\r
+ * @param measureOffset 小節位置の移動量(負数も指定可)\r
+ */\r
+ private void moveMeasure(int measureOffset) {\r
+ if( measureOffset == 0 || seqModel == null )\r
+ return;\r
+ SequenceTickIndex seqIndex = seqModel.getSequenceTickIndex();\r
+ int measurePosition = seqIndex.tickToMeasure(sequencer.getTickPosition());\r
+ long newTickPosition = seqIndex.measureToTick(measurePosition + measureOffset);\r
+ if( newTickPosition < 0 ) {\r
+ // 下限\r
+ newTickPosition = 0;\r
+ }\r
+ else {\r
+ long tickLength = sequencer.getTickLength();\r
+ if( newTickPosition > tickLength ) {\r
+ // 上限\r
+ newTickPosition = tickLength - 1;\r
+ }\r
+ }\r
+ sequencer.setTickPosition(newTickPosition);\r
+ fireStateChanged();\r
+ }\r
+ /**\r
+ * 繰り返し再生ON/OFF切り替えアクション\r
+ */\r
+ public Action toggleRepeatAction = new AbstractAction() {\r
{\r
- putValue( SHORT_DESCRIPTION, "Repeat - 繰り返し再生" );\r
- putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.REPEAT_ICON) );\r
- putValue( SELECTED_KEY, false );\r
+ putValue(SHORT_DESCRIPTION, "Repeat - 繰り返し再生");\r
+ putValue(LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.REPEAT_ICON));\r
+ putValue(SELECTED_KEY, false);\r
}\r
+ @Override\r
public void actionPerformed(ActionEvent event) { }\r
};\r
- public SequencerTimeRangeModel( MidiDeviceManager device_manager ) {\r
- this.deviceManager = device_manager;\r
- this.sequencer = device_manager.getSequencer();\r
- timer = new javax.swing.Timer(\r
- INTERVAL_MS,\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- if( ! valueIsAdjusting ) fireStateChanged();\r
- }\r
- }\r
- );\r
- timer.setCoalesce(true);\r
- sequencer.addMetaEventListener(\r
- new MetaEventListener() {\r
- public void meta(MetaMessage msg) {\r
- if( msg.getType() != 0x2F /* End-Of-Track */)\r
- return;\r
- timer.stop();\r
- startStopAction.setRunning(false);\r
- sequencer.setMicrosecondPosition(0);\r
- if(\r
- (Boolean)toggle_repeat_action.getValue( Action.SELECTED_KEY ) ||\r
- SequencerTimeRangeModel.this.deviceManager.editorDialog.loadNext(1)\r
- ) start();\r
- else fireStateChanged();\r
- }\r
- }\r
- );\r
+ /**\r
+ * 新しい {@link SequencerTimeRangeModel} を構築します。\r
+ * @param deviceModelList MIDIデバイスモデルリスト\r
+ */\r
+ public SequencerTimeRangeModel(MidiDeviceModelList deviceModelList) {\r
+ this.deviceModelList = deviceModelList;\r
+ sequencer = deviceModelList.getSequencer();\r
+ sequencer.addMetaEventListener(this);\r
}\r
+ @Override\r
+ public void meta(MetaMessage msg) {\r
+ if( msg.getType() != 0x2F ) return;\r
+ /* End-Of-Track */\r
+ timer.stop();\r
+ startStopAction.setRunning(false);\r
+ sequencer.setMicrosecondPosition(0);\r
+ if(\r
+ (Boolean)toggleRepeatAction.getValue(Action.SELECTED_KEY)\r
+ ||\r
+ deviceModelList.editorDialog.loadNext(1)\r
+ )\r
+ start();\r
+ else\r
+ fireStateChanged();\r
+ }\r
+ @Override\r
public int getExtent() { return 0; }\r
- public int getMaximum() { return (int)(getMicrosecondLength()/1000L); }\r
+ @Override\r
public int getMinimum() { return 0; }\r
- public int getValue() { return (int)(getMicrosecondPosition()/1000L); }\r
- public boolean getValueIsAdjusting() { return valueIsAdjusting; }\r
- public void setExtent(int new_extent) {}\r
- public void setMaximum(int new_maximum) {}\r
- public void setMinimum(int new_minimum) {}\r
+ private long getMicrosecondLength() {\r
+ //\r
+ // Sequencer.getMicrosecondLength() returns NEGATIVE value\r
+ // when over 0x7FFFFFFF microseconds (== 35.7913941166666... minutes),\r
+ // should be corrected when negative\r
+ //\r
+ long usLength = sequencer.getMicrosecondLength();\r
+ return usLength < 0 ? 0x100000000L + usLength : usLength ;\r
+ }\r
+ @Override\r
+ public int getMaximum() {\r
+ return (int)(getMicrosecondLength()/1000L);\r
+ }\r
+ private long getMicrosecondPosition() {\r
+ long usPosition = sequencer.getMicrosecondPosition();\r
+ return usPosition < 0 ? 0x100000000L + usPosition : usPosition ;\r
+ }\r
+ @Override\r
+ public int getValue() {\r
+ return (int)(getMicrosecondPosition()/1000L);\r
+ }\r
+ @Override\r
+ public void setExtent(int newExtent) {}\r
+ @Override\r
+ public void setMaximum(int newMaximum) {}\r
+ @Override\r
+ public void setMinimum(int newMinimum) {}\r
+ @Override\r
public void setRangeProperties(int value, int extent, int min, int max, boolean adjusting) {\r
sequencer.setMicrosecondPosition( 1000L * (long)value );\r
valueIsAdjusting = adjusting;\r
fireStateChanged();\r
}\r
- public void setValue(int new_value) {\r
- sequencer.setMicrosecondPosition( 1000L * (long)new_value );\r
+ @Override\r
+ public void setValue(int newValue) {\r
+ sequencer.setMicrosecondPosition( 1000L * (long)newValue );\r
fireStateChanged();\r
}\r
+ /**\r
+ * 値調整中のときtrue\r
+ */\r
+ private boolean valueIsAdjusting = false;\r
+ @Override\r
+ public boolean getValueIsAdjusting() {\r
+ return valueIsAdjusting;\r
+ }\r
+ @Override\r
public void setValueIsAdjusting(boolean b) {\r
valueIsAdjusting = b;\r
}\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ if( ! valueIsAdjusting ) fireStateChanged();\r
+ }\r
+ /**\r
+ * イベントリスナーのリスト\r
+ */\r
+ protected EventListenerList listenerList = new EventListenerList();\r
+ @Override\r
public void addChangeListener(ChangeListener listener) {\r
listenerList.add(ChangeListener.class, listener);\r
}\r
+ @Override\r
public void removeChangeListener(ChangeListener listener) {\r
listenerList.remove(ChangeListener.class, listener);\r
}\r
+ /**\r
+ * 状態が変わったことをリスナーに通知します。\r
+ */\r
public void fireStateChanged() {\r
Object[] listeners = listenerList.getListenerList();\r
for (int i = listeners.length-2; i>=0; i-=2) {\r
}\r
}\r
}\r
- long getMicrosecondLength() {\r
- //\r
- // Sequencer.getMicrosecondLength() returns NEGATIVE value\r
- // when over 0x7FFFFFFF microseconds (== 35.7913941166666... minutes),\r
- // should be corrected when negative\r
- //\r
- long us_len = sequencer.getMicrosecondLength();\r
- return us_len < 0 ? 0x100000000L + us_len : us_len ;\r
- }\r
- long getMicrosecondPosition() {\r
- long us_pos = sequencer.getMicrosecondPosition();\r
- return us_pos < 0 ? 0x100000000L + us_pos : us_pos ;\r
+ private MidiSequenceTableModel seqModel = null;\r
+ public MidiSequenceTableModel getSequenceTableModel() {\r
+ return seqModel;\r
}\r
- private MidiSequenceModel seq_model = null;\r
- public MidiSequenceModel getSequenceModel() { return seq_model; }\r
- public boolean setSequenceModel( MidiSequenceModel seq_model ) {\r
+ public boolean setSequenceModel(MidiSequenceTableModel seqModel) {\r
//\r
// javax.sound.midi:Sequencer.setSequence() のドキュメントにある\r
// 「このメソッドは、Sequencer が閉じている場合でも呼び出すことができます。 」\r
// 連鎖的に stop() が呼ばれるために IllegalStateException sequencer not open が出る。\r
// この現象を回避するため、あらかじめチェックしてから setSequence() を呼び出している。\r
//\r
- if( seq_model != null || sequencer.isOpen() ) {\r
+ if( seqModel != null || sequencer.isOpen() ) {\r
try {\r
// Set new MIDI data\r
- sequencer.setSequence(\r
- seq_model == null ? null : seq_model.getSequence()\r
- );\r
+ sequencer.setSequence(seqModel==null ? null : seqModel.getSequence());\r
} catch ( InvalidMidiDataException e ) {\r
e.printStackTrace();\r
return false;\r
}\r
}\r
- this.seq_model = seq_model;\r
+ this.seqModel = seqModel;\r
fireStateChanged();\r
return true;\r
}\r
- // 小節位置の相対移動\r
- public void moveMeasure( int measure_offset ) {\r
- if( measure_offset == 0 || seq_model == null ) return;\r
- SequenceIndex seq_index = seq_model.getSequenceIndex();\r
- long new_tick_pos =\r
- seq_index.measureToTick(\r
- measure_offset + seq_index.tickToMeasure(\r
- sequencer.getTickPosition()\r
- )\r
- );\r
- if( new_tick_pos < 0 ) new_tick_pos = 0;\r
- else {\r
- long tick_len = sequencer.getTickLength();\r
- if( new_tick_pos > tick_len ) new_tick_pos = tick_len - 1;\r
- }\r
- sequencer.setTickPosition( new_tick_pos );\r
- fireStateChanged();\r
- }\r
\r
- // 開始/終了\r
- public boolean isStartable() {\r
- return sequencer.isOpen() && sequencer.getSequence() != null ;\r
- }\r
public void start() {\r
- if( ! isStartable() ) {\r
+ if( ! sequencer.isOpen() || sequencer.getSequence() == null ) {\r
startStopAction.setRunning(false);\r
return;\r
}\r
startStopAction.setRunning(true);\r
timer.start();\r
- if( deviceManager.isRecordable() ) {\r
- deviceManager.resetMicrosecondPosition();\r
+ if( deviceModelList.isRecordable() ) {\r
+ for( MidiConnecterListModel model : deviceModelList )\r
+ model.resetMicrosecondPosition();\r
System.gc();\r
sequencer.startRecording();\r
}\r
fireStateChanged();\r
}\r
public void stop() {\r
- if( sequencer.isOpen() ) sequencer.stop();\r
+ if( sequencer.isOpen() )\r
+ sequencer.stop();\r
timer.stop();\r
startStopAction.setRunning(false);\r
fireStateChanged();\r