/[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 1752 - (show annotations) (download)
Mon Aug 11 22:51:24 2008 UTC (15 years, 8 months ago) by iliev
File size: 48263 byte(s)
* Added toolbar to the Database Instrument Chooser dialog
* Instrument Chooser and Database Instrument Chooser dialogs
  are now resizable
* Fantasia: Added toolbar to the Right-Side Pane's Instruments Database

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

  ViewVC Help
Powered by ViewVC