OSDN Git Service

MIDIデバイスケーブル描画とメタイベント受信を中心に見直し
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sat, 16 Jul 2016 17:08:03 +0000 (02:08 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sat, 16 Jul 2016 17:08:03 +0000 (02:08 +0900)
src/camidion/chordhelper/ChordDisplayLabel.java
src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/ChordTextField.java
src/camidion/chordhelper/MidiChordHelper.java
src/camidion/chordhelper/chordmatrix/ChordGuide.java
src/camidion/chordhelper/mididevice/MidiCablePane.java
src/camidion/chordhelper/midieditor/PlaylistTableModel.java
src/camidion/chordhelper/midieditor/TempoSelecter.java
src/camidion/chordhelper/midieditor/TimeSignatureSelecter.java

index a916273..abb5c95 100644 (file)
@@ -4,8 +4,8 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
 
 import javax.swing.JLabel;
 
@@ -19,7 +19,7 @@ import camidion.chordhelper.pianokeyboard.PianoKeyboard;
 /**
  * 和音表示ラベル
  */
-public class ChordDisplayLabel extends JLabel implements MouseListener {
+public class ChordDisplayLabel extends JLabel {
        private String defaultString = null;
        private Chord chord = null;
        private int noteNumber = -1;
@@ -33,12 +33,42 @@ public class ChordDisplayLabel extends JLabel implements MouseListener {
         */
        public ChordDisplayLabel(String defaultString, ChordMatrix chordMatrix, PianoKeyboard keyboard) {
                super(defaultString, JLabel.CENTER);
-               this.defaultString = defaultString;
-               this.keyboard = keyboard;
-               if( (this.chordMatrix = chordMatrix) != null ) {
-                       addMouseListener(this);
-                       addMouseWheelListener(chordMatrix);
-               }
+               if( chordMatrix == null ) return;
+               addMouseListener(new MouseAdapter() {
+                       @Override
+                       public void mousePressed(MouseEvent e) {
+                               if( chord != null ) { // コードが表示されている場合
+                                       if( (e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {
+                                               // 右クリックでコードを止める
+                                               chordMatrix.setSelectedChord((Chord)null);
+                                       }
+                                       else {
+                                               // コードを鳴らす。
+                                               //   キーボードが指定されている場合、オリジナルキー(カポ反映済)のコードを使う。
+                                               if( keyboard == null )
+                                                       chordMatrix.setSelectedChord(chord);
+                                               else
+                                                       chordMatrix.setSelectedChordCapo(chord);
+                                       }
+                               }
+                               else if( noteNumber >= 0 ) { // 音階が表示されている場合
+                                       keyboard.noteOn(noteNumber);
+                               }
+                       }
+                       @Override
+                       public void mouseReleased(MouseEvent e) {
+                               if( noteNumber >= 0 ) keyboard.noteOff(noteNumber);
+                       }
+                       @Override
+                       public void mouseEntered(MouseEvent e) { mouseEntered(true); }
+                       @Override
+                       public void mouseExited(MouseEvent e) { mouseEntered(false); }
+                       private void mouseEntered(boolean isMouseEntered) {
+                               ChordDisplayLabel.this.isMouseEntered = isMouseEntered;
+                               if( noteNumber >= 0 || chord != null ) repaint();
+                       }
+               });
+               addMouseWheelListener(chordMatrix);
        }
        @Override
        public void paint(Graphics g) {
@@ -49,43 +79,6 @@ public class ChordDisplayLabel extends JLabel implements MouseListener {
                        g.drawRect( 0, 0, d.width-1, d.height-1 );
                }
        }
-       private PianoKeyboard keyboard = null;
-       private ChordMatrix chordMatrix = null;
-       @Override
-       public void mousePressed(MouseEvent e) {
-               if( chord != null ) { // コードが表示されている場合
-                       if( (e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {
-                               // 右クリックでコードを止める
-                               chordMatrix.setSelectedChord((Chord)null);
-                       }
-                       else {
-                               // コードを鳴らす。
-                               //   キーボードが指定されている場合、オリジナルキー(カポ反映済)のコードを使う。
-                               if( keyboard == null )
-                                       chordMatrix.setSelectedChord(chord);
-                               else
-                                       chordMatrix.setSelectedChordCapo(chord);
-                       }
-               }
-               else if( noteNumber >= 0 ) { // 音階が表示されている場合
-                       keyboard.noteOn(noteNumber);
-               }
-       }
-       @Override
-       public void mouseReleased(MouseEvent e) {
-               if( noteNumber >= 0 ) keyboard.noteOff(noteNumber);
-       }
-       @Override
-       public void mouseEntered(MouseEvent e) { mouseEntered(true); }
-       @Override
-       public void mouseExited(MouseEvent e) { mouseEntered(false); }
-       @Override
-       public void mouseClicked(MouseEvent e) {
-       }
-       private void mouseEntered(boolean isMouseEntered) {
-               this.isMouseEntered = isMouseEntered;
-               if( noteNumber >= 0 || chord != null ) repaint();
-       }
        /**
         * 音階を表示します。
         * @param noteNumber MIDIノート番号
index 3767e28..e480e34 100644 (file)
@@ -283,7 +283,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public static class VersionInfo {
                public static final String      NAME = "MIDI Chord Helper";
-               public static final String      VERSION = "Ver.20160712.1";
+               public static final String      VERSION = "Ver.20160716.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/";
@@ -370,17 +370,26 @@ public class ChordHelperApplet extends JApplet {
         * アプリケーションのアイコンイメージ
         */
        public Image iconImage;
+       private static final String IMAGE_ICON_PATH = "midichordhelper.png";
+       private void loadIconImage() {
+               URL imageIconUrl = getClass().getResource(IMAGE_ICON_PATH);
+               if( imageIconUrl == null ) {
+                       System.out.println("Icon image " + IMAGE_ICON_PATH + " not found");
+               }
+               else {
+                       iconImage = (imageIcon = new ImageIcon(imageIconUrl)).getImage();
+               }
+       }
        /**
         * ボタンの余白を詰めたいときに setMargin() の引数に指定するインセット
         */
        public static final Insets ZERO_INSETS = new Insets(0,0,0,0);
        //
-       private static final String IMAGE_ICON_PATH = "midichordhelper.png";
        //
        MidiSequenceEditorDialog midiEditor;
        PlaylistTableModel playlistModel;
        MidiSequencerModel sequencerModel;
-       public ChordMatrix chordMatrix;
+       private ChordMatrix chordMatrix;
        private JPanel keyboardSequencerPanel;
        private JPanel chordGuide;
        private Color rootPaneDefaultBgcolor;
@@ -393,26 +402,15 @@ public class ChordHelperApplet extends JApplet {
        private MidiKeyboardPanel keyboardPanel;
        private InversionAndOmissionLabel inversionOmissionButton;
        private JToggleButton darkModeToggleButton;
-       private MidiDeviceDialog midiDeviceDialog;
        private ChordDiagram chordDiagram;
-       private TempoSelecter tempoSelecter;
-       private TimeSignatureSelecter timesigSelecter;
        private KeySignatureLabel keysigLabel;
-       private JLabel songTitleLabel = new JLabel();
        private AnoGakkiPane anoGakkiPane;
        private JToggleButton anoGakkiToggleButton;
        private MidiDeviceModelList deviceModelList;
 
        public void init() {
+               loadIconImage();
                //
-               // アイコンイメージの取得
-               URL imageIconUrl = getClass().getResource(IMAGE_ICON_PATH);
-               if( imageIconUrl == null ) {
-                       System.out.println("Icon image "+IMAGE_ICON_PATH+" not found");
-               }
-               else {
-                       iconImage = (imageIcon = new ImageIcon(imageIconUrl)).getImage();
-               }
                // 背景色の取得
                rootPaneDefaultBgcolor = getContentPane().getBackground();
                //
@@ -467,7 +465,8 @@ public class ChordHelperApplet extends JApplet {
                //
                // MIDIデバイス一覧を構築
                deviceModelList = new MidiDeviceModelList(Arrays.asList(guiMidiDevice));
-               (midiDeviceDialog = new MidiDeviceDialog(deviceModelList)).setIconImage(iconImage);
+               MidiDeviceDialog midiDeviceDialog = new MidiDeviceDialog(deviceModelList);
+               midiDeviceDialog.setIconImage(iconImage);
                //
                // MIDIデバイス一覧のシーケンサと連携するプレイリストを構築
                playlistModel = new PlaylistTableModel(sequencerModel = deviceModelList.getSequencerModel());
@@ -482,48 +481,63 @@ public class ChordHelperApplet extends JApplet {
                keyboardPanel.setEventDialog(midiEditor.eventDialog);
                //
                // 歌詞表示
-               lyricDisplay = new ChordTextField(sequencerModel) {{
-                       addActionListener(new ActionListener() {
-                               @Override
-                               public void actionPerformed(ActionEvent event) {
-                                       String symbol = event.getActionCommand().trim().split("[ \t\r\n]")[0];
-                                       chordMatrix.setSelectedChord(symbol);
-                               }
-                       });
-               }};
+               (lyricDisplay = new ChordTextField(sequencerModel)).addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent event) {
+                               chordMatrix.setSelectedChord(event.getActionCommand().trim().split("[ \t\r\n]")[0]);
+                       }
+               });
                lyricDisplayDefaultBorder = lyricDisplay.getBorder();
                lyricDisplayDefaultBgcolor = lyricDisplay.getBackground();
                //
                // メタイベント(テンポ・拍子・調号)を受信して表示するリスナーを登録
-               Sequencer sequencer = sequencerModel.getSequencer();
-               sequencer.addMetaEventListener(tempoSelecter = new TempoSelecter() {{ setEditable(false); }});
-               sequencer.addMetaEventListener(timesigSelecter = new TimeSignatureSelecter() {{ setEditable(false); }});
-               sequencer.addMetaEventListener(new MetaEventListener() {
-                       private Key key;
+               TempoSelecter tempoSelecter = new TempoSelecter() {{ setEditable(false); }};
+               TimeSignatureSelecter timesigSelecter = new TimeSignatureSelecter() {{ setEditable(false); }};
+               sequencerModel.getSequencer().addMetaEventListener(new MetaEventListener() {
                        @Override
                        public void meta(MetaMessage msg) {
                                switch(msg.getType()) {
-                               case 0x59: // Key signature (2 bytes) : 調号
-                                       key = new Key(msg.getData());
+                               case 0x51: // Tempo (3 bytes) - テンポ
+                                       byte[] qpm = msg.getData();
                                        if( SwingUtilities.isEventDispatchThread() ) {
-                                               keysigLabel.setKeySignature(key);
-                                               chordMatrix.setKeySignature(key);
+                                               tempoSelecter.setTempo(qpm);
                                        } else {
                                                // MIDIシーケンサのスレッドから呼ばれた場合、GUI更新は自分で行わず、
                                                // AWTイベントディスパッチスレッドに依頼する。
                                                SwingUtilities.invokeLater(new Runnable() {
                                                        @Override
-                                                       public void run() {
-                                                               keysigLabel.setKeySignature(key);
-                                                               chordMatrix.setKeySignature(key);
-                                                       }
+                                                       public void run() { tempoSelecter.setTempo(qpm);}
+                                               });
+                                       }
+                                       break;
+                               case 0x58: // Time signature (4 bytes) - 拍子
+                                       byte[] timesig = msg.getData();
+                                       if( SwingUtilities.isEventDispatchThread() ) {
+                                               timesigSelecter.setValue(timesig);
+                                       } else {
+                                               SwingUtilities.invokeLater(new Runnable() {
+                                                       @Override
+                                                       public void run() { timesigSelecter.setValue(timesig);}
+                                               });
+                                       }
+                                       break;
+                               case 0x59: // Key signature (2 bytes) : 調号
+                                       Key key = new Key(msg.getData());
+                                       if( SwingUtilities.isEventDispatchThread() ) {
+                                               setKeySignature(key);
+                                       } else {
+                                               SwingUtilities.invokeLater(new Runnable() {
+                                                       @Override
+                                                       public void run() { setKeySignature(key); }
                                                });
                                        }
                                        break;
                                }
                        }
+
                });
                //シーケンサーの時間スライダーの値が変わったときのリスナーを登録
+               JLabel songTitleLabel = new JLabel();
                sequencerModel.addChangeListener(new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
@@ -565,67 +579,63 @@ public class ChordHelperApplet extends JApplet {
                                                        keysigLabel.clear();
                                                }
                                                else {
-                                                       Key key = new Key(msg.getData());
-                                                       keysigLabel.setKeySignature(key);
-                                                       chordMatrix.setKeySignature(key);
+                                                       setKeySignature(new Key(msg.getData()));
                                                }
                                        }
                                }
                        }
                });
                sequencerModel.fireStateChanged();
-               chordGuide = new JPanel() {
-                       {
-                               setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
-                               add( Box.createHorizontalStrut(2) );
-                               add( chordMatrix.chordGuide );
-                               add( Box.createHorizontalStrut(2) );
-                               add( lyricDisplay );
-                               add( Box.createHorizontalStrut(2) );
-                               add( enterButtonLabel = new ChordButtonLabel("Enter",chordMatrix) {{
-                                       addMouseListener(new MouseAdapter() {
-                                               public void mousePressed(MouseEvent event) {
-                                                       if( (event.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) // RightClicked
-                                                               chordMatrix.setSelectedChord((Chord)null);
-                                                       else {
-                                                               chordMatrix.setSelectedChord(lyricDisplay.getText());
-                                                       }
-                                               }
-                                       });
-                               }});
-                               add( Box.createHorizontalStrut(5) );
-                               add( chordMatrix.chordDisplay );
-                               add( Box.createHorizontalStrut(5) );
-                               add( darkModeToggleButton = new JToggleButton(new ButtonIcon(ButtonIcon.DARK_MODE_ICON)) {{
-                                       setMargin(ZERO_INSETS);
-                                       addItemListener(new ItemListener() {
-                                               public void itemStateChanged(ItemEvent e) {
-                                                       innerSetDarkMode(darkModeToggleButton.isSelected());
-                                               }
-                                       });
-                                       setToolTipText("Light / Dark - 明かりを点灯/消灯");
-                                       setBorder(null);
-                               }});
-                               add( Box.createHorizontalStrut(5) );
-                               add( anoGakkiToggleButton = new JToggleButton(new ButtonIcon(ButtonIcon.ANO_GAKKI_ICON)) {{
-                                       setOpaque(false);
-                                       setMargin(ZERO_INSETS);
-                                       setBorder( null );
-                                       setToolTipText("あの楽器");
-                                       addItemListener(new ItemListener() {
-                                               public void itemStateChanged(ItemEvent e) {
-                                                       keyboardPanel.keyboardCenterPanel.keyboard.anoGakkiPane
-                                                       = anoGakkiToggleButton.isSelected() ? anoGakkiPane : null ;
+               chordGuide = new JPanel() {{
+                       setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+                       add( Box.createHorizontalStrut(2) );
+                       add( chordMatrix.chordGuide );
+                       add( Box.createHorizontalStrut(2) );
+                       add( lyricDisplay );
+                       add( Box.createHorizontalStrut(2) );
+                       add( enterButtonLabel = new ChordButtonLabel("Enter",chordMatrix) {{
+                               addMouseListener(new MouseAdapter() {
+                                       public void mousePressed(MouseEvent event) {
+                                               if( (event.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ) // RightClicked
+                                                       chordMatrix.setSelectedChord((Chord)null);
+                                               else {
+                                                       chordMatrix.setSelectedChord(lyricDisplay.getText());
                                                }
-                                       });
-                               }} );
-                               add( Box.createHorizontalStrut(5) );
-                               add( inversionOmissionButton = new InversionAndOmissionLabel() );
-                               add( Box.createHorizontalStrut(5) );
-                               add( chordMatrix.capoSelecter );
-                               add( Box.createHorizontalStrut(2) );
-                       }
-               };
+                                       }
+                               });
+                       }});
+                       add( Box.createHorizontalStrut(5) );
+                       add( chordMatrix.chordDisplay );
+                       add( Box.createHorizontalStrut(5) );
+                       add( darkModeToggleButton = new JToggleButton(new ButtonIcon(ButtonIcon.DARK_MODE_ICON)) {{
+                               setMargin(ZERO_INSETS);
+                               addItemListener(new ItemListener() {
+                                       public void itemStateChanged(ItemEvent e) {
+                                               innerSetDarkMode(darkModeToggleButton.isSelected());
+                                       }
+                               });
+                               setToolTipText("Light / Dark - 明かりを点灯/消灯");
+                               setBorder(null);
+                       }});
+                       add( Box.createHorizontalStrut(5) );
+                       add( anoGakkiToggleButton = new JToggleButton(new ButtonIcon(ButtonIcon.ANO_GAKKI_ICON)) {{
+                               setOpaque(false);
+                               setMargin(ZERO_INSETS);
+                               setBorder( null );
+                               setToolTipText("あの楽器");
+                               addItemListener(new ItemListener() {
+                                       public void itemStateChanged(ItemEvent e) {
+                                               keyboardPanel.keyboardCenterPanel.keyboard.anoGakkiPane
+                                               = anoGakkiToggleButton.isSelected() ? anoGakkiPane : null ;
+                                       }
+                               });
+                       }} );
+                       add( Box.createHorizontalStrut(5) );
+                       add( inversionOmissionButton = new InversionAndOmissionLabel() );
+                       add( Box.createHorizontalStrut(5) );
+                       add( chordMatrix.capoSelecter );
+                       add( Box.createHorizontalStrut(2) );
+               }};
                keyboardSequencerPanel = new JPanel() {{
                        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
                        add(chordGuide);
@@ -748,6 +758,11 @@ public class ChordHelperApplet extends JApplet {
                keyboardPanel.setDarkMode(isDark);
        }
 
+       private void setKeySignature(Key key) {
+               keysigLabel.setKeySignature(key);
+               chordMatrix.setKeySignature(key);
+       }
+
        private int[] chordOnNotes = null;
        /**
         * 和音を発音します。
index 89c67e6..fe74f96 100644 (file)
@@ -13,7 +13,7 @@ import camidion.chordhelper.mididevice.MidiSequencerModel;
 import camidion.chordhelper.midieditor.SequenceTrackListTableModel;
 import camidion.chordhelper.music.Chord;
 
-public class ChordTextField extends JTextField implements MetaEventListener {
+public class ChordTextField extends JTextField {
        private MidiSequencerModel sequencerModel;
        public ChordTextField(MidiSequencerModel sequencerModel) {
                super(80);
@@ -25,46 +25,34 @@ public class ChordTextField extends JTextField implements MetaEventListener {
                //
                // To reduce resized height, set maximum size to screen size.
                //
-               setMaximumSize(
-                       java.awt.Toolkit.getDefaultToolkit().getScreenSize()
-               );
-               this.sequencerModel = sequencerModel;
-               sequencerModel.getSequencer().addMetaEventListener(this);
-       }
-       @Override
-       public void meta(MetaMessage msg) {
-               int t = msg.getType();
-               switch(t) {
-               case 0x01: // Text(任意のテキスト:コメントなど)
-               case 0x05: // Lyrics(歌詞)
-               case 0x02: // Copyright(著作権表示)
-               case 0x03: // Sequence Name / Track Name(曲名またはトラック名)
-               case 0x06: // Marker
-                       byte[] d = msg.getData();
-                       if( ! SwingUtilities.isEventDispatchThread() ) {
-                               // MIDIシーケンサの EDT から呼ばれた場合、
-                               // 表示処理を Swing の EDT に振り直す。
-                               SwingUtilities.invokeLater(new AddTextJob(t,d));
-                               return;
+               setMaximumSize(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
+               (this.sequencerModel = sequencerModel).getSequencer().addMetaEventListener(new MetaEventListener() {
+                       @Override
+                       public void meta(MetaMessage msg) {
+                               int t = msg.getType();
+                               switch(t) {
+                               case 0x01: // Text(任意のテキスト:コメントなど)
+                               case 0x05: // Lyrics(歌詞)
+                               case 0x02: // Copyright(著作権表示)
+                               case 0x03: // Sequence Name / Track Name(曲名またはトラック名)
+                               case 0x06: // Marker
+                                       byte[] d = msg.getData();
+                                       if( SwingUtilities.isEventDispatchThread() ) {
+                                               addText(t,d);
+                                       } else {
+                                               // MIDIシーケンサのEDTから呼ばれた場合
+                                               // 表示処理をSwingのEDTに振り直す
+                                               SwingUtilities.invokeLater(new Runnable() {
+                                                       @Override
+                                                       public void run() { addText(t,d); }
+                                               });
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
                        }
-                       addText(t,d);
-                       break;
-               default:
-                       return;
-               }
-       }
-       /**
-        * 歌詞を追加するジョブ
-        */
-       public class AddTextJob implements Runnable {
-               private int type;
-               private byte[] data;
-               public AddTextJob(int type, byte[] data) {
-                       this.type = type;
-                       this.data = data;
-               }
-               @Override
-               public void run() { addText(type, data); }
+               });
        }
        /**
         * 前回のタイムスタンプ
index f564968..93f8b9a 100644 (file)
@@ -28,7 +28,6 @@ import javax.swing.event.ChangeListener;
 import javax.swing.event.TableModelEvent;
 import javax.swing.event.TableModelListener;
 
-import camidion.chordhelper.mididevice.MidiSequencerModel;
 import camidion.chordhelper.midieditor.PlaylistTableModel;
 import camidion.chordhelper.midieditor.SequenceTrackListTableModel;
 
@@ -95,8 +94,7 @@ public class MidiChordHelper {
                                 */
                                @Override
                                public void stateChanged(ChangeEvent event) {
-                                       MidiSequencerModel sequencerModel = (MidiSequencerModel) event.getSource();
-                                       setFilenameToTitle(sequencerModel.getSequenceTrackListTableModel());
+                                       setFilenameToTitle(applet.sequencerModel.getSequenceTrackListTableModel());
                                }
                        });
                        applet.playlistModel.addTableModelListener(new TableModelListener() {
@@ -107,8 +105,7 @@ public class MidiChordHelper {
                                public void tableChanged(TableModelEvent event) {
                                        int col = event.getColumn();
                                        if( col == PlaylistTableModel.Column.FILENAME.ordinal() || col == TableModelEvent.ALL_COLUMNS ) {
-                                               PlaylistTableModel pl = (PlaylistTableModel) event.getSource();
-                                               setFilenameToTitle(pl.getSequencerModel().getSequenceTrackListTableModel());
+                                               setFilenameToTitle(applet.sequencerModel.getSequenceTrackListTableModel());
                                        }
                                }
                        });
index c6be45b..1c55a96 100644 (file)
@@ -14,32 +14,32 @@ import javax.swing.JPopupMenu;
  * コードサフィックスのヘルプ
  */
 public class ChordGuide extends JPanel {
-       private class ChordGuideLabel extends ChordButtonLabel {
+       private static class ChordGuideLabel extends ChordButtonLabel {
                private JPopupMenu popupMenu = new JPopupMenu();
                public ChordGuideLabel(String txt, ChordMatrix cm) {
                        super(txt,cm);
-                       addMouseListener(
-                               new MouseAdapter() {
-                                       public void mousePressed(MouseEvent e) {
-                                               popupMenu.show( e.getComponent(), 0, getHeight() );
-                                       }
+                       addMouseListener(new MouseAdapter() {
+                               public void mousePressed(MouseEvent e) {
+                                       popupMenu.show( e.getComponent(), 0, getHeight() );
                                }
-                       );
+                       });
                }
                public void addMenu(JMenuItem menuItem) { popupMenu.add(menuItem); }
                public void addSeparator() { popupMenu.addSeparator(); }
        }
        private ChordGuideLabel guide76, guide5, guide9;
        public ChordGuide(ChordMatrix cm) {
-               guide76 = new ChordGuideLabel(" 6  7  M7 ",cm) {
+               setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+               add(guide76 = new ChordGuideLabel(" 6  7  M7 ",cm) {
                        {
                                setToolTipText("How to add 7th, major 7th, 6th");
                                addMenu(new JMenuItem("7        = <RightClick>"));
                                addMenu(new JMenuItem("M7(maj7) = [Shift] <RightClick>"));
                                addMenu(new JMenuItem("6        = [Shift]"));
                        }
-               };
-               guide5 = new ChordGuideLabel(" -5 dim +5 aug ",cm){
+               });
+               add( Box.createHorizontalStrut(2) );
+               add(guide5 = new ChordGuideLabel(" -5 dim +5 aug ",cm){
                        {
                                setToolTipText("How to add -5, dim, +5, aug");
                                addMenu(new JMenuItem("-5 (b5)      = [Alt]"));
@@ -50,8 +50,9 @@ public class ChordGuide extends JPanel {
                                addMenu(new JMenuItem("m7-5 = [Alt] minor <RightClick>"));
                                addMenu(new JMenuItem("aug7 (7+5)  = [Alt] sus4 <RightClick>"));
                        }
-               };
-               guide9 = new ChordGuideLabel(" add9 ",cm) {
+               });
+               add( Box.createHorizontalStrut(2) );
+               add(guide9 = new ChordGuideLabel(" add9 ",cm) {
                        {
                                setToolTipText("How to add 9th");
                                addMenu(new JMenuItem("add9  = [Ctrl]"));
@@ -61,13 +62,7 @@ public class ChordGuide extends JPanel {
                                addMenu(new JMenuItem("69    = [Ctrl] [Shift]"));
                                addMenu(new JMenuItem("dim9  = [Ctrl] [Shift] [Alt] minor"));
                        }
-               };
-               setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
-               add(guide76);
-               add( Box.createHorizontalStrut(2) );
-               add(guide5);
-               add( Box.createHorizontalStrut(2) );
-               add(guide9);
+               });
        }
        public void setDarkMode(boolean is_dark) {
                setBackground( is_dark ? Color.black : null );
index 7d037c0..ccb9107 100644 (file)
@@ -133,7 +133,7 @@ public class MidiCablePane extends JComponent {
                        MidiDeviceFrame f = (MidiDeviceFrame)frame;
                        MidiDeviceModel m = f.getMidiDeviceModel();
                        List<Receiver> rxList = m.getMidiDevice().getReceivers();
-                       for( Receiver rx : rxList ) colorMap.remove(rx);
+                       for( Receiver rx : rxList ) rxToColor.remove(rx);
                        repaint();
                }
        };
@@ -180,60 +180,69 @@ public class MidiCablePane extends JComponent {
                new Color(191,0,191,144)
        );
        private static final Color NEW_CABLE_COLOR = new Color(0, 0, 0, 144);
-       private Hashtable<Receiver,Color> colorMap = new Hashtable<>();
+       private Hashtable<Receiver,Color> rxToColor = new Hashtable<>();
        private Color colorOf(Receiver rx) {
-               Color color = colorMap.get(rx);
-               if( color == null ) {
-                       for( Color c : CABLE_COLORS ) {
-                               if( ! colorMap.containsValue(c) ) {
-                                       colorMap.put(rx, c);
-                                       return c;
-                               }
-                       }
-                       color = CABLE_COLORS.get((int)( Math.random() * CABLE_COLORS.size() ));
-                       colorMap.put(rx, color);
+               // そのレシーバに割り当て済みの色を探す
+               Color myColor = rxToColor.get(rx);
+               if( myColor != null ) return myColor;
+               // なければ、未使用の色を探して割り当てる
+               for( Color virginColor : CABLE_COLORS ) {
+                       if( rxToColor.containsValue(virginColor) ) continue;
+                       rxToColor.put(rx, virginColor);
+                       return virginColor;
                }
-               return color;
+               // 全色使われていたら、重複してでもランダムに割り当てる
+               Color randomColor = CABLE_COLORS.get((int)( Math.random() * CABLE_COLORS.size() ));
+               rxToColor.put(rx, randomColor);
+               return randomColor;
        }
        @Override
        public void paint(Graphics g) {
                super.paint(g);
                Graphics2D g2 = (Graphics2D)g;
                JInternalFrame[] frames = desktopPane.getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
+               //
+               // 各フレームをスキャン
                for( JInternalFrame frame : frames ) {
                        if( ! (frame instanceof MidiDeviceFrame) ) continue;
                        MidiDeviceFrame fromFrame = (MidiDeviceFrame)frame;
                        MidiDeviceModel fromDeviceModel = fromFrame.getMidiDeviceModel();
                        //
-                       // Receiverからドラッグ中の場合、その線を描画
-                       if( draggingLocation != null && fromDeviceModel.getMidiDevice().getReceivers().contains(draggingSource)) {
-                               Receiver rx = (Receiver)draggingSource;
-                               Rectangle rxBounds = fromFrame.getBoundsOf(rx);
-                               if( rxBounds == null ) continue;
-                               int r = (rxBounds.height - 5) / 2;
-                               rxBounds.translate(r+4, r+4);
-                               if( draggingDestination instanceof Transmitter ) {
-                                       g2.setStroke(CABLE_STROKE);
-                               } else {
-                                       g2.setStroke(VIRTUAL_CABLE_STROKE);
-                               }
-                               g2.setColor(colorOf(rx));
-                               g2.drawLine(rxBounds.x, rxBounds.y, draggingLocation.x, draggingLocation.y);
-                       }
-                       // Transmitterを全部スキャン
+                       // Transmitterをスキャン
                        TransmitterListModel txListModel = fromDeviceModel.getTransmitterListModel();
                        int ntx = txListModel == null ? 0 : txListModel.getSize();
                        for( int index=0 ; index < ntx; index++ ) {
                                Transmitter tx = txListModel.getElementAt(index);
-                               //
-                               // Transmitterの場所を特定
+                               Receiver rx = tx.getReceiver();
+                               if( rx == null && (draggingLocation == null || ! tx.equals(draggingSource)) ) {
+                                       // このTransmitterから描画すべきケーブルはない
+                                       continue;
+                               }
+                               // Transmitterの表示場所を特定
                                Rectangle txBounds = fromFrame.getBoundsOf(tx);
                                if( txBounds == null ) continue;
                                int r = (txBounds.height - 5) / 2;
                                txBounds.translate(r+4, r+4);
+                               //
+                               // TransmitterからReceiverへのケーブルを描画
+                               if( rx != null ) {
+                                       // Receiverの表示場所を探す
+                                       for( JInternalFrame toFrame : frames ) {
+                                               if( ! (toFrame instanceof MidiDeviceFrame) ) continue;
+                                               Rectangle rxBounds = ((MidiDeviceFrame)toFrame).getBoundsOf(rx);
+                                               if( rxBounds == null ) continue;
+                                               r = (rxBounds.height - 5) / 2;
+                                               rxBounds.translate(r+4, r+4);
+                                               //
+                                               // 場所が判明したら描画
+                                               g2.setStroke(tx.equals(draggingSource) ? VIRTUAL_CABLE_STROKE : CABLE_STROKE);
+                                               g2.setColor(colorOf(rx));
+                                               g2.drawLine(txBounds.x, txBounds.y, rxBounds.x, rxBounds.y);
+                                               break;
+                                       }
+                               }
+                               // Transmitterからドラッグ中のケーブルを描画
                                if( draggingLocation != null && tx.equals(draggingSource) ) {
-                                       //
-                                       // Transmitterからドラッグされている線を描画
                                        if( draggingDestination instanceof Receiver ) {
                                                g2.setStroke(CABLE_STROKE);
                                                g2.setColor(colorOf((Receiver)draggingDestination));
@@ -243,22 +252,21 @@ public class MidiCablePane extends JComponent {
                                        }
                                        g2.drawLine(txBounds.x, txBounds.y, draggingLocation.x, draggingLocation.y);
                                }
-                               //
-                               // スキャン中のTransmitterに現在接続されているReceiverを把握
-                               Receiver rx = tx.getReceiver();
-                               if( rx == null ) continue;
-                               for( JInternalFrame toFrame : frames ) {
-                                       if( ! (toFrame instanceof MidiDeviceFrame) ) continue;
-                                       Rectangle rxBounds = ((MidiDeviceFrame)toFrame).getBoundsOf(rx);
-                                       if( rxBounds == null ) continue;
-                                       r = (rxBounds.height - 5) / 2;
+                       }
+                       // Receiverからドラッグ中のケーブルを描画
+                       if( draggingLocation != null && fromDeviceModel.getMidiDevice().getReceivers().contains(draggingSource) ) {
+                               Receiver rx = (Receiver)draggingSource;
+                               Rectangle rxBounds = fromFrame.getBoundsOf(rx);
+                               if( rxBounds != null ) {
+                                       int r = (rxBounds.height - 5) / 2;
                                        rxBounds.translate(r+4, r+4);
-                                       //
-                                       // Transmitter⇔Receiver間の線を描画
-                                       g2.setStroke(tx.equals(draggingSource) ? VIRTUAL_CABLE_STROKE : CABLE_STROKE);
+                                       if( draggingDestination instanceof Transmitter ) {
+                                               g2.setStroke(CABLE_STROKE);
+                                       } else {
+                                               g2.setStroke(VIRTUAL_CABLE_STROKE);
+                                       }
                                        g2.setColor(colorOf(rx));
-                                       g2.drawLine(txBounds.x, txBounds.y, rxBounds.x, rxBounds.y);
-                                       break;
+                                       g2.drawLine(rxBounds.x, rxBounds.y, draggingLocation.x, draggingLocation.y);
                                }
                        }
                }
index 72824c4..a435e8e 100644 (file)
@@ -88,35 +88,30 @@ public class PlaylistTableModel extends AbstractTableModel {
        public PlaylistTableModel(MidiSequencerModel sequencerModel) {
                this.sequencerModel = sequencerModel;
                sequencerModel.addChangeListener(secondPosition);
-               sequencerModel.getSequencer().addMetaEventListener(
-                       new MetaEventListener() {
-                               /**
-                                * {@inheritDoc}
-                                *
-                                * <p>EOT (End Of Track、type==0x2F) を受信したとき、次の曲へ進みます。
-                                * </p>
-                                * <p>これは MetaEventListener のための実装なので、多くの場合
-                                * Swing EDT ではなく MIDI シーケンサの EDT から起動されます。
-                                * Swing EDT とは違うスレッドで動いていた場合は Swing EDT に振り直されます。
-                                * </p>
-                                */
-                               @Override
-                               public void meta(MetaMessage msg) {
-                                       if( msg.getType() == 0x2F ) {
-                                               if( ! SwingUtilities.isEventDispatchThread() ) {
-                                                       SwingUtilities.invokeLater(
-                                                               new Runnable() {
-                                                                       @Override
-                                                                       public void run() { goNext(); }
-                                                               }
-                                                       );
-                                                       return;
-                                               }
+               sequencerModel.getSequencer().addMetaEventListener(new MetaEventListener() {
+                       /**
+                        * {@inheritDoc}
+                        *
+                        * <p>EOT (End Of Track、type==0x2F) を受信したとき、次の曲へ進みます。
+                        * </p>
+                        * <p>多くの場合、このメソッドは Swing の EDT(Event Dispatch Thread) ではなく
+                        * MIDI シーケンサの EDT から起動されるので、GUI 処理を Swing EDT に振り直します。
+                        * </p>
+                        */
+                       @Override
+                       public void meta(MetaMessage msg) {
+                               if( msg.getType() == 0x2F ) {
+                                       if( SwingUtilities.isEventDispatchThread() ) {
                                                goNext();
+                                       } else {
+                                               SwingUtilities.invokeLater(new Runnable() {
+                                                       @Override
+                                                       public void run() { goNext(); }
+                                               });
                                        }
                                }
                        }
-               );
+               });
                emptyTrackListTableModel = new SequenceTrackListTableModel(this, null, null);
                emptyEventListTableModel = new TrackEventListTableModel(emptyTrackListTableModel, null);
        }
index aee1957..c88e241 100644 (file)
@@ -1,18 +1,15 @@
 package camidion.chordhelper.midieditor;
 
 import java.awt.Component;
+import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
 
-import javax.sound.midi.MetaEventListener;
-import javax.sound.midi.MetaMessage;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JSpinner;
 import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
 
 import camidion.chordhelper.ButtonIcon;
 import camidion.chordhelper.music.MIDISpec;
@@ -20,7 +17,7 @@ import camidion.chordhelper.music.MIDISpec;
 /**
  * テンポ選択(QPM: Quarter Per Minute)
  */
-public class TempoSelecter extends JPanel implements MouseListener, MetaEventListener {
+public class TempoSelecter extends JPanel {
        static final int DEFAULT_QPM = 120;
        protected SpinnerNumberModel tempoSpinnerModel =
                new SpinnerNumberModel(DEFAULT_QPM, 1, 999, 1);
@@ -41,49 +38,28 @@ public class TempoSelecter extends JPanel implements MouseListener, MetaEventLis
                add(tempoSpinner);
                add(tempoValueLabel);
                setEditable(true);
-               tempoLabel.addMouseListener(this);
-       }
-       private long prevBeatMicrosecondPosition = 0;
-       private class SetTempoRunnable implements Runnable {
-               byte[] qpm;
-               public SetTempoRunnable(byte[] qpm) { this.qpm = qpm; }
-               @Override
-               public void run() { setTempo(qpm);}
-       }
-       @Override
-       public void meta(MetaMessage msg) {
-               switch(msg.getType()) {
-               case 0x51: // Tempo (3 bytes) - テンポ
-                       if( SwingUtilities.isEventDispatchThread() ) {
-                               setTempo(msg.getData());
-                       } else {
-                               SwingUtilities.invokeLater(new SetTempoRunnable(msg.getData()));
-                       }
-                       break;
-               }
-       }
-       @Override
-       public void mousePressed(MouseEvent e) {
-               Component obj = e.getComponent();
-               if(obj == tempoLabel && isEditable()) {
-                       //
-                       // Adjust tempo by interval time between two clicks
-                       //
-                       long currentMicrosecond = System.nanoTime()/1000;
-                       // midi_ch_selecter.noteOn( 9, 37, 100 );
-                       long interval_us = currentMicrosecond - prevBeatMicrosecondPosition;
-                       prevBeatMicrosecondPosition = currentMicrosecond;
-                       if( interval_us < 2000000L /* Shorter than 2 sec only */ ) {
-                               int tempo_in_bpm = (int)(240000000L / interval_us) >> 2; //  n/4拍子の場合のみを想定
-                       int old_tempo_in_bpm = getTempoInQpm();
-                       setTempo( ( tempo_in_bpm + old_tempo_in_bpm * 2 ) / 3 );
+               tempoLabel.addMouseListener(new MouseAdapter() {
+                       @Override
+                       public void mousePressed(MouseEvent e) {
+                               Component obj = e.getComponent();
+                               if(obj == tempoLabel && isEditable()) {
+                                       //
+                                       // Adjust tempo by interval time between two clicks (tapping)
+                                       //
+                                       long currentMicrosecond = System.nanoTime()/1000;
+                                       // midi_ch_selecter.noteOn( 9, 37, 100 );
+                                       long interval_us = currentMicrosecond - prevBeatMicrosecondPosition;
+                                       prevBeatMicrosecondPosition = currentMicrosecond;
+                                       if( interval_us < 2000000L /* Shorter than 2 sec only */ ) {
+                                               int tempo_in_bpm = (int)(240000000L / interval_us) >> 2; //  n/4拍子の場合のみを想定
+                                       int old_tempo_in_bpm = getTempoInQpm();
+                                       setTempo( ( tempo_in_bpm + old_tempo_in_bpm * 2 ) / 3 );
+                                       }
+                               }
                        }
-               }
+               });
        }
-       public void mouseReleased(MouseEvent e) { }
-       public void mouseEntered(MouseEvent e) { }
-       public void mouseExited(MouseEvent e) { }
-       public void mouseClicked(MouseEvent e) { }
+       private long prevBeatMicrosecondPosition = 0;
        private boolean editable;
        /**
         * 編集可能かどうかを返します。
index 57f96be..6b5a9a9 100644 (file)
@@ -1,22 +1,17 @@
 package camidion.chordhelper.midieditor;
 
-import javax.sound.midi.MetaEventListener;
-import javax.sound.midi.MetaMessage;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JSpinner;
 import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
 
 /**
  * 拍子選択ビュー
  */
-public class TimeSignatureSelecter extends JPanel implements MetaEventListener {
+public class TimeSignatureSelecter extends JPanel {
        SpinnerNumberModel upperTimesigSpinnerModel = new SpinnerNumberModel(4, 1, 32, 1);
-       private JSpinner upperTimesigSpinner = new JSpinner(
-               upperTimesigSpinnerModel
-       ) {
+       private JSpinner upperTimesigSpinner = new JSpinner(upperTimesigSpinnerModel) {
                {
                        setToolTipText("Time signature (upper digit) - 拍子の分子");
                }
@@ -28,24 +23,6 @@ public class TimeSignatureSelecter extends JPanel implements MetaEventListener {
                        setSelectedIndex(2);
                }
        };
-       private class SetValueRunnable implements Runnable {
-               byte[] timesig;
-               public SetValueRunnable(byte[] timesig) { this.timesig = timesig; }
-               @Override
-               public void run() { setValue(timesig);}
-       }
-       @Override
-       public void meta(MetaMessage msg) {
-               switch(msg.getType()) {
-               case 0x58: // Time signature (4 bytes) - 拍子
-                       if( SwingUtilities.isEventDispatchThread() ) {
-                               setValue(msg.getData());
-                       } else {
-                               SwingUtilities.invokeLater(new SetValueRunnable(msg.getData()));
-                       }
-                       break;
-               }
-       }
        private class TimeSignatureLabel extends JLabel {
                private byte upper = -1;
                private byte lower_index = -1;