/* For License see bottom */
package jpianotrain.gui;
import static jpianotrain.util.ConfigurationKeys.KEYBOARD_IN_DEVICE;
import static jpianotrain.util.ConfigurationKeys.MIDI_METRONOME_DEVICE;
import static jpianotrain.util.ConfigurationKeys.MIDI_OUT_DEVICE;
import static jpianotrain.util.ResourceKeys.CHECKBOX_LOG_MIDI;
import static jpianotrain.util.ResourceKeys.LABEL_DESCRIPTION;
import static jpianotrain.util.ResourceKeys.LABEL_DEVICE_KEYBOARD;
import static jpianotrain.util.ResourceKeys.LABEL_DEVICE_METRONOME;
import static jpianotrain.util.ResourceKeys.LABEL_DEVICE_OUT;
import static jpianotrain.util.ResourceKeys.LABEL_METRONOME_TICK_TOCK;
import static jpianotrain.util.ResourceKeys.LABEL_MIDI_CHANNEL;
import static jpianotrain.util.ResourceKeys.LIST_ITEM_UNDEFINED;
import static jpianotrain.util.ResourceKeys.MESSAGE_MIDI_INIT_FAILED;
import static jpianotrain.util.ResourceKeys.MESSAGE_NO_RECEIVER;
import static jpianotrain.util.ResourceKeys.MESSAGE_NO_TRANSMITTER;
import static jpianotrain.util.ResourceKeys.TITLE_DESCRIPTION;
import static jpianotrain.util.ResourceKeys.TITLE_DEVICE;
import static jpianotrain.util.ResourceKeys.TITLE_MIDI_INIT_FAILED;
import static jpianotrain.util.ResourceKeys.TITLE_TEST;
import static jpianotrain.util.ResourceKeys.TOOLTIP_DESCRIBE_DEVICE;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Synthesizer;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import jpianotrain.ApplicationContext;
import jpianotrain.event.SynthesizerPanelListener;
import jpianotrain.midi.MidiThread;
import jpianotrain.util.ResourceFactory;
import jpianotrain.util.UserConfiguration;
import org.apache.log4j.Logger;
/**
* Panel to configure MIDI for in- and output.
* Includes a {@link TestSettings} panel and
* a {@link DeviceDescription} panel.
*
* @since 0
* @author Alexander Methke
*/
public class MidiPanel extends ConfigurationPanel
implements ActionListener,
MidiChooser,
SynthesizerPanelListener {
private static final Logger log=Logger.getLogger(MidiPanel.class);
/** Creates new form MidiSettings */
public MidiPanel() {
initComponents();
initValues();
}
@Override
public void initData() {
}
@Override
public void saveData() {
boolean flag=false;
UserConfiguration uc=UserConfiguration.getInstance();
ApplicationContext ctx=ApplicationContext.getInstance();
try {
this.midiOutIndex=midiOutBox.getSelectedIndex();
uc.putProperty(MIDI_OUT_DEVICE, midiOutIndex);
MidiDevice.Info outInfo=(MidiDevice.Info)midiOutBox.getSelectedItem();
this.metronomeIndex=metronomeOutBox.getSelectedIndex();
uc.putProperty(MIDI_METRONOME_DEVICE, metronomeIndex);
MidiDevice.Info metronomeInfo=null;
if (metronomeIndex>0) {
metronomeInfo=(MidiDevice.Info)metronomeOutBox.getSelectedItem();
}
this.keyInIndex=keyboardInBox.getSelectedIndex();
uc.putProperty(KEYBOARD_IN_DEVICE, keyInIndex);
MidiDevice.Info keyInfo=(MidiDevice.Info)keyboardInBox.getSelectedItem();
MidiDevice metroDev=null;
if (metronomeInfo!=null) {
metroDev=MidiSystem.getMidiDevice(metronomeInfo);
if (metroDev.getMaxReceivers()==0) {
JOptionPane.showMessageDialog(ctx.getDefaultDialogOwner(),
ResourceFactory.getString(MESSAGE_NO_RECEIVER),
ResourceFactory.getString(TITLE_MIDI_INIT_FAILED),
JOptionPane.ERROR_MESSAGE);
}
}
MidiDevice outDev=MidiSystem.getMidiDevice(outInfo);
if (outDev.getMaxReceivers()==0) {
JOptionPane.showMessageDialog(ctx.getDefaultDialogOwner(),
ResourceFactory.getString(MESSAGE_NO_RECEIVER),
ResourceFactory.getString(TITLE_MIDI_INIT_FAILED),
JOptionPane.ERROR_MESSAGE);
}
MidiDevice keyDev=MidiSystem.getMidiDevice(keyInfo);
if (keyDev.getMaxTransmitters()==0) {
JOptionPane.showMessageDialog(ctx.getDefaultDialogOwner(),
ResourceFactory.getString(MESSAGE_NO_TRANSMITTER),
ResourceFactory.getString(TITLE_MIDI_INIT_FAILED),
JOptionPane.ERROR_MESSAGE);
}
flag=MidiThread.getInstance().init(keyDev, outDev, metroDev);
} catch (Exception ex) {
log.error("failed to init midi thread", ex);
}
if (flag) {
ctx.setMidiStatus(ApplicationContext.MidiStatus.ON);
} else {
ctx.setMidiStatus(ApplicationContext.MidiStatus.OFF);
JOptionPane.showMessageDialog(ctx.getDefaultDialogOwner(),
ResourceFactory.getString(MESSAGE_MIDI_INIT_FAILED),
ResourceFactory.getString(TITLE_MIDI_INIT_FAILED),
JOptionPane.ERROR_MESSAGE);
}
}
@Override
public void rejectData() {
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents() {
setLayout(new GridBagLayout());
GridBagConstraints gbc=new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
testSettings = new TestSettings();
testSettings.setBorder(createBorder(TITLE_TEST));
deviceDescription = new DeviceDescription();
deviceDescription.setBorder(createBorder(TITLE_DESCRIPTION));
JPanel devPanel=createDevicePanel();
devPanel.setBorder(createBorder(TITLE_DEVICE));
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
add(devPanel, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weightx=1.0;
gbc.weighty=1.0;
gbc.gridheight = 2;
gbc.gridwidth=GridBagConstraints.REMAINDER;
add(deviceDescription, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weightx=0;
gbc.weighty=0;
gbc.gridwidth=1;
gbc.gridheight=1;
add(testSettings, gbc);
}
private JPanel createDevicePanel() {
JPanel devicePanel=new JPanel();
devicePanel.setLayout(new GridBagLayout());
GridBagConstraints gbc=new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor=GridBagConstraints.EAST;
devicePanel.add(createLabel(LABEL_DEVICE_KEYBOARD), gbc);
gbc.gridy++;
devicePanel.add(createLabel(LABEL_DEVICE_OUT), gbc);
gbc.gridy++;
devicePanel.add(createLabel(LABEL_MIDI_CHANNEL), gbc);
gbc.gridy++;
devicePanel.add(createLabel(LABEL_DEVICE_METRONOME), gbc);
gbc.gridy++;
devicePanel.add(createLabel(LABEL_MIDI_CHANNEL), gbc);
gbc.gridy++;
devicePanel.add(createLabel(LABEL_METRONOME_TICK_TOCK), gbc);
gbc.gridx++;
gbc.gridy=0;
gbc.gridwidth=2;
gbc.fill = GridBagConstraints.HORIZONTAL;
keyboardInBox = new JComboBox();
keyboardInBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
keyboardInBoxItemStateChanged(evt);
}
});
devicePanel.add(keyboardInBox, gbc);
midiOutBox = new JComboBox();
midiOutBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
midiOutBoxItemStateChanged(evt);
}
});
gbc.gridy++;
devicePanel.add(midiOutBox, gbc);
channelOutSpinner = new JSpinner();
gbc.gridy++;
devicePanel.add(channelOutSpinner, gbc);
metronomeOutBox = new JComboBox();
metronomeOutBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
metronomeOutBoxItemStateChanged(evt);
}
});
gbc.gridy++;
devicePanel.add(metronomeOutBox, gbc);
channelMetronomeSpinner = new JSpinner();
gbc.gridy++;
devicePanel.add(channelMetronomeSpinner, gbc);
gbc.gridwidth=1;
gbc.gridy++;
metronomeLow=createMidiNoteSpinner();
devicePanel.add(metronomeLow, gbc);
gbc.gridx++;
metronomeHigh=createMidiNoteSpinner();
devicePanel.add(metronomeHigh, gbc);
gbc.gridx=1;
spoolBox = new JCheckBox(ResourceFactory.getString(CHECKBOX_LOG_MIDI));
spoolBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
spoolBoxActionPerformed(evt);
}
});
gbc.gridy++;
gbc.anchor = GridBagConstraints.WEST;
gbc.fill=GridBagConstraints.NONE;
devicePanel.add(spoolBox, gbc);
describeButton1=createButton(LABEL_DESCRIPTION,TOOLTIP_DESCRIBE_DEVICE);
gbc.gridx = 3;
gbc.gridy = 0;
devicePanel.add(describeButton1, gbc);
describeButton2=createButton(LABEL_DESCRIPTION,TOOLTIP_DESCRIBE_DEVICE);
gbc.gridy++;
devicePanel.add(describeButton2, gbc);
describeButton3=createButton(LABEL_DESCRIPTION,TOOLTIP_DESCRIBE_DEVICE);
gbc.gridy+=2;
devicePanel.add(describeButton3, gbc);
return devicePanel;
}
private void spoolBoxActionPerformed(ActionEvent evt) {
ApplicationContext.getInstance().setSpoolMidi(spoolBox.isSelected());
}
private void describeButton3ActionPerformed(ActionEvent evt) {
if (keyboardInBox.getSelectedIndex()>0) {
deviceDescription.setDeviceInfo((MidiDevice.Info)keyboardInBox.getSelectedItem());
} else {
deviceDescription.setDeviceInfo(null);
}
}
private void describeButton2ActionPerformed(ActionEvent evt) {
deviceDescription.setDeviceInfo((MidiDevice.Info)metronomeOutBox.getSelectedItem());
}
private void describeButton1ActionPerformed(ActionEvent evt) {
deviceDescription.setDeviceInfo((MidiDevice.Info)midiOutBox.getSelectedItem());
}
private void keyboardInBoxItemStateChanged(ItemEvent evt) {
if (initiating) {
return;
}
deviceDescription.setDeviceInfo((MidiDevice.Info)keyboardInBox.getSelectedItem());
}
private void metronomeOutBoxItemStateChanged(ItemEvent evt) {
if (initiating) {
return;
}
if (metronomeOutBox.getSelectedIndex()>0) {
deviceDescription.setDeviceInfo((MidiDevice.Info)metronomeOutBox.getSelectedItem());
enableMetronome(true);
} else {
enableMetronome(false);
}
}
private void midiOutBoxItemStateChanged(ItemEvent evt) {
if (initiating) {
return;
}
deviceDescription.setDeviceInfo((MidiDevice.Info)midiOutBox.getSelectedItem());
}
private void enableMetronome(boolean flag) {
channelMetronomeSpinner.setEnabled(flag);
testSettings.setMetronomeEnabled(flag);
metronomeHigh.setEnabled(flag);
metronomeLow.setEnabled(flag);
}
private void initValues() {
//spoolBox.setSelected(JRackAttack.spoolMidi());
testSettings.setMidiChooser(this);
((SpinnerNumberModel)channelOutSpinner.getModel()).setMinimum(0);
((SpinnerNumberModel)channelOutSpinner.getModel()).setMaximum(15);
((SpinnerNumberModel)channelMetronomeSpinner.getModel()).setMinimum(0);
((SpinnerNumberModel)channelMetronomeSpinner.getModel()).setMaximum(15);
// Load available Midi Devices
MidiDevice.Info[] info=MidiSystem.getMidiDeviceInfo();
int c=info.length;
MidiDevice dev;
keyboardInBox.removeAllItems();
metronomeOutBox.removeAllItems();
midiOutBox.removeAllItems();
UserConfiguration uc=UserConfiguration.getInstance();
if (keyInIndex==-1) {
keyInIndex=uc.getIntProperty(KEYBOARD_IN_DEVICE, -1);
}
if (metronomeIndex==-1) {
metronomeIndex=uc.getIntProperty(MIDI_METRONOME_DEVICE, -1);
}
if (midiOutIndex==-1) {
midiOutIndex=uc.getIntProperty(MIDI_OUT_DEVICE, -1);
}
try {
metronomeOutBox.addItem(ResourceFactory.getString(LIST_ITEM_UNDEFINED));
for (int i=0;i<c;i++) {
dev=MidiSystem.getMidiDevice(info[i]);
int maxR=dev.getMaxReceivers();
int maxT=dev.getMaxTransmitters();
if (maxT==-1 || maxT>0) {
keyboardInBox.addItem(info[i]);
} else if (maxR==-1 || maxR>0){
metronomeOutBox.addItem(info[i]);
midiOutBox.addItem(info[i]);
}
}
if (keyInIndex!=-1) {
keyboardInBox.setSelectedIndex(keyInIndex);
}
if (metronomeIndex!=-1) {
metronomeOutBox.setSelectedIndex(metronomeIndex);
}
if (midiOutIndex!=-1) {
midiOutBox.setSelectedIndex(midiOutIndex);
}
} catch (Exception ex) {
log.error("failure while filling midi device lists", ex);
}
if (metronomeOutBox.getSelectedIndex()==0) {
channelMetronomeSpinner.setEnabled(false);
testSettings.setMetronomeEnabled(false);
}
}
// ActionListener
public void actionPerformed(ActionEvent e) {
if (e.getSource()==describeButton1) {
describeButton1ActionPerformed(e);
} else if (e.getSource()==describeButton2) {
describeButton2ActionPerformed(e);
} else if (e.getSource()==describeButton3) {
describeButton3ActionPerformed(e);
}
}
// MidiChooser
@Override
public MidiDevice.Info getSelectedOutputDevice() {
return (MidiDevice.Info) midiOutBox.getSelectedItem();
}
public int getSelectedChannel() {
return ((Integer)channelOutSpinner.getValue()).intValue();
}
@Override
public Instrument getSelectedInstrument() {
return null;
}
@Override
public Synthesizer getSelectedSynthesizer() {
return null;
}
// SynthesizerPanelListener
@Override
public void synthesizerPanelEnabled(boolean state) {
boolean myState=!state;
setEnabled(myState);
testSettings.setEnabled(myState);
channelOutSpinner.setEnabled(myState);
channelMetronomeSpinner.setEnabled(myState);
metronomeHigh.setEnabled(myState);
metronomeLow.setEnabled(myState);
describeButton1.setEnabled(myState);
describeButton2.setEnabled(myState);
describeButton3.setEnabled(myState);
deviceDescription.setEnabled(myState);
keyboardInBox.setEnabled(myState);
metronomeOutBox.setEnabled(myState);
midiOutBox.setEnabled(myState);
spoolBox.setEnabled(myState);
}
private JSpinner channelOutSpinner;
private JSpinner channelMetronomeSpinner;
private JSpinner metronomeHigh;
private JSpinner metronomeLow;
private JButton describeButton1;
private JButton describeButton2;
private JButton describeButton3;
private DeviceDescription deviceDescription;
private JComboBox keyboardInBox;
private JComboBox metronomeOutBox;
private JComboBox midiOutBox;
private JCheckBox spoolBox;
private TestSettings testSettings;
private int metronomeIndex=-1;
private int midiOutIndex=-1;
private int keyInIndex=-1;
private boolean initiating;
}
/*
Copyright (C) 2008 Alexander Methke
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program (gplv3.txt).
*/