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

  ViewVC Help
Powered by ViewVC