/[svn]/jsampler/trunk/src/org/jsampler/view/classic/Channel.java
ViewVC logotype

Contents of /jsampler/trunk/src/org/jsampler/view/classic/Channel.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1341 - (show annotations) (download)
Mon Sep 10 22:29:09 2007 UTC (16 years, 7 months ago) by iliev
File size: 45966 byte(s)
* Fantasia: Added button to the channel screen for starting an instrument
  editor (point the mouse cursor over the channel screen and click 'Edit')

1 /*
2 * JSampler - a java front-end for LinuxSampler
3 *
4 * Copyright (C) 2005-2007 Grigor Iliev <grigor@grigoriliev.com>
5 *
6 * This file is part of JSampler.
7 *
8 * JSampler is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * JSampler is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with JSampler; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23 package org.jsampler.view.classic;
24
25 import java.awt.BorderLayout;
26 import java.awt.Color;
27 import java.awt.Cursor;
28 import java.awt.Dimension;
29 import java.awt.GridBagConstraints;
30 import java.awt.GridBagLayout;
31 import java.awt.Insets;
32
33 import java.awt.datatransfer.Transferable;
34
35 import java.awt.event.ActionEvent;
36 import java.awt.event.ActionListener;
37 import java.awt.event.HierarchyEvent;
38 import java.awt.event.HierarchyListener;
39 import java.awt.event.MouseAdapter;
40 import java.awt.event.MouseEvent;
41 import java.awt.event.MouseMotionAdapter;
42
43 import java.beans.PropertyChangeEvent;
44 import java.beans.PropertyChangeListener;
45
46 import java.net.URL;
47
48 import java.util.Vector;
49
50 import java.util.logging.Level;
51
52 import javax.swing.Action;
53 import javax.swing.AbstractAction;
54 import javax.swing.BorderFactory;
55 import javax.swing.Box;
56 import javax.swing.BoxLayout;
57 import javax.swing.JComponent;
58 import javax.swing.ImageIcon;
59 import javax.swing.JButton;
60 import javax.swing.JComboBox;
61 import javax.swing.JLabel;
62 import javax.swing.JPanel;
63 import javax.swing.JSeparator;
64 import javax.swing.JSlider;
65 import javax.swing.JToggleButton;
66 import javax.swing.JToolBar;
67 import javax.swing.TransferHandler;
68
69 import javax.swing.border.Border;
70 import javax.swing.border.LineBorder;
71 import javax.swing.border.TitledBorder;
72
73 import javax.swing.event.ChangeEvent;
74 import javax.swing.event.ChangeListener;
75
76 import net.sf.juife.InformationDialog;
77 import net.sf.juife.JuifeUtils;
78
79 import org.jsampler.AudioDeviceModel;
80 import org.jsampler.CC;
81 import org.jsampler.HF;
82 import org.jsampler.Instrument;
83 import org.jsampler.MidiDeviceModel;
84 import org.jsampler.MidiInstrumentMap;
85 import org.jsampler.SamplerChannelModel;
86 import org.jsampler.SamplerModel;
87
88 import org.jsampler.event.ListEvent;
89 import org.jsampler.event.ListListener;
90 import org.jsampler.event.MidiDeviceEvent;
91 import org.jsampler.event.MidiDeviceListEvent;
92 import org.jsampler.event.MidiDeviceListListener;
93 import org.jsampler.event.MidiDeviceListener;
94 import org.jsampler.event.SamplerAdapter;
95 import org.jsampler.event.SamplerChannelAdapter;
96 import org.jsampler.event.SamplerChannelEvent;
97 import org.jsampler.event.SamplerChannelListEvent;
98 import org.jsampler.event.SamplerChannelListListener;
99 import org.jsampler.event.SamplerChannelListener;
100 import org.jsampler.event.SamplerEvent;
101 import org.jsampler.event.SamplerListener;
102
103 import org.jsampler.view.std.JSChannelOutputRoutingDlg;
104 import org.jsampler.view.std.JSFxSendsPane;
105 import org.jsampler.view.std.JSInstrumentChooser;
106
107 import org.linuxsampler.lscp.AudioOutputDevice;
108 import org.linuxsampler.lscp.MidiInputDevice;
109 import org.linuxsampler.lscp.MidiPort;
110 import org.linuxsampler.lscp.SamplerChannel;
111 import org.linuxsampler.lscp.SamplerEngine;
112
113 import static org.jsampler.view.classic.ClassicI18n.i18n;
114
115
116 /**
117 *
118 * @author Grigor Iliev
119 */
120 public class Channel extends org.jsampler.view.JSChannel {
121 private final static ImageIcon iconMuteOn;
122 private final static ImageIcon iconMuteOff;
123 private final static ImageIcon iconMutedBySolo;
124
125 private final static ImageIcon iconSoloOn;
126 private final static ImageIcon iconSoloOff;
127
128 private final static ImageIcon iconShowProperties;
129 private final static ImageIcon iconHideProperties;
130
131 private static Border borderSelected;
132 private static Border borderHighlighted;
133 private static Border borderDeselected;
134
135 private static Color chnColor;
136 private static Color borderColor;
137 private static Color borderHighlightedColor;
138 private static Color chnSelectedColor;
139 private static Color chnHighlightedColor;
140
141 private final static Vector<PropertyChangeListener> propertyChangeListeners
142 = new Vector<PropertyChangeListener>();
143
144 static {
145 String path = "org/jsampler/view/classic/res/icons/";
146 URL url = ClassLoader.getSystemClassLoader().getResource(path + "mute_on.png");
147 iconMuteOn = new ImageIcon(url);
148
149 url = ClassLoader.getSystemClassLoader().getResource(path + "mute_off.png");
150 iconMuteOff = new ImageIcon(url);
151
152 url = ClassLoader.getSystemClassLoader().getResource(path + "muted_by_solo.png");
153 iconMutedBySolo = new ImageIcon(url);
154
155 url = ClassLoader.getSystemClassLoader().getResource(path + "solo_on.png");
156 iconSoloOn = new ImageIcon(url);
157
158 url = ClassLoader.getSystemClassLoader().getResource(path + "solo_off.png");
159 iconSoloOff = new ImageIcon(url);
160
161 url = ClassLoader.getSystemClassLoader().getResource(path + "Back16.gif");
162 iconShowProperties = new ImageIcon(url);
163
164 iconHideProperties = Res.iconDown16;
165
166 if(ClassicPrefs.getCustomChannelBorderColor())
167 setBorderColor(ClassicPrefs.getChannelBorderColor());
168 else setBorderColor(ClassicPrefs.getDefaultChannelBorderColor());
169
170 if(ClassicPrefs.getCustomChannelBorderHlColor())
171 setBorderHighlightedColor(ClassicPrefs.getChannelBorderHlColor());
172 else setBorderHighlightedColor(ClassicPrefs.getDefaultChannelBorderHlColor());
173
174 borderSelected = new LineBorder(getBorderColor(), 2, true);
175 borderHighlighted = new LineBorder(getBorderHighlightedColor(), 2, true);
176 borderDeselected = BorderFactory.createEmptyBorder(2, 2, 2, 2);
177
178 chnColor = new JPanel().getBackground();
179
180 if(ClassicPrefs.getCustomSelectedChannelBgColor()) {
181 chnSelectedColor = ClassicPrefs.getSelectedChannelBgColor();
182 } else {
183 int r = chnColor.getRed() - 14 < 0 ? 0 : chnColor.getRed() - 14;
184 int g = chnColor.getGreen() - 8 < 0 ? 0 : chnColor.getGreen() - 8;
185 int b = chnColor.getBlue() - 3 < 0 ? 0 : chnColor.getBlue() - 3;
186
187 chnSelectedColor = new Color(r, g, b);
188 }
189
190 /*r = r + 5 > 255 ? 255 : r + 5;
191 g = g + 4 > 255 ? 255 : g + 4;
192 b = b + 1 > 255 ? 255 : b + 1;*/
193
194 chnHighlightedColor = new Color(chnColor.getRGB());
195 }
196
197 /**
198 * Registers the specified listener for receiving property change events.
199 * @param l The <code>PropertyChangeListener</code> to register.
200 */
201 public void
202 addPropertyChangeListener(PropertyChangeListener l) {
203 propertyChangeListeners.add(l);
204 }
205
206 /**
207 * Removes the specified listener.
208 * @param l The <code>PropertyChangeListener</code> to remove.
209 */
210 public void
211 removePropertyChangeListener(PropertyChangeListener l) {
212 propertyChangeListeners.remove(l);
213 }
214
215 /**
216 * Gets the border color that is used when the channel is selected.
217 * @return The border color that is used when the channel is selected.
218 */
219 public static Color
220 getBorderColor() { return borderColor; }
221
222 /**
223 * Sets the border color to be used when the channel is selected.
224 * @param c The border color to be used when the channel is selected.
225 */
226 public static void
227 setBorderColor(Color c) {
228 if(borderColor != null && borderColor.getRGB() == c.getRGB()) return;
229
230 Color oldColor = borderColor;
231 borderColor = c;
232 borderSelected = new LineBorder(getBorderColor(), 2, true);
233 firePropertyChanged("borderColor", oldColor, borderColor);
234 }
235
236 /**
237 * Gets the border color that is used when the mouse pointer is over a channel.
238 * @return The border color that is used when the mouse pointer is over a channel.
239 */
240 public static Color
241 getBorderHighlightedColor() { return borderHighlightedColor; }
242
243 /**
244 * Sets the border color to be used when the mouse pointer is over a channel.
245 * @param c The border color to be used when the mouse pointer is over a channel.
246 */
247 public static void
248 setBorderHighlightedColor(Color c) {
249 Color oldColor = borderHighlightedColor;
250 if(oldColor != null && oldColor.getRGB() == c.getRGB()) return;
251
252 borderHighlightedColor = c;
253 borderHighlighted = new LineBorder(getBorderHighlightedColor(), 2, true);
254 firePropertyChanged("borderHighlightedColor", oldColor, borderHighlightedColor);
255 }
256
257 /**
258 * Gets the background color that is used when a channel is selected.
259 * @return The background color that is used when a channel is selected.
260 */
261 public static Color
262 getSelectedChannelBgColor() { return chnSelectedColor; }
263
264 /**
265 * Sets the background color that is used when a channel is selected.
266 * @param c The background color to be used when a channel is selected.
267 */
268 public static void
269 setSelectedChannelBgColor(Color c) {
270 Color oldColor = chnSelectedColor;
271 if(oldColor != null && oldColor.getRGB() == c.getRGB()) return;
272
273 chnSelectedColor = c;
274 firePropertyChanged("selectedChannelBgColor", oldColor, chnSelectedColor);
275 }
276
277 /**
278 * Gets the background color that is used when the mouse pointer is over a channel.
279 * @return The background color that is used when the mouse pointer is over a channel.
280 */
281 public static Color
282 getHighlightedChannelBgColor() { return chnHighlightedColor; }
283
284 /**
285 * Sets the background color to be used when the mouse pointer is over a channel.
286 * @param c The background color to be used when the mouse pointer is over a channel.
287 */
288 public static void
289 setHighlightedChannelBgColor(Color c) {
290 Color oldColor = chnHighlightedColor;
291 if(oldColor != null && oldColor.getRGB() == c.getRGB()) return;
292
293 chnHighlightedColor = c;
294 firePropertyChanged("highlightedChannelBgColor", oldColor, chnHighlightedColor);
295 }
296
297 private static void
298 firePropertyChanged(String propertyName, Object oldValue, Object newValue) {
299 PropertyChangeEvent e =
300 new PropertyChangeEvent(Channel.class, propertyName, oldValue, newValue);
301
302 for(PropertyChangeListener l : propertyChangeListeners) l.propertyChange(e);
303 }
304
305
306 private final JPanel mainPane = new JPanel();
307 private final ChannelProperties propertiesPane;
308 private final JButton btnInstr = new InstrumentButton(i18n.getLabel("Channel.btnInstr"));
309 private final Action actInstr;
310 private final JButton btnMute = new JButton();
311 private final JButton btnSolo = new JButton();
312 private final JSlider slVolume = new JSlider(0, 100);
313 private final JLabel lVolume = new JLabel();
314 private final JLabel lVolImg = new JLabel(Res.iconVolume16);
315 private final JLabel lStreams = new JLabel("--");
316 private final JLabel lVoices = new JLabel("--");
317 private final JToggleButton btnProperties = new JToggleButton();
318
319 private static int count = 2;
320
321 private boolean selected = false;
322 private boolean mouseOver = false;
323
324
325 /**
326 * Creates a new instance of <code>Channel</code> using the specified
327 * non-<code>null</code> channel model.
328 * @param model The model to be used by this channel.
329 * @throws IllegalArgumentException If the model is <code>null</code>.
330 */
331 public
332 Channel(SamplerChannelModel model) {
333 super(model);
334
335 setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
336
337 mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS));
338 addMouseListener(getHandler());
339 addHierarchyListener(getHandler());
340
341 JPanel p = new JPanel();
342 p.setOpaque(false);
343 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
344 p.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
345
346 setToolTipText(i18n.getLabel("Channel.tt", getModel().getChannelId()));
347
348 Dimension d = btnInstr.getPreferredSize();
349 btnInstr.setMaximumSize(new Dimension(Short.MAX_VALUE, d.height));
350 p.add(btnInstr);
351 p.add(Box.createRigidArea(new Dimension(6, 0)));
352
353 lStreams.setHorizontalAlignment(JLabel.CENTER);
354 lVoices.setHorizontalAlignment(JLabel.CENTER);
355
356 JPanel statPane = new JPanel();
357 statPane.setOpaque(false);
358 statPane.setBorder(BorderFactory.createLoweredBevelBorder());
359 statPane.setLayout(new BoxLayout(statPane, BoxLayout.X_AXIS));
360 statPane.add(Box.createRigidArea(new Dimension(6, 0)));
361 statPane.add(lStreams);
362 statPane.add(new JLabel("/"));
363 statPane.add(lVoices);
364 statPane.add(Box.createRigidArea(new Dimension(6, 0)));
365
366 p.add(statPane);
367
368 p.add(Box.createRigidArea(new Dimension(6, 0)));
369
370 btnMute.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
371 p.add(btnMute);
372 p.add(Box.createRigidArea(new Dimension(6, 0)));
373
374 btnSolo.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
375 p.add(btnSolo);
376 p.add(Box.createRigidArea(new Dimension(6, 0)));
377
378 JPanel volumePane = new JPanel();
379 volumePane.setOpaque(false);
380 volumePane.setBorder(BorderFactory.createLoweredBevelBorder());
381 volumePane.setLayout(new BoxLayout(volumePane, BoxLayout.X_AXIS));
382 volumePane.add(Box.createRigidArea(new Dimension(6, 0)));
383
384 volumePane.add(lVolImg);
385 volumePane.add(Box.createRigidArea(new Dimension(1, 0)));
386
387 d = slVolume.getPreferredSize();
388 slVolume.setMaximumSize(new Dimension(d.width > 300 ? d.width : 300, d.height));
389 slVolume.setOpaque(false);
390 volumePane.add(slVolume);
391
392 lVolume.setBorder(BorderFactory.createEmptyBorder(3, 6, 3, 6));
393 lVolume.setHorizontalAlignment(lVolume.RIGHT);
394
395 // We use this to set the size of the lVolume that will be used in setVolume()
396 // to prevent the frequent resizing of lVolume
397 lVolume.setText("100%");
398
399 volumePane.add(lVolume);
400
401 p.add(volumePane);
402 p.add(Box.createRigidArea(new Dimension(6, 0)));
403
404 btnProperties.setContentAreaFilled(false);
405 btnProperties.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
406 btnProperties.setIcon(iconShowProperties);
407 btnProperties.setSelectedIcon(iconHideProperties);
408 p.add(btnProperties);
409
410 mainPane.add(p);
411
412 propertiesPane = new ChannelProperties(model);
413 propertiesPane.setBorder(BorderFactory.createEmptyBorder(0, 3, 3, 3));
414 propertiesPane.setVisible(false);
415 mainPane.add(propertiesPane);
416 add(mainPane);
417
418 d = getPreferredSize();
419 setMaximumSize(new Dimension(getMaximumSize().width, d.height));
420
421 getModel().addSamplerChannelListener(getHandler());
422
423 actInstr = new AbstractAction() {
424 public void
425 actionPerformed(ActionEvent e) {
426 if(actInstr.isEnabled()) loadInstrument();
427 }
428 };
429
430 btnInstr.addActionListener(actInstr);
431
432 btnMute.addActionListener(new ActionListener() {
433 public void
434 actionPerformed(ActionEvent e) { changeMute(); }
435 });
436
437 btnSolo.addActionListener(new ActionListener() {
438 public void
439 actionPerformed(ActionEvent e) { changeSolo(); }
440 });
441
442 slVolume.addChangeListener(new ChangeListener() {
443 public void
444 stateChanged(ChangeEvent e) { setVolume(); }
445 });
446
447 btnProperties.addActionListener(new ActionListener() {
448 public void
449 actionPerformed(ActionEvent e) {
450 showProperties(btnProperties.isSelected());
451
452 String s;
453 if(btnProperties.isSelected()) {
454 s = i18n.getButtonLabel("Channel.ttHideProps");
455 } else {
456 s = i18n.getButtonLabel("Channel.ttShowProps");
457 }
458
459 btnProperties.setToolTipText(s);
460 }
461 });
462
463 btnProperties.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
464
465 String s;
466 if(btnProperties.isSelected()) s = i18n.getButtonLabel("Channel.ttHideProps");
467 else s = i18n.getButtonLabel("Channel.ttShowProps");
468
469 btnProperties.setToolTipText(s);
470
471 addPropertyChangeListener(getHandler());
472
473 updateChannelInfo();
474 }
475
476 public class InstrumentButton extends JButton {
477 private boolean dragging = false;
478
479 InstrumentButton(String s) {
480 super(s);
481
482 setTransferHandler(new TransferHandler("instrument"));
483
484 addMouseListener(new MouseAdapter() {
485 public void
486 mouseExited(MouseEvent e) {
487 if(!dragging) return;
488
489 int b1 = e.BUTTON1_DOWN_MASK;
490 if((e.getModifiersEx() & b1) != b1) return;
491
492 actInstr.setEnabled(false);
493 doClick(0);
494 actInstr.setEnabled(true);
495
496 JComponent c = (JComponent)e.getSource();
497 TransferHandler handler = c.getTransferHandler();
498 handler.exportAsDrag(c, e, TransferHandler.COPY);
499 }
500
501 public void
502 mouseReleased(MouseEvent e) { dragging = false; }
503 });
504
505 addMouseMotionListener(new MouseMotionAdapter() {
506 public void
507 mouseDragged(MouseEvent e) { dragging = true; }
508 });
509 }
510
511 public String
512 getInstrument() {
513 SamplerChannel sc = Channel.this.getChannelInfo();
514
515 if(sc.getInstrumentName() == null || sc.getInstrumentStatus() < 0)
516 return null;
517
518 Instrument instr = new Instrument();
519 instr.setName(sc.getInstrumentName());
520 instr.setInstrumentIndex(sc.getInstrumentIndex());
521 instr.setPath(sc.getInstrumentFile());
522 return instr.getDnDString();
523 }
524
525 public void setInstrument(String instr) {
526 if(!Instrument.isDnDString(instr)) return;
527
528 String[] args = instr.split("\n");
529 if(args.length < 6) return;
530
531 try {
532 int idx = Integer.parseInt(args[5]);
533 Channel.this.getModel().loadBackendInstrument(args[4], idx);
534 } catch(Exception x) {
535 CC.getLogger().log(Level.INFO, HF.getErrorMessage(x), x);
536 }
537 }
538 }
539
540 private final EventHandler eventHandler = new EventHandler();
541
542 private EventHandler
543 getHandler() { return eventHandler; }
544
545 private class EventHandler extends MouseAdapter implements SamplerChannelListener,
546 PropertyChangeListener, HierarchyListener {
547 /**
548 * Invoked when changes are made to a sampler channel.
549 * @param e A <code>SamplerChannelEvent</code> instance
550 * containing event information.
551 */
552 public void
553 channelChanged(SamplerChannelEvent e) { updateChannelInfo(); }
554
555 /**
556 * Invoked when the number of active disk streams has changed.
557 * @param e A <code>SamplerChannelEvent</code> instance
558 * containing event information.
559 */
560 public void
561 streamCountChanged(SamplerChannelEvent e) {
562 updateStreamCount(getModel().getStreamCount());
563 }
564
565 /**
566 * Invoked when the number of active voices has changed.
567 * @param e A <code>SamplerChannelEvent</code> instance
568 * containing event information.
569 */
570 public void
571 voiceCountChanged(SamplerChannelEvent e) {
572 updateVoiceCount(getModel().getVoiceCount());
573 }
574
575 public void
576 propertyChange(PropertyChangeEvent e) {
577 if (
578 e.getPropertyName() == "borderColor" ||
579 e.getPropertyName() == "borderHighlightedColor" ||
580 e.getPropertyName() == "selectedChannelBgColor" ||
581 e.getPropertyName() == "highlightedChannelBgColor"
582 ) {
583 updateColors(isSelected());
584 }
585 }
586
587 public void
588 mouseEntered(MouseEvent e) {
589 mouseOver = true;
590 updateColors(isSelected());
591 }
592
593 public void
594 mouseExited(MouseEvent e) {
595 if(getMousePosition(true) != null) return;
596
597 mouseOver = false;
598 updateColors(isSelected());
599 }
600
601
602
603 /** Called when the hierarchy has been changed. */
604 public void
605 hierarchyChanged(HierarchyEvent e) {
606 if((e.getChangeFlags() & e.SHOWING_CHANGED) == e.SHOWING_CHANGED) {
607 if(getMousePosition() == null) mouseExited(null);
608 else mouseEntered(null);
609 }
610 }
611 }
612
613 /**
614 * Determines whether the channel is selected.
615 * @return <code>true</code> if the channel is selected, <code>false</code> otherwise.
616 */
617 public boolean isSelected() { return selected; }
618
619 /**
620 * Sets the selection state of this channel.
621 * This method is invoked when the selection state of the channel has changed.
622 * @param select Specifies the new selection state of this channel;
623 * <code>true</code> to select the channel, <code>false</code> otherwise.
624 */
625 public void
626 setSelected(boolean select) {
627 updateColors(select);
628
629 selected = select;
630 }
631
632 /**
633 * Updates the channel background and border colors.
634 * @param selected Specifies the selection state of this channel.
635 */
636 private void
637 updateColors(boolean selected) {
638 if(selected) {
639 mainPane.setBorder(borderSelected);
640 mainPane.setBackground(chnSelectedColor);
641 } else {
642 if(mouseOver) {
643 mainPane.setBorder(borderHighlighted);
644 mainPane.setBackground(chnHighlightedColor);
645 } else {
646 mainPane.setBorder(borderDeselected);
647 mainPane.setBackground(chnColor);
648 }
649 }
650 }
651
652 /** Hides the channel properties. */
653 public void
654 collapseChannel() { if(btnProperties.isSelected()) btnProperties.doClick(); }
655
656 /** Shows the channel properties. */
657 public void
658 expandChannel() { if(!btnProperties.isSelected()) btnProperties.doClick(); }
659
660 /**
661 * Updates the channel settings. This method is invoked when changes to the
662 * channel were made.
663 */
664 private void
665 updateChannelInfo() {
666 SamplerChannel sc = getChannelInfo();
667
668 int status = sc.getInstrumentStatus();
669 if(status >= 0 && status < 100) {
670 btnInstr.setText(i18n.getLabel("Channel.loadingInstrument", status));
671 } else if(status == -1) {
672 btnInstr.setText(i18n.getLabel("Channel.btnInstr"));
673 } else if(status < -1) {
674 btnInstr.setText(i18n.getLabel("Channel.errorLoadingInstrument"));
675 } else {
676 if(sc.getInstrumentName() != null) btnInstr.setText(sc.getInstrumentName());
677 else btnInstr.setText(i18n.getLabel("Channel.btnInstr"));
678 }
679
680 updateMuteIcon(sc);
681
682 if(sc.isSoloChannel()) btnSolo.setIcon(iconSoloOn);
683 else btnSolo.setIcon(iconSoloOff);
684
685 slVolume.setValue((int)(sc.getVolume() * 100));
686
687 boolean b = sc.getEngine() != null;
688 slVolume.setEnabled(b);
689 btnSolo.setEnabled(b);
690 btnMute.setEnabled(b);
691 }
692
693 /** Invoked when the user clicks the mute button. */
694 private void
695 changeMute() {
696 SamplerChannel sc = getChannelInfo();
697 boolean b = true;
698
699 /*
700 * Changing the mute button icon now instead of
701 * leaving the work to the notification mechanism of the LinuxSampler.
702 */
703 if(sc.isMuted() && !sc.isMutedBySolo()) {
704 b = false;
705 boolean hasSolo = CC.getSamplerModel().hasSoloChannel();
706
707 if(sc.isSoloChannel() || !hasSolo) btnMute.setIcon(iconMuteOff);
708 else btnMute.setIcon(iconMutedBySolo);
709 } else btnMute.setIcon(iconMuteOn);
710
711 getModel().setBackendMute(b);
712 }
713
714 /** Invoked when the user clicks the solo button. */
715 private void
716 changeSolo() {
717 SamplerChannel sc = getChannelInfo();
718 boolean b = !sc.isSoloChannel();
719
720 /*
721 * Changing the solo button icon (and related) now instead of
722 * leaving the work to the notification mechanism of the LinuxSampler.
723 */
724 if(b) {
725 btnSolo.setIcon(iconSoloOn);
726 if(sc.isMutedBySolo()) btnMute.setIcon(iconMuteOff);
727 } else {
728 btnSolo.setIcon(iconSoloOff);
729 if(!sc.isMuted() && CC.getSamplerModel().getSoloChannelCount() > 1)
730 btnMute.setIcon(iconMutedBySolo);
731 }
732
733 getModel().setBackendSolo(b);
734 }
735
736 /** Invoked when the user changes the volume */
737 private void
738 setVolume() {
739 updateVolume();
740
741 if(slVolume.getValueIsAdjusting()) return;
742
743 int vol = (int)(getChannelInfo().getVolume() * 100);
744
745 if(vol == slVolume.getValue()) return;
746
747 /*
748 * If the model's volume is not equal to the slider
749 * value we assume that the change is due to user input.
750 * So we must update the volume at the backend too.
751 */
752 float volume = slVolume.getValue();
753 volume /= 100;
754 getModel().setBackendVolume(volume);
755 }
756
757 private void
758 updateVolume() {
759 int volume = slVolume.getValue();
760 slVolume.setToolTipText(i18n.getLabel("Channel.volume", volume));
761 lVolImg.setToolTipText(i18n.getLabel("Channel.volume", volume));
762
763 setVolumeLabel(volume);
764
765
766 }
767
768 private void
769 setVolumeLabel(int volume) {
770 Dimension d = lVolume.getPreferredSize();
771 lVolume.setText(String.valueOf(volume) + '%');
772 d = JuifeUtils.getUnionSize(d, lVolume.getPreferredSize());
773 lVolume.setMinimumSize(d);
774 lVolume.setPreferredSize(d);
775 lVolume.setMaximumSize(d);
776 }
777
778 /**
779 * Updates the mute button with the proper icon regarding to information obtained
780 * from <code>channel</code>.
781 * @param channel A <code>SamplerChannel</code> instance containing the new settings
782 * for this channel.
783 */
784 private void
785 updateMuteIcon(SamplerChannel channel) {
786 if(channel.isMutedBySolo()) btnMute.setIcon(iconMutedBySolo);
787 else if(channel.isMuted()) btnMute.setIcon(iconMuteOn);
788 else btnMute.setIcon(iconMuteOff);
789 }
790
791 /**
792 * Updates the number of active disk streams.
793 * @param count The new number of active disk streams.
794 */
795 private void
796 updateStreamCount(int count) {
797 Dimension d = lStreams.getPreferredSize();
798 lStreams.setText(count == 0 ? "--" : String.valueOf(count));
799 d = JuifeUtils.getUnionSize(d, lStreams.getPreferredSize());
800 lStreams.setMinimumSize(d);
801 lStreams.setPreferredSize(d);
802 lStreams.setMaximumSize(d);
803 }
804
805 /**
806 * Updates the number of active voices.
807 * @param count The new number of active voices.
808 */
809 private void
810 updateVoiceCount(int count) {
811 Dimension d = lVoices.getPreferredSize();
812 lVoices.setText(count == 0 ? "--" : String.valueOf(count));
813 d = JuifeUtils.getUnionSize(d, lVoices.getPreferredSize());
814 lVoices.setMinimumSize(d);
815 lVoices.setPreferredSize(d);
816 lVoices.setMaximumSize(d);
817 }
818
819 private void
820 showProperties(boolean show) {propertiesPane.setVisible(show); }
821
822 private void
823 loadInstrument() {
824 JSInstrumentChooser dlg = new JSInstrumentChooser(CC.getMainFrame());
825 dlg.setVisible(true);
826
827 if(dlg.isCancelled()) return;
828
829 SamplerEngine engine = getChannelInfo().getEngine();
830 if(dlg.getEngine() != null) {
831 if(engine == null || !dlg.getEngine().equals(engine.getName()));
832 getModel().setBackendEngineType(dlg.getEngine());
833 }
834
835 int idx = dlg.getInstrumentIndex();
836 getModel().loadBackendInstrument(dlg.getInstrumentFile(), idx);
837
838 }
839 }
840
841 class ChannelProperties extends JPanel {
842 private final JLabel lMidiDevice =
843 new JLabel(i18n.getLabel("ChannelProperties.lMidiDevice"));
844 private final JLabel lMidiPort =
845 new JLabel(i18n.getLabel("ChannelProperties.lMidiPort"));
846 private final JLabel lMidiChannel =
847 new JLabel(i18n.getLabel("ChannelProperties.lMidiChannel"));
848
849 private final JLabel lInstrumentMap =
850 new JLabel(i18n.getLabel("ChannelProperties.lInstrumentMap"));
851
852 private final JLabel lAudioDevice =
853 new JLabel(i18n.getLabel("ChannelProperties.lAudioDevice"));
854
855 private final JComboBox cbEngines = new JComboBox();
856
857 private final JComboBox cbInstrumentMap = new JComboBox();
858 private final JComboBox cbMidiDevice = new JComboBox();
859 private final JComboBox cbMidiPort = new JComboBox();
860 private final JComboBox cbMidiChannel = new JComboBox();
861 private final JComboBox cbAudioDevice = new JComboBox();
862
863 private final JButton btnFxSends = new JButton(Res.iconFxSends22);
864 private final JButton btnAudioProps = new JButton(Res.iconAudioProps16);
865 private InformationDialog fxSendsDlg = null;
866
867 private SamplerChannelModel channelModel = null;
868 private MidiDeviceModel midiDevice = null;
869
870 private boolean update = false;
871
872 private final SamplerListener samplerListener;
873 private final MapListListener mapListListener = new MapListListener();
874
875 private class NoMap {
876 public String
877 toString() { return "[None]"; }
878 }
879
880 private NoMap noMap = new NoMap();
881
882 private class DefaultMap {
883 public String
884 toString() { return "[Default]"; }
885 }
886
887 private DefaultMap defaultMap = new DefaultMap();
888
889 /**
890 * Creates a new instance of <code>ChannelProperties</code> using the specified non-null
891 * channel model.
892 * @param model The model to be used by this channel properties pane.
893 */
894 ChannelProperties(SamplerChannelModel model) {
895 channelModel = model;
896
897 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
898 setOpaque(false);
899
900 add(new JSeparator());
901
902 JPanel enginesPane = createEnginePane();
903
904 JPanel devicesPane = new JPanel();
905 devicesPane.setOpaque(false);
906 devicesPane.setLayout(new BoxLayout(devicesPane, BoxLayout.X_AXIS));
907
908 devicesPane.add(Box.createRigidArea(new Dimension(3, 0)));
909
910 devicesPane.add(createMidiPane());
911
912 devicesPane.add(Box.createRigidArea(new Dimension(3, 0)));
913
914 devicesPane.add(enginesPane);
915
916 devicesPane.add(Box.createRigidArea(new Dimension(3, 0)));
917
918 JPanel audioPane = createAudioPane();
919 Dimension d = audioPane.getPreferredSize();
920 d.height = Short.MAX_VALUE;
921
922 audioPane.setMaximumSize(d);
923 devicesPane.add(audioPane);
924
925 add(devicesPane);
926 add(Box.createRigidArea(new Dimension(0, 6)));
927
928 add(new JSeparator());
929
930 cbMidiChannel.addItem("All");
931 for(int i = 1; i <= 16; i++) cbMidiChannel.addItem(String.valueOf(i));
932
933 cbMidiDevice.addActionListener(new ActionListener() {
934 public void
935 actionPerformed(ActionEvent e) { setMidiDevice(); }
936 });
937
938 cbMidiPort.addActionListener(new ActionListener() {
939 public void
940 actionPerformed(ActionEvent e) { setMidiPort(); }
941 });
942
943 cbMidiChannel.addActionListener(new ActionListener() {
944 public void
945 actionPerformed(ActionEvent e) { setMidiChannel(); }
946 });
947
948 cbEngines.addActionListener(new ActionListener() {
949 public void
950 actionPerformed(ActionEvent e) { setEngineType(); }
951 });
952
953 cbAudioDevice.addActionListener(new ActionListener() {
954 public void
955 actionPerformed(ActionEvent e) { setAudioDevice(); }
956 });
957
958 getModel().addSamplerChannelListener(new SamplerChannelAdapter() {
959 public void
960 channelChanged(SamplerChannelEvent e) { updateChannelProperties(); }
961 });
962
963 samplerListener = new SamplerAdapter() {
964 /** Invoked when the default MIDI instrument map is changed. */
965 public void
966 defaultMapChanged(SamplerEvent e) {
967 updateCbInstrumentMapToolTipText();
968 }
969 };
970
971 CC.getSamplerModel().addSamplerListener(samplerListener);
972
973 cbInstrumentMap.addItem(noMap);
974 cbInstrumentMap.addItem(defaultMap);
975 for(MidiInstrumentMap map : CC.getSamplerModel().getMidiInstrumentMaps()) {
976 cbInstrumentMap.addItem(map);
977 }
978
979 int map = getModel().getChannelInfo().getMidiInstrumentMapId();
980 cbInstrumentMap.setSelectedItem(CC.getSamplerModel().getMidiInstrumentMapById(map));
981 if(cbInstrumentMap.getSelectedItem() == null) {
982 if(map == -1) cbInstrumentMap.setSelectedItem(noMap);
983 else if(map == -2) {
984 cbInstrumentMap.setSelectedItem(defaultMap);
985 }
986 }
987
988 updateCbInstrumentMapToolTipText();
989
990 if(getModel().getChannelInfo().getEngine() == null) {
991 cbInstrumentMap.setEnabled(false);
992 }
993
994 cbInstrumentMap.addActionListener(new ActionListener() {
995 public void
996 actionPerformed(ActionEvent e) { updateInstrumentMap(); }
997 });
998
999 CC.getSamplerModel().addMidiDeviceListListener(getHandler());
1000 CC.getSamplerModel().addAudioDeviceListListener(getHandler());
1001 CC.getSamplerModel().addSamplerChannelListListener(getHandler());
1002 CC.getSamplerModel().addMidiInstrumentMapListListener(mapListListener);
1003
1004 btnAudioProps.setToolTipText(i18n.getLabel("ChannelProperties.routing"));
1005 btnAudioProps.setEnabled(false);
1006 btnAudioProps.addActionListener(new ActionListener() {
1007 public void
1008 actionPerformed(ActionEvent e) {
1009 SamplerChannel c = getModel().getChannelInfo();
1010 new JSChannelOutputRoutingDlg(CC.getMainFrame(), c).setVisible(true);
1011
1012 }
1013 });
1014
1015 btnFxSends.setToolTipText(i18n.getButtonLabel("ChannelProperties.btnFxSends"));
1016 btnFxSends.addActionListener(new ActionListener() {
1017 public void
1018 actionPerformed(ActionEvent e) {
1019 if(fxSendsDlg != null && fxSendsDlg.isVisible()) {
1020 fxSendsDlg.toFront();
1021 return;
1022 }
1023
1024 FxSendsPane p = new FxSendsPane(getModel());
1025 int id = getModel().getChannelId();
1026 fxSendsDlg = new InformationDialog(CC.getMainFrame(), p);
1027 fxSendsDlg.setTitle(i18n.getLabel("FxSendsDlg.title", id));
1028 fxSendsDlg.setModal(false);
1029 fxSendsDlg.showCloseButton(false);
1030 fxSendsDlg.setVisible(true);
1031 }
1032 });
1033
1034 updateMidiDevices();
1035 updateAudioDevices();
1036 updateChannelProperties();
1037 }
1038
1039 class FxSendsPane extends JSFxSendsPane {
1040 FxSendsPane(SamplerChannelModel model) {
1041 super(model);
1042
1043 actionAddFxSend.putValue(Action.SMALL_ICON, Res.iconNew16);
1044 actionRemoveFxSend.putValue(Action.SMALL_ICON, Res.iconDelete16);
1045 }
1046
1047 protected JToolBar
1048 createToolBar() {
1049 JToolBar tb = new JToolBar();
1050 Dimension d = new Dimension(Short.MAX_VALUE, tb.getPreferredSize().height);
1051 tb.setMaximumSize(d);
1052 tb.setFloatable(false);
1053 tb.setAlignmentX(JPanel.RIGHT_ALIGNMENT);
1054
1055 tb.add(new ToolbarButton(actionAddFxSend));
1056 tb.add(new ToolbarButton(actionRemoveFxSend));
1057
1058 return tb;
1059 }
1060 }
1061
1062 private JPanel
1063 createEnginePane() {
1064 for(SamplerEngine e : CC.getSamplerModel().getEngines()) cbEngines.addItem(e);
1065
1066 cbEngines.setMaximumSize(cbEngines.getPreferredSize());
1067
1068 JPanel p = new JPanel();
1069 p.setOpaque(false);
1070 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1071 p.add(cbEngines);
1072 p.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
1073
1074 //enginesPane.add(Box.createGlue());
1075 JPanel enginesPane = new JPanel();
1076 enginesPane.setOpaque(false);
1077 enginesPane.setLayout(new BorderLayout());
1078 enginesPane.add(p, BorderLayout.SOUTH);
1079 //enginesPane.add(Box.createRigidArea(new Dimension(0, 3)));
1080
1081 String s = i18n.getLabel("ChannelProperties.enginesPane");
1082 enginesPane.setBorder(BorderFactory.createTitledBorder(s));
1083 Dimension d = new Dimension(enginesPane.getPreferredSize().width, Short.MAX_VALUE);
1084 enginesPane.setMaximumSize(d);
1085 return enginesPane;
1086 }
1087
1088 private JPanel
1089 createMidiPane() {
1090 JPanel midiPane = new JPanel();
1091 midiPane.setOpaque(false);
1092
1093 GridBagLayout gridbag = new GridBagLayout();
1094 GridBagConstraints c = new GridBagConstraints();
1095
1096 midiPane.setLayout(gridbag);
1097
1098 c.gridx = 1;
1099 c.gridy = 0;
1100 c.insets = new Insets(0, 3, 3, 3);
1101 gridbag.setConstraints(lMidiDevice, c);
1102 midiPane.add(lMidiDevice);
1103
1104 c.gridx = 2;
1105 c.gridy = 0;
1106 gridbag.setConstraints(lMidiPort, c);
1107 midiPane.add(lMidiPort);
1108
1109 c.gridx = 3;
1110 c.gridy = 0;
1111 gridbag.setConstraints(lMidiChannel, c);
1112 midiPane.add(lMidiChannel);
1113
1114 c.gridx = 4;
1115 c.gridy = 0;
1116 c.insets = new Insets(0, 10, 3, 3);
1117 gridbag.setConstraints(lInstrumentMap, c);
1118 midiPane.add(lInstrumentMap);
1119
1120 btnFxSends.setMargin(new Insets(0, 0, 0, 0));
1121 c.gridx = 0;
1122 c.gridy = 0;
1123 c.gridheight = 2;
1124 c.insets = new Insets(0, 5, 0, 8);
1125 gridbag.setConstraints(btnFxSends, c);
1126 midiPane.add(btnFxSends);
1127
1128 c.gridx = 1;
1129 c.gridy = 1;
1130 c.gridheight = 1;
1131 c.insets = new Insets(0, 4, 4, 3);
1132 c.fill = GridBagConstraints.HORIZONTAL;
1133 gridbag.setConstraints(cbMidiDevice, c);
1134 midiPane.add(cbMidiDevice);
1135
1136 c.gridx = 3;
1137 c.gridy = 1;
1138 gridbag.setConstraints(cbMidiChannel, c);
1139 midiPane.add(cbMidiChannel);
1140
1141 c.gridx = 2;
1142 c.gridy = 1;
1143 gridbag.setConstraints(cbMidiPort, c);
1144 midiPane.add(cbMidiPort);
1145
1146 c.gridx = 4;
1147 c.gridy = 1;
1148 c.weightx = 1.0;
1149 c.insets = new Insets(0, 10, 3, 3);
1150 gridbag.setConstraints(cbInstrumentMap, c);
1151 midiPane.add(cbInstrumentMap);
1152
1153 String s = i18n.getLabel("ChannelProperties.midiPane");
1154 TitledBorder border = BorderFactory.createTitledBorder(s);
1155 //border.setTitlePosition(border.TOP);
1156 midiPane.setBorder(border);
1157 return midiPane;
1158 }
1159
1160 private JPanel
1161 createAudioPane() {
1162 JPanel audioPane = new JPanel();
1163 audioPane.setOpaque(false);
1164
1165 GridBagLayout gridbag = new GridBagLayout();
1166 GridBagConstraints c = new GridBagConstraints();
1167
1168 audioPane.setLayout(gridbag);
1169
1170 c.gridx = 0;
1171 c.gridy = 0;
1172 c.insets = new Insets(0, 3, 3, 3);
1173 gridbag.setConstraints(lAudioDevice, c);
1174 audioPane.add(lAudioDevice);
1175
1176 c.gridx = 0;
1177 c.gridy = 1;
1178 c.fill = GridBagConstraints.HORIZONTAL;
1179 gridbag.setConstraints(cbAudioDevice, c);
1180 audioPane.add(cbAudioDevice);
1181
1182 btnAudioProps.setMargin(new Insets(0, 0, 0, 0));
1183 c.gridx = 1;
1184 c.gridy = 1;
1185 c.fill = GridBagConstraints.NONE;
1186 gridbag.setConstraints(btnAudioProps, c);
1187 audioPane.add(btnAudioProps);
1188
1189 String s = i18n.getLabel("ChannelProperties.audioPane");
1190 audioPane.setBorder(BorderFactory.createTitledBorder(s));
1191
1192 return audioPane;
1193 }
1194
1195 /**
1196 * Gets the model that is currently used by this channel properties pane.
1197 * @return model The <code>SamplerChannelModel</code> instance
1198 * that provides information about the channel whose settings are
1199 * represented by this channel properties pane.
1200 */
1201 public SamplerChannelModel
1202 getModel() { return channelModel; }
1203
1204
1205 private void
1206 updateInstrumentMap() {
1207 updateCbInstrumentMapToolTipText();
1208
1209 int id = getModel().getChannelInfo().getMidiInstrumentMapId();
1210 Object o = cbInstrumentMap.getSelectedItem();
1211 if(o == null && id == -1) return;
1212
1213 int cbId;
1214 if(o == null || o == noMap) cbId = -1;
1215 else if(o == defaultMap) cbId = -2;
1216 else cbId = ((MidiInstrumentMap)o).getMapId();
1217
1218 if(cbId == id) return;
1219
1220 channelModel.setBackendMidiInstrumentMap(cbId);
1221 }
1222
1223 private void
1224 updateCbInstrumentMapToolTipText() {
1225 if(cbInstrumentMap.getSelectedItem() != defaultMap) {
1226 cbInstrumentMap.setToolTipText(null);
1227 return;
1228 }
1229
1230 MidiInstrumentMap m = CC.getSamplerModel().getDefaultMidiInstrumentMap();
1231 if(m != null) {
1232 String s = i18n.getLabel("Channel.ttDefault", m.getName());
1233 cbInstrumentMap.setToolTipText(s);
1234 } else {
1235 cbInstrumentMap.setToolTipText(null);
1236 }
1237 }
1238
1239 /**
1240 * Updates the channel settings. This method is invoked when changes to the
1241 * channel were made.
1242 */
1243 private void
1244 updateChannelProperties() {
1245 SamplerModel sm = CC.getSamplerModel();
1246 SamplerChannel sc = getModel().getChannelInfo();
1247
1248 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1249 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1250
1251 if(isUpdate()) CC.getLogger().warning("Unexpected update state!");
1252
1253 setUpdate(true);
1254
1255 try {
1256 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1257
1258 cbEngines.setSelectedItem(sc.getEngine());
1259
1260 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1261 btnAudioProps.setEnabled(am != null);
1262 } catch(Exception x) {
1263 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1264 }
1265
1266 if(sc.getEngine() != null) {
1267 cbInstrumentMap.setEnabled(true);
1268 int id = sc.getMidiInstrumentMapId();
1269 Object o;
1270 if(id == -2) o = defaultMap;
1271 else if(id == -1) o = noMap;
1272 else o = CC.getSamplerModel().getMidiInstrumentMapById(id);
1273
1274 if(cbInstrumentMap.getSelectedItem() != o) {
1275 cbInstrumentMap.setSelectedItem(o);
1276 }
1277 } else {
1278 cbInstrumentMap.setSelectedItem(noMap);
1279 cbInstrumentMap.setEnabled(false);
1280 }
1281
1282 setUpdate(false);
1283 }
1284
1285 /**
1286 * Updates the MIDI device list.
1287 */
1288 private void
1289 updateMidiDevices() {
1290 SamplerModel sm = CC.getSamplerModel();
1291 SamplerChannel sc = getModel().getChannelInfo();
1292
1293 setUpdate(true);
1294
1295 try {
1296 cbMidiDevice.removeAllItems();
1297
1298 for(MidiDeviceModel m : sm.getMidiDevices())
1299 cbMidiDevice.addItem(m.getDeviceInfo());
1300
1301 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1302 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1303 } catch(Exception x) {
1304 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1305 }
1306
1307 setUpdate(false);
1308 }
1309
1310 /**
1311 * Updates the audio device list.
1312 */
1313 private void
1314 updateAudioDevices() {
1315 SamplerModel sm = CC.getSamplerModel();
1316 SamplerChannel sc = getModel().getChannelInfo();
1317
1318 setUpdate(true);
1319
1320 try {
1321 cbAudioDevice.removeAllItems();
1322
1323 for(AudioDeviceModel m : sm.getAudioDevices())
1324 cbAudioDevice.addItem(m.getDeviceInfo());
1325
1326 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1327 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1328 } catch(Exception x) {
1329 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1330 }
1331
1332 setUpdate(false);
1333 }
1334
1335 private void
1336 setMidiDevice() {
1337 MidiInputDevice mid = (MidiInputDevice)cbMidiDevice.getSelectedItem();
1338
1339 if(!isUpdate()) {
1340 if(mid != null) getModel().setBackendMidiInputDevice(mid.getDeviceId());
1341 return;
1342 }
1343
1344 if(midiDevice != null) midiDevice.removeMidiDeviceListener(getHandler());
1345
1346 cbMidiPort.removeAllItems();
1347
1348 if(mid == null) {
1349 midiDevice = null;
1350 cbMidiPort.setEnabled(false);
1351
1352 cbMidiChannel.setSelectedItem(null);
1353 cbMidiChannel.setEnabled(false);
1354 } else {
1355 midiDevice = CC.getSamplerModel().getMidiDeviceById(mid.getDeviceId());
1356 if(midiDevice != null) midiDevice.addMidiDeviceListener(getHandler());
1357
1358 cbMidiPort.setEnabled(true);
1359
1360 MidiPort[] ports = mid.getMidiPorts();
1361 for(MidiPort port : ports) cbMidiPort.addItem(port);
1362
1363 int p = getModel().getChannelInfo().getMidiInputPort();
1364 cbMidiPort.setSelectedItem(p >= 0 && p < ports.length ? ports[p] : null);
1365
1366 cbMidiChannel.setEnabled(true);
1367 int c = getModel().getChannelInfo().getMidiInputChannel();
1368 cbMidiChannel.setSelectedItem(c == -1 ? "All" : String.valueOf(c + 1));
1369 }
1370
1371
1372 }
1373
1374 private void
1375 setMidiPort() {
1376 if(isUpdate()) return;
1377
1378 getModel().setBackendMidiInputPort(cbMidiPort.getSelectedIndex());
1379 }
1380
1381 private void
1382 setMidiChannel() {
1383 if(isUpdate()) return;
1384
1385 Object o = cbMidiChannel.getSelectedItem();
1386 if(o == null) return;
1387
1388 int c = o.toString().equals("All") ? -1 : Integer.parseInt(o.toString()) - 1;
1389
1390 getModel().setBackendMidiInputChannel(c);
1391 }
1392
1393 /** Invoked when the user selects an engine. */
1394 private void
1395 setEngineType() {
1396 Object oldEngine = getModel().getChannelInfo().getEngine();
1397 SamplerEngine newEngine = (SamplerEngine)cbEngines.getSelectedItem();
1398
1399 if(oldEngine != null) { if(oldEngine.equals(newEngine)) return; }
1400 else if(newEngine == null) return;
1401
1402 getModel().setBackendEngineType(newEngine.getName());
1403
1404 }
1405
1406 private void
1407 setAudioDevice() {
1408 if(isUpdate()) return;
1409 AudioOutputDevice dev = (AudioOutputDevice)cbAudioDevice.getSelectedItem();
1410 if(dev != null) getModel().setBackendAudioOutputDevice(dev.getDeviceId());
1411 }
1412
1413 /**
1414 * Determines whether the currently processed changes are due to update.
1415 * @return <code>true</code> if the currently processed changes are due to update and
1416 * <code>false</code> if the currently processed changes are due to user input.
1417 */
1418 private boolean
1419 isUpdate() { return update; }
1420
1421 /**
1422 * Sets whether the currently processed changes are due to update.
1423 * @param b Specify <code>true</code> to indicate that the currently
1424 * processed changes are due to update; <code>false</code>
1425 * indicates that the currently processed changes are due to user input.
1426 */
1427 private void
1428 setUpdate(boolean b) { update = b; }
1429
1430 private final Handler handler = new Handler();
1431
1432 private Handler
1433 getHandler() { return handler; }
1434
1435 private class Handler implements MidiDeviceListListener, ListListener<AudioDeviceModel>,
1436 SamplerChannelListListener, MidiDeviceListener {
1437
1438 /**
1439 * Invoked when a new MIDI device is created.
1440 * @param e A <code>MidiDeviceListEvent</code>
1441 * instance providing the event information.
1442 */
1443 public void
1444 deviceAdded(MidiDeviceListEvent e) {
1445 cbMidiDevice.addItem(e.getMidiDeviceModel().getDeviceInfo());
1446 }
1447
1448 /**
1449 * Invoked when a MIDI device is removed.
1450 * @param e A <code>MidiDeviceListEvent</code>
1451 * instance providing the event information.
1452 */
1453 public void
1454 deviceRemoved(MidiDeviceListEvent e) {
1455 cbMidiDevice.removeItem(e.getMidiDeviceModel().getDeviceInfo());
1456 }
1457
1458 /**
1459 * Invoked when a new audio device is created.
1460 * @param e An <code>AudioDeviceListEvent</code>
1461 * instance providing the event information.
1462 */
1463 public void
1464 entryAdded(ListEvent<AudioDeviceModel> e) {
1465 cbAudioDevice.addItem(e.getEntry().getDeviceInfo());
1466 }
1467
1468 /**
1469 * Invoked when an audio device is removed.
1470 * @param e An <code>AudioDeviceListEvent</code>
1471 * instance providing the event information.
1472 */
1473 public void
1474 entryRemoved(ListEvent<AudioDeviceModel> e) {
1475 cbAudioDevice.removeItem(e.getEntry().getDeviceInfo());
1476 }
1477
1478 /**
1479 * Invoked when a new sampler channel is created.
1480 * @param e A <code>SamplerChannelListEvent</code>
1481 * instance providing the event information.
1482 */
1483 public void
1484 channelAdded(SamplerChannelListEvent e) { }
1485
1486 /**
1487 * Invoked when a sampler channel is removed.
1488 * @param e A <code>SamplerChannelListEvent</code>
1489 * instance providing the event information.
1490 */
1491 public void
1492 channelRemoved(SamplerChannelListEvent e) {
1493 // Some cleanup when the channel is removed.
1494 if(e.getChannelModel().getChannelId() == channelModel.getChannelId()) {
1495 SamplerModel sm = CC.getSamplerModel();
1496
1497 sm.removeMidiDeviceListListener(getHandler());
1498 sm.removeAudioDeviceListListener(getHandler());
1499 sm.removeMidiInstrumentMapListListener(mapListListener);
1500 sm.removeSamplerListener(samplerListener);
1501 sm.removeSamplerChannelListListener(getHandler());
1502
1503 if(midiDevice != null) {
1504 midiDevice.removeMidiDeviceListener(getHandler());
1505 }
1506 }
1507 }
1508
1509 public void
1510 settingsChanged(MidiDeviceEvent e) {
1511 if(isUpdate()) {
1512 CC.getLogger().warning("Invalid update state");
1513 return;
1514 }
1515
1516 setUpdate(true);
1517 int idx = cbMidiPort.getSelectedIndex();
1518 MidiInputDevice d = e.getMidiDeviceModel().getDeviceInfo();
1519
1520 cbMidiPort.removeAllItems();
1521 for(MidiPort port : d.getMidiPorts()) cbMidiPort.addItem(port);
1522
1523 if(idx >= cbMidiPort.getModel().getSize()) idx = 0;
1524
1525 setUpdate(false);
1526
1527 if(cbMidiPort.getModel().getSize() > 0) cbMidiPort.setSelectedIndex(idx);
1528 }
1529 }
1530
1531 private class MapListListener implements ListListener<MidiInstrumentMap> {
1532 /** Invoked when a new MIDI instrument map is added to a list. */
1533 public void
1534 entryAdded(ListEvent<MidiInstrumentMap> e) {
1535 cbInstrumentMap.insertItemAt(e.getEntry(), cbInstrumentMap.getItemCount());
1536 boolean b = getModel().getChannelInfo().getEngine() != null;
1537 if(b && !cbInstrumentMap.isEnabled()) cbInstrumentMap.setEnabled(true);
1538 }
1539
1540 /** Invoked when a new MIDI instrument map is removed from a list. */
1541 public void
1542 entryRemoved(ListEvent<MidiInstrumentMap> e) {
1543 cbInstrumentMap.removeItem(e.getEntry());
1544 if(cbInstrumentMap.getItemCount() == 0) {
1545 cbInstrumentMap.setSelectedItem(noMap);
1546 cbInstrumentMap.setEnabled(false);
1547 }
1548 }
1549 }
1550 }

  ViewVC Help
Powered by ViewVC