/[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 1318 - (show annotations) (download)
Sat Sep 1 13:46:04 2007 UTC (16 years, 7 months ago) by iliev
File size: 41872 byte(s)
* Fantasia: Added scrollbar to the channels pane
* Implemented automatic scrolling when new channel is
  created to ensure that it is visible on the screen

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

  ViewVC Help
Powered by ViewVC