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;
/**
* 和音表示ラベル
*/
-public class ChordDisplayLabel extends JLabel implements MouseListener {
+public class ChordDisplayLabel extends JLabel {
private String defaultString = null;
private Chord chord = null;
private int noteNumber = -1;
*/
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) {
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ノート番号
*/
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/";
* アプリケーションのアイコンイメージ
*/
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;
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();
//
//
// 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());
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) {
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);
keyboardPanel.setDarkMode(isDark);
}
+ private void setKeySignature(Key key) {
+ keysigLabel.setKeySignature(key);
+ chordMatrix.setKeySignature(key);
+ }
+
private int[] chordOnNotes = null;
/**
* 和音を発音します。
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);
//
// 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); }
+ });
}
/**
* 前回のタイムスタンプ
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;
*/
@Override
public void stateChanged(ChangeEvent event) {
- MidiSequencerModel sequencerModel = (MidiSequencerModel) event.getSource();
- setFilenameToTitle(sequencerModel.getSequenceTrackListTableModel());
+ setFilenameToTitle(applet.sequencerModel.getSequenceTrackListTableModel());
}
});
applet.playlistModel.addTableModelListener(new TableModelListener() {
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());
}
}
});
* コードサフィックスのヘルプ
*/
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]"));
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]"));
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 );
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();
}
};
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));
}
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);
}
}
}
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);
}
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;
/**
* テンポ選択(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);
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;
/**
* 編集可能かどうかを返します。
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) - 拍子の分子");
}
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;