From: Akiyoshi Kamide Date: Sun, 5 Jun 2016 14:04:57 +0000 (+0900) Subject: ・再生スピード調整をよりわかりやすくした X-Git-Url: http://git.osdn.net/view?p=midichordhelper%2FMIDIChordHelper.git;a=commitdiff_plain;h=4dd2df1e98061d53e4900ba6cc765002d34c5d7f ・再生スピード調整をよりわかりやすくした ・終了時にMIDIデバイスを全部閉じるようにした (Eclipse上で実行するとMIDIデバイスが閉じないようなので) --- diff --git a/src/camidion/chordhelper/ChordHelperApplet.java b/src/camidion/chordhelper/ChordHelperApplet.java index 9d82d13..0b7c3b6 100644 --- a/src/camidion/chordhelper/ChordHelperApplet.java +++ b/src/camidion/chordhelper/ChordHelperApplet.java @@ -285,7 +285,7 @@ public class ChordHelperApplet extends JApplet { */ public static class VersionInfo { public static final String NAME = "MIDI Chord Helper"; - public static final String VERSION = "Ver.20160604.1"; + public static final String VERSION = "Ver.20160605.1"; public static final String COPYRIGHT = "Copyright (C) 2004-2016"; public static final String AUTHER = "@きよし - Akiyoshi Kamide"; public static final String URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/"; @@ -403,6 +403,7 @@ public class ChordHelperApplet extends JApplet { private JLabel songTitleLabel = new JLabel(); private AnoGakkiPane anoGakkiPane; private JToggleButton anoGakkiToggleButton; + private MidiTransceiverListModelList deviceModelList; public void init() { // @@ -467,7 +468,7 @@ public class ChordHelperApplet extends JApplet { VirtualMidiDevice guiMidiDevice = keyboardPanel.keyboardCenterPanel.keyboard.midiDevice; // // MIDIデバイス一覧を構築 - MidiTransceiverListModelList deviceModelList = new MidiTransceiverListModelList(Arrays.asList(guiMidiDevice)); + deviceModelList = new MidiTransceiverListModelList(Arrays.asList(guiMidiDevice)); (midiDeviceDialog = new MidiDeviceDialog(deviceModelList)).setIconImage(iconImage); // // MIDIデバイス一覧のシーケンサと連携するプレイリストを構築 @@ -698,6 +699,11 @@ public class ChordHelperApplet extends JApplet { setPreferredSize(new Dimension(750,470)); } @Override + public void destroy() { + deviceModelList.closeAllDevices(); + super.destroy(); + } + @Override public void start() { // // コードボタンで設定されている現在の調を diff --git a/src/camidion/chordhelper/MidiChordHelper.java b/src/camidion/chordhelper/MidiChordHelper.java index a470ecf..f564968 100644 --- a/src/camidion/chordhelper/MidiChordHelper.java +++ b/src/camidion/chordhelper/MidiChordHelper.java @@ -83,7 +83,10 @@ public class MidiChordHelper { if( ! applet.playlistModel.isModified() || applet.midiEditor.confirm( "MIDI file not saved, exit anyway ?\n"+ "保存されていないMIDIファイルがありますが、終了してよろしいですか?" - )) System.exit(0); + )) { + applet.destroy(); + System.exit(0); + } } }); applet.sequencerModel.addChangeListener(new ChangeListener() { @@ -105,7 +108,7 @@ public class MidiChordHelper { int col = event.getColumn(); if( col == PlaylistTableModel.Column.FILENAME.ordinal() || col == TableModelEvent.ALL_COLUMNS ) { PlaylistTableModel pl = (PlaylistTableModel) event.getSource(); - setFilenameToTitle(pl.sequencerModel.getSequenceTrackListTableModel()); + setFilenameToTitle(pl.getSequencerModel().getSequenceTrackListTableModel()); } } }); diff --git a/src/camidion/chordhelper/mididevice/MidiTransceiverListModelList.java b/src/camidion/chordhelper/mididevice/MidiTransceiverListModelList.java index 1c3fc70..4bd10ac 100644 --- a/src/camidion/chordhelper/mididevice/MidiTransceiverListModelList.java +++ b/src/camidion/chordhelper/mididevice/MidiTransceiverListModelList.java @@ -125,4 +125,10 @@ public class MidiTransceiverListModelList extends Vector= 0 ) text = String.format(text+" - MIDI file No.%d", index); setText(text); if( newModel == null ) { - newModel = oldModel.sequenceListTableModel.emptyTrackListTableModel; + newModel = oldModel.getParent().emptyTrackListTableModel; addTrackAction.setEnabled(false); } else { addTrackAction.setEnabled(true); } - oldModel.trackListSelectionModel.removeListSelectionListener(trackSelectionListener); + oldModel.getSelectionModel().removeListSelectionListener(trackSelectionListener); setModel(newModel); - setSelectionModel(newModel.trackListSelectionModel); - newModel.trackListSelectionModel.addListSelectionListener(trackSelectionListener); + setSelectionModel(newModel.getSelectionModel()); + newModel.getSelectionModel().addListSelectionListener(trackSelectionListener); trackSelectionListener.valueChanged(null); } } /** * トラック選択リスナー */ - TrackSelectionListener trackSelectionListener; - /** - * 選択トラックの変更に反応するリスナー - */ - private class TrackSelectionListener implements ListSelectionListener { + ListSelectionListener trackSelectionListener = new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { if( e != null && e.getValueIsAdjusting() ) return; - ListSelectionModel tlsm = getModel().trackListSelectionModel; + ListSelectionModel tlsm = getModel().getSelectionModel(); deleteTrackAction.setEnabled(! tlsm.isSelectionEmpty()); eventListTable.titleLabel.update(tlsm, getModel()); } - } + }; /** * {@inheritDoc} * @@ -679,7 +676,7 @@ public class MidiSequenceEditor extends JDialog { * @param model トラック(イベントリスト)データモデル */ public EventListTable(TrackEventListTableModel model) { - super(model, null, model.eventSelectionModel); + super(model, null, model.getSelectionModel()); // // 列モデルにセルエディタを設定 eventCellEditor = new MidiEventCellEditor(); @@ -724,7 +721,7 @@ public class MidiSequenceEditor extends JDialog { if( oldTrackModel == newTrackModel ) return; if( newTrackModel == null ) { - newTrackModel = getModel().sequenceTrackListTableModel.sequenceListTableModel.emptyEventListTableModel; + newTrackModel = getModel().getParent().getParent().emptyEventListTableModel; queryJumpEventAction.setEnabled(false); queryAddEventAction.setEnabled(false); @@ -737,10 +734,10 @@ public class MidiSequenceEditor extends JDialog { queryJumpEventAction.setEnabled(true); queryAddEventAction.setEnabled(true); } - oldTrackModel.eventSelectionModel.removeListSelectionListener(eventSelectionListener); + oldTrackModel.getSelectionModel().removeListSelectionListener(eventSelectionListener); setModel(newTrackModel); - setSelectionModel(newTrackModel.eventSelectionModel); - newTrackModel.eventSelectionModel.addListSelectionListener(eventSelectionListener); + setSelectionModel(newTrackModel.getSelectionModel()); + newTrackModel.getSelectionModel().addListSelectionListener(eventSelectionListener); } } @@ -753,7 +750,7 @@ public class MidiSequenceEditor extends JDialog { */ private class EventSelectionListener implements ListSelectionListener { public EventSelectionListener() { - getModel().eventSelectionModel.addListSelectionListener(this); + getModel().getSelectionModel().addListSelectionListener(this); } @Override public void valueChanged(ListSelectionEvent e) { @@ -846,12 +843,12 @@ public class MidiSequenceEditor extends JDialog { */ private void setSelectedEvent(TrackEventListTableModel trackModel) { this.trackModel = trackModel; - SequenceTrackListTableModel sequenceTableModel = trackModel.sequenceTrackListTableModel; + SequenceTrackListTableModel sequenceTableModel = trackModel.getParent(); int ppq = sequenceTableModel.getSequence().getResolution(); eventDialog.midiMessageForm.durationForm.setPPQ(ppq); tickPositionModel.setSequenceIndex(sequenceTableModel.getSequenceTickIndex()); - selectedIndex = trackModel.eventSelectionModel.getMinSelectionIndex(); + selectedIndex = trackModel.getSelectionModel().getMinSelectionIndex(); selectedMidiEvent = selectedIndex < 0 ? null : trackModel.getMidiEvent(selectedIndex); currentTick = selectedMidiEvent == null ? 0 : selectedMidiEvent.getTick(); tickPositionModel.setTickPosition(currentTick); @@ -860,7 +857,7 @@ public class MidiSequenceEditor extends JDialog { MidiEvent partnerEvent = null; eventDialog.midiMessageForm.setMessage( selectedMidiEvent.getMessage(), - trackModel.sequenceTrackListTableModel.charset + trackModel.getParent().charset ); if( eventDialog.midiMessageForm.isNote() ) { int partnerIndex = trackModel.getIndexOfPartnerFor(selectedIndex); @@ -896,8 +893,8 @@ public class MidiSequenceEditor extends JDialog { clipBoard.paste(trackModel, tick); scrollToEventAt(tick); // ペーストで曲の長さが変わったことをプレイリストに通知 - SequenceTrackListTableModel seqModel = trackModel.sequenceTrackListTableModel; - seqModel.sequenceListTableModel.fireSequenceModified(seqModel); + SequenceTrackListTableModel seqModel = trackModel.getParent(); + seqModel.getParent().fireSequenceModified(seqModel); eventDialog.setVisible(false); trackModel = null; } @@ -905,7 +902,7 @@ public class MidiSequenceEditor extends JDialog { private boolean applyEvent() { long tick = tickPositionModel.getTickPosition(); MidiMessageForm form = eventDialog.midiMessageForm; - SequenceTrackListTableModel seqModel = trackModel.sequenceTrackListTableModel; + SequenceTrackListTableModel seqModel = trackModel.getParent(); MidiEvent newMidiEvent = new MidiEvent(form.getMessage(seqModel.charset), tick); if( midiEventsToBeOverwritten != null ) { // 上書き消去するための選択済イベントがあった場合 @@ -933,7 +930,7 @@ public class MidiSequenceEditor extends JDialog { scrollToEventAt(partnerTick > tick ? partnerTick : tick); } } - seqModel.sequenceListTableModel.fireSequenceModified(seqModel); + seqModel.getParent().fireSequenceModified(seqModel); eventDialog.setVisible(false); return true; } @@ -979,7 +976,7 @@ public class MidiSequenceEditor extends JDialog { private int copiedEventsPPQ = 0; public void copy(TrackEventListTableModel model, boolean withRemove) { copiedEventsToPaste = model.getSelectedMidiEvents(); - copiedEventsPPQ = model.sequenceTrackListTableModel.getSequence().getResolution(); + copiedEventsPPQ = model.getParent().getSequence().getResolution(); if( withRemove ) model.removeMidiEvents(copiedEventsToPaste); boolean en = (copiedEventsToPaste != null && copiedEventsToPaste.length > 0); queryPasteEventAction.setEnabled(en); @@ -1166,7 +1163,9 @@ public class MidiSequenceEditor extends JDialog { add(new JButton(newSequenceDialog.openAction) {{ setMargin(ZERO_INSETS); }}); if( sequenceListTable.midiFileChooser != null ) { add( Box.createRigidArea(new Dimension(5, 0)) ); - add(new JButton(sequenceListTable.midiFileChooser.openMidiFileAction) {{ setMargin(ZERO_INSETS); }}); + add(new JButton(sequenceListTable.midiFileChooser.openMidiFileAction) { + { setMargin(ZERO_INSETS); } + }); } if(sequenceListTable.base64EncodeAction != null) { add(Box.createRigidArea(new Dimension(5, 0))); @@ -1179,17 +1178,19 @@ public class MidiSequenceEditor extends JDialog { add(new JButton(playlistTableModel.moveToBottomAction) {{ setMargin(ZERO_INSETS); }}); if( sequenceListTable.midiFileChooser != null ) { add(Box.createRigidArea(new Dimension(5, 0))); - add(new JButton(sequenceListTable.midiFileChooser.saveMidiFileAction) {{ setMargin(ZERO_INSETS); }}); + add(new JButton(sequenceListTable.midiFileChooser.saveMidiFileAction) { + { setMargin(ZERO_INSETS); } + }); } add( Box.createRigidArea(new Dimension(5, 0)) ); add(new JButton(sequenceListTable.deleteSequenceAction) {{ setMargin(ZERO_INSETS); }}); add( Box.createRigidArea(new Dimension(5, 0)) ); - add(new SequencerSpeedSlider(playlistTableModel.sequencerModel.speedSliderModel)); + add(new SequencerSpeedSlider(playlistTableModel.getSequencerModel().speedSliderModel)); add( Box.createRigidArea(new Dimension(5, 0)) ); add(new JPanel() {{ - MidiSequencerModel sequencerModel = sequenceListTable.getModel().sequencerModel; - add(new JLabel("SyncMode:")); - add(new JLabel("Master")); + setBorder(new EtchedBorder()); + MidiSequencerModel sequencerModel = sequenceListTable.getModel().getSequencerModel(); + add(new JLabel("Sync Master")); add(new JComboBox(sequencerModel.masterSyncModeModel)); add(new JLabel("Slave")); add(new JComboBox(sequencerModel.slaveSyncModeModel)); diff --git a/src/camidion/chordhelper/midieditor/PlaylistTableModel.java b/src/camidion/chordhelper/midieditor/PlaylistTableModel.java index 29e18b5..48873cc 100644 --- a/src/camidion/chordhelper/midieditor/PlaylistTableModel.java +++ b/src/camidion/chordhelper/midieditor/PlaylistTableModel.java @@ -41,10 +41,11 @@ import camidion.chordhelper.music.ChordProgression; * プレイリスト(MIDIシーケンスリスト)のテーブルデータモデル */ public class PlaylistTableModel extends AbstractTableModel { + private MidiSequencerModel sequencerModel; /** - * MIDIシーケンサモデル + * このプレイリストと連携しているMIDIシーケンサモデルを返します。 */ - public MidiSequencerModel sequencerModel; + public MidiSequencerModel getSequencerModel() { return sequencerModel; } /** * 空のトラックリストモデル */ @@ -61,13 +62,32 @@ public class PlaylistTableModel extends AbstractTableModel { setSelectionMode(ListSelectionModel.SINGLE_SELECTION); } }; + /** 再生中のシーケンサーの秒位置リスナー */ + private ChangeListener secondPosition = new ChangeListener() { + private int value = 0; + @Override + public void stateChanged(ChangeEvent event) { + Object src = event.getSource(); + if( src instanceof MidiSequencerModel ) { + int newValue = ((MidiSequencerModel)src).getValue() / 1000; + if(value == newValue) return; + value = newValue; + int rowIndex = indexOfSequenceOnSequencer(); + fireTableCellUpdated(rowIndex, Column.POSITION.ordinal()); + } + } + @Override + public String toString() { + return String.format("%02d:%02d", value/60, value%60); + } + }; /** * 新しいプレイリストのテーブルモデルを構築します。 * @param sequencerModel 連携するMIDIシーケンサーモデル */ public PlaylistTableModel(MidiSequencerModel sequencerModel) { this.sequencerModel = sequencerModel; - sequencerModel.addChangeListener(secondPosition = new SecondPosition()); + sequencerModel.addChangeListener(secondPosition); sequencerModel.getSequencer().addMetaEventListener( new MetaEventListener() { /** @@ -176,31 +196,6 @@ public class PlaylistTableModel extends AbstractTableModel { public void actionPerformed(ActionEvent event) { } }; /** - * 再生中のシーケンサーの秒位置 - */ - private class SecondPosition implements ChangeListener { - private int value = 0; - /** - * 再生中のシーケンサーの秒位置が変わったときに表示を更新します。 - * @param event 変更イベント - */ - @Override - public void stateChanged(ChangeEvent event) { - Object src = event.getSource(); - if( src instanceof MidiSequencerModel ) { - int newValue = ((MidiSequencerModel)src).getValue() / 1000; - if(value == newValue) return; - value = newValue; - int rowIndex = indexOfSequenceOnSequencer(); - fireTableCellUpdated(rowIndex, Column.POSITION.ordinal()); - } - } - @Override - public String toString() { - return String.format("%02d:%02d", value/60, value%60); - } - } - /** * 曲の先頭または前の曲へ戻るアクション */ public Action moveToTopAction = new AbstractAction() { @@ -245,8 +240,7 @@ public class PlaylistTableModel extends AbstractTableModel { public boolean isCellEditable() { return true; } // ダブルクリックだけ有効 @Override public Object getValueOf(SequenceTrackListTableModel sequenceModel) { - return sequenceModel.isOnSequencer() - ? sequenceModel.sequenceListTableModel.secondPosition : ""; + return sequenceModel.isOnSequencer() ? sequenceModel.getParent().secondPosition : ""; } }, /** シーケンスの時間長(分:秒) */ @@ -351,8 +345,6 @@ public class PlaylistTableModel extends AbstractTableModel { public boolean isCellEditable(int row, int column) { return Column.values()[column].isCellEditable(); } - /** 再生中のシーケンサーの秒位置 */ - private SecondPosition secondPosition; @Override public Object getValueAt(int row, int column) { PlaylistTableModel.Column c = Column.values()[column]; diff --git a/src/camidion/chordhelper/midieditor/SequenceTrackListTableModel.java b/src/camidion/chordhelper/midieditor/SequenceTrackListTableModel.java index bae324b..22f35cf 100644 --- a/src/camidion/chordhelper/midieditor/SequenceTrackListTableModel.java +++ b/src/camidion/chordhelper/midieditor/SequenceTrackListTableModel.java @@ -56,10 +56,11 @@ public class SequenceTrackListTableModel extends AbstractTableModel { this.preferredWidth = preferredWidth; } } + private PlaylistTableModel sequenceListTableModel; /** - * 親のプレイリスト + * このモデルを収容している親のプレイリストを返します。 */ - PlaylistTableModel sequenceListTableModel; + public PlaylistTableModel getParent() { return sequenceListTableModel; } /** * ラップされたMIDIシーケンス */ @@ -80,15 +81,16 @@ public class SequenceTrackListTableModel extends AbstractTableModel { * トラックリスト */ private List trackModelList = new ArrayList<>(); - /** - * 選択されているトラックのインデックス - */ - ListSelectionModel trackListSelectionModel = new DefaultListSelectionModel(){ + private ListSelectionModel trackListSelectionModel = new DefaultListSelectionModel(){ { setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); } }; /** + * 選択状態を返します。 + */ + public ListSelectionModel getSelectionModel() { return trackListSelectionModel; } + /** * MIDIシーケンスとファイル名から {@link SequenceTrackListTableModel} を構築します。 * @param sequenceListTableModel 親のプレイリスト * @param sequence MIDIシーケンス @@ -140,9 +142,9 @@ public class SequenceTrackListTableModel extends AbstractTableModel { case TRACK_NUMBER: return row; case EVENTS: return sequence.getTracks()[row].size(); case MUTE: - return isOnSequencer() ? sequenceListTableModel.sequencerModel.getSequencer().getTrackMute(row) : ""; + return isOnSequencer() ? sequenceListTableModel.getSequencerModel().getSequencer().getTrackMute(row) : ""; case SOLO: - return isOnSequencer() ? sequenceListTableModel.sequencerModel.getSequencer().getTrackSolo(row) : ""; + return isOnSequencer() ? sequenceListTableModel.getSequencerModel().getSequencer().getTrackSolo(row) : ""; case RECORD_CHANNEL: return isOnSequencer() ? trackModelList.get(row).getRecordingChannel() : ""; case CHANNEL: { @@ -176,10 +178,10 @@ public class SequenceTrackListTableModel extends AbstractTableModel { SequenceTrackListTableModel.Column c = Column.values()[column]; switch(c) { case MUTE: - sequenceListTableModel.sequencerModel.getSequencer().setTrackMute(row, ((Boolean)val).booleanValue()); + sequenceListTableModel.getSequencerModel().getSequencer().setTrackMute(row, ((Boolean)val).booleanValue()); break; case SOLO: - sequenceListTableModel.sequencerModel.getSequencer().setTrackSolo(row, ((Boolean)val).booleanValue()); + sequenceListTableModel.getSequencerModel().getSequencer().setTrackSolo(row, ((Boolean)val).booleanValue()); break; case RECORD_CHANNEL: trackModelList.get(row).setRecordingChannel((String)val); @@ -229,7 +231,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel { private void setSequence(Sequence sequence) { // // 旧シーケンスの録音モードを解除 - sequenceListTableModel.sequencerModel.getSequencer().recordDisable(null); // The "null" means all tracks + sequenceListTableModel.getSequencerModel().getSequencer().recordDisable(null); // The "null" means all tracks // // トラックリストをクリア int oldSize = trackModelList.size(); @@ -411,7 +413,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel { * @return シーケンサーが操作していたらtrue */ public boolean isOnSequencer() { - return sequence == sequenceListTableModel.sequencerModel.getSequencer().getSequence(); + return sequence == sequenceListTableModel.getSequencerModel().getSequencer().getSequence(); } /** * 録音しようとしているチャンネルの設定されたトラックがあるか調べます。 diff --git a/src/camidion/chordhelper/midieditor/SequencerSpeedSlider.java b/src/camidion/chordhelper/midieditor/SequencerSpeedSlider.java index 2c63dc8..3d48fdd 100644 --- a/src/camidion/chordhelper/midieditor/SequencerSpeedSlider.java +++ b/src/camidion/chordhelper/midieditor/SequencerSpeedSlider.java @@ -1,88 +1,133 @@ package camidion.chordhelper.midieditor; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.NumberFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Hashtable; import java.util.List; -import javax.swing.AbstractSpinnerModel; import javax.swing.BoundedRangeModel; import javax.swing.BoxLayout; +import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; -import javax.swing.JSpinner; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; +import javax.swing.border.EtchedBorder; + +import camidion.chordhelper.ChordHelperApplet; /** * シーケンサーの再生スピード調整スライダビュー */ public class SequencerSpeedSlider extends JPanel { + private static int RESOLUTION = 1200; + private static final List maxFactors = Arrays.asList( + "x1", "x1.2", "x1.25", "x1.5", "x2", "x3", "x4", "x5", "x6", + "x8", "x12", "x16", "x24", "x32"); public static float tempoFactorOf(int val) { - return (float) Math.pow( 2, ((double)val)/12.0 ); + return (float) Math.pow( 2, ((double)val)/RESOLUTION ); } - private static final List> labeltables = new ArrayList>() {{ - for( int i = 0; i < 5; i++ ) { - Hashtable e = new Hashtable<>(); - add(e); - e.put(-i * 12, new JLabel( "x" + Double.toString(Math.pow( 2, (double)(-i) )) )); - e.put(0, new JLabel( "x1.0" )); - e.put(i * 12, new JLabel( "x" + Double.toString(Math.pow( 2, (double)i )) )); + private static final List> + tickLabeltables = new ArrayList>() + { + { + NumberFormat formetter = NumberFormat.getInstance(); + for( String maxFactorString : maxFactors ) { + Hashtable e = new Hashtable<>(); + Double maxFactor = Double.parseDouble(maxFactorString.substring(1)); + add(e); + int maxValue = (int) Math.round(Math.log(maxFactor) / Math.log(2) * RESOLUTION); + if( maxFactorString.equals("x1") ) { + e.put(0, new JLabel("Play speed : x1 (Original)")); + } else { + e.put(-maxValue, new JLabel("x" + formetter.format(1/maxFactor))); + e.put(0, new JLabel("x1")); + e.put(maxValue, new JLabel(maxFactorString)); + } + } } - }}; - private JLabel titleLabel; + }; private JSlider slider; + private void changeSliderScale(String maxFactorString) { + int index = maxFactors.indexOf(maxFactorString); + slider.setLabelTable(tickLabeltables.get(index)); + BoundedRangeModel sliderModel = slider.getModel(); + Double maxFactor = Double.parseDouble(maxFactorString.substring(1)); + int maxValue = (int) Math.round(Math.log(maxFactor) / Math.log(2) * RESOLUTION); + slider.setMajorTickSpacing((int) Math.round((double)maxValue / 2.0)); + if( index > 0 ) { + sliderModel.setMinimum(-maxValue); + sliderModel.setMaximum(maxValue); + slider.setEnabled(true); + } else { + sliderModel.setMinimum(-1); + sliderModel.setValue(0); + sliderModel.setMaximum(1); + slider.setEnabled(false); + } + } public SequencerSpeedSlider(BoundedRangeModel model) { + setBorder(new EtchedBorder()); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); - add(titleLabel = new JLabel("Speed: ")); - add(slider = new JSlider(model){{ - setPaintTicks(true); - setMajorTickSpacing(12); - setMinorTickSpacing(1); - setPaintLabels(true); - setVisible(false); - }}); - add(new JLabel("x")); - add(new JSpinner(new AbstractSpinnerModel() { - private int index = 0; - @Override - public Object getValue() { return Math.pow( 2, (double)index ); } - @Override - public void setValue(Object value) { - index = (int) Math.round( Math.log((Double)value) / Math.log(2) ); - fireStateChanged(); + add(slider = new JSlider(model){ + { + setPaintTicks(true); + setMajorTickSpacing(RESOLUTION/2); + setPaintLabels(true); + setLabelTable(tickLabeltables.get(0)); + setEnabled(false); } - @Override - public Object getNextValue() { - return index >= 4 ? null : Math.pow( 2, (double)(++index) ); - } - @Override - public Object getPreviousValue() { - return index <= 0 ? null : Math.pow( 2, (double)(--index) ); - } - }) {{ - addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - int index = (int) Math.round( Math.log((Double)getValue()) / Math.log(2) ); - BoundedRangeModel model = slider.getModel(); - if( index == 0 ) { - model.setValue(0); - slider.setVisible(false); - titleLabel.setVisible(true); - return; + }); + add(new JPanel() { + private int index = 0; + private JButton push, pull; + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(pull = new JButton("=>|") { + { + setSize(new Dimension(20,20)); + setMargin(ChordHelperApplet.ZERO_INSETS); + addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + int max = maxFactors.size() - 1; + if( index >= max ) return; + changeSliderScale(maxFactors.get(++index)); + if( index >= max ) { + setEnabled(false); + push.requestFocusInWindow(); + return; + } + push.setEnabled(true); + } + }); } - int maxValue = index * 12; - model.setMinimum(-maxValue); - model.setMaximum(maxValue); - slider.setMajorTickSpacing(12); - slider.setMinorTickSpacing(index > 2 ? 12 : 1); - slider.setLabelTable(labeltables.get(index)); - slider.setVisible(true); - titleLabel.setVisible(false); - } - }); - }}); + }); + add(push = new JButton("<=|") { + { + setSize(new Dimension(20,20)); + setMargin(ChordHelperApplet.ZERO_INSETS); + setEnabled(false); + addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if( index <= 0 ) return; + changeSliderScale(maxFactors.get(--index)); + if( index <= 0 ) { + setEnabled(false); + pull.requestFocusInWindow(); + return; + } + pull.setEnabled(true); + } + }); + } + }); + } + }); } -} \ No newline at end of file +} diff --git a/src/camidion/chordhelper/midieditor/TrackEventListTableModel.java b/src/camidion/chordhelper/midieditor/TrackEventListTableModel.java index e0870a7..5c591f7 100644 --- a/src/camidion/chordhelper/midieditor/TrackEventListTableModel.java +++ b/src/camidion/chordhelper/midieditor/TrackEventListTableModel.java @@ -105,19 +105,23 @@ public class TrackEventListTableModel extends AbstractTableModel { * ラップされているMIDIトラック */ private Track track; + private SequenceTrackListTableModel sequenceTrackListTableModel; /** - * 親のシーケンスモデル + * このトラックモデルを収容している親のシーケンスモデルを返します。 */ - SequenceTrackListTableModel sequenceTrackListTableModel; - /** - * 選択されているイベントのインデックス - */ - ListSelectionModel eventSelectionModel = new DefaultListSelectionModel() { + public SequenceTrackListTableModel getParent() { + return sequenceTrackListTableModel; + } + private ListSelectionModel eventSelectionModel = new DefaultListSelectionModel() { { setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); } }; /** + * 選択状態を返します。 + */ + public ListSelectionModel getSelectionModel() { return eventSelectionModel; } + /** * シーケンスを親にして、その特定のトラックに連動する * MIDIトラックモデルを構築します。 * @@ -216,7 +220,7 @@ public class TrackEventListTableModel extends AbstractTableModel { fireTableDataChanged(); if( MIDISpec.isEOT(msg) ) { // EOTの場所が変わると曲の長さが変わるので、親モデルへ通知する。 - sequenceTrackListTableModel.sequenceListTableModel.fireSequenceModified(sequenceTrackListTableModel); + sequenceTrackListTableModel.getParent().fireSequenceModified(sequenceTrackListTableModel); } } /** @@ -248,7 +252,7 @@ public class TrackEventListTableModel extends AbstractTableModel { if( ! MIDISpec.setNameBytesOf(track, b) ) return false; sequenceTrackListTableModel.setModified(true); - sequenceTrackListTableModel.sequenceListTableModel.fireSequenceModified(sequenceTrackListTableModel); + sequenceTrackListTableModel.getParent().fireSequenceModified(sequenceTrackListTableModel); fireTableDataChanged(); return true; } @@ -263,7 +267,7 @@ public class TrackEventListTableModel extends AbstractTableModel { * @param recordingChannel 録音中のMIDIチャンネル */ public void setRecordingChannel(String recordingChannel) { - Sequencer sequencer = sequenceTrackListTableModel.sequenceListTableModel.sequencerModel.getSequencer(); + Sequencer sequencer = sequenceTrackListTableModel.getParent().getSequencerModel().getSequencer(); if( recordingChannel.equals("OFF") ) { sequencer.recordDisable( track ); } @@ -539,7 +543,7 @@ public class TrackEventListTableModel extends AbstractTableModel { int oldLastIndex = lastIndex + midiEvents.length; if(lastIndex < 0) lastIndex = 0; fireTableRowsDeleted(oldLastIndex, lastIndex); - sequenceTrackListTableModel.sequenceListTableModel.fireSelectedSequenceModified(); + sequenceTrackListTableModel.getParent().fireSelectedSequenceModified(); } /** * 引数の選択内容が示すMIDIイベントを除去します。