/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad 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 2 of the License, or * (at your option) any later version. * * Nomad 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 Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.sf.nmedit.nordmodular; import java.awt.Event; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import javax.swing.AbstractAction; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.sf.nmedit.jpatch.clavia.nordmodular.NMPatch; import net.sf.nmedit.jsynth.Slot; import net.sf.nmedit.jsynth.SynthException; import net.sf.nmedit.jsynth.clavia.nordmodular.NmSlot; import net.sf.nmedit.jsynth.clavia.nordmodular.NordModular; import net.sf.nmedit.jsynth.clavia.nordmodular.worker.StorePatchInSlotWorker; import net.sf.nmedit.jsynth.event.SlotEvent; import net.sf.nmedit.jsynth.event.SlotListener; import net.sf.nmedit.jsynth.event.SlotManagerListener; import net.sf.nmedit.jsynth.event.SynthesizerEvent; import net.sf.nmedit.jsynth.event.SynthesizerStateListener; import net.sf.nmedit.jsynth.nomad.forms.SynthObjectForm; import net.sf.nmedit.jsynth.nomad.forms.SynthPropertiesDialog; import net.sf.nmedit.jsynth.nomad.forms.SynthPropertiesDialog.DialogPane; import net.sf.nmedit.jsynth.worker.RequestPatchWorker; import net.sf.nmedit.jtheme.clavia.nordmodular.JTNMPatch; import net.sf.nmedit.nmutils.swing.WorkIndicator; import net.sf.nmedit.nomad.core.Nomad; import net.sf.nmedit.nomad.core.forms.ExceptionDialog; import net.sf.nmedit.nomad.core.swing.document.DefaultDocumentManager; import net.sf.nmedit.nomad.core.swing.document.Document; import net.sf.nmedit.nomad.core.swing.document.DocumentManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class NMSynthDeviceContext extends SynthObjectForm<NordModular> { /** * */ private static final long serialVersionUID = 6337542133829436194L; //private Collection<Action> SpecialActions = null; public NMSynthDeviceContext(NordModular synth) { super(synth); (new PatchOpener(synth)).install(); } protected NmEventHandler createEventHandler() { return new NmEventHandler(); } public void openOrSelectPatch(Slot slot) { NmSlot nmslot = (NmSlot) slot; NMPatch patch = nmslot.getPatch(); if (patch != null) { // find out if patch is open DefaultDocumentManager dm = Nomad.sharedInstance().getDocumentManager(); for (Document d: dm.getDocuments()) { if ( d instanceof PatchDocument ) { PatchDocument pd = (PatchDocument) d; if (pd.getPatch() == patch) { // found -> select dm.setSelection(d); return ; } } } // not found -> create document try { final PatchDocument pd = NmFileService.createPatchDoc(patch); SwingUtilities.invokeLater(new Runnable(){ public void run() { DocumentManager dm = Nomad.sharedInstance() .getDocumentManager(); dm.add(pd); dm.setSelection(pd); } }); } catch (Exception e) { Log log = LogFactory.getLog(getClass()); if (log.isWarnEnabled()) { log.warn(e); } ExceptionDialog.showErrorDialog( Nomad.sharedInstance().getWindow().getRootPane(), e.getMessage(), "could not open patch", e); return; } return; } try { slot.createRequestPatchWorker().requestPatch(); } catch (SynthException e1) { e1.printStackTrace(); } } protected class NmEventHandler extends EventHandler { public void install() { super.install(); //getSynthesizer().addPropertyChangeListener(this); } /* public void propertyChange(PropertyChangeEvent evt) { super.propertyChange(evt); s }*/ } protected SlotObject<NordModular> createSlotObject(Slot slot) { return new NmSlotObject(this, slot); } protected static class NmSlotObject extends SlotObject<NordModular> { public NmSlotObject(NMSynthDeviceContext sdc, Slot slot) { super(sdc, slot); } public NmSlot getSlot() { return (NmSlot) super.getSlot(); } } protected void dropTransfer(SlotObject<NordModular> s, DropTargetDropEvent dtde) { if (!acceptsDropData(s, dtde.getCurrentDataFlavors())) { dtde.rejectDrop(); return; } if (!dtde.isLocalTransfer()) { dtde.rejectDrop(); return; } try { NMPatch patch = (NMPatch) dtde .getTransferable() .getTransferData(JTNMPatch.nmPatchFlavor); if (patch.getSlot() != null) patch.setSlot(null); (new StorePatchInSlotWorker((NmSlot)s.getSlot(), patch)).store(); } catch (IOException e) { dtde.rejectDrop(); } catch (UnsupportedFlavorException e) { dtde.rejectDrop(); } } protected boolean acceptsDropData(SlotObject<NordModular> s, DataFlavor[] flavors) { for (int i=0;i<flavors.length;i++) if (JTNMPatch.nmPatchFlavor.equals(flavors[i])) return true; return false; } /* protected EventHandler createEventHandler() { return new NMEventHandler(this); } public JPopupMenu getSlotPopup(SlotLeaf leaf) { JPopupMenu menu = new JPopupMenu(); menu.add(new SlotAction(leaf, SlotAction.OPEN_PATCH)); menu.add(new SlotAction(leaf, SlotAction.NEW_PATCH)); menu.addSeparator(); menu.add(new SlotAction(leaf, SlotAction.ENABLE_DISABLE_SLOT)); menu.add(new SlotAction(leaf, SlotAction.SELECT_SLOT)); return menu; } */ private static class SlotAction extends AbstractAction { /** * */ private static final long serialVersionUID = -8238875184398804108L; public static final String OPEN_PATCH = "open.patch"; public static final String NEW_PATCH = "new.patch"; public static final String ENABLE_DISABLE_SLOT = "EnableDisable"; public static final String SELECT_SLOT = "select"; //private SlotLeaf leaf; private NmSlot slot; public SlotAction(SlotObject leaf, String command) { //this.leaf = leaf; this.slot = (NmSlot) leaf.getSlot(); putValue(ACTION_COMMAND_KEY, command); if (command == OPEN_PATCH) { putValue(NAME, "Open Patch"); } else if (command == NEW_PATCH) { putValue(NAME, "New Patch"); setEnabled(false); } else if (command == ENABLE_DISABLE_SLOT) { putValue(NAME, slot.isEnabled() ? "Disable Slot" : "Enable Slot"); } else if (command == SELECT_SLOT) { putValue(NAME, "Select"); setEnabled(slot.isEnabled()); } } public void actionPerformed(ActionEvent e) { if (!isEnabled()) return; String cmd = e.getActionCommand(); if (cmd == OPEN_PATCH) { try { slot.createRequestPatchWorker().requestPatch(); } catch (SynthException e1) { e1.printStackTrace(); } } else if (cmd == NEW_PATCH); else if (cmd == ENABLE_DISABLE_SLOT) slot.setEnabled(!slot.isEnabled()); else if (cmd == SELECT_SLOT) slot.setSelected(true); } } private static class PatchOpener implements SlotManagerListener, SlotListener { private NordModular synth; private PatchOpener(NordModular synth) { this.synth = synth; } public void install() { synth.getSlotManager().addSlotManagerListener(this); for (int i=0;i<synth.getSlotCount();i++) { installSlot(synth.getSlot(i)); } } public void slotAdded(SlotEvent e) { installSlot((NmSlot) e.getSlot()); } public void slotRemoved(SlotEvent e) { uninstallSlot((NmSlot) e.getSlot()); } public void installSlot(NmSlot slot) { slot.addSlotListener(this); } public void uninstallSlot(NmSlot slot) { slot.removeSlotListener(this); } public void newPatchInSlot(SlotEvent e) { //NMPatch oldpatch = (NMPatch) e.getOldPatch(); final NMPatch newpatch = (NMPatch) e.getNewPatch(); if (newpatch == null) return; Runnable run = new Runnable() { public void run() { NmFileService.selectOrOpen(newpatch); } }; run = WorkIndicator.create(Nomad.sharedInstance().getWindow(), run); SwingUtilities.invokeLater(run); } } protected void addForms(final SynthPropertiesDialog<NordModular> spd) { super.addForms(spd); DialogPane<NordModular> dp = new SSF(getSynthesizer()); dp.install(spd); } protected static class SSF extends DialogPane<NordModular> implements PropertyChangeListener, ChangeListener, SynthesizerStateListener { private SynthSettingsFrm frm; public SSF(NordModular synth) { super(synth, "synthsettings", "Settings"); } public void dispose() { super.dispose(); synth.removePropertyChangeListener(this); synth.removeSynthesizerStateListener(this); } private SynthSettingsFrm getForm(boolean create) { if (frm == null && create) { frm = new SynthSettingsFrm(); setFormControlOptions(); updateForm(); synth.addPropertyChangeListener(this); synth.addSynthesizerStateListener(this); installFormListeners(); updateFormEnabledState(); } return frm; } private SpinnerNumberModel numberModel(int min, int max, int value) { return new SpinnerNumberModel(value, min, max, 1); } private void setFormControlOptions() { // change listener frm.spMIDIClockRate.setModel(numberModel(31, 239, 120)); frm.spMIDIVelScaleMin.setModel(numberModel(0, 127, 0)); frm.spMIDIVelScaleMax.setModel(numberModel(0, 127, 127)); frm.spGlobalSyncBeats.setModel(numberModel(1, 32, 4)); frm.spMasterTune.setModel(numberModel(-127, 127, 0)); frm.spChannelSlotA.setModel(numberModel(1, 16, 1)); frm.spChannelSlotB.setModel(numberModel(1, 16, 2)); frm.spChannelSlotC.setModel(numberModel(1, 16, 3)); frm.spChannelSlotD.setModel(numberModel(1, 16, 4)); } private void installFormListeners() { // action listener frm.jtSynthName.addActionListener(this); frm.cbLEDsActive.addActionListener(this); frm.cbLocalOff.addActionListener(this); frm.cbProgramChangeReceive.addActionListener(this); frm.cbProgramChangeSend.addActionListener(this); frm.rbKBModeSelectedSlots.addActionListener(this); frm.rbKBModeActiveSlot.addActionListener(this); frm.rbKnobModeHook.addActionListener(this); frm.rbKnobModeImmediate.addActionListener(this); frm.rbMIDIClockInternal.addActionListener(this); frm.rbMIDIClockExternal.addActionListener(this); frm.rbPedalPolarityInverted.addActionListener(this); frm.rbPedalPolarityNormal.addActionListener(this); // change listener frm.spMIDIClockRate.addChangeListener(this); frm.spMIDIVelScaleMin.addChangeListener(this); frm.spMIDIVelScaleMax.addChangeListener(this); frm.spGlobalSyncBeats.addChangeListener(this); frm.spMasterTune.addChangeListener(this); frm.spActiveSlotA.addChangeListener(this); frm.spActiveSlotB.addChangeListener(this); frm.spActiveSlotC.addChangeListener(this); frm.spActiveSlotD.addChangeListener(this); frm.spChannelSlotA.addChangeListener(this); frm.spChannelSlotB.addChangeListener(this); frm.spChannelSlotC.addChangeListener(this); frm.spChannelSlotD.addChangeListener(this); } public void actionPerformed(ActionEvent e) { if (frm == null) { // forward event to super class super.actionPerformed(e); return ; } Object src = e.getSource(); if (src == frm.jtSynthName) { String text = frm.jtSynthName.getText(); if (text == null) text = ""; if (text.length()>16) { frm.jtSynthName.setText(text.substring(0, 16)); return; } synth.setName(text); synth.syncSettings(); } else if (src==frm.cbLEDsActive) { synth.setLEDsActive(frm.cbLEDsActive.isSelected()); } else if (src==frm.cbLocalOff) { synth.setLocalOn(!frm.cbLocalOff.isSelected()); } else if (src==frm.cbProgramChangeReceive) { synth.setProgramChangeReceive(frm.cbProgramChangeReceive.isSelected()); } else if (src==frm.cbProgramChangeSend) { synth.setProgramChangeSend(frm.cbProgramChangeSend.isSelected()); } else if (src==frm.rbKBModeSelectedSlots||src==frm.rbKBModeActiveSlot) { boolean selectedSlots = frm.rbKBModeSelectedSlots.isSelected(); boolean activeSlot = frm.rbKBModeActiveSlot.isSelected(); if (selectedSlots == activeSlot) { // intermediate state, another event will occure immediatelly return; } synth.setKeyboardMode(selectedSlots); } else if (src==frm.rbKnobModeHook||src==frm.rbKnobModeImmediate) { boolean hook = frm.rbKnobModeHook.isSelected(); boolean immediate = frm.rbKnobModeImmediate.isSelected(); if (hook == immediate) { // intermediate state, another event will occure immediatelly return; } synth.setKnobMode(hook); } else if (src==frm.rbMIDIClockInternal||src==frm.rbMIDIClockExternal) { boolean intern = frm.rbMIDIClockInternal.isSelected(); boolean extern = frm.rbMIDIClockExternal.isSelected(); if (intern == extern) { // intermediate state, another event will occure immediatelly return; } synth.setMidiClockSource(intern); } else if (src==frm.rbPedalPolarityInverted||src==frm.rbPedalPolarityNormal) { boolean inverted = frm.rbPedalPolarityInverted.isSelected(); boolean normal = frm.rbPedalPolarityNormal.isSelected(); if (inverted == normal) { // intermediate state, another event will occure immediatelly return; } synth.setPedalPolarity(inverted); } else { // forward event to super class super.actionPerformed(e); } synth.syncSettings(); } private int val(JSpinner spinner) { return ((Integer)(spinner.getValue())).intValue(); } private boolean slotExists(int index) { return index>=0 && index<synth.getSlotCount(); } public void stateChanged(ChangeEvent e) { if (frm == null) return ; Object src = e.getSource(); if (src==frm.spMIDIClockRate) { synth.setMidiClockBPM(val(frm.spMIDIClockRate)); } else if (src==frm.spMIDIVelScaleMin) { synth.setMidiVelScaleMin(val(frm.spMIDIVelScaleMin)); } else if (src==frm.spMIDIVelScaleMax) { synth.setMidiVelScaleMax(val(frm.spMIDIVelScaleMax)); } else if (src==frm.spGlobalSyncBeats) { synth.setGlobalSync(val(frm.spGlobalSyncBeats)-1); } else if (src==frm.spMasterTune) { synth.setMasterTune(val(frm.spMasterTune)); } else if (src==frm.spActiveSlotA || src == frm.spChannelSlotA) { if (slotExists(0)) { boolean selected = frm.spActiveSlotA.isSelected(); frm.spChannelSlotA.setEnabled(selected); if (frm.spChannelSlotA==src&&(!selected)) return; int number = val(frm.spChannelSlotA)-1; synth.setMidiChannel(0, selected ? number : 16); } } else if (src==frm.spActiveSlotB || src == frm.spChannelSlotB) { if (slotExists(1)) { boolean selected = frm.spActiveSlotB.isSelected(); frm.spChannelSlotB.setEnabled(selected); if (frm.spChannelSlotB==src&&(!selected)) return; int number = val(frm.spChannelSlotB)-1; synth.setMidiChannel(1, selected ? number : 16); } } else if (src==frm.spActiveSlotC || src == frm.spChannelSlotC) { if (slotExists(2)) { boolean selected = frm.spActiveSlotC.isSelected(); frm.spChannelSlotC.setEnabled(selected); if (frm.spChannelSlotC==src&&(!selected)) return; int number = val(frm.spChannelSlotC)-1; synth.setMidiChannel(2, selected ? number : 16); } } else if (src==frm.spActiveSlotD || src == frm.spChannelSlotD) { if (slotExists(3)) { boolean selected = frm.spActiveSlotD.isSelected(); frm.spChannelSlotD.setEnabled(selected); if (frm.spChannelSlotD==src&&(!selected)) return; int number = val(frm.spChannelSlotD)-1; synth.setMidiChannel(3, selected ? number : 16); } } synth.syncSettings(); } public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if ("settings".equals(name)) { // settings changed at synth updateForm(); return; } } private void updateForm() { frm.jtSynthName.setText(synth.getName()); frm.cbLEDsActive.setSelected(synth.isLEDsActive()); frm.cbLocalOff.setSelected(!synth.isLocalOn()); frm.cbProgramChangeReceive.setSelected(synth.getProgramChangeReceive()); frm.cbProgramChangeSend.setSelected(synth.getProgramChangeSend()); frm.rbKBModeSelectedSlots.setSelected(synth.getKeyboardMode()); frm.rbKBModeActiveSlot.setSelected(!synth.getKeyboardMode()); frm.rbKnobModeHook.setSelected(synth.getKnobMode()); frm.rbKnobModeImmediate.setSelected(!synth.getKnobMode()); frm.rbMIDIClockInternal.setSelected(synth.getMidiClockSource()); frm.rbMIDIClockExternal.setSelected(!synth.getMidiClockSource()); frm.rbPedalPolarityInverted.setSelected(synth.getPedalPolarity()); frm.rbPedalPolarityNormal.setSelected(!synth.getPedalPolarity()); frm.spMIDIClockRate.setValue(synth.getMidiClockBPM()); frm.spMIDIVelScaleMin.setValue(synth.getMidiVelScaleMin()); frm.spMIDIVelScaleMax.setValue(synth.getMidiVelScaleMax()); frm.spGlobalSyncBeats.setValue(1+synth.getGlobalSync()); frm.spMasterTune.setValue(synth.getMasterTune()); JCheckBox[] active = {frm.spActiveSlotA, frm.spActiveSlotB, frm.spActiveSlotC, frm.spActiveSlotD}; JSpinner[] chan = {frm.spChannelSlotA, frm.spChannelSlotB, frm.spChannelSlotC, frm.spChannelSlotD}; for (int i=0;i<4;i++) { boolean slotExists = i<synth.getSlotCount(); if (!slotExists) { active[i].setEnabled(false); chan[i].setEnabled(false); } else { int channel = 1+synth.getMidiChannel(i); boolean validChannel = channel <= 16; chan[i].setEnabled(validChannel); active[i].setEnabled(true); if (active[i].isSelected()!=validChannel) active[i].setSelected(validChannel); if (validChannel) chan[i].setValue(channel); } } } @Override protected JComponent createDialogComponent() { JComponent frm = getForm(true); JScrollPane sc = new JScrollPane(frm); sc.setBorder(null); return sc; } public void synthConnectionStateChanged(SynthesizerEvent e) { updateFormEnabledState(); } public void updateFormEnabledState() { if (frm == null) return ; boolean enabled = synth.isConnected(); frm.setEnabled(enabled); frm.cbLEDsActive.setEnabled(enabled); frm.cbLocalOff.setEnabled(enabled); frm.cbProgramChangeReceive.setEnabled(enabled); frm.cbProgramChangeSend.setEnabled(enabled); frm.rbKBModeActiveSlot.setEnabled(enabled); frm.rbKBModeSelectedSlots.setEnabled(enabled); frm.rbKnobModeHook.setEnabled(enabled); frm.rbKnobModeImmediate.setEnabled(enabled); frm.rbMIDIClockExternal.setEnabled(enabled); frm.rbMIDIClockInternal.setEnabled(enabled); frm.rbPedalPolarityInverted.setEnabled(enabled); frm.rbPedalPolarityNormal.setEnabled(enabled); frm.jtSynthName.setEnabled(enabled); frm.spActiveSlotA.setEnabled(enabled); frm.spActiveSlotB.setEnabled(enabled); frm.spActiveSlotC.setEnabled(enabled); frm.spActiveSlotD.setEnabled(enabled); frm.spChannelSlotA.setEnabled(enabled); frm.spChannelSlotB.setEnabled(enabled); frm.spChannelSlotC.setEnabled(enabled); frm.spChannelSlotD.setEnabled(enabled); frm.spGlobalSyncBeats.setEnabled(enabled); frm.spMasterTune.setEnabled(enabled); frm.spMIDIClockRate.setEnabled(enabled); frm.spMIDIVelScaleMax.setEnabled(enabled); frm.spMIDIVelScaleMin.setEnabled(enabled); } } /* private boolean showSettings2() { NordModular synth = getSynthesizer(); MidiPlug inPlug = synth.getPCInPort().getPlug(); MidiDevice.Info in = inPlug != null ? inPlug.getDeviceInfo() : null; MidiPlug outPlug = synth.getPCOutPort().getPlug(); MidiDevice.Info out = outPlug != null ? outPlug.getDeviceInfo() : null; NomadMidiDialog dialog = new NomadMidiDialog(Nomad.sharedInstance().getWindow(), "MIDI"); NomadMidiDialogFrmHandler form = dialog.getForm(); form.setPreviousInput(in); form.setPreviousOutput(out); dialog.setModal(true); if (dialog.showDialog() == NomadMidiDialog.APPROVE_OPTION) { in = form.getSelectedInput(); out = form.getSelectedOutput(); if (in == null || out == null) return false; try { synth.getPCInPort().setPlug(new MidiPlug(in)); synth.getPCOutPort().setPlug(new MidiPlug(out)); } catch (SynthException e) { // TODO Auto-generated catch block return false; } return true; } return false; }*/ protected void processEvent(Event event, Slot slot) { NmSlot nmslot = (NmSlot) slot; NMPatch patch = nmslot.getPatch(); if (patch==null) { RequestPatchWorker worker = slot.createRequestPatchWorker(); try { worker.requestPatch(); } catch (SynthException e) { e.printStackTrace(); } } else { NmFileService.selectOrOpen(patch); } } }