OSDN Git Service

リファクタリング
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Fri, 24 Mar 2017 17:10:51 +0000 (02:10 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Fri, 24 Mar 2017 17:10:51 +0000 (02:10 +0900)
15 files changed:
src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/MidiChordHelper.java
src/camidion/chordhelper/anogakki/AnoGakkiPane.java
src/camidion/chordhelper/mididevice/MidiDeviceDesktopPane.java
src/camidion/chordhelper/mididevice/MidiDeviceDialog.java
src/camidion/chordhelper/mididevice/SequencerTimeView.java
src/camidion/chordhelper/midieditor/Base64Dialog.java
src/camidion/chordhelper/midieditor/MidiMessageForm.java
src/camidion/chordhelper/midieditor/MidiProgramSelecter.java
src/camidion/chordhelper/midieditor/MidiSequenceEditorDialog.java
src/camidion/chordhelper/midieditor/NewSequenceDialog.java
src/camidion/chordhelper/midieditor/PlaylistTableModel.java
src/camidion/chordhelper/midieditor/SequenceTrackListTableModel.java
src/camidion/chordhelper/music/MIDISpec.java
src/camidion/chordhelper/pianokeyboard/MidiKeyboardPanel.java

index 2efb985..93b2eac 100644 (file)
@@ -11,6 +11,7 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.io.IOException;
+import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.security.AccessControlException;
@@ -18,6 +19,7 @@ import java.util.Arrays;
 
 import javax.sound.midi.InvalidMidiDataException;
 import javax.sound.midi.MetaMessage;
+import javax.sound.midi.MidiSystem;
 import javax.sound.midi.Sequence;
 import javax.sound.midi.Sequencer;
 import javax.swing.Box;
@@ -92,7 +94,7 @@ public class ChordHelperApplet extends JApplet {
        public int addRandomSongToPlaylist(int measureLength) throws InvalidMidiDataException {
                NewSequenceDialog d = midiEditor.newSequenceDialog;
                d.setRandomChordProgression(measureLength);
-               return playlistModel.addSequenceAndPlay(d.getMidiSequence());
+               return playlistModel.play(d.getMidiSequence());
        }
        /**
         * URLで指定されたMIDIファイルをプレイリストへ追加します。
@@ -105,7 +107,10 @@ public class ChordHelperApplet extends JApplet {
         */
        public int addToPlaylist(String midiFileUrl) {
                try {
-                       return playlistModel.addSequenceFromURL(midiFileUrl);
+                       URL url = (new URI(midiFileUrl)).toURL();
+                       String filename = url.getFile().replaceFirst("^.*/","");
+                       Sequence sequence = MidiSystem.getSequence(url);
+                       return playlistModel.add(sequence, filename);
                } catch( URISyntaxException|IOException|InvalidMidiDataException e ) {
                        midiEditor.showWarning(e);
                } catch( AccessControlException e ) {
@@ -133,12 +138,7 @@ public class ChordHelperApplet extends JApplet {
        public int addToPlaylistBase64(String base64EncodedText, String filename) {
                Base64Dialog d = midiEditor.base64Dialog;
                d.setBase64Data(base64EncodedText);
-               try {
-                       return playlistModel.addSequence(d.getMIDIData(), filename);
-               } catch (Exception e) {
-                       midiEditor.showWarning(e);
-                       return -1;
-               }
+               return d.addToPlaylist();
        }
        /**
         * プレイリスト上で現在選択されているMIDIシーケンスを、
@@ -173,8 +173,9 @@ public class ChordHelperApplet extends JApplet {
         * 現在シーケンサにロードされているMIDIデータを
         * Base64テキストに変換した結果を返します。
         * @return MIDIデータをBase64テキストに変換した結果
+        * @throws IOException MIDIデータの読み込みに失敗した場合
         */
-       public String getMidiDataBase64() {
+       public String getMidiDataBase64() throws IOException {
                SequenceTrackListTableModel sequenceModel = sequencerModel.getSequenceTrackListTableModel();
                midiEditor.base64Dialog.setMIDIData(sequenceModel.getMIDIdata());
                return midiEditor.base64Dialog.getBase64Data();
@@ -249,8 +250,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public void setChordDiagramVisible(boolean isVisible) {
                keyboardSplitPane.resetToPreferredSizes();
-               if( ! isVisible )
-                       keyboardSplitPane.setDividerLocation((double)1.0);
+               if( ! isVisible ) keyboardSplitPane.setDividerLocation((double)1.0);
        }
        /**
         * コードダイヤグラムをギターモードに変更します。
@@ -271,7 +271,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public static class VersionInfo {
                public static final String NAME = "MIDI Chord Helper";
-               public static final String VERSION = "Ver.20170320.1";
+               public static final String VERSION = "Ver.20170324.1";
                public static final String COPYRIGHT = "Copyright (C) 2004-2017";
                public static final String AUTHER = "@きよし - Akiyoshi Kamide";
                public static final String URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";
@@ -332,30 +332,31 @@ public class ChordHelperApplet extends JApplet {
                // コードダイアグラム、コードボタン、ピアノ鍵盤のセットアップ
                CapoComboBoxModel capoComboBoxModel = new CapoComboBoxModel();
                chordDiagram = new ChordDiagram(capoComboBoxModel);
-               chordMatrix = new ChordMatrix(capoComboBoxModel) {{
-                       addChordMatrixListener(new ChordMatrixListener(){
-                               public void keySignatureChanged() {
-                                       Key capoKey = getKeySignatureCapo();
-                                       keyboardPanel.keySelecter.setSelectedKey(capoKey);
-                                       keyboardPanel.keyboardCenterPanel.keyboard.setKeySignature(capoKey);
-                               }
-                               public void chordChanged() { chordOn(); }
-                       });
-                       capoSelecter.checkbox.addItemListener(e->{
+               chordMatrix = new ChordMatrix(capoComboBoxModel) {
+                       private void clearChord() {
                                chordOn();
                                keyboardPanel.keyboardCenterPanel.keyboard.chordDisplay.clear();
                                chordDiagram.clear();
-                       });
-                       capoSelecter.valueSelecter.addActionListener(e->{
-                               chordOn();
-                               keyboardPanel.keyboardCenterPanel.keyboard.chordDisplay.clear();
-                               chordDiagram.clear();
-                       });
-               }};
+                       }
+                       {
+                               addChordMatrixListener(new ChordMatrixListener(){
+                                       public void keySignatureChanged() {
+                                               Key capoKey = getKeySignatureCapo();
+                                               keyboardPanel.keySelecter.setSelectedKey(capoKey);
+                                               keyboardPanel.keyboardCenterPanel.keyboard.setKeySignature(capoKey);
+                                       }
+                                       public void chordChanged() { chordOn(); }
+                               });
+                               capoSelecter.checkbox.addItemListener(e->clearChord());
+                               capoSelecter.valueSelecter.addActionListener(e->clearChord());
+                       }
+               };
                keysigLabel = new KeySignatureLabel() {{
                        addMouseListener(new MouseAdapter() {
                                @Override
-                               public void mousePressed(MouseEvent e) { chordMatrix.setKeySignature(getKey()); }
+                               public void mousePressed(MouseEvent e) {
+                                       chordMatrix.setKeySignature(getKey());
+                               }
                        });
                }};
                keyboardPanel = new MidiKeyboardPanel(chordMatrix) {{
@@ -363,13 +364,9 @@ public class ChordHelperApplet extends JApplet {
                                @Override
                                public void pianoKeyPressed(int n, InputEvent e) { chordDiagram.clear(); }
                        });
-                       keySelecter.getKeysigCombobox().addActionListener(
-                               e -> chordMatrix.setKeySignature(
-                                       keySelecter.getSelectedKey().transposedKey(
-                                               -chordMatrix.capoSelecter.getCapo()
-                                       )
-                               )
-                       );
+                       keySelecter.getKeysigCombobox().addActionListener(e->chordMatrix.setKeySignature(
+                               keySelecter.getSelectedKey().transposedKey(-chordMatrix.capoSelecter.getCapo())
+                       ));
                        keyboardCenterPanel.keyboard.setPreferredSize(new Dimension(571, 80));
                }};
                VirtualMidiDevice guiMidiDevice = keyboardPanel.keyboardCenterPanel.keyboard.midiDevice;
@@ -421,18 +418,15 @@ public class ChordHelperApplet extends JApplet {
                sequencerModel.addChangeListener(e->{
                        SequenceTrackListTableModel sequenceTableModel = sequencerModel.getSequenceTrackListTableModel();
                        int loadedSequenceIndex = playlistModel.indexOfSequenceOnSequencer();
-                       songTitleLabel.setText(
-                               "<html>"+(
-                                       loadedSequenceIndex < 0 ? "[No MIDI file loaded]" :
-                                       "MIDI file " + loadedSequenceIndex + ": " + (
-                                               sequenceTableModel == null ||
-                                               sequenceTableModel.toString() == null ||
-                                               sequenceTableModel.toString().isEmpty() ?
-                                               "[Untitled]" :
-                                               "<font color=maroon>"+sequenceTableModel+"</font>"
-                                       )
-                               )+"</html>"
-                       );
+                       songTitleLabel.setText("<html>"+(
+                               loadedSequenceIndex < 0 ? "[No MIDI file loaded]" :
+                               "MIDI file " + loadedSequenceIndex + ": " + (
+                                       sequenceTableModel == null ||
+                                       sequenceTableModel.toString().isEmpty() ?
+                                       "[Untitled]" :
+                                       "<font color=maroon>"+sequenceTableModel+"</font>"
+                               )
+                       )+"</html>");
                        Sequencer sequencer = sequencerModel.getSequencer();
                        chordMatrix.setPlaying(sequencer.isRunning());
                        if( sequenceTableModel != null ) {
@@ -545,7 +539,7 @@ public class ChordHelperApplet extends JApplet {
                                        add( Box.createHorizontalStrut(10) );
                                }});
                                add(new JPanel() {{
-                                       add(new JButton(midiDeviceDialog.openAction));
+                                       add(new JButton(midiDeviceDialog.getOpenAction()));
                                        add(new JButton(about.getOpenAction()));
                                }});
                        }});
@@ -587,10 +581,10 @@ public class ChordHelperApplet extends JApplet {
                //
                // アプレットのパラメータにMIDIファイルのURLが指定されていたら
                // それを再生する
-               String midi_url = getParameter("midi_file");
+               String midiUrl = getParameter("midi_file");
                System.gc();
-               if( midi_url != null ) {
-                       addToPlaylist(midi_url);
+               if( midiUrl != null ) {
+                       addToPlaylist(midiUrl);
                        try {
                                play();
                        } catch (InvalidMidiDataException ex) {
index 5fc3014..b86fb54 100644 (file)
@@ -14,10 +14,11 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Vector;
+import java.util.stream.Collectors;
 
 import javax.swing.JFrame;
 import javax.swing.JLabel;
@@ -32,14 +33,13 @@ import camidion.chordhelper.midieditor.SequenceTrackListTableModel;
  * MIDI Chord Helper を Java アプリとして起動します。
  */
 public class MidiChordHelper {
-       private static List<File> fileList = new Vector<File>();
        /**
         * MIDI Chord Helper を Java アプリとして起動します。
         * @param args コマンドライン引数
         * @throws Exception 何らかの異常が発生した場合にスローされる
         */
        public static void main(String[] args) throws Exception {
-               for(String arg : args) fileList.add(new File(arg));
+               List<File> fileList = Arrays.asList(args).stream().map(arg -> new File(arg)).collect(Collectors.toList());
                SwingUtilities.invokeLater(()->new AppletFrame(new ChordHelperApplet(), fileList));
        }
        private static class AppletFrame extends JFrame implements AppletStub, AppletContext {
@@ -88,7 +88,7 @@ public class MidiChordHelper {
                                        setFilenameToTitle(applet.sequencerModel.getSequenceTrackListTableModel());
                                }
                        });
-                       applet.midiEditor.loadAndPlay(fileList);
+                       applet.midiEditor.play(fileList);
                }
                @Override
                public boolean isActive() { return true; }
index 0d11298..61d01e3 100644 (file)
@@ -222,13 +222,7 @@ public class AnoGakkiPane extends JComponent {
                Graphics2D g2 = (Graphics2D)g;
                g2.setStroke(stroke);
                g2.setColor(color);
-               synchronized(queue) {
-                       Iterator<QueueEntry> i = queue.iterator();
-                       while(i.hasNext()) {
-                               QueueEntry entry = i.next();
-                               entry.shape.draw(g2, entry);
-                       }
-               }
+               synchronized(queue) { queue.forEach(e -> e.shape.draw(g2, e)); }
        }
        /**
         * 指定された長方形領域({@link Rectangle})の中央から図形の表示を開始します。
@@ -253,7 +247,7 @@ public class AnoGakkiPane extends JComponent {
                        return;
                }
                point = SwingUtilities.convertPoint(source, point, this);
-               synchronized (queue) { queue.add(new QueueEntry(point)); }
+               synchronized(queue) { queue.add(new QueueEntry(point)); }
                timer.start();
                prevStartedAt = startedAt;
        }
index 296e0aa..e427784 100644 (file)
@@ -29,41 +29,36 @@ public class MidiDeviceDesktopPane extends JDesktopPane implements TreeSelection
        /**
         * MIDIデバイスモデルからフレームを割り出すためのマップ
         */
-       private Map<MidiDeviceModel, MidiDeviceFrame> frameMap = new HashMap<>();
+       private Map<MidiDeviceModel, MidiDeviceFrame> frameOfModel = new HashMap<>();
        /**
-        * MIDIデバイスモデルに対応するMIDIデバイスフレームを返すマップを返します。
-        */
-       public Map<MidiDeviceModel, MidiDeviceFrame> getFrameMap() {
-               return frameMap;
-       }
-       /**
-        * ツリー上で選択状態が変わったとき、このデスクトップ上のフレームの選択状態に反映します。
+        * MIDIデバイスツリービューで選択状態が変わったとき、
+        * このデスクトップで表示しているフレームの選択状態に反映します。
         */
        @Override
        public void valueChanged(TreeSelectionEvent tse) {
-               TreePath treePath = tse.getNewLeadSelectionPath();
-               if( treePath != null ) {
-                       Object lastSelected = treePath.getLastPathComponent();
-                       if( lastSelected instanceof MidiDeviceModel ) {
-                               MidiDeviceModel deviceModel = (MidiDeviceModel)lastSelected;
-                               if( deviceModel.getMidiDevice().isOpen() ) {
+               TreePath selectedTreePath = tse.getNewLeadSelectionPath();
+               if( selectedTreePath != null ) {
+                       Object selectedLeaf = selectedTreePath.getLastPathComponent();
+                       if( selectedLeaf instanceof MidiDeviceModel ) {
+                               MidiDeviceModel selectedModel = (MidiDeviceModel)selectedLeaf;
+                               if( selectedModel.getMidiDevice().isOpen() ) {
                                        // 開いているMIDIデバイスがツリー上で選択されたら、対応するフレームを選択
-                                       MidiDeviceFrame deviceFrame = frameMap.get(deviceModel);
-                                       if( deviceFrame == null ) return;
-                                       deviceFrame.toFront();
-                                       try {
-                                               deviceFrame.setSelected(true);
-                                       } catch( PropertyVetoException ex ) {
-                                               ex.printStackTrace();
+                                       MidiDeviceFrame deviceFrame = frameOfModel.get(selectedModel);
+                                       if( deviceFrame != null ) {
+                                               deviceFrame.toFront();
+                                               try {
+                                                       deviceFrame.setSelected(true);
+                                               } catch( PropertyVetoException ex ) {
+                                                       ex.printStackTrace();
+                                               }
+                                               return;
                                        }
-                                       return;
                                }
                        }
                }
                // それ以外が選択されたら、現在選択されているフレームを非選択
                JInternalFrame frame = getSelectedFrame();
-               if( ! (frame instanceof MidiDeviceFrame) ) return;
-               try {
+               if( frame instanceof MidiDeviceFrame ) try {
                        ((MidiDeviceFrame)frame).setSelected(false);
                } catch( PropertyVetoException ex ) {
                        ex.printStackTrace();
@@ -97,39 +92,44 @@ public class MidiDeviceDesktopPane extends JDesktopPane implements TreeSelection
                        public void treeNodesRemoved(TreeModelEvent e) { }
                        @Override
                        public void treeStructureChanged(TreeModelEvent e) {
-                               // USBから切断されてツリーから消滅したMIDIデバイスモデルのフレームを削除
-                               frameMap.keySet().stream().filter(m-> ! deviceTreeModel.contains(m))
-                                       .collect(Collectors.toList()).stream().map(m-> frameMap.remove(m))
-                                       .filter(f-> f != null).forEach(f-> remove(f));
+                               // ツリーから削除されたMIDIデバイスモデルのフレームを削除
+                               frameOfModel.keySet().stream()
+                                       .filter(m-> ! deviceTreeModel.contains(m))
+                                       .collect(Collectors.toSet()).stream()
+                                       .map(m-> frameOfModel.remove(m))
+                                       .filter(f-> f != null)
+                                       .forEach(f-> remove(f));
                                //
                                // ツリーに追加されたMIDIデバイスモデルのフレームを生成
-                               deviceTreeModel.stream().filter(dm -> ! frameMap.containsKey(dm)).forEach(dm->{
-                                       MidiDeviceFrame frame = new MidiDeviceFrame(dm, cablePane);
-                                       frameMap.put(dm, frame);
-                                       //
-                                       // トランスミッタリストモデルが変化したときにMIDIケーブルを再描画
-                                       TransmitterListModel txListModel = dm.getTransmitterListModel();
-                                       if( txListModel != null ) txListModel.addListDataListener(cablePane.midiConnecterListDataListener);
-                                       //
-                                       // レシーバリストモデルが変化したときにMIDIケーブルを再描画
-                                       ReceiverListModel rxListModel = dm.getReceiverListModel();
-                                       if( rxListModel != null ) rxListModel.addListDataListener(cablePane.midiConnecterListDataListener);
-                                       //
-                                       // デバイスフレームが開閉したときの動作
-                                       frame.addInternalFrameListener(cablePane.midiDeviceFrameListener);
-                                       frame.addInternalFrameListener(deviceTreeView.midiDeviceFrameListener);
-                                       frame.addInternalFrameListener(deviceInfoPane.midiDeviceFrameListener);
-                                       //
-                                       // 移動または変形時の動作
-                                       frame.addComponentListener(cablePane.midiDeviceFrameComponentListener);
-                                       //
-                                       // サイズを設定したフレームをデスクトップに追加
-                                       frame.setSize(250, dm.getInOutType() == MidiDeviceInOutType.MIDI_IN_OUT ? 90 : 70);
-                                       add(frame);
-                                       //
-                                       // デバイスが開いていたら表示
-                                       if( dm.getMidiDevice().isOpen() ) frame.setVisible(true);
-                               });
+                               deviceTreeModel.stream()
+                                       .filter(dm -> ! frameOfModel.containsKey(dm))
+                                       .forEach(dm->{
+                                               MidiDeviceFrame frame = new MidiDeviceFrame(dm, cablePane);
+                                               frameOfModel.put(dm, frame);
+                                               //
+                                               // トランスミッタリストモデルが変化したときにMIDIケーブルを再描画
+                                               TransmitterListModel txListModel = dm.getTransmitterListModel();
+                                               if( txListModel != null ) txListModel.addListDataListener(cablePane.midiConnecterListDataListener);
+                                               //
+                                               // レシーバリストモデルが変化したときにMIDIケーブルを再描画
+                                               ReceiverListModel rxListModel = dm.getReceiverListModel();
+                                               if( rxListModel != null ) rxListModel.addListDataListener(cablePane.midiConnecterListDataListener);
+                                               //
+                                               // デバイスフレームが開閉したときの動作
+                                               frame.addInternalFrameListener(cablePane.midiDeviceFrameListener);
+                                               frame.addInternalFrameListener(deviceTreeView.midiDeviceFrameListener);
+                                               frame.addInternalFrameListener(deviceInfoPane.midiDeviceFrameListener);
+                                               //
+                                               // 移動または変形時の動作
+                                               frame.addComponentListener(cablePane.midiDeviceFrameComponentListener);
+                                               //
+                                               // サイズを設定したフレームをデスクトップに追加
+                                               frame.setSize(250, dm.getInOutType() == MidiDeviceInOutType.MIDI_IN_OUT ? 90 : 70);
+                                               add(frame);
+                                               //
+                                               // デバイスが開いていたら表示
+                                               if( dm.getMidiDevice().isOpen() ) frame.setVisible(true);
+                                       });
                        }
                };
                deviceTreeModel.addTreeModelListener(treeModelListener);
@@ -140,7 +140,7 @@ public class MidiDeviceDesktopPane extends JDesktopPane implements TreeSelection
                int toY = 10;
                for( MidiDeviceModel deviceModel : deviceTreeModel ) {
                        if( ! deviceModel.getMidiDevice().isOpen() ) continue;
-                       frameMap.get(deviceModel).setLocation(toX, toY);
+                       frameOfModel.get(deviceModel).setLocation(toX, toY);
                        toX = (toX == 10 ? 270 : 10);
                        toY += 70;
                }
@@ -175,7 +175,7 @@ public class MidiDeviceDesktopPane extends JDesktopPane implements TreeSelection
                                MidiDeviceModel deviceModel = null;
                                try {
                                        deviceModel = (MidiDeviceModel)support.getTransferable().getTransferData(flavor);
-                                       MidiDeviceFrame deviceFrame = frameMap.get(deviceModel);
+                                       MidiDeviceFrame deviceFrame = frameOfModel.get(deviceModel);
                                        if( deviceFrame == null ) return false;
                                        deviceModel.open();
                                        if( ! deviceModel.getMidiDevice().isOpen() ) {
index 09cfc0e..60d642b 100644 (file)
@@ -19,10 +19,7 @@ import camidion.chordhelper.ButtonIcon;
  */
 public class MidiDeviceDialog extends JDialog {
        public static final Icon MIDI_CONNECTER_ICON = new ButtonIcon(ButtonIcon.MIDI_CONNECTOR_ICON);
-       /**
-        * MIDIデバイスダイアログを開くアクション
-        */
-       public Action openAction = new AbstractAction() {
+       private Action openAction = new AbstractAction() {
                {
                        putValue(NAME, "MIDI device connection");
                        putValue(SHORT_DESCRIPTION, "MIDIデバイス間の接続を編集");
@@ -32,6 +29,10 @@ public class MidiDeviceDialog extends JDialog {
                public void actionPerformed(ActionEvent event) { setVisible(true); }
        };
        /**
+        * MIDIデバイスダイアログを開くアクションを返します。
+        */
+       public Action getOpenAction() { return openAction; }
+       /**
         * MIDIデバイスダイアログを構築します。
         * @param deviceTreeModel デバイスツリーモデル
         */
@@ -39,7 +40,7 @@ public class MidiDeviceDialog extends JDialog {
                setTitle(openAction.getValue(Action.NAME).toString());
                setBounds( 300, 300, 820, 540 );
                MidiDeviceTreeView deviceTreeView = new MidiDeviceTreeView(deviceTreeModel);
-               final MidiDeviceInfoPane deviceInfoPane = new MidiDeviceInfoPane();
+               MidiDeviceInfoPane deviceInfoPane = new MidiDeviceInfoPane();
                deviceTreeView.addTreeSelectionListener(deviceInfoPane);
                MidiDeviceDesktopPane desktopPane = new MidiDeviceDesktopPane(deviceTreeView, deviceInfoPane, this);
                deviceTreeView.addTreeSelectionListener(desktopPane);
index 435a7c8..1378dde 100644 (file)
@@ -5,35 +5,11 @@ import java.awt.Color;
 import javax.swing.BoxLayout;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
 
 /**
  * シーケンサの現在位置(分:秒)を表示するビュー
  */
 public class SequencerTimeView extends JPanel {
-       private TimeLabel timePositionLabel = new TimePositionLabel();
-       private TimeLabel timeLengthLabel = new TimeLengthLabel();
-       /**
-        * シーケンサの現在位置と曲の長さを(分:秒)で表示するビューを構築します。
-        * @param model MIDIシーケンサモデル
-        */
-       public SequencerTimeView(MidiSequencerModel model) {
-               setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
-               add(timePositionLabel);
-               add(timeLengthLabel);
-               model.addChangeListener(new ChangeListener() {
-                       @Override
-                       public void stateChanged(ChangeEvent e) {
-                               Object source = e.getSource();
-                               if( source instanceof MidiSequencerModel ) {
-                                       MidiSequencerModel model = (MidiSequencerModel)source;
-                                       timeLengthLabel.changeTimeInSecond(model.getMaximum()/1000);
-                                       timePositionLabel.changeTimeInSecond(model.getValue()/1000);
-                               }
-                       }
-               });
-       }
        private static abstract class TimeLabel extends JLabel {
                { setTimeInSecond(0); }
                protected String toTimeString(int sec) {
@@ -48,19 +24,34 @@ public class SequencerTimeView extends JPanel {
                        if(valueInSec != sec) setTimeInSecond(sec);
                }
        }
-       private static class TimePositionLabel extends TimeLabel {
+       private TimeLabel timePositionLabel = new TimeLabel() {
                {
                        setFont( getFont().deriveFont(getFont().getSize2D() + 4) );
                        setForeground( new Color(0x80,0x00,0x00) );
                        setToolTipText("Time position - 現在位置(分:秒)");
                }
-       }
-       private static class TimeLengthLabel extends TimeLabel {
-               {
-                       setToolTipText("Time length - 曲の長さ(分:秒)");
-               }
+       };
+       private TimeLabel timeLengthLabel = new TimeLabel() {
+               { setToolTipText("Time length - 曲の長さ(分:秒)"); }
                protected String toTimeString(int sec) {
                        return "/"+super.toTimeString(sec);
                }
+       };
+       /**
+        * シーケンサの現在位置と曲の長さを(分:秒)で表示するビューを構築します。
+        * @param model MIDIシーケンサモデル
+        */
+       public SequencerTimeView(MidiSequencerModel model) {
+               setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+               add(timePositionLabel);
+               add(timeLengthLabel);
+               model.addChangeListener(e->{
+                       Object source = e.getSource();
+                       if( source instanceof MidiSequencerModel ) {
+                               MidiSequencerModel sourceModel = (MidiSequencerModel)source;
+                               timeLengthLabel.changeTimeInSecond(sourceModel.getMaximum()/1000);
+                               timePositionLabel.changeTimeInSecond(sourceModel.getValue()/1000);
+                       }
+               });
        }
 }
index 1e33cd8..7ac6f4a 100644 (file)
@@ -1,9 +1,14 @@
 package camidion.chordhelper.midieditor;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.Base64;
 import java.util.regex.Pattern;
 
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.MidiSystem;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.Box;
@@ -33,25 +38,32 @@ public class Base64Dialog extends JDialog implements DocumentListener {
                base64TextArea.requestFocusInWindow();
        }
        /**
+        * 入力されたBase64テキストをデコードし、MIDIシーケンスとしてプレイリストに追加します。
+        * @return プレイリストに追加されたMIDIシーケンスのインデックス(先頭が0)、追加に失敗した場合は -1
+        */
+       public int addToPlaylist() {
+               byte[] midiData = null;
+               try {
+                       midiData = getMIDIData();
+               } catch(Exception e) {
+                       error("Base64デコードに失敗しました。\n"+e);
+                       return -1;
+               }
+               try (InputStream in = new ByteArrayInputStream(midiData)) {
+                       return midiEditor.sequenceListTable.getModel().add(MidiSystem.getSequence(in), null);
+               } catch( IOException|InvalidMidiDataException e ) {
+                       error("Base64デコードされたデータが正しいMIDI形式になっていません。\n"+e);
+                       return -1;
+               }
+       }
+       /**
         * Base64デコードアクション
         */
        public Action addBase64Action = new AbstractAction("Add to PlayList", new ButtonIcon(ButtonIcon.EJECT_ICON)) {
                { putValue(Action.SHORT_DESCRIPTION, "Base64デコードして、プレイリストへ追加"); }
                @Override
                public void actionPerformed(ActionEvent event) {
-                       byte[] midiData = null;
-                       try {
-                               midiData = getMIDIData();
-                       } catch(Exception e) {
-                               error("Base64デコードに失敗しました。\n"+e);
-                               return;
-                       }
-                       try {
-                               midiEditor.sequenceListTable.getModel().addSequence(midiData, null);
-                       } catch(Exception e) {
-                               error("Base64デコードされたデータが正しいMIDI形式になっていません。\n"+e);
-                               return;
-                       }
+                       addToPlaylist();
                        setVisible(false);
                }
        };
@@ -140,4 +152,11 @@ public class Base64Dialog extends JDialog implements DocumentListener {
                base64TextArea.setText(null);
                base64TextArea.append(base64Data);
        }
+       /**
+        * テキスト文字列を設定します(例外が発生したときのメッセージ出力用)。
+        * @param text テキスト文字列
+        */
+       public void setText(String text) {
+               base64TextArea.setText(text);
+       }
 }
index 918533e..bb9fde1 100644 (file)
@@ -359,7 +359,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
        /**
         * 入力している内容からMIDIメッセージを生成して返します。
         * @param charset 文字コード
-        * @return 入力している内容から生成したMIDIメッセージ
+        * @return 入力している内容から生成したMIDIメッセージ(生成できなかった場合はnull)
         */
        public MidiMessage getMessage(Charset charset) {
                int msgStatus = statusText.getValue();
index 8a84584..8f4e2b7 100644 (file)
@@ -9,12 +9,12 @@ import camidion.chordhelper.music.MIDISpec;
  */
 public class MidiProgramSelecter extends JComboBox<String> {
        private int family;
-       private MidiProgramFamilySelecter family_selecter = null;
+       private MidiProgramFamilySelecter familySelecter = null;
        public MidiProgramSelecter() {
                setFamily(-1);
        }
        public void setFamilySelecter( MidiProgramFamilySelecter mpfs ) {
-               family_selecter = mpfs;
+               familySelecter = mpfs;
        }
        public void setFamily( int family ) {
                int program_no = getProgram();
@@ -49,7 +49,7 @@ public class MidiProgramSelecter extends JComboBox<String> {
                }
                else {
                        if( family >= 0 ) setFamily(-1);
-                       if( family_selecter != null ) family_selecter.setSelectedIndex(0);
+                       if( familySelecter != null ) familySelecter.setSelectedIndex(0);
                        if( program_no < getItemCount() ) setSelectedIndex(program_no);
                }
        }
index 8c16890..f665c7e 100644 (file)
@@ -12,12 +12,14 @@ import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
 import java.awt.event.MouseEvent;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.security.AccessControlException;
 import java.util.Arrays;
 import java.util.EventObject;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -26,7 +28,7 @@ import javax.sound.midi.InvalidMidiDataException;
 import javax.sound.midi.MidiChannel;
 import javax.sound.midi.MidiEvent;
 import javax.sound.midi.MidiMessage;
-import javax.sound.midi.Sequence;
+import javax.sound.midi.MidiSystem;
 import javax.sound.midi.Sequencer;
 import javax.sound.midi.ShortMessage;
 import javax.swing.AbstractAction;
@@ -125,29 +127,33 @@ public class MidiSequenceEditorDialog extends JDialog {
                @Override
                public boolean importData(TransferSupport support) {
                        try {
-                               loadAndPlay((List<File>)support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor));
+                               play((List<File>)support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor));
                                return true;
                        } catch (Exception e) { showError(e); return false; }
                }
        };
 
        /**
-        * 複数のMIDIファイルを読み込み、再生されていなかったら再生します。
+        * 指定されたリストに格納されたMIDIファイルを読み込んで再生します。
         * すでに再生されていた場合、このエディタダイアログを表示します。
-        *
         * @param fileList 読み込むMIDIファイルのリスト
-        * @throws InvalidMidiDataException {@link Sequencer#setSequence(Sequence)} を参照
-        * @see #loadAndPlay(File)
         */
-       public void loadAndPlay(List<File> fileList) {
-               int indexOfAddedTop = -1;
+       public void play(List<File> fileList) {
                PlaylistTableModel playlist = sequenceListTable.getModel();
-               try {
-                       indexOfAddedTop = playlist.addSequences(fileList);
-               } catch(IOException|InvalidMidiDataException e) {
-                       showWarning(e);
-               } catch(AccessControlException e) {
-                       showError(e);
+               int firstIndex = -1;
+               Iterator<File> itr = fileList.iterator();
+               while(itr.hasNext()) {
+                       File file = itr.next();
+                       try (FileInputStream in = new FileInputStream(file)) {
+                               int lastIndex = playlist.add(MidiSystem.getSequence(in), file.getName());
+                               if( firstIndex < 0 ) firstIndex = lastIndex;
+                       } catch(IOException|InvalidMidiDataException e) {
+                               String message = "Could not open as MIDI file "+file+"\n"+e;
+                               if( ! itr.hasNext() ) { showWarning(message); break; }
+                               if( ! confirm(message + "\n\nContinue to open next file ?") ) break;
+                       } catch(AccessControlException e) {
+                               showError(e); break;
+                       }
                }
                MidiSequencerModel sequencerModel = playlist.getSequencerModel();
                if( sequencerModel.getSequencer().isRunning() ) {
@@ -155,24 +161,13 @@ public class MidiSequenceEditorDialog extends JDialog {
                        openAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, command));
                        return;
                }
-               if( indexOfAddedTop >= 0 ) {
+               if( firstIndex >= 0 ) {
                        try {
-                               playlist.loadToSequencer(indexOfAddedTop);
+                               playlist.loadToSequencer(firstIndex);
                        } catch (InvalidMidiDataException e) { showError(e); return; }
                        sequencerModel.start();
                }
        }
-       /**
-        * 1件のMIDIファイルを読み込み、再生されていなかったら再生します。
-        * すでに再生されていた場合、このエディタダイアログを表示します。
-        *
-        * @param file 読み込むMIDIファイル
-        * @throws InvalidMidiDataException {@link Sequencer#setSequence(Sequence)} を参照
-        * @see #loadAndPlay(List) loadAndPlay(List&lt;File&gt;)
-        */
-       public void loadAndPlay(File file) throws InvalidMidiDataException {
-               loadAndPlay(Arrays.asList(file));
-       }
 
        private static final Insets ZERO_INSETS = new Insets(0,0,0,0);
        private static final Icon deleteIcon = new ButtonIcon(ButtonIcon.X_ICON);
@@ -252,8 +247,14 @@ public class MidiSequenceEditorDialog extends JDialog {
                                        byte[] data = null;
                                        String filename = null;
                                        if( mstm != null ) {
-                                               data = mstm.getMIDIdata();
                                                filename = mstm.getFilename();
+                                               try {
+                                                       data = mstm.getMIDIdata();
+                                               } catch (IOException ioe) {
+                                                       base64Dialog.setText("File["+filename+"]:"+ioe.toString());
+                                                       base64Dialog.setVisible(true);
+                                                       return;
+                                               }
                                        }
                                        base64Dialog.setMIDIData(data, filename);
                                        base64Dialog.setVisible(true);
@@ -479,9 +480,7 @@ public class MidiSequenceEditorDialog extends JDialog {
                                @Override
                                public void actionPerformed(ActionEvent event) {
                                        if( showOpenDialog((Component)event.getSource()) != JFileChooser.APPROVE_OPTION ) return;
-                                       try {
-                                               loadAndPlay(getSelectedFile());
-                                       } catch (InvalidMidiDataException ex) { showError(ex); }
+                                       play(Arrays.asList(getSelectedFile()));
                                }
                        };
                };
@@ -860,7 +859,11 @@ public class MidiSequenceEditorDialog extends JDialog {
                                long tick = tickPositionModel.getTickPosition();
                                MidiMessageForm form = eventDialog.midiMessageForm;
                                SequenceTrackListTableModel seqModel = trackModel.getParent();
-                               MidiEvent newMidiEvent = new MidiEvent(form.getMessage(seqModel.charset), tick);
+                               MidiMessage msg = form.getMessage(seqModel.charset);
+                               if( msg == null ) {
+                                       return false;
+                               }
+                               MidiEvent newMidiEvent = new MidiEvent(msg, tick);
                                if( midiEventsToBeOverwritten != null ) {
                                        // 上書き消去するための選択済イベントがあった場合
                                        trackModel.removeMidiEvents(midiEventsToBeOverwritten);
index 9d80da2..a99d19b 100644 (file)
@@ -106,8 +106,7 @@ public class NewSequenceDialog extends JDialog {
                @Override
                public void actionPerformed(ActionEvent event) {
                        try {
-                               int index = playlist.addSequenceAndPlay(getMidiSequence());
-                               playlist.getSequenceModelList().get(index).setModified(true);
+                               playlist.getSequenceModelList().get(playlist.play(getMidiSequence())).setModified(true);
                        } catch (InvalidMidiDataException ex) {
                                ex.printStackTrace();
                                JOptionPane.showMessageDialog(
index 88c5dea..fb495fe 100644 (file)
@@ -1,14 +1,6 @@
 package camidion.chordhelper.midieditor;
 
 import java.awt.event.ActionEvent;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.List;
@@ -16,14 +8,12 @@ import java.util.Map;
 import java.util.Vector;
 
 import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MidiSystem;
 import javax.sound.midi.Sequence;
 import javax.sound.midi.Sequencer;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.DefaultListSelectionModel;
 import javax.swing.Icon;
-import javax.swing.JOptionPane;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingUtilities;
 import javax.swing.event.ChangeEvent;
@@ -33,7 +23,6 @@ import javax.swing.event.ListSelectionListener;
 import javax.swing.table.AbstractTableModel;
 
 import camidion.chordhelper.ButtonIcon;
-import camidion.chordhelper.ChordHelperApplet;
 import camidion.chordhelper.mididevice.MidiSequencerModel;
 import camidion.chordhelper.music.ChordProgression;
 
@@ -89,7 +78,13 @@ public class PlaylistTableModel extends AbstractTableModel {
                sequencerModel.addChangeListener(mmssPosition);
                // EOF(0x2F)が来たら曲の終わりなので次の曲へ進める
                sequencerModel.getSequencer().addMetaEventListener(msg->{
-                       if(msg.getType() == 0x2F) SwingUtilities.invokeLater(()->goNext());
+                       if(msg.getType() == 0x2F) SwingUtilities.invokeLater(()->{
+                               try {
+                                       goNext();
+                               } catch (InvalidMidiDataException e) {
+                                       throw new RuntimeException("Could not play next sequence after end-of-track",e);
+                               }
+                       });
                });
                emptyTrackListTableModel = new SequenceTrackListTableModel(this, null, null);
                emptyEventListTableModel = new TrackEventListTableModel(emptyTrackListTableModel, null);
@@ -100,8 +95,9 @@ public class PlaylistTableModel extends AbstractTableModel {
         * <p>リピートモードの場合は同じ曲をもう一度再生、そうでない場合は次の曲へ進んで再生します。
         * 次の曲がなければ、そこで停止します。いずれの場合も曲の先頭へ戻ります。
         * </p>
+        * @throws InvalidMidiDataException {@link Sequencer#setSequence(Sequence)} を参照
         */
-       private void goNext() {
+       private void goNext() throws InvalidMidiDataException {
                // とりあえず曲の先頭へ戻る
                sequencerModel.getSequencer().setMicrosecondPosition(0);
                if( (Boolean)toggleRepeatAction.getValue(Action.SELECTED_KEY) || loadNext(1) ) {
@@ -175,8 +171,15 @@ public class PlaylistTableModel extends AbstractTableModel {
                        );
                        putValue(LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.TOP_ICON));
                }
+               @Override
                public void actionPerformed(ActionEvent event) {
-                       if( sequencerModel.getSequencer().getTickPosition() <= 40 ) loadNext(-1);
+                       if( sequencerModel.getSequencer().getTickPosition() <= 40 ) {
+                               try {
+                                       loadNext(-1);
+                               } catch (InvalidMidiDataException e) {
+                                       throw new RuntimeException("Could not play previous sequence",e);
+                               }
+                       }
                        sequencerModel.setValue(0);
                }
        };
@@ -190,7 +193,11 @@ public class PlaylistTableModel extends AbstractTableModel {
                        putValue(LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.BOTTOM_ICON));
                }
                public void actionPerformed(ActionEvent event) {
-                       if(loadNext(1)) sequencerModel.setValue(0);
+                       try {
+                               if(loadNext(1)) sequencerModel.setValue(0);
+                       } catch (InvalidMidiDataException e) {
+                               throw new RuntimeException("Could not play next sequence",e);
+                       }
                }
        };
        /**
@@ -360,13 +367,10 @@ public class PlaylistTableModel extends AbstractTableModel {
         * @return 全シーケンスの合計時間長 [秒]
         */
        public int getTotalTimeInSeconds() {
-               int total = 0;
-               long usec;
-               for( SequenceTrackListTableModel m : sequenceModelList ) {
-                       usec = m.getSequence().getMicrosecondLength();
-                       total += (int)( (usec < 0 ? usec += 0x100000000L : usec)/1000L/1000L );
-               }
-               return total;
+               return sequenceModelList.stream().mapToInt(m->{
+                       long usec = m.getSequence().getMicrosecondLength();
+                       return (int)( (usec < 0 ? usec += 0x100000000L : usec)/1000L/1000L );
+               }).sum();
        }
        /**
         * 選択されたMIDIシーケンスのテーブルモデルを返します。
@@ -408,7 +412,7 @@ public class PlaylistTableModel extends AbstractTableModel {
         * @param filename ファイル名(nullの場合、ファイル名なし)
         * @return 追加されたシーケンスのインデックス(先頭が 0)
         */
-       public int addSequence(Sequence sequence, String filename) {
+       public int add(Sequence sequence, String filename) {
                if( sequence == null ) sequence = (new ChordProgression()).toMidiSequence();
                sequenceModelList.add(new SequenceTrackListTableModel(this, sequence, filename));
                //
@@ -419,87 +423,19 @@ public class PlaylistTableModel extends AbstractTableModel {
                return lastIndex;
        }
        /**
-        * バイト列とファイル名からMIDIシーケンスを追加します。
-        * @param data バイト列(nullの場合、シーケンスを自動生成して追加)
-        * @param filename ファイル名
-        * @return 追加先インデックス(先頭が 0)
-        * @throws IOException バイト列の読み込みに失敗した場合
-        * @throws InvalidMidiDataException MIDIデータが正しくない場合
-        */
-       public int addSequence(byte[] data, String filename) throws IOException, InvalidMidiDataException {
-               Sequence sequence = null;
-               if( data != null ) {
-                       try (InputStream in = new ByteArrayInputStream(data)) {
-                               sequence = MidiSystem.getSequence(in);
-                       } catch( IOException|InvalidMidiDataException e ) {
-                               throw e;
-                       }
-               }
-               return addSequence(sequence, filename);
-       }
-       /**
-        * MIDIファイルを追加します。
-        * @param midiFile MIDIファイル(nullの場合、シーケンスを自動生成して追加)
-        * @return 追加先インデックス(先頭が 0)
-        * @throws IOException ファイル入出力に失敗した場合
-        * @throws InvalidMidiDataException ファイル内のMIDIデータが正しくない場合
-        */
-       public int addSequence(File midiFile) throws InvalidMidiDataException, IOException {
-               Sequence sequence = null;
-               String filename = null;
-               if( midiFile != null ) {
-                       try (FileInputStream in = new FileInputStream(midiFile)) {
-                               sequence = MidiSystem.getSequence(in);
-                       } catch( IOException|InvalidMidiDataException e ) {
-                               throw e;
-                       }
-                       filename = midiFile.getName();
-               }
-               return addSequence(sequence, filename);
-       }
-       /**
-        * MIDIシーケンスを追加し、再生されていなかった場合は追加したシーケンスから再生を開始します。
+        * 指定されたMIDIシーケンスをこのプレイリストに追加して再生します。
         * @param sequence MIDIシーケンス
         * @return 追加されたシーケンスのインデックス(先頭が 0)
         * @throws InvalidMidiDataException {@link Sequencer#setSequence(Sequence)} を参照
         */
-       public int addSequenceAndPlay(Sequence sequence) throws InvalidMidiDataException {
-               int lastIndex = addSequence(sequence,"");
+       public int play(Sequence sequence) throws InvalidMidiDataException {
+               int lastIndex = add(sequence,"");
                if( ! sequencerModel.getSequencer().isRunning() ) {
                        loadToSequencer(lastIndex);
                        sequencerModel.start();
                }
                return lastIndex;
        }
-       /**
-        * 複数のMIDIファイルを追加します。
-        * @param fileList 追加するMIDIファイルのリスト
-        * @return 追加先の最初のインデックス(先頭が 0、追加されなかった場合は -1)
-        * @throws InvalidMidiDataException ファイル内のMIDIデータが正しくない場合
-        * @throws IOException ファイル入出力に失敗した場合
-        */
-       public int addSequences(List<File> fileList) throws InvalidMidiDataException, IOException {
-               int firstIndex = -1;
-               for( File file : fileList ) {
-                       int lastIndex = addSequence(file);
-                       if( firstIndex == -1 ) firstIndex = lastIndex;
-               }
-               return firstIndex;
-       }
-       /**
-        * URLから読み込んだMIDIシーケンスを追加します。
-        * @param midiFileUrl MIDIファイルのURL
-        * @return 追加先インデックス(先頭が 0、失敗した場合は -1)
-        * @throws URISyntaxException URLの形式に誤りがある場合
-        * @throws IOException 入出力に失敗した場合
-        * @throws InvalidMidiDataException MIDIデータが正しくない場合
-        */
-       public int addSequenceFromURL(String midiFileUrl)
-               throws URISyntaxException, IOException, InvalidMidiDataException
-       {
-               URL url = (new URI(midiFileUrl)).toURL();
-               return addSequence(MidiSystem.getSequence(url), url.getFile().replaceFirst("^.*/",""));
-       }
 
        /**
         * 選択されたシーケンスを除去します。
@@ -550,18 +486,18 @@ public class PlaylistTableModel extends AbstractTableModel {
        /**
         * 引数で示された数だけ次へ進めたシーケンスをロードします。
         * @param offset 進みたいシーケンス数
-        * @return true:ロード成功、false:これ以上進めない
+        * @return 以前と異なるインデックスのシーケンスをロードできた場合true
+        * @throws InvalidMidiDataException {@link Sequencer#setSequence(Sequence)} を参照
         */
-       public boolean loadNext(int offset) {
+       private boolean loadNext(int offset) throws InvalidMidiDataException {
                int loadedIndex = indexOfSequenceOnSequencer();
-               int index = (loadedIndex < 0 ? 0 : loadedIndex + offset);
-               if( index < 0 || index >= sequenceModelList.size() ) return false;
-               try {
-                       loadToSequencer(index);
-               } catch (InvalidMidiDataException ex) {
-                       JOptionPane.showMessageDialog(null, ex, ChordHelperApplet.VersionInfo.NAME, JOptionPane.ERROR_MESSAGE);
-                       return false;
+               int newIndex = loadedIndex + offset;
+               if( newIndex < 0 ) newIndex = 0; else {
+                       int sz = sequenceModelList.size();
+                       if( newIndex >= sz ) newIndex = sz - 1;
                }
+               if( newIndex == loadedIndex ) return false;
+               loadToSequencer(newIndex);
                return true;
        }
 }
index c54c5c4..f9f6fa1 100644 (file)
@@ -282,6 +282,9 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
         * @return ファイル名
         */
        public String getFilename() { return filename; }
+       /**
+        * このシーケンスを表す文字列としてシーケンス名を返します。シーケンス名がない場合は空文字列を返します。
+        */
        @Override
        public String toString() {
                byte b[] = MIDISpec.getNameBytesOf(sequence);
@@ -301,9 +304,10 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
        }
        /**
         * このシーケンスのMIDIデータのバイト列を返します。
-        * @return MIDIデータのバイト列(失敗した場合null)
+        * @return MIDIデータのバイト列(ない場合はnull)
+        * @throws IOException バイト列の出力に失敗した場合
         */
-       public byte[] getMIDIdata() {
+       public byte[] getMIDIdata() throws IOException {
                if( sequence == null || sequence.getTracks().length == 0 ) {
                        return null;
                }
@@ -311,8 +315,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
                        MidiSystem.write(sequence, 1, out);
                        return out.toByteArray();
                } catch ( IOException e ) {
-                       e.printStackTrace();
-                       return null;
+                       throw e;
                }
        }
        /**
index 1ac62ef..2cdea60 100644 (file)
@@ -130,7 +130,7 @@ public class MIDISpec {
        /**
         * トラック名のバイト列を返します。
         * @param track MIDIトラック
-        * @return トラック名のバイト列
+        * @return トラック名のバイト列(トラック名が見つからない場合はnull)
         */
        public static byte[] getNameBytesOf(Track track) {
                MidiEvent midiEvent;
@@ -192,11 +192,9 @@ public class MIDISpec {
        }
        /**
         * シーケンス名のバイト列を返します。
-        * <p>トラック名の入った最初のトラックにあるトラック名を
-        * シーケンス名として返します。
-        * </p>
+        * <p>トラック名の入った最初のトラックにあるトラック名をシーケンス名として返します。</p>
         * @param seq MIDIシーケンス
-        * @return シーケンス名のバイト列
+        * @return シーケンス名のバイト列(見つからない場合はnull)
         */
        public static byte[] getNameBytesOf(Sequence seq) {
                // Returns name of the MIDI sequence.
index d49f029..ce98e73 100644 (file)
@@ -74,7 +74,7 @@ public class MidiKeyboardPanel extends JPanel {
                                                        public void actionPerformed(ActionEvent e) {
                                                                VirtualMidiDevice vmd = keyboardCenterPanel.keyboard.midiDevice;
                                                                MidiMessage msg = eventDialog.midiMessageForm.getMessage(Charset.defaultCharset());
-                                                               vmd.sendMidiMessage(msg);
+                                                               if( msg != null ) vmd.sendMidiMessage(msg);
                                                        }
                                                },
                                                keyboardCenterPanel.keyboard.midiChComboboxModel.getSelectedChannel()