/[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 1341 - (show annotations) (download)
Mon Sep 10 22:29:09 2007 UTC (16 years, 7 months ago) by iliev
File size: 45681 byte(s)
* Fantasia: Added button to the channel screen for starting an instrument
  editor (point the mouse cursor over the channel screen and click 'Edit')

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

  ViewVC Help
Powered by ViewVC