*/
public static class VersionInfo {
public static final String NAME = "MIDI Chord Helper";
- public static final String VERSION = "Ver.20161010.1";
+ public static final String VERSION = "Ver.20161106.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/";
* カポ選択コンボボックスモデル(選択範囲:1~11)
*/
public class CapoComboBoxModel implements ComboBoxModel<Integer> {
- private Integer selectedValue = Integer.valueOf(1);
+ private Integer selectedValue = 1;
@Override
public int getSize() { return 11; }
@Override
- public Integer getElementAt(int index) { return Integer.valueOf(index + 1); }
+ public Integer getElementAt(int index) { return index + 1; }
@Override
public void addListDataListener(ListDataListener l) { }
@Override
* @return カポ位置
*/
public int getCapo() {
- return checkbox.isSelected() ? valueSelecter.getSelectedIndex()+1 : 0;
+ return checkbox.isSelected() ? (int) valueSelecter.getModel().getSelectedItem() : 0;
}
}
\ No newline at end of file
new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
- setToolTipText(
- diagramDisplay.chordVariations.getIndexDescription()
- );
+ setToolTipText(diagramDisplay.chordVariations.getIndexDescription());
}
}
);
@Override
public Transmitter getTransmitter() throws MidiUnavailableException {
if( maxTransmitters == 0 ) throw new MidiUnavailableException();
- Transmitter new_tx = new Transmitter() {
+ Transmitter newTx = new Transmitter() {
private Receiver rx = null;
@Override
public void close() { txList.remove(this); }
@Override
public void setReceiver(Receiver rx) { this.rx = rx; }
};
- txList.add(new_tx);
- return new_tx;
+ txList.add(newTx);
+ return newTx;
}
@Override
public void sendMidiMessage(MidiMessage msg) {
package camidion.chordhelper.mididevice;
+import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.Receiver;
import javax.sound.midi.Transmitter;
this.description = description;
this.shortName = shortName;
}
- public static MidiDeviceInOutType getValueFor(TransmitterListModel txListModel, ReceiverListModel rxListModel) {
+ public static MidiDeviceInOutType getValueFor(MidiDevice device) {
// tx:IN rx:OUT
- return rxListModel == null ?
- (txListModel == null ? MIDI_NONE : MIDI_IN) :
- (txListModel == null ? MIDI_OUT : MIDI_IN_OUT);
+ return device.getMaxReceivers() == 0 ?
+ (device.getMaxTransmitters() == 0 ? MIDI_NONE : MIDI_IN) :
+ (device.getMaxTransmitters() == 0 ? MIDI_OUT : MIDI_IN_OUT);
}
public String getDescription() { return description; }
private String description;
* MIDIデバイスからモデルを構築します。
*
* @param device 対象MIDIデバイス
- * @param deviceTreeModel このMIDIデバイスモデルのマネージャー(接続相手となりうるMIDIデバイス)
+ * @param deviceTreeModel このモデルの親ツリー
*/
public MidiDeviceModel(MidiDevice device, MidiDeviceTreeModel deviceTreeModel) {
this.deviceTreeModel = deviceTreeModel;
this.device = device;
if( device.getMaxTransmitters() != 0 ) txListModel = new TransmitterListModel(this);
if( device.getMaxReceivers() != 0 ) rxListModel = new ReceiverListModel(this);
- ioType = MidiDeviceInOutType.getValueFor(txListModel, rxListModel);
+ ioType = MidiDeviceInOutType.getValueFor(device);
treePath = new TreePath(new Object[] {deviceTreeModel, ioType ,this});
}
/**
@Override
public String toString() { return "MIDI devices"; }
- // MIDIデバイスモデルリストとツリー
protected List<MidiDeviceModel> deviceModelList = new Vector<>();
+ @Override
+ public int size() { return deviceModelList.size(); }
+ @Override
+ public MidiDeviceModel get(int index) { return deviceModelList.get(index); }
protected Map<MidiDeviceInOutType, List<MidiDeviceModel>> deviceModelTree; {
deviceModelTree = new EnumMap<>(MidiDeviceInOutType.class);
deviceModelTree.put(MidiDeviceInOutType.MIDI_OUT, new ArrayList<>());
deviceModelTree.put(MidiDeviceInOutType.MIDI_IN_OUT, new ArrayList<>());
};
/**
- * MIDIデバイスモデルを追加します。
- *
+ * {@link #add()}の非public版です。
* @param dm 追加するMIDIデバイスモデル
- * @return 呼出しの結果としてこのリストが変更された場合はtrue
+ * @return true({@link AbstractList#add()}と同じ)
*/
- protected boolean addDeviceModel(MidiDeviceModel dm) {
+ protected boolean addInternally(MidiDeviceModel dm) {
if( ! deviceModelList.add(dm) ) return false;
- deviceModelTree.get(dm.getInOutType()).add(dm); return true;
- }
- /**
- * MIDIデバイス情報をモデルとして追加します。
- *
- * @param info 追加するMIDIデバイス情報({@link MidiDevice.Info})
- * @return 呼出しの結果としてこのリストが変更された場合はtrue
- * @throws MidiUnavailableException {@link MidiDeviceModel#MidiDeviceModel(MidiDevice.Info, MidiDeviceTreeModel) MidiDeviceModelコンストラクタ}からの例外
- */
- protected boolean addDeviceModel(MidiDevice.Info info) throws MidiUnavailableException {
- return addDeviceModel(new MidiDeviceModel(info, this));
- }
- /**
- * リストとツリーモデルから、指定されたMIDIデバイスモデル(複数指定可)を除去します。
- *
- * @param deviceModelsToRemove 除去したいMIDIデバイスモデル
- * @return 指定されたMIDIデバイスモデルがこのリストに含まれていた場合はtrue
- */
- protected boolean removeDeviceModels(Collection<MidiDeviceModel> deviceModelsToRemove) {
- if( ! deviceModelList.removeAll(deviceModelsToRemove) ) return false;
- for( MidiDeviceModel dm : deviceModelsToRemove )
- deviceModelTree.get(dm.getInOutType()).remove(dm);
+ deviceModelTree.get(dm.getInOutType()).add(dm);
return true;
}
/**
- * リスト、ツリーモデル、接続マップから、指定されたMIDIデバイスモデル(複数指定可)を除去します。
- *
- * @param deviceModelsToRemove 除去したいMIDIデバイスモデル
- * @param rxToTxConnections MIDIデバイスモデル接続マップ({@link #disconnectAllDevices()}の戻り値)
- * @return 指定されたMIDIデバイスモデルがこのリストに含まれていた場合はtrue
+ * {@link #removeAll()}の非public版です。
+ * @param c 削除する要素のコレクション
+ * @return {@link AbstractList#removeAll()}と同じ
*/
- protected boolean removeDeviceModels(
- Collection<MidiDeviceModel> deviceModelsToRemove,
- Map<MidiDeviceModel, Collection<MidiDeviceModel>> rxToTxConnections) {
- if( ! removeDeviceModels(deviceModelsToRemove) ) return false;
- Set<MidiDeviceModel> rxModels = rxToTxConnections.keySet();
- rxModels.removeAll(deviceModelsToRemove);
- for( MidiDeviceModel m : rxModels )
- rxToTxConnections.get(m).removeAll(deviceModelsToRemove);
+ protected boolean removeAllInternally(Collection<?> c) {
+ if( ! deviceModelList.removeAll(c) ) return false;
+ for( Object o : c ) {
+ if( o instanceof MidiDeviceModel ) {
+ MidiDeviceInOutType ioType = ((MidiDeviceModel)o).getInOutType();
+ deviceModelTree.get(ioType).remove(o);
+ }
+ }
return true;
}
-
- /**
- * このMIDIデバイスツリーモデルに登録されているMIDIシーケンサーモデルを返します。
- * @return MIDIシーケンサーモデル
- */
- public MidiSequencerModel getSequencerModel() { return sequencerModel; }
- protected MidiSequencerModel sequencerModel;
- //
- // リスト用インターフェース
- @Override
- public MidiDeviceModel get(int index) { return deviceModelList.get(index); }
- @Override
- public int size() { return deviceModelList.size(); }
- //
// ツリーモデル用インターフェース
@Override
public Object getRoot() { return this; }
}
/**
+ * このMIDIデバイスツリーモデルに登録されているMIDIシーケンサーモデルを返します。
+ * @return MIDIシーケンサーモデル
+ */
+ public MidiSequencerModel getSequencerModel() { return sequencerModel; }
+ protected MidiSequencerModel sequencerModel;
+
+ /**
* 引数で与えられたGUI仮想MIDIデバイスと、{@link #getMidiDeviceInfo()}から取得したMIDIデバイス情報から、
* MIDIデバイスツリーモデルを初期構築します。
*
*/
public MidiDeviceTreeModel(VirtualMidiDevice guiVirtualDevice) {
MidiDeviceModel guiModel = new MidiDeviceModel(guiVirtualDevice, this);
- addDeviceModel(guiModel);
+ addInternally(guiModel);
try {
- addDeviceModel(sequencerModel = new MidiSequencerModel(MidiSystem.getSequencer(false), this));
+ addInternally(sequencerModel = new MidiSequencerModel(MidiSystem.getSequencer(false), this));
} catch( MidiUnavailableException e ) {
System.out.println(ChordHelperApplet.VersionInfo.NAME +" : MIDI sequencer unavailable");
e.printStackTrace();
if( device instanceof Sequencer ) continue; // シーケンサはすでに取得済み
if( device instanceof Synthesizer ) { // Java内蔵シンセサイザ
try {
- addDeviceModel(synthModel = new MidiDeviceModel(MidiSystem.getSynthesizer(), this));
+ addInternally(synthModel = new MidiDeviceModel(MidiSystem.getSynthesizer(), this));
} catch( MidiUnavailableException e ) {
System.out.println(ChordHelperApplet.VersionInfo.NAME +
" : Java internal MIDI synthesizer unavailable");
// 最初の MIDI IN(USB MIDI インターフェースにつながったMIDIキーボードなど)
if( firstMidiInModel == null && m.getTransmitterListModel() != null ) firstMidiInModel = m;
//
- addDeviceModel(m);
+ addInternally(m);
}
// 開くMIDIデバイスモデルの一覧を作成
//
toRemove.add(m);
}
// 削除されたデバイスのモデルを除去
- removeDeviceModels(toRemove, rxToTxConnections);
- //
+ if( removeAllInternally(toRemove) ) {
+ Set<MidiDeviceModel> rxModels = rxToTxConnections.keySet();
+ rxModels.removeAll(toRemove);
+ for( MidiDeviceModel m : rxModels ) rxToTxConnections.get(m).removeAll(toRemove);
+ }
// 追加されたデバイスのモデルを登録
for( MidiDevice.Info info : toAdd ) {
try {
- addDeviceModel(info);
+ addInternally(new MidiDeviceModel(info, this));
} catch( MidiUnavailableException e ) {
e.printStackTrace();
}
return this;
}
});
- //
// ツリーノードのToolTipを有効化
ToolTipManager.sharedInstance().registerComponent(this);
//
*/
public class MidiSequencerModel extends MidiDeviceModel implements BoundedRangeModel {
/**
+ * 再生位置スライダーモデルの最小単位 [μ秒]
+ */
+ public static final long RESOLUTION_MICROSECOND = 1000L;
+ /**
* MIDIシーケンサモデルを構築します。
* @param sequencer シーケンサーMIDIデバイス
* @param deviceModelTree 親のMIDIデバイスツリーモデル
return usLength < 0 ? 0x100000000L + usLength : usLength ;
}
@Override
- public int getMaximum() { return (int)(getMicrosecondLength()/1000L); }
+ public int getMaximum() { return (int)(getMicrosecondLength()/RESOLUTION_MICROSECOND); }
@Override
public void setMaximum(int newMaximum) {}
@Override
return usPosition < 0 ? 0x100000000L + usPosition : usPosition ;
}
@Override
- public int getValue() { return (int)(getMicrosecondPosition()/1000L); }
+ public int getValue() { return (int)(getMicrosecondPosition()/RESOLUTION_MICROSECOND); }
@Override
public void setValue(int newValue) {
- getSequencer().setMicrosecondPosition(1000L * (long)newValue);
+ getSequencer().setMicrosecondPosition(RESOLUTION_MICROSECOND * (long)newValue);
fireStateChanged();
}
/**
}
@Override
public void setRangeProperties(int value, int extent, int min, int max, boolean valueIsAdjusting) {
- getSequencer().setMicrosecondPosition(1000L * (long)value);
+ getSequencer().setMicrosecondPosition(RESOLUTION_MICROSECOND * (long)value);
setValueIsAdjusting(valueIsAdjusting);
fireStateChanged();
}
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
-import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
import camidion.chordhelper.ButtonIcon;
import camidion.chordhelper.ChordHelperApplet;
/**
* Base64テキスト入力ダイアログ
*/
-public class Base64Dialog extends JDialog {
- private Base64TextArea base64TextArea = new Base64TextArea(8,56);
+public class Base64Dialog extends JDialog implements DocumentListener {
+ public static final Pattern HEADER_PATTERN = Pattern.compile("^.*:.*$", Pattern.MULTILINE);
+ private JTextArea base64TextArea = new JTextArea(8,56);
private MidiSequenceEditorDialog midiEditor;
+ private void error(String message) {
+ JOptionPane.showMessageDialog(base64TextArea, (Object)message,
+ ChordHelperApplet.VersionInfo.NAME, JOptionPane.WARNING_MESSAGE);
+ base64TextArea.requestFocusInWindow();
+ }
/**
* Base64デコードアクション
*/
- public Action addBase64Action = new AbstractAction(
- "Base64 Decode & Add to PlayList",
- new ButtonIcon(ButtonIcon.EJECT_ICON)
- ) {
+ public Action addBase64Action = new AbstractAction("Add to PlayList", new ButtonIcon(ButtonIcon.EJECT_ICON)) {
{ putValue(Action.SHORT_DESCRIPTION, "Base64デコードして、プレイリストへ追加"); }
@Override
public void actionPerformed(ActionEvent event) {
- String message = null;
+ byte[] midiData = null;
+ try {
+ midiData = getMIDIData();
+ } catch(Exception e) {
+ e.printStackTrace();
+ error("Base64デコードに失敗しました。\n"+e);
+ return;
+ }
try {
- byte[] data = getMIDIData();
- if( data == null || data.length == 0 ) {
- message = "No data on textbox - データが入力されていません。";
- } else {
- midiEditor.sequenceListTable.getModel().addSequence(data, null);
- setVisible(false);
- }
+ midiEditor.sequenceListTable.getModel().addSequence(midiData, null);
} catch(Exception e) {
e.printStackTrace();
- message = "Base64デコードまたはMIDIデータの読み込みに失敗しました。\n"+e;
+ error("Base64デコードされたデータが正しいMIDI形式になっていません。\n"+e);
+ return;
}
- if( message == null ) return;
- JOptionPane.showMessageDialog(base64TextArea, (Object)message,
- ChordHelperApplet.VersionInfo.NAME, JOptionPane.WARNING_MESSAGE);
- base64TextArea.requestFocusInWindow();
+ setVisible(false);
}
};
/**
* Base64テキストクリアアクション
*/
- public Action clearAction = new AbstractAction("Clear") {
+ public Action clearAction = new AbstractAction("Clear", new ButtonIcon(ButtonIcon.X_ICON)) {
@Override
- public void actionPerformed(ActionEvent e) {
- base64TextArea.setText(null);
- }
+ public void actionPerformed(ActionEvent e) { base64TextArea.setText(null); }
};
- private static class Base64TextArea extends JTextArea {
- private static final Pattern headerLineFormat =
- Pattern.compile( "^.*:.*$", Pattern.MULTILINE );
- public Base64TextArea(int rows, int columns) {
- super(rows,columns);
- }
- public byte[] getBinary() {
- String text = headerLineFormat.matcher(getText()).replaceAll("");
- return Base64.getMimeDecoder().decode(text.getBytes());
- }
- public void setBinary(byte[] binary_data, String content_type, String filename) {
- if( binary_data != null && binary_data.length > 0 ) {
- String header = "";
- if( content_type != null && filename != null ) {
- header += "Content-Type: " + content_type + "; name=\"" + filename + "\"\n";
- header += "Content-Transfer-Encoding: base64\n";
- header += "\n";
- }
- setText(header + Base64.getMimeEncoder().encodeToString(binary_data) + "\n");
- }
- }
- }
/**
* Base64テキスト入力ダイアログを構築します。
* @param midiEditor 親画面となるMIDIエディタ
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
- add(new JLabel("Base64-encoded MIDI sequence:"));
add(Box.createRigidArea(new Dimension(10, 0)));
add(new JButton(addBase64Action){{setMargin(ChordHelperApplet.ZERO_INSETS);}});
add(new JButton(clearAction){{setMargin(ChordHelperApplet.ZERO_INSETS);}});
add(new JScrollPane(base64TextArea));
}});
setBounds( 300, 250, 660, 300 );
+ base64TextArea.setToolTipText("Paste Base64-encoded MIDI sequence here");
+ base64TextArea.getDocument().addDocumentListener(this);
+ addBase64Action.setEnabled(false);
+ clearAction.setEnabled(false);
+ }
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ addBase64Action.setEnabled(true);
+ clearAction.setEnabled(true);
}
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ if( e.getDocument().getLength() > 0 ) return;
+ addBase64Action.setEnabled(false);
+ clearAction.setEnabled(false);
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) { }
/**
* バイナリー形式でMIDIデータを返します。
* @return バイナリー形式のMIDIデータ
* @throws IllegalArgumentException 入力されているテキストが有効なBase64スキームになっていない場合
*/
public byte[] getMIDIData() {
- return base64TextArea.getBinary();
+ String body = HEADER_PATTERN.matcher(base64TextArea.getText()).replaceAll("");
+ return Base64.getMimeDecoder().decode(body.getBytes());
}
/**
* バイナリー形式のMIDIデータを設定します。
* @param midiData バイナリー形式のMIDIデータ
*/
- public void setMIDIData( byte[] midiData ) {
- base64TextArea.setBinary(midiData, null, null);
- }
+ public void setMIDIData(byte[] midiData) { setMIDIData(midiData, null); }
/**
* バイナリー形式のMIDIデータを、ファイル名をつけて設定します。
* @param midiData バイナリー形式のMIDIデータ
* @param filename ファイル名
*/
- public void setMIDIData( byte[] midiData, String filename ) {
- base64TextArea.setBinary(midiData, "audio/midi", filename);
+ public void setMIDIData(byte[] midiData, String filename) {
+ if( midiData == null || midiData.length == 0 ) return;
+ if( filename == null ) filename = "";
+ String text =
+ "Content-Type: audio/midi; name=\"" + filename + "\"\n"
+ + "Content-Transfer-Encoding: base64\n\n" +
+ Base64.getMimeEncoder().encodeToString(midiData) + "\n";
+ base64TextArea.setText(text);
base64TextArea.selectAll();
}
/**
* Base64形式でMIDIデータを返します。
* @return Base64形式のMIDIデータ
*/
- public String getBase64Data() {
- return base64TextArea.getText();
- }
+ public String getBase64Data() { return base64TextArea.getText(); }
/**
* Base64形式のMIDIデータを設定します。
* @param base64Data Base64形式のMIDIデータ