/[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 1357 - (show annotations) (download)
Sat Sep 22 17:27:06 2007 UTC (16 years, 7 months ago) by iliev
File size: 47092 byte(s)
* Added options for setting the maximum master and channel volume
  (choose Edit/Preferences)
* Fantasia: Edit instrument button is now shown on the channel
  screen only when there is loaded instrument on that channel
* Fantasia: Added options for showing additional device parameters in
  audio/MIDI device panes (Edit/Preferences, then click the `View' tab)
* Fantasia: Master volume is now fully implemented

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

  ViewVC Help
Powered by ViewVC