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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1285 - (show annotations) (download)
Fri Aug 10 19:55:03 2007 UTC (16 years, 8 months ago) by iliev
File size: 40867 byte(s)
* Updated to version 0.6a. The Fantasia distribution is now
  capable of controlling all features available in LinuxSampler

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.fantasia;
24
25 import java.awt.Cursor;
26 import java.awt.Dimension;
27 import java.awt.Graphics;
28 import java.awt.Insets;
29
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.awt.event.MouseAdapter;
33 import java.awt.event.MouseEvent;
34
35 import java.beans.PropertyChangeEvent;
36 import java.beans.PropertyChangeListener;
37
38 import java.util.logging.Level;
39
40 import javax.swing.Action;
41 import javax.swing.BorderFactory;
42 import javax.swing.Box;
43 import javax.swing.BoxLayout;
44 import javax.swing.DefaultListCellRenderer;
45 import javax.swing.JButton;
46 import javax.swing.JComboBox;
47 import javax.swing.JLabel;
48 import javax.swing.JMenuItem;
49 import javax.swing.JPanel;
50 import javax.swing.JPopupMenu;
51 import javax.swing.JToggleButton;
52 import javax.swing.JToolBar;
53 import javax.swing.SwingConstants;
54
55 import javax.swing.event.ChangeEvent;
56 import javax.swing.event.ChangeListener;
57
58 import net.sf.juife.Dial;
59 import net.sf.juife.InformationDialog;
60 import net.sf.juife.JuifeUtils;
61 import net.sf.juife.TitleBar;
62
63 import org.jdesktop.swingx.JXCollapsiblePane;
64
65 import org.jsampler.AudioDeviceModel;
66 import org.jsampler.CC;
67 import org.jsampler.MidiDeviceModel;
68 import org.jsampler.MidiInstrumentMap;
69 import org.jsampler.SamplerChannelModel;
70 import org.jsampler.SamplerModel;
71
72 import org.jsampler.event.ListEvent;
73 import org.jsampler.event.ListListener;
74 import org.jsampler.event.MidiDeviceEvent;
75 import org.jsampler.event.MidiDeviceListEvent;
76 import org.jsampler.event.MidiDeviceListListener;
77 import org.jsampler.event.MidiDeviceListener;
78 import org.jsampler.event.SamplerAdapter;
79 import org.jsampler.event.SamplerChannelAdapter;
80 import org.jsampler.event.SamplerChannelEvent;
81 import org.jsampler.event.SamplerChannelListEvent;
82 import org.jsampler.event.SamplerChannelListListener;
83 import org.jsampler.event.SamplerChannelListener;
84 import org.jsampler.event.SamplerEvent;
85 import org.jsampler.event.SamplerListener;
86
87 import org.jsampler.view.std.JSChannelOutputRoutingDlg;
88 import org.jsampler.view.std.JSFxSendsPane;
89 import org.jsampler.view.std.JSInstrumentChooser;
90
91 import org.jvnet.lafwidget.animation.FadeConfigurationManager;
92 import org.jvnet.lafwidget.animation.FadeKind;
93
94 import org.jvnet.substance.SubstanceImageCreator;
95 import org.jvnet.substance.SubstanceLookAndFeel;
96
97 import org.linuxsampler.lscp.AudioOutputDevice;
98 import org.linuxsampler.lscp.MidiInputDevice;
99 import org.linuxsampler.lscp.MidiPort;
100 import org.linuxsampler.lscp.SamplerChannel;
101 import org.linuxsampler.lscp.SamplerEngine;
102
103 import static org.jsampler.view.fantasia.FantasiaI18n.i18n;
104 import static org.jsampler.view.fantasia.FantasiaPrefs.*;
105
106
107 /**
108 *
109 * @author Grigor Iliev
110 */
111 public class Channel extends org.jsampler.view.JSChannel {
112 private final JXCollapsiblePane mainPane;
113 private final ChannelScreen screen = new ChannelScreen(this);
114 private final ChannelOptions optionsPane = new ChannelOptions(this);
115
116 private final PowerButton btnPower = new PowerButton();
117 private final MuteButton btnMute = new MuteButton();
118 private final SoloButton btnSolo = new SoloButton();
119 private final OptionsButton btnOptions = new OptionsButton();
120
121 private final EnhancedDial dialVolume = new EnhancedDial();
122
123 private boolean selected = false;
124
125 /**
126 * Creates a new instance of <code>Channel</code> using the specified
127 * non-<code>null</code> channel model.
128 * @param model The model to be used by this channel.
129 * @throws IllegalArgumentException If the model is <code>null</code>.
130 */
131 public
132 Channel(SamplerChannelModel model) {
133 super(model);
134
135 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
136 ChannelPane p = new ChannelPane();
137 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
138
139 //p.add(Box.createRigidArea(new Dimension(3, 0)));
140
141 btnPower.setAlignmentY(JPanel.TOP_ALIGNMENT);
142
143 JPanel tb = new JPanel();
144 tb.setBorder(BorderFactory.createEmptyBorder(3, 3, 0, 4));
145 tb.setLayout(new BoxLayout(tb, BoxLayout.X_AXIS));
146 tb.setOpaque(false);
147 tb.setAlignmentY(JPanel.TOP_ALIGNMENT);
148 tb.add(btnPower);
149 tb.setPreferredSize(new Dimension(tb.getPreferredSize().width, 58));
150 tb.setMinimumSize(tb.getPreferredSize());
151 tb.setMaximumSize(tb.getPreferredSize());
152 p.add(tb);
153
154 //p.add(Box.createRigidArea(new Dimension(4, 0)));
155
156 p.add(createVSeparator());
157
158 //p.add(Box.createRigidArea(new Dimension(3, 0)));
159
160 JPanel p2 = new JPanel();
161 p2.setOpaque(false);
162 p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
163 p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
164 p2.setBorder(BorderFactory.createEmptyBorder(5, 3, 0, 2));
165 p2.add(screen);
166 p.add(p2);
167
168 p.add(createVSeparator());
169
170 p2 = new JPanel();
171 p2.setOpaque(false);
172 p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
173 p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
174 p2.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
175 p2.add(new JLabel(Res.gfxMuteTitle));
176 p2.add(btnMute);
177 p2.add(new JLabel(Res.gfxSoloTitle));
178 p2.add(btnSolo);
179
180 p.add(p2);
181
182 p.add(createVSeparator());
183
184 p2 = new JPanel();
185 p2.setOpaque(false);
186 p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
187 p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
188 p2.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
189 JLabel l = new JLabel(Res.gfxVolumeTitle);
190 l.setAlignmentX(JPanel.CENTER_ALIGNMENT);
191 l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
192 p2.add(l);
193 dialVolume.setDialPixmap(Res.gfxVolumeDial, 30, 330);
194 dialVolume.setAlignmentX(JPanel.CENTER_ALIGNMENT);
195 p2.add(dialVolume);
196 p.add(p2);
197
198 p.add(createVSeparator());
199
200 p2 = new JPanel();
201 p2.setOpaque(false);
202 p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
203 p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
204 p2.setBorder(BorderFactory.createEmptyBorder(27, 0, 0, 0));
205 l = new JLabel(Res.gfxOptionsTitle);
206 l.setAlignmentX(JPanel.CENTER_ALIGNMENT);
207 l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
208 p2.add(l);
209
210 p2.add(Box.createRigidArea(new Dimension(0, 3)));
211
212 btnOptions.setAlignmentX(JPanel.CENTER_ALIGNMENT);
213 p2.add(btnOptions);
214 p.add(p2);
215
216
217 p.setPreferredSize(new Dimension(420, 60));
218 p.setMinimumSize(p.getPreferredSize());
219 p.setMaximumSize(p.getPreferredSize());
220 //p.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0));
221
222 p.setAlignmentX(JPanel.CENTER_ALIGNMENT);
223 optionsPane.setAlignmentX(JPanel.CENTER_ALIGNMENT);
224
225 mainPane = new JXCollapsiblePane();
226 mainPane.getContentPane().setLayout (
227 new BoxLayout(mainPane.getContentPane(), BoxLayout.Y_AXIS)
228 );
229
230 mainPane.add(p);
231 mainPane.add(optionsPane);
232
233 setOpaque(false);
234
235 getModel().addSamplerChannelListener(getHandler());
236
237 updateChannelInfo();
238
239 add(mainPane);
240
241 mainPane.setAnimated(false);
242 mainPane.setCollapsed(true);
243 mainPane.setAnimated(preferences().getBoolProperty(ANIMATED));
244 mainPane.setCollapsed(false);
245
246 preferences().addPropertyChangeListener(ANIMATED, new PropertyChangeListener() {
247 public void
248 propertyChange(PropertyChangeEvent e) {
249 mainPane.setAnimated(preferences().getBoolProperty(ANIMATED));
250 }
251 });
252 }
253
254 private JPanel
255 createVSeparator() {
256 PixmapPane p = new PixmapPane(Res.gfxVLine);
257 p.setAlignmentY(JPanel.TOP_ALIGNMENT);
258 p.setPreferredSize(new Dimension(2, 60));
259 p.setMinimumSize(p.getPreferredSize());
260 p.setMaximumSize(p.getPreferredSize());
261 return p;
262 }
263
264 /**
265 * Determines whether the channel is selected.
266 * @return <code>true</code> if the channel is selected, <code>false</code> otherwise.
267 */
268 public boolean isSelected() { return selected; }
269
270 /**
271 * Sets the selection state of this channel.
272 * This method is invoked when the selection state of the channel has changed.
273 * @param select Specifies the new selection state of this channel;
274 * <code>true</code> to select the channel, <code>false</code> otherwise.
275 */
276 public void
277 setSelected(boolean select) {
278
279 selected = select;
280 }
281
282 /** Shows the channel properties. */
283 public void
284 expandChannel() { expandChannel(optionsPane.isAnimated()); }
285
286 /** Shows the channel properties. */
287 public void
288 expandChannel(boolean animated) {
289 if(btnOptions.isSelected()) return;
290
291 boolean b = optionsPane.isAnimated();
292 optionsPane.setAnimated(animated);
293 btnOptions.doClick();
294 optionsPane.setAnimated(b);
295 }
296
297
298 /** Invoked when the user changes the volume */
299 private void
300 setVolume() {
301 screen.updateVolumeInfo(dialVolume.getValue());
302
303 if(dialVolume.getValueIsAdjusting()) return;
304
305 int vol = (int)(getChannelInfo().getVolume() * 100);
306
307 if(vol == dialVolume.getValue()) return;
308
309
310 /*
311 * If the model's volume is not equal to the dial knob
312 * value we assume that the change is due to user input.
313 * So we must update the volume at the backend too.
314 */
315 float volume = dialVolume.getValue();
316 volume /= 100;
317 getModel().setBackendVolume(volume);
318 }
319
320 /**
321 * Updates the channel settings. This method is invoked when changes to the
322 * channel were made.
323 */
324 private void
325 updateChannelInfo() {
326 SamplerChannel sc = getChannelInfo();
327
328 screen.updateScreenInfo(sc);
329 updateMuteIcon(sc);
330
331 if(sc.isSoloChannel()) btnSolo.setIcon(Res.gfxSoloOn);
332 else btnSolo.setIcon(Res.gfxSoloOff);
333
334 dialVolume.setValue((int)(sc.getVolume() * 100));
335
336 boolean b = sc.getEngine() != null;
337 dialVolume.setEnabled(b);
338 btnSolo.setEnabled(b);
339 btnMute.setEnabled(b);
340 }
341
342 /**
343 * Updates the mute button with the proper icon regarding to information obtained
344 * from <code>channel</code>.
345 * @param channel A <code>SamplerChannel</code> instance containing the new settings
346 * for this channel.
347 */
348 private void
349 updateMuteIcon(SamplerChannel channel) {
350 if(channel.isMutedBySolo()) btnMute.setIcon(Res.gfxMutedBySolo);
351 else if(channel.isMuted()) btnMute.setIcon(Res.gfxMuteOn);
352 else btnMute.setIcon(Res.gfxMuteOff);
353 }
354
355 private class EnhancedDial extends Dial {
356 EnhancedDial() {
357 super(0, 100);
358
359 setMouseHandlerMode(MouseHandlerMode.LEFT_TO_RIGHT_AND_DOWN_TO_UP);
360
361 addMouseListener(new MouseAdapter() {
362 public void
363 mouseClicked(MouseEvent e) {
364 if(e.getButton() == e.BUTTON3) {
365 setValue(getMaximum() / 2);
366 return;
367 }
368
369 if(e.getButton() != e.BUTTON1) return;
370
371 if(e.getClickCount() < 2) return;
372 setValue(getValueByPoint(e.getPoint()));
373 }
374 });
375
376 addChangeListener(new ChangeListener() {
377 public void
378 stateChanged(ChangeEvent e) { setVolume(); }
379 });
380 }
381 }
382
383 private final EventHandler eventHandler = new EventHandler();
384
385 private EventHandler
386 getHandler() { return eventHandler; }
387
388 private class EventHandler implements SamplerChannelListener {
389 /**
390 * Invoked when changes are made to a sampler channel.
391 * @param e A <code>SamplerChannelEvent</code> instance
392 * containing event information.
393 */
394 public void
395 channelChanged(SamplerChannelEvent e) { updateChannelInfo(); }
396
397 /**
398 * Invoked when the number of active disk streams has changed.
399 * @param e A <code>SamplerChannelEvent</code> instance
400 * containing event information.
401 */
402 public void
403 streamCountChanged(SamplerChannelEvent e) {
404 screen.updateStreamCount(getModel().getStreamCount());
405 }
406
407 /**
408 * Invoked when the number of active voices has changed.
409 * @param e A <code>SamplerChannelEvent</code> instance
410 * containing event information.
411 */
412 public void
413 voiceCountChanged(SamplerChannelEvent e) {
414 screen.updateVoiceCount(getModel().getVoiceCount());
415 }
416 }
417
418
419 private class PowerButton extends PixmapToggleButton
420 implements ActionListener, PropertyChangeListener {
421
422 PowerButton() {
423 super(Res.gfxPowerOff, Res.gfxPowerOn);
424
425 setSelected(true);
426 addActionListener(this);
427 }
428
429 public void
430 actionPerformed(ActionEvent e) {
431 if(!mainPane.isAnimated()) {
432 CC.getSamplerModel().removeBackendChannel(getChannelId());
433 return;
434 }
435
436 String s = JXCollapsiblePane.ANIMATION_STATE_KEY;
437 mainPane.addPropertyChangeListener(s, this);
438 mainPane.setCollapsed(true);
439 }
440
441 public void
442 propertyChange(PropertyChangeEvent e) {
443 if(e.getNewValue() == "collapsed") {
444 CC.getSamplerModel().removeBackendChannel(getChannelId());
445 }
446 }
447
448 public boolean
449 contains(int x, int y) { return (x - 11)*(x - 11) + (y - 11)*(y - 11) < 71; }
450 }
451
452 private class MuteButton extends PixmapButton implements ActionListener {
453 MuteButton() {
454 super(Res.gfxMuteOff);
455 //setDisabledIcon(Res.gfxMuteSoloDisabled);
456 setDisabledIcon (
457 SubstanceImageCreator.makeTransparent(this, Res.gfxMuteOff, 0.4)
458 );
459 addActionListener(this);
460 }
461
462 public void
463 actionPerformed(ActionEvent e) {
464 SamplerChannel sc = getChannelInfo();
465 boolean b = true;
466
467 /*
468 * Changing the mute button icon now instead of
469 * leaving the work to the notification mechanism of the LinuxSampler.
470 */
471 if(sc.isMuted() && !sc.isMutedBySolo()) {
472 b = false;
473 boolean hasSolo = CC.getSamplerModel().hasSoloChannel();
474
475 if(sc.isSoloChannel() || !hasSolo) setIcon(Res.gfxMuteOff);
476 else setIcon(Res.gfxMutedBySolo);
477 } else setIcon(Res.gfxMuteOn);
478
479 Channel.this.getModel().setBackendMute(b);
480 }
481
482 public boolean
483 contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); }
484 }
485
486 private class SoloButton extends PixmapButton implements ActionListener {
487 SoloButton() {
488 super(Res.gfxSoloOff);
489 //setDisabledIcon(Res.gfxMuteSoloDisabled);
490 setDisabledIcon (
491 SubstanceImageCreator.makeTransparent(this, Res.gfxSoloOff, 0.4)
492 );
493 addActionListener(this);
494 }
495
496 public void
497 actionPerformed(ActionEvent e) {
498 SamplerChannel sc = getChannelInfo();
499 boolean b = !sc.isSoloChannel();
500
501 /*
502 * Changing the solo button icon (and related) now instead of
503 * leaving the work to the notification mechanism of the LinuxSampler.
504 */
505 if(b) {
506 setIcon(Res.gfxSoloOn);
507 if(sc.isMutedBySolo()) btnMute.setIcon(Res.gfxMuteOff);
508 } else {
509 setIcon(Res.gfxSoloOff);
510 if(!sc.isMuted() && CC.getSamplerModel().getSoloChannelCount() > 1)
511 btnMute.setIcon(Res.gfxMutedBySolo);
512 }
513
514 Channel.this.getModel().setBackendSolo(b);
515 }
516
517 public boolean
518 contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); }
519 }
520
521 private class OptionsButton extends PixmapToggleButton implements ActionListener {
522 OptionsButton() {
523 super(Res.gfxOptionsOff, Res.gfxOptionsOn);
524 setRolloverIcon(Res.gfxOptionsOffRO);
525 this.setRolloverSelectedIcon(Res.gfxOptionsOnRO);
526 addActionListener(this);
527 }
528
529 public void
530 actionPerformed(ActionEvent e) {
531 showOptionsPane(isSelected());
532
533 String s;
534 if(isSelected()) s = i18n.getButtonLabel("OptionsButton.ttHideOptions");
535 else s = i18n.getButtonLabel("OptionsButton.ttShowOptions");
536
537 setToolTipText(s);
538 }
539
540 private void
541 showOptionsPane(boolean show) {
542 optionsPane.setCollapsed(!show);
543 }
544
545 public boolean
546 contains(int x, int y) { return super.contains(x, y) & y < 13; }
547 }
548 }
549
550 class ChannelPane extends PixmapPane {
551 ChannelPane() {
552 super(Res.gfxChannel);
553 setPixmapInsets(new Insets(3, 3, 3, 3));
554 }
555 }
556
557 class ChannelScreen extends PixmapPane {
558 private final Channel channel;
559 private JButton btnInstr = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnInstr"));
560
561 private final JButton btnFxSends =
562 new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnFxSends"));
563
564 private final JButton btnEngine
565 = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnEngine"));
566
567 private final JPopupMenu menuEngines = new JPopupMenu();
568
569 private final JLabel lVolume = new Label();
570 private final JLabel lStreams = new Label("--");
571 private final JLabel lVoices = new Label("--");
572
573 private InformationDialog fxSendsDlg = null;
574
575 private Dimension dimVolume;
576
577 class Label extends JLabel {
578 Label() { this(""); }
579
580 Label(String s) {
581 super(s);
582 setFont(Res.fontScreen);
583 setForeground(new java.awt.Color(0xFFA300));
584 }
585 }
586
587 ChannelScreen(final Channel channel) {
588 super(Res.gfxChannelScreen);
589 setPixmapInsets(new Insets(6, 6, 6, 6));
590 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
591
592 this.channel = channel;
593
594 setOpaque(false);
595
596 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
597
598 btnInstr.setAlignmentX(CENTER_ALIGNMENT);
599 btnInstr.setRolloverEnabled(false);
600 btnInstr.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
601
602 add(btnInstr);
603
604 JPanel p = new JPanel();
605 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
606 p.setAlignmentX(CENTER_ALIGNMENT);
607 p.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
608
609 btnFxSends.setToolTipText(i18n.getButtonLabel("ChannelScreen.btnFxSends.tt"));
610 btnFxSends.addActionListener(new ActionListener() {
611 public void
612 actionPerformed(ActionEvent e) {
613 if(fxSendsDlg != null && fxSendsDlg.isVisible()) {
614 fxSendsDlg.toFront();
615 return;
616 }
617 FxSendsPane p = new FxSendsPane(channel.getModel());
618 int id = channel.getModel().getChannelId();
619 fxSendsDlg = new InformationDialog(CC.getMainFrame(), p);
620 fxSendsDlg.setTitle(i18n.getLabel("FxSendsDlg.title", id));
621 fxSendsDlg.setModal(false);
622 fxSendsDlg.showCloseButton(false);
623 fxSendsDlg.setVisible(true);
624 }
625 });
626
627 p.add(btnFxSends);
628
629 p.add(Box.createRigidArea(new Dimension(6, 0)));
630
631 btnEngine.setIcon(Res.iconEngine12);
632 p.add(btnEngine);
633 //p.add(new Label("|"));
634
635 //p.add(Box.createRigidArea(new Dimension(6, 0)));
636
637 //p.add(btnReset);
638
639 p.add(Box.createGlue());
640
641 p.add(lStreams);
642 p.add(new Label("/"));
643 p.add(lVoices);
644
645 p.add(Box.createRigidArea(new Dimension(12, 0)));
646
647 lVolume.setIcon(Res.iconVolume14);
648 lVolume.setAlignmentX(RIGHT_ALIGNMENT);
649 updateVolumeInfo(100);
650 dimVolume = lVolume.getPreferredSize();
651 p.add(lVolume);
652 p.setPreferredSize(new Dimension(250, p.getPreferredSize().height));
653 p.setMinimumSize(p.getPreferredSize());
654 p.setMaximumSize(p.getPreferredSize());
655
656 //btnInstr.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
657 p.setOpaque(false);
658 add(p);
659
660
661 setPreferredSize(new Dimension(270, 48));
662 setMinimumSize(getPreferredSize());
663 setMaximumSize(getPreferredSize());
664
665 createEngineMenu();
666 installListeners();
667 }
668
669 private void
670 createEngineMenu() {
671 for(final SamplerEngine engine : CC.getSamplerModel().getEngines()) {
672 JMenuItem mi = new JMenuItem(engine.getDescription());
673
674 mi.addActionListener(new ActionListener() {
675 public void
676 actionPerformed(ActionEvent e) {
677 channel.getModel().setBackendEngineType(engine.getName());
678 }
679 });
680
681 menuEngines.add(mi);
682 }
683 }
684
685 private void
686 installListeners() {
687 btnInstr.addActionListener(new ActionListener() {
688 public void
689 actionPerformed(ActionEvent e) { loadInstrument(); }
690 });
691
692 btnEngine.addActionListener(new ActionListener() {
693 public void
694 actionPerformed(ActionEvent e) {
695 int y = btnEngine.getHeight() + 1;
696 menuEngines.show(btnEngine, 0, y);
697 }
698 });
699 }
700
701 private void
702 loadInstrument() {
703 JSInstrumentChooser dlg = new JSInstrumentChooser(CC.getMainFrame());
704 dlg.setVisible(true);
705
706 if(!dlg.isCancelled()) {
707 SamplerChannelModel m = channel.getModel();
708 m.loadBackendInstrument(dlg.getInstrumentFile(), dlg.getInstrumentIndex());
709 }
710 }
711
712 protected void
713 updateScreenInfo(SamplerChannel sc) {
714 int status = sc.getInstrumentStatus();
715 if(status >= 0 && status < 100) {
716 btnInstr.setText(i18n.getLabel("ChannelScreen.loadingInstrument", status));
717 } else if(status == -1) {
718 btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr"));
719 } else if(status < -1) {
720 btnInstr.setText(i18n.getLabel("ChannelScreen.errorLoadingInstrument"));
721 } else {
722 if(sc.getInstrumentName() != null) btnInstr.setText(sc.getInstrumentName());
723 else btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr"));
724 }
725
726 if(sc.getEngine() != null) {
727 String s = sc.getEngine().getDescription();
728 if(!s.equals(btnEngine.getText())) btnEngine.setText(s);
729 }
730
731 }
732
733 protected void
734 updateVolumeInfo(int volume) {
735 lVolume.setText(i18n.getLabel("ChannelScreen.volume", volume));
736 lVolume.setMinimumSize(dimVolume);
737 lVolume.setPreferredSize(dimVolume);
738
739 }
740
741 /**
742 * Updates the number of active disk streams.
743 * @param count The new number of active disk streams.
744 */
745 protected void
746 updateStreamCount(int count) {
747 Dimension d = lStreams.getPreferredSize();
748 lStreams.setText(count == 0 ? "--" : String.valueOf(count));
749 d = JuifeUtils.getUnionSize(d, lStreams.getPreferredSize());
750 lStreams.setMinimumSize(d);
751 lStreams.setPreferredSize(d);
752 lStreams.setMaximumSize(d);
753 }
754
755 /**
756 * Updates the number of active voices.
757 * @param count The new number of active voices.
758 */
759 protected void
760 updateVoiceCount(int count) {
761 Dimension d = lVoices.getPreferredSize();
762 lVoices.setText(count == 0 ? "--" : String.valueOf(count));
763 d = JuifeUtils.getUnionSize(d, lVoices.getPreferredSize());
764 lVoices.setMinimumSize(d);
765 lVoices.setPreferredSize(d);
766 lVoices.setMaximumSize(d);
767 }
768
769 class FxSendsPane extends JSFxSendsPane {
770 FxSendsPane(SamplerChannelModel model) {
771 super(model);
772
773 actionAddFxSend.putValue(Action.SMALL_ICON, Res.iconNew16);
774 actionRemoveFxSend.putValue(Action.SMALL_ICON, Res.iconDelete16);
775 }
776
777 protected JToolBar
778 createToolBar() {
779 JToolBar tb = new JToolBar();
780 Dimension d = new Dimension(Short.MAX_VALUE, tb.getPreferredSize().height);
781 tb.setMaximumSize(d);
782 tb.setFloatable(false);
783 tb.setAlignmentX(JPanel.RIGHT_ALIGNMENT);
784
785 tb.add(new ToolbarButton(actionAddFxSend));
786 tb.add(new ToolbarButton(actionRemoveFxSend));
787
788 return tb;
789 }
790 }
791
792 static class ScreenButton extends JButton {
793 ScreenButton(String s) {
794 super(s);
795 setContentAreaFilled(false);
796 setFocusPainted(false);
797 setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
798 setMargin(new Insets(0, 0, 0, 0));
799
800 putClientProperty (
801 SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, Boolean.TRUE
802 );
803
804 putClientProperty (
805 SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, Boolean.TRUE
806 );
807
808 putClientProperty(SubstanceLookAndFeel.FLAT_PROPERTY, Boolean.TRUE);
809
810 FadeConfigurationManager.getInstance().disallowFades(FadeKind.ROLLOVER, this);
811
812 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
813 setFont(Res.fontScreen);
814 setForeground(new java.awt.Color(0xFFA300));
815 }
816 }
817 }
818
819 class ChannelOptions extends JXCollapsiblePane {
820 private final Channel channel;
821 private MidiDeviceModel midiDevice = null;
822
823 private final JComboBox cbMidiDevice = new FantasiaComboBox();
824 private final JComboBox cbMidiPort = new FantasiaComboBox();
825 private final JComboBox cbMidiChannel = new FantasiaComboBox();
826 private final JComboBox cbInstrumentMap = new FantasiaComboBox();
827 private final JComboBox cbAudioDevice = new FantasiaComboBox();
828
829 private final PixmapButton btnChannelRouting;
830
831 private boolean update = false;
832
833 private final SamplerListener samplerListener;
834 private final MapListListener mapListListener = new MapListListener();
835
836 private class NoMap {
837 public String
838 toString() { return "[None]"; }
839 }
840
841 private NoMap noMap = new NoMap();
842
843 private class DefaultMap {
844 public String
845 toString() { return "[Default]"; }
846 }
847
848 private DefaultMap defaultMap = new DefaultMap();
849
850 ChannelOptions(final Channel channel) {
851 setAnimated(false);
852 setCollapsed(true);
853 setAnimated(preferences().getBoolProperty(ANIMATED));
854
855 preferences().addPropertyChangeListener(ANIMATED, new PropertyChangeListener() {
856 public void
857 propertyChange(PropertyChangeEvent e) {
858 setAnimated(preferences().getBoolProperty(ANIMATED));
859 }
860 });
861
862 PixmapPane bgp = new PixmapPane(Res.gfxChannelOptions);
863 bgp.setPixmapInsets(new Insets(1, 1, 1, 1));
864
865 this.channel = channel;
866
867 bgp.setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 4));
868 bgp.setLayout(new BoxLayout(bgp, BoxLayout.X_AXIS));
869
870 bgp.setPreferredSize(new Dimension(420, 44));
871 bgp.setMinimumSize(getPreferredSize());
872 bgp.setMaximumSize(getPreferredSize());
873
874 JPanel p = new JPanel();
875 p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
876 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
877 JLabel l = new JLabel(Res.gfxMidiInputTitle);
878 l.setAlignmentX(LEFT_ALIGNMENT);
879 p.add(l);
880
881 JPanel p2 = new JPanel();
882 p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
883 p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
884
885 Object o = cbMidiDevice.getRenderer();
886 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
887
888 cbMidiDevice.setPreferredSize(new Dimension(40, 18));
889 cbMidiDevice.setMinimumSize(cbMidiDevice.getPreferredSize());
890 cbMidiDevice.setMaximumSize(cbMidiDevice.getPreferredSize());
891 p2.add(cbMidiDevice);
892
893 p2.add(Box.createRigidArea(new Dimension(3, 0)));
894
895 o = cbMidiPort.getRenderer();
896 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
897
898 cbMidiPort.setPreferredSize(new Dimension(62, 18));
899 cbMidiPort.setMinimumSize(cbMidiPort.getPreferredSize());
900 cbMidiPort.setMaximumSize(cbMidiPort.getPreferredSize());
901 p2.add(cbMidiPort);
902
903 p2.add(Box.createRigidArea(new Dimension(3, 0)));
904
905 o = cbMidiChannel.getRenderer();
906 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
907
908 cbMidiChannel.addItem("All");
909 for(int i = 1; i <= 16; i++) cbMidiChannel.addItem("Channel " + String.valueOf(i));
910 cbMidiChannel.setPreferredSize(new Dimension(80, 18));
911 cbMidiChannel.setMinimumSize(cbMidiChannel.getPreferredSize());
912 cbMidiChannel.setMaximumSize(cbMidiChannel.getPreferredSize());
913
914 p2.add(cbMidiChannel);
915 p2.setAlignmentX(LEFT_ALIGNMENT);
916 p2.setOpaque(false);
917 p.add(p2);
918 p.setBackground(new java.awt.Color(0x818181));
919
920 bgp.add(p);
921
922 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
923
924 p = new JPanel();
925 p.setOpaque(true);
926 p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
927 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
928 l = new JLabel(Res.gfxInstrumentMapTitle);
929 l.setAlignmentX(LEFT_ALIGNMENT);
930 l.setAlignmentX(LEFT_ALIGNMENT);
931 p.add(l);
932
933 p.add(Box.createRigidArea(new Dimension(0, 3)));
934
935 //o = cbInstrumentMap.getRenderer();
936 //if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
937
938 cbInstrumentMap.setPreferredSize(new Dimension(126, 18));
939 cbInstrumentMap.setMinimumSize(cbInstrumentMap.getPreferredSize());
940 cbInstrumentMap.setMaximumSize(cbInstrumentMap.getPreferredSize());
941 cbInstrumentMap.setAlignmentX(LEFT_ALIGNMENT);
942 p.add(cbInstrumentMap);
943 p.setBackground(new java.awt.Color(0x818181));
944 bgp.add(p);
945
946 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
947
948 p = new JPanel();
949 p.setOpaque(true);
950 p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
951 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
952 l = new JLabel(Res.gfxAudioOutputTitle);
953 l.setAlignmentX(LEFT_ALIGNMENT);
954 p.add(l);
955
956 //p.add(Box.createRigidArea(new Dimension(0, 3)));
957
958 p2 = new JPanel();
959 p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
960 p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
961 p2.setOpaque(false);
962 p2.setAlignmentX(LEFT_ALIGNMENT);
963
964 o = cbAudioDevice.getRenderer();
965 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.RIGHT);
966
967 cbAudioDevice.setPreferredSize(new Dimension(40, 18));
968 cbAudioDevice.setMinimumSize(cbAudioDevice.getPreferredSize());
969 cbAudioDevice.setMaximumSize(cbAudioDevice.getPreferredSize());
970
971 p2.add(cbAudioDevice);
972 p2.add(Box.createRigidArea(new Dimension(3, 0)));
973 btnChannelRouting = new PixmapButton(Res.gfxBtnCr, Res.gfxBtnCrRO);
974 btnChannelRouting.setPressedIcon(Res.gfxBtnCrRO);
975 btnChannelRouting.setEnabled(false);
976 btnChannelRouting.setToolTipText(i18n.getLabel("ChannelOptions.routing"));
977
978 btnChannelRouting.addActionListener(new ActionListener() {
979 public void
980 actionPerformed(ActionEvent e) {
981 SamplerChannel c = channel.getChannelInfo();
982 new JSChannelOutputRoutingDlg(CC.getMainFrame(), c).setVisible(true);
983
984 }
985 });
986
987 p2.add(btnChannelRouting);
988
989 p.add(p2);
990 p.setBackground(new java.awt.Color(0x818181));
991 p2 = new JPanel();
992 p2.setLayout(new java.awt.BorderLayout());
993 p.add(p2);
994 bgp.add(p);
995
996 setContentPane(bgp);
997
998 cbMidiDevice.addActionListener(new ActionListener() {
999 public void
1000 actionPerformed(ActionEvent e) { setMidiDevice(); }
1001 });
1002
1003 cbMidiPort.addActionListener(new ActionListener() {
1004 public void
1005 actionPerformed(ActionEvent e) { setMidiPort(); }
1006 });
1007
1008 cbMidiChannel.addActionListener(new ActionListener() {
1009 public void
1010 actionPerformed(ActionEvent e) { setMidiChannel(); }
1011 });
1012
1013 samplerListener = new SamplerAdapter() {
1014 /** Invoked when the default MIDI instrument map is changed. */
1015 public void
1016 defaultMapChanged(SamplerEvent e) {
1017 updateCbInstrumentMapToolTipText();
1018
1019 }
1020 };
1021
1022 CC.getSamplerModel().addSamplerListener(samplerListener);
1023
1024 cbInstrumentMap.addItem(noMap);
1025 cbInstrumentMap.addItem(defaultMap);
1026 for(MidiInstrumentMap map : CC.getSamplerModel().getMidiInstrumentMaps()) {
1027 cbInstrumentMap.addItem(map);
1028 }
1029
1030 int map = channel.getModel().getChannelInfo().getMidiInstrumentMapId();
1031 cbInstrumentMap.setSelectedItem(CC.getSamplerModel().getMidiInstrumentMapById(map));
1032 if(cbInstrumentMap.getSelectedItem() == null) {
1033 if(map == -1) cbInstrumentMap.setSelectedItem(noMap);
1034 else if(map == -2) {
1035 cbInstrumentMap.setSelectedItem(defaultMap);
1036 }
1037 }
1038
1039 updateCbInstrumentMapToolTipText();
1040
1041 if(channel.getModel().getChannelInfo().getEngine() == null) {
1042 cbInstrumentMap.setEnabled(false);
1043 }
1044
1045 cbInstrumentMap.addActionListener(new ActionListener() {
1046 public void
1047 actionPerformed(ActionEvent e) { updateInstrumentMap(); }
1048 });
1049
1050 CC.getSamplerModel().addSamplerChannelListListener(getHandler());
1051 CC.getSamplerModel().addMidiInstrumentMapListListener(mapListListener);
1052
1053 cbAudioDevice.addActionListener(new ActionListener() {
1054 public void
1055 actionPerformed(ActionEvent e) { setBackendAudioDevice(); }
1056 });
1057
1058 channel.getModel().addSamplerChannelListener(new SamplerChannelAdapter() {
1059 public void
1060 channelChanged(SamplerChannelEvent e) { updateChannelProperties(); }
1061 });
1062
1063 CC.getSamplerModel().addMidiDeviceListListener(getHandler());
1064 CC.getSamplerModel().addAudioDeviceListListener(getHandler());
1065
1066 updateMidiDevices();
1067 updateAudioDevices();
1068 updateChannelProperties();
1069 }
1070
1071 /**
1072 * Updates the channel settings. This method is invoked when changes to the
1073 * channel were made.
1074 */
1075 private void
1076 updateChannelProperties() {
1077 SamplerModel sm = CC.getSamplerModel();
1078 SamplerChannel sc = channel.getModel().getChannelInfo();
1079
1080 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1081 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1082
1083 if(isUpdate()) CC.getLogger().warning("Unexpected update state!");
1084
1085 setUpdate(true);
1086
1087 try {
1088 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1089
1090 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1091 btnChannelRouting.setEnabled(am != null);
1092 } catch(Exception x) {
1093 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1094 }
1095
1096 if(sc.getEngine() != null) {
1097 cbInstrumentMap.setEnabled(true);
1098 int id = sc.getMidiInstrumentMapId();
1099 Object o;
1100 if(id == -2) o = defaultMap;
1101 else if(id == -1) o = noMap;
1102 else o = CC.getSamplerModel().getMidiInstrumentMapById(id);
1103
1104 if(cbInstrumentMap.getSelectedItem() != o) {
1105 cbInstrumentMap.setSelectedItem(o);
1106 }
1107 } else {
1108 cbInstrumentMap.setSelectedItem(noMap);
1109 cbInstrumentMap.setEnabled(false);
1110 }
1111
1112 setUpdate(false);
1113 }
1114
1115 /**
1116 * Updates the MIDI device list.
1117 */
1118 private void
1119 updateMidiDevices() {
1120 SamplerModel sm = CC.getSamplerModel();
1121 SamplerChannel sc = channel.getModel().getChannelInfo();
1122
1123 setUpdate(true);
1124
1125 try {
1126 cbMidiDevice.removeAllItems();
1127
1128 for(MidiDeviceModel m : sm.getMidiDevices())
1129 cbMidiDevice.addItem(m.getDeviceInfo());
1130
1131 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1132 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1133 } catch(Exception x) {
1134 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1135 }
1136
1137 setUpdate(false);
1138 }
1139
1140
1141 private void
1142 updateInstrumentMap() {
1143 updateCbInstrumentMapToolTipText();
1144
1145 int id = channel.getModel().getChannelInfo().getMidiInstrumentMapId();
1146 Object o = cbInstrumentMap.getSelectedItem();
1147 if(o == null && id == -1) return;
1148
1149 int cbId;
1150 if(o == null || o == noMap) cbId = -1;
1151 else if(o == defaultMap) cbId = -2;
1152 else cbId = ((MidiInstrumentMap)o).getMapId();
1153
1154 if(cbId == id) return;
1155
1156 channel.getModel().setBackendMidiInstrumentMap(cbId);
1157 }
1158
1159 private void
1160 updateCbInstrumentMapToolTipText() {
1161 if(cbInstrumentMap.getSelectedItem() != defaultMap) {
1162 cbInstrumentMap.setToolTipText(null);
1163 return;
1164 }
1165
1166 MidiInstrumentMap m = CC.getSamplerModel().getDefaultMidiInstrumentMap();
1167 if(m != null) {
1168 String s = i18n.getLabel("Channel.ttDefault", m.getName());
1169 cbInstrumentMap.setToolTipText(s);
1170 } else {
1171 cbInstrumentMap.setToolTipText(null);
1172 }
1173 }
1174
1175 /**
1176 * Updates the audio device list.
1177 */
1178 private void
1179 updateAudioDevices() {
1180 SamplerModel sm = CC.getSamplerModel();
1181 SamplerChannel sc = channel.getModel().getChannelInfo();
1182
1183 setUpdate(true);
1184
1185 try {
1186 cbAudioDevice.removeAllItems();
1187
1188 for(AudioDeviceModel m : sm.getAudioDevices())
1189 cbAudioDevice.addItem(m.getDeviceInfo());
1190
1191 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1192 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1193 } catch(Exception x) {
1194 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1195 }
1196
1197 setUpdate(false);
1198 }
1199
1200 private void
1201 setMidiDevice() {
1202 MidiInputDevice mid = (MidiInputDevice)cbMidiDevice.getSelectedItem();
1203
1204 if(!isUpdate()) {
1205 if(mid != null) {
1206 channel.getModel().setBackendMidiInputDevice(mid.getDeviceId());
1207 }
1208
1209 return;
1210 }
1211
1212 if(midiDevice != null) midiDevice.removeMidiDeviceListener(getHandler());
1213
1214 cbMidiPort.removeAllItems();
1215
1216 if(mid == null) {
1217 midiDevice = null;
1218 cbMidiPort.setEnabled(false);
1219
1220 cbMidiChannel.setSelectedItem(null);
1221 cbMidiChannel.setEnabled(false);
1222 } else {
1223 midiDevice = CC.getSamplerModel().getMidiDeviceById(mid.getDeviceId());
1224 if(midiDevice != null) midiDevice.addMidiDeviceListener(getHandler());
1225
1226 cbMidiPort.setEnabled(true);
1227
1228 MidiPort[] ports = mid.getMidiPorts();
1229 for(MidiPort port : ports) cbMidiPort.addItem(port);
1230
1231 int p = channel.getModel().getChannelInfo().getMidiInputPort();
1232 cbMidiPort.setSelectedItem(p >= 0 && p < ports.length ? ports[p] : null);
1233
1234 cbMidiChannel.setEnabled(true);
1235 int c = channel.getModel().getChannelInfo().getMidiInputChannel();
1236 cbMidiChannel.setSelectedItem(c == -1 ? "All" : "Channel " + (c + 1));
1237 }
1238 }
1239
1240 private void
1241 setMidiPort() {
1242 if(isUpdate()) return;
1243
1244 channel.getModel().setBackendMidiInputPort(cbMidiPort.getSelectedIndex());
1245 }
1246
1247 private void
1248 setMidiChannel() {
1249 if(isUpdate()) return;
1250
1251 Object o = cbMidiChannel.getSelectedItem();
1252 if(o == null) return;
1253 String s = o.toString();
1254
1255 int c = s.equals("All") ? -1 : Integer.parseInt(s.substring(8)) - 1;
1256
1257 channel.getModel().setBackendMidiInputChannel(c);
1258 }
1259
1260 private void
1261 setBackendAudioDevice() {
1262 if(isUpdate()) return;
1263 AudioOutputDevice dev = (AudioOutputDevice)cbAudioDevice.getSelectedItem();
1264 if(dev != null) channel.getModel().setBackendAudioOutputDevice(dev.getDeviceId());
1265 }
1266
1267 /**
1268 * Determines whether the currently processed changes are due to update.
1269 * @return <code>true</code> if the currently processed changes are due to update and
1270 * <code>false</code> if the currently processed changes are due to user input.
1271 */
1272 private boolean
1273 isUpdate() { return update; }
1274
1275 /**
1276 * Sets whether the currently processed changes are due to update.
1277 * @param b Specify <code>true</code> to indicate that the currently
1278 * processed changes are due to update; <code>false</code>
1279 * indicates that the currently processed changes are due to user input.
1280 */
1281 private void
1282 setUpdate(boolean b) { update = b; }
1283
1284 private final Handler handler = new Handler();
1285
1286 private Handler
1287 getHandler() { return handler; }
1288
1289 private class Handler implements MidiDeviceListListener, ListListener<AudioDeviceModel>,
1290 SamplerChannelListListener, MidiDeviceListener {
1291 /**
1292 * Invoked when a new MIDI device is created.
1293 * @param e A <code>MidiDeviceListEvent</code>
1294 * instance providing the event information.
1295 */
1296 public void
1297 deviceAdded(MidiDeviceListEvent e) {
1298 cbMidiDevice.addItem(e.getMidiDeviceModel().getDeviceInfo());
1299 }
1300
1301 /**
1302 * Invoked when a MIDI device is removed.
1303 * @param e A <code>MidiDeviceListEvent</code>
1304 * instance providing the event information.
1305 */
1306 public void
1307 deviceRemoved(MidiDeviceListEvent e) {
1308 cbMidiDevice.removeItem(e.getMidiDeviceModel().getDeviceInfo());
1309 }
1310
1311 /**
1312 * Invoked when a new audio device is created.
1313 * @param e An <code>AudioDeviceListEvent</code>
1314 * instance providing the event information.
1315 */
1316 public void
1317 entryAdded(ListEvent<AudioDeviceModel> e) {
1318 cbAudioDevice.addItem(e.getEntry().getDeviceInfo());
1319 }
1320
1321 /**
1322 * Invoked when an audio device is removed.
1323 * @param e An <code>AudioDeviceListEvent</code>
1324 * instance providing the event information.
1325 */
1326 public void
1327 entryRemoved(ListEvent<AudioDeviceModel> e) {
1328 cbAudioDevice.removeItem(e.getEntry().getDeviceInfo());
1329 }
1330
1331 /**
1332 * Invoked when a new sampler channel is created.
1333 * @param e A <code>SamplerChannelListEvent</code>
1334 * instance providing the event information.
1335 */
1336 public void
1337 channelAdded(SamplerChannelListEvent e) { }
1338
1339 /**
1340 * Invoked when a sampler channel is removed.
1341 * @param e A <code>SamplerChannelListEvent</code>
1342 * instance providing the event information.
1343 */
1344 public void
1345 channelRemoved(SamplerChannelListEvent e) {
1346 // Some cleanup when the channel is removed.
1347 if(e.getChannelModel().getChannelId() == channel.getChannelId()) {
1348 SamplerModel sm = CC.getSamplerModel();
1349
1350 sm.removeMidiDeviceListListener(getHandler());
1351 sm.removeAudioDeviceListListener(getHandler());
1352 sm.removeMidiInstrumentMapListListener(mapListListener);
1353 sm.removeSamplerListener(samplerListener);
1354 sm.removeSamplerChannelListListener(getHandler());
1355
1356 if(midiDevice != null) {
1357 midiDevice.removeMidiDeviceListener(getHandler());
1358 }
1359 }
1360 }
1361
1362 public void
1363 settingsChanged(MidiDeviceEvent e) {
1364 if(isUpdate()) {
1365 CC.getLogger().warning("Invalid update state");
1366 return;
1367 }
1368
1369 setUpdate(true);
1370 int idx = cbMidiPort.getSelectedIndex();
1371 MidiInputDevice d = e.getMidiDeviceModel().getDeviceInfo();
1372
1373 cbMidiPort.removeAllItems();
1374 for(MidiPort port : d.getMidiPorts()) cbMidiPort.addItem(port);
1375
1376 if(idx >= cbMidiPort.getModel().getSize()) idx = 0;
1377
1378 setUpdate(false);
1379
1380 if(cbMidiPort.getModel().getSize() > 0) cbMidiPort.setSelectedIndex(idx);
1381 }
1382 }
1383
1384 private class MapListListener implements ListListener<MidiInstrumentMap> {
1385 /** Invoked when a new MIDI instrument map is added to a list. */
1386 public void
1387 entryAdded(ListEvent<MidiInstrumentMap> e) {
1388 cbInstrumentMap.insertItemAt(e.getEntry(), cbInstrumentMap.getItemCount());
1389 boolean b = channel.getModel().getChannelInfo().getEngine() != null;
1390 if(b && !cbInstrumentMap.isEnabled()) cbInstrumentMap.setEnabled(true);
1391 }
1392
1393 /** Invoked when a new MIDI instrument map is removed from a list. */
1394 public void
1395 entryRemoved(ListEvent<MidiInstrumentMap> e) {
1396 cbInstrumentMap.removeItem(e.getEntry());
1397 if(cbInstrumentMap.getItemCount() == 0) { // TODO: ?
1398 cbInstrumentMap.setSelectedItem(noMap);
1399 cbInstrumentMap.setEnabled(false);
1400 }
1401 }
1402 }
1403 }

  ViewVC Help
Powered by ViewVC