/[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 1343 - (show annotations) (download)
Tue Sep 11 15:38:28 2007 UTC (16 years, 7 months ago) by iliev
File size: 46527 byte(s)
* JS Classic: Added new button to sampler channels
  for starting an instrument editor
* The last used instrument selection method is now
  saved for the next session
* Fantasia: Removed the lock border from non-editable
  text fields in properties panes and LS Console

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

  ViewVC Help
Powered by ViewVC