/[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 1343 - (show annotations) (download)
Tue Sep 11 15:38:28 2007 UTC (16 years, 7 months ago) by iliev
File size: 45761 byte(s)
* JS Classic: Added new button to sampler channels
  for starting an instrument editor
* The last used instrument selection method is now
  saved for the next session
* Fantasia: Removed the lock border from non-editable
  text fields in properties panes and LS Console

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 btnEditInstr.setToolTipText(i18n.getLabel("ChannelScreen.btnEditInstr.tt"));
885 sbbEditInstr.setVisible(false);
886 setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 6));
887
888 update();
889 }
890
891 public void
892 update() {
893 int a = btnInstr.getMinimumSize().width;
894 int b = 0;
895 if(sbbEditInstr.isVisible()) b = sbbEditInstr.getPreferredSize().width;
896
897 int max = 254 - b;
898 if(a > max) a = max;
899
900 int h = btnInstr.getPreferredSize().height;
901 btnInstr.setPreferredSize(new Dimension(a, h));
902 h = btnInstr.getMaximumSize().height;
903 btnInstr.setMaximumSize(new Dimension(a, h));
904
905
906 int i = (254 - btnInstr.getPreferredSize().width) / 2;
907
908 int j = i;
909 if(sbbEditInstr.isVisible()) j -= sbbEditInstr.getPreferredSize().width;
910 if(i < 0 || j < 0) i = j = 0;
911
912 Dimension d = new Dimension(i, 1);
913 leftPane.setMinimumSize(d);
914 leftPane.setPreferredSize(d);
915 leftPane.setMaximumSize(d);
916
917 d = new Dimension(j, 1);
918 rightPane.setMinimumSize(d);
919 rightPane.setPreferredSize(d);
920 rightPane.setMaximumSize(d);
921
922 validate();
923 }
924 }
925
926 class FxSendsPane extends JSFxSendsPane {
927 FxSendsPane(SamplerChannelModel model) {
928 super(model);
929
930 actionAddFxSend.putValue(Action.SMALL_ICON, Res.iconNew16);
931 actionRemoveFxSend.putValue(Action.SMALL_ICON, Res.iconDelete16);
932 }
933
934 protected JToolBar
935 createToolBar() {
936 JToolBar tb = new JToolBar();
937 Dimension d = new Dimension(Short.MAX_VALUE, tb.getPreferredSize().height);
938 tb.setMaximumSize(d);
939 tb.setFloatable(false);
940 tb.setAlignmentX(JPanel.RIGHT_ALIGNMENT);
941
942 tb.add(new ToolbarButton(actionAddFxSend));
943 tb.add(new ToolbarButton(actionRemoveFxSend));
944
945 return tb;
946 }
947 }
948
949 static class ScreenButton extends JButton {
950 ScreenButton(String s) {
951 super(s);
952 setContentAreaFilled(false);
953 setFocusPainted(false);
954 setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
955 setMargin(new Insets(0, 0, 0, 0));
956
957 putClientProperty (
958 SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, Boolean.TRUE
959 );
960
961 putClientProperty (
962 SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, Boolean.TRUE
963 );
964
965 putClientProperty(SubstanceLookAndFeel.FLAT_PROPERTY, Boolean.TRUE);
966
967 FadeConfigurationManager.getInstance().disallowFades(FadeKind.ROLLOVER, this);
968
969 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
970 setFont(Res.fontScreen);
971 setForeground(new java.awt.Color(0xFFA300));
972 }
973 }
974
975 static class ScreenButtonBg extends PixmapPane {
976 ScreenButtonBg(JButton btn) {
977 super(Res.gfxScreenBtnBg);
978 setPixmapInsets(new Insets(4, 4, 4, 4));
979 setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
980 setBorder(BorderFactory.createEmptyBorder(0, 7, 0, 7));
981 add(btn);
982 setPreferredSize(new Dimension(getPreferredSize().width, 13));
983 }
984
985 public Dimension
986 getPreferredSize() {
987 return new Dimension(super.getPreferredSize().width, 13);
988 }
989 }
990
991 private final EventHandler eventHandler = new EventHandler();
992
993 private EventHandler
994 getHandler() { return eventHandler; }
995
996 private class EventHandler extends MouseAdapter implements HierarchyListener {
997 public void
998 mouseEntered(MouseEvent e) {
999 if(!sbbEditInstr.isVisible()) {
1000 sbbEditInstr.setVisible(true);
1001 instrumentPane.update();
1002 }
1003 }
1004
1005 public void
1006 mouseExited(MouseEvent e) {
1007 if(getMousePosition(true) != null) return;
1008 if(sbbEditInstr.isVisible()) {
1009 sbbEditInstr.setVisible(false);
1010 instrumentPane.update();
1011 }
1012 }
1013
1014 /** Called when the hierarchy has been changed. */
1015 public void
1016 hierarchyChanged(HierarchyEvent e) {
1017 if((e.getChangeFlags() & e.SHOWING_CHANGED) == e.SHOWING_CHANGED) {
1018 if(getMousePosition() == null) mouseExited(null);
1019 else mouseEntered(null);
1020 }
1021 }
1022 }
1023 }
1024
1025 class ChannelOptions extends JXCollapsiblePane {
1026 private final Channel channel;
1027 private MidiDeviceModel midiDevice = null;
1028
1029 private final JComboBox cbMidiDevice = new FantasiaComboBox();
1030 private final JComboBox cbMidiPort = new FantasiaComboBox();
1031 private final JComboBox cbMidiChannel = new FantasiaComboBox();
1032 private final JComboBox cbInstrumentMap = new FantasiaComboBox();
1033 private final JComboBox cbAudioDevice = new FantasiaComboBox();
1034
1035 private final PixmapButton btnChannelRouting;
1036
1037 private boolean update = false;
1038
1039 private final SamplerListener samplerListener;
1040 private final MapListListener mapListListener = new MapListListener();
1041
1042 private class NoMap {
1043 public String
1044 toString() { return "[None]"; }
1045 }
1046
1047 private NoMap noMap = new NoMap();
1048
1049 private class DefaultMap {
1050 public String
1051 toString() { return "[Default]"; }
1052 }
1053
1054 private DefaultMap defaultMap = new DefaultMap();
1055
1056 ChannelOptions(final Channel channel) {
1057 setAnimated(false);
1058 setCollapsed(true);
1059 setAnimated(preferences().getBoolProperty(ANIMATED));
1060
1061 preferences().addPropertyChangeListener(ANIMATED, new PropertyChangeListener() {
1062 public void
1063 propertyChange(PropertyChangeEvent e) {
1064 setAnimated(preferences().getBoolProperty(ANIMATED));
1065 }
1066 });
1067
1068 PixmapPane bgp = new PixmapPane(Res.gfxChannelOptions);
1069 bgp.setPixmapInsets(new Insets(1, 1, 1, 1));
1070
1071 this.channel = channel;
1072
1073 bgp.setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 4));
1074 bgp.setLayout(new BoxLayout(bgp, BoxLayout.X_AXIS));
1075
1076 bgp.setPreferredSize(new Dimension(420, 44));
1077 bgp.setMinimumSize(getPreferredSize());
1078 bgp.setMaximumSize(getPreferredSize());
1079
1080 JPanel p = new JPanel();
1081 p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1082 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1083 JLabel l = new JLabel(Res.gfxMidiInputTitle);
1084 l.setAlignmentX(LEFT_ALIGNMENT);
1085 p.add(l);
1086
1087 JPanel p2 = new JPanel();
1088 p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
1089 p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
1090
1091 Object o = cbMidiDevice.getRenderer();
1092 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1093
1094 cbMidiDevice.setPreferredSize(new Dimension(40, 18));
1095 cbMidiDevice.setMinimumSize(cbMidiDevice.getPreferredSize());
1096 cbMidiDevice.setMaximumSize(cbMidiDevice.getPreferredSize());
1097 p2.add(cbMidiDevice);
1098
1099 p2.add(Box.createRigidArea(new Dimension(3, 0)));
1100
1101 o = cbMidiPort.getRenderer();
1102 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1103
1104 cbMidiPort.setPreferredSize(new Dimension(62, 18));
1105 cbMidiPort.setMinimumSize(cbMidiPort.getPreferredSize());
1106 cbMidiPort.setMaximumSize(cbMidiPort.getPreferredSize());
1107 p2.add(cbMidiPort);
1108
1109 p2.add(Box.createRigidArea(new Dimension(3, 0)));
1110
1111 o = cbMidiChannel.getRenderer();
1112 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1113
1114 cbMidiChannel.addItem("All");
1115 for(int i = 1; i <= 16; i++) cbMidiChannel.addItem("Channel " + String.valueOf(i));
1116 cbMidiChannel.setPreferredSize(new Dimension(80, 18));
1117 cbMidiChannel.setMinimumSize(cbMidiChannel.getPreferredSize());
1118 cbMidiChannel.setMaximumSize(cbMidiChannel.getPreferredSize());
1119
1120 p2.add(cbMidiChannel);
1121 p2.setAlignmentX(LEFT_ALIGNMENT);
1122 p2.setOpaque(false);
1123 p.add(p2);
1124 p.setBackground(new java.awt.Color(0x818181));
1125
1126 bgp.add(p);
1127
1128 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
1129
1130 p = new JPanel();
1131 p.setOpaque(true);
1132 p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1133 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1134 l = new JLabel(Res.gfxInstrumentMapTitle);
1135 l.setAlignmentX(LEFT_ALIGNMENT);
1136 l.setAlignmentX(LEFT_ALIGNMENT);
1137 p.add(l);
1138
1139 p.add(Box.createRigidArea(new Dimension(0, 3)));
1140
1141 //o = cbInstrumentMap.getRenderer();
1142 //if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1143
1144 cbInstrumentMap.setPreferredSize(new Dimension(126, 18));
1145 cbInstrumentMap.setMinimumSize(cbInstrumentMap.getPreferredSize());
1146 cbInstrumentMap.setMaximumSize(cbInstrumentMap.getPreferredSize());
1147 cbInstrumentMap.setAlignmentX(LEFT_ALIGNMENT);
1148 p.add(cbInstrumentMap);
1149 p.setBackground(new java.awt.Color(0x818181));
1150 bgp.add(p);
1151
1152 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
1153
1154 p = new JPanel();
1155 p.setOpaque(true);
1156 p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1157 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1158 l = new JLabel(Res.gfxAudioOutputTitle);
1159 l.setAlignmentX(LEFT_ALIGNMENT);
1160 p.add(l);
1161
1162 //p.add(Box.createRigidArea(new Dimension(0, 3)));
1163
1164 p2 = new JPanel();
1165 p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
1166 p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
1167 p2.setOpaque(false);
1168 p2.setAlignmentX(LEFT_ALIGNMENT);
1169
1170 o = cbAudioDevice.getRenderer();
1171 if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.RIGHT);
1172
1173 cbAudioDevice.setPreferredSize(new Dimension(40, 18));
1174 cbAudioDevice.setMinimumSize(cbAudioDevice.getPreferredSize());
1175 cbAudioDevice.setMaximumSize(cbAudioDevice.getPreferredSize());
1176
1177 p2.add(cbAudioDevice);
1178 p2.add(Box.createRigidArea(new Dimension(3, 0)));
1179 btnChannelRouting = new PixmapButton(Res.gfxBtnCr, Res.gfxBtnCrRO);
1180 btnChannelRouting.setPressedIcon(Res.gfxBtnCrRO);
1181 btnChannelRouting.setEnabled(false);
1182 btnChannelRouting.setToolTipText(i18n.getLabel("ChannelOptions.routing"));
1183
1184 btnChannelRouting.addActionListener(new ActionListener() {
1185 public void
1186 actionPerformed(ActionEvent e) {
1187 SamplerChannel c = channel.getChannelInfo();
1188 new JSChannelOutputRoutingDlg(CC.getMainFrame(), c).setVisible(true);
1189
1190 }
1191 });
1192
1193 p2.add(btnChannelRouting);
1194
1195 p.add(p2);
1196 p.setBackground(new java.awt.Color(0x818181));
1197 p2 = new JPanel();
1198 p2.setLayout(new java.awt.BorderLayout());
1199 p.add(p2);
1200 bgp.add(p);
1201
1202 setContentPane(bgp);
1203
1204 cbMidiDevice.addActionListener(new ActionListener() {
1205 public void
1206 actionPerformed(ActionEvent e) { setMidiDevice(); }
1207 });
1208
1209 cbMidiPort.addActionListener(new ActionListener() {
1210 public void
1211 actionPerformed(ActionEvent e) { setMidiPort(); }
1212 });
1213
1214 cbMidiChannel.addActionListener(new ActionListener() {
1215 public void
1216 actionPerformed(ActionEvent e) { setMidiChannel(); }
1217 });
1218
1219 samplerListener = new SamplerAdapter() {
1220 /** Invoked when the default MIDI instrument map is changed. */
1221 public void
1222 defaultMapChanged(SamplerEvent e) {
1223 updateCbInstrumentMapToolTipText();
1224
1225 }
1226 };
1227
1228 CC.getSamplerModel().addSamplerListener(samplerListener);
1229
1230 cbInstrumentMap.addItem(noMap);
1231 cbInstrumentMap.addItem(defaultMap);
1232 for(MidiInstrumentMap map : CC.getSamplerModel().getMidiInstrumentMaps()) {
1233 cbInstrumentMap.addItem(map);
1234 }
1235
1236 int map = channel.getModel().getChannelInfo().getMidiInstrumentMapId();
1237 cbInstrumentMap.setSelectedItem(CC.getSamplerModel().getMidiInstrumentMapById(map));
1238 if(cbInstrumentMap.getSelectedItem() == null) {
1239 if(map == -1) cbInstrumentMap.setSelectedItem(noMap);
1240 else if(map == -2) {
1241 cbInstrumentMap.setSelectedItem(defaultMap);
1242 }
1243 }
1244
1245 updateCbInstrumentMapToolTipText();
1246
1247 if(channel.getModel().getChannelInfo().getEngine() == null) {
1248 cbInstrumentMap.setEnabled(false);
1249 }
1250
1251 cbInstrumentMap.addActionListener(new ActionListener() {
1252 public void
1253 actionPerformed(ActionEvent e) { updateInstrumentMap(); }
1254 });
1255
1256 CC.getSamplerModel().addMidiInstrumentMapListListener(mapListListener);
1257
1258 cbAudioDevice.addActionListener(new ActionListener() {
1259 public void
1260 actionPerformed(ActionEvent e) { setBackendAudioDevice(); }
1261 });
1262
1263 channel.getModel().addSamplerChannelListener(new SamplerChannelAdapter() {
1264 public void
1265 channelChanged(SamplerChannelEvent e) { updateChannelProperties(); }
1266 });
1267
1268 CC.getSamplerModel().addMidiDeviceListListener(getHandler());
1269 CC.getSamplerModel().addAudioDeviceListListener(getHandler());
1270
1271 updateMidiDevices();
1272 updateAudioDevices();
1273 updateChannelProperties();
1274 }
1275
1276 /**
1277 * Updates the channel settings. This method is invoked when changes to the
1278 * channel were made.
1279 */
1280 private void
1281 updateChannelProperties() {
1282 SamplerModel sm = CC.getSamplerModel();
1283 SamplerChannel sc = channel.getModel().getChannelInfo();
1284
1285 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1286 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1287
1288 if(isUpdate()) CC.getLogger().warning("Unexpected update state!");
1289
1290 setUpdate(true);
1291
1292 try {
1293 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1294
1295 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1296 btnChannelRouting.setEnabled(am != null);
1297 } catch(Exception x) {
1298 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1299 }
1300
1301 if(sc.getEngine() != null) {
1302 cbInstrumentMap.setEnabled(true);
1303 int id = sc.getMidiInstrumentMapId();
1304 Object o;
1305 if(id == -2) o = defaultMap;
1306 else if(id == -1) o = noMap;
1307 else o = CC.getSamplerModel().getMidiInstrumentMapById(id);
1308
1309 if(cbInstrumentMap.getSelectedItem() != o) {
1310 cbInstrumentMap.setSelectedItem(o);
1311 }
1312 } else {
1313 cbInstrumentMap.setSelectedItem(noMap);
1314 cbInstrumentMap.setEnabled(false);
1315 }
1316
1317 setUpdate(false);
1318 }
1319
1320 /**
1321 * Updates the MIDI device list.
1322 */
1323 private void
1324 updateMidiDevices() {
1325 SamplerModel sm = CC.getSamplerModel();
1326 SamplerChannel sc = channel.getModel().getChannelInfo();
1327
1328 setUpdate(true);
1329
1330 try {
1331 cbMidiDevice.removeAllItems();
1332
1333 for(MidiDeviceModel m : sm.getMidiDevices())
1334 cbMidiDevice.addItem(m.getDeviceInfo());
1335
1336 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1337 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1338 } catch(Exception x) {
1339 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1340 }
1341
1342 setUpdate(false);
1343 }
1344
1345
1346 private void
1347 updateInstrumentMap() {
1348 updateCbInstrumentMapToolTipText();
1349
1350 int id = channel.getModel().getChannelInfo().getMidiInstrumentMapId();
1351 Object o = cbInstrumentMap.getSelectedItem();
1352 if(o == null && id == -1) return;
1353
1354 int cbId;
1355 if(o == null || o == noMap) cbId = -1;
1356 else if(o == defaultMap) cbId = -2;
1357 else cbId = ((MidiInstrumentMap)o).getMapId();
1358
1359 if(cbId == id) return;
1360
1361 channel.getModel().setBackendMidiInstrumentMap(cbId);
1362 }
1363
1364 private void
1365 updateCbInstrumentMapToolTipText() {
1366 if(cbInstrumentMap.getSelectedItem() != defaultMap) {
1367 cbInstrumentMap.setToolTipText(null);
1368 return;
1369 }
1370
1371 MidiInstrumentMap m = CC.getSamplerModel().getDefaultMidiInstrumentMap();
1372 if(m != null) {
1373 String s = i18n.getLabel("Channel.ttDefault", m.getName());
1374 cbInstrumentMap.setToolTipText(s);
1375 } else {
1376 cbInstrumentMap.setToolTipText(null);
1377 }
1378 }
1379
1380 /**
1381 * Updates the audio device list.
1382 */
1383 private void
1384 updateAudioDevices() {
1385 SamplerModel sm = CC.getSamplerModel();
1386 SamplerChannel sc = channel.getModel().getChannelInfo();
1387
1388 setUpdate(true);
1389
1390 try {
1391 cbAudioDevice.removeAllItems();
1392
1393 for(AudioDeviceModel m : sm.getAudioDevices())
1394 cbAudioDevice.addItem(m.getDeviceInfo());
1395
1396 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1397 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1398 } catch(Exception x) {
1399 CC.getLogger().log(Level.WARNING, "Unkown error", x);
1400 }
1401
1402 setUpdate(false);
1403 }
1404
1405 private void
1406 setMidiDevice() {
1407 MidiInputDevice mid = (MidiInputDevice)cbMidiDevice.getSelectedItem();
1408
1409 if(!isUpdate()) {
1410 if(mid != null) {
1411 channel.getModel().setBackendMidiInputDevice(mid.getDeviceId());
1412 }
1413
1414 return;
1415 }
1416
1417 if(midiDevice != null) midiDevice.removeMidiDeviceListener(getHandler());
1418
1419 cbMidiPort.removeAllItems();
1420
1421 if(mid == null) {
1422 midiDevice = null;
1423 cbMidiPort.setEnabled(false);
1424
1425 cbMidiChannel.setSelectedItem(null);
1426 cbMidiChannel.setEnabled(false);
1427 } else {
1428 midiDevice = CC.getSamplerModel().getMidiDeviceById(mid.getDeviceId());
1429 if(midiDevice != null) midiDevice.addMidiDeviceListener(getHandler());
1430
1431 cbMidiPort.setEnabled(true);
1432
1433 MidiPort[] ports = mid.getMidiPorts();
1434 for(MidiPort port : ports) cbMidiPort.addItem(port);
1435
1436 int p = channel.getModel().getChannelInfo().getMidiInputPort();
1437 cbMidiPort.setSelectedItem(p >= 0 && p < ports.length ? ports[p] : null);
1438
1439 cbMidiChannel.setEnabled(true);
1440 int c = channel.getModel().getChannelInfo().getMidiInputChannel();
1441 cbMidiChannel.setSelectedItem(c == -1 ? "All" : "Channel " + (c + 1));
1442 }
1443 }
1444
1445 private void
1446 setMidiPort() {
1447 if(isUpdate()) return;
1448
1449 channel.getModel().setBackendMidiInputPort(cbMidiPort.getSelectedIndex());
1450 }
1451
1452 private void
1453 setMidiChannel() {
1454 if(isUpdate()) return;
1455
1456 Object o = cbMidiChannel.getSelectedItem();
1457 if(o == null) return;
1458 String s = o.toString();
1459
1460 int c = s.equals("All") ? -1 : Integer.parseInt(s.substring(8)) - 1;
1461
1462 channel.getModel().setBackendMidiInputChannel(c);
1463 }
1464
1465 private void
1466 setBackendAudioDevice() {
1467 if(isUpdate()) return;
1468 AudioOutputDevice dev = (AudioOutputDevice)cbAudioDevice.getSelectedItem();
1469 if(dev != null) channel.getModel().setBackendAudioOutputDevice(dev.getDeviceId());
1470 }
1471
1472 /**
1473 * Determines whether the currently processed changes are due to update.
1474 * @return <code>true</code> if the currently processed changes are due to update and
1475 * <code>false</code> if the currently processed changes are due to user input.
1476 */
1477 private boolean
1478 isUpdate() { return update; }
1479
1480 /**
1481 * Sets whether the currently processed changes are due to update.
1482 * @param b Specify <code>true</code> to indicate that the currently
1483 * processed changes are due to update; <code>false</code>
1484 * indicates that the currently processed changes are due to user input.
1485 */
1486 private void
1487 setUpdate(boolean b) { update = b; }
1488
1489 protected void
1490 onDestroy() {
1491 SamplerModel sm = CC.getSamplerModel();
1492
1493 sm.removeMidiDeviceListListener(getHandler());
1494 sm.removeAudioDeviceListListener(getHandler());
1495 sm.removeMidiInstrumentMapListListener(mapListListener);
1496 sm.removeSamplerListener(samplerListener);
1497
1498 if(midiDevice != null) {
1499 midiDevice.removeMidiDeviceListener(getHandler());
1500 }
1501 }
1502
1503 private final Handler handler = new Handler();
1504
1505 private Handler
1506 getHandler() { return handler; }
1507
1508 private class Handler implements MidiDeviceListListener, ListListener<AudioDeviceModel>,
1509 MidiDeviceListener {
1510 /**
1511 * Invoked when a new MIDI device is created.
1512 * @param e A <code>MidiDeviceListEvent</code>
1513 * instance providing the event information.
1514 */
1515 public void
1516 deviceAdded(MidiDeviceListEvent e) {
1517 cbMidiDevice.addItem(e.getMidiDeviceModel().getDeviceInfo());
1518 }
1519
1520 /**
1521 * Invoked when a MIDI device is removed.
1522 * @param e A <code>MidiDeviceListEvent</code>
1523 * instance providing the event information.
1524 */
1525 public void
1526 deviceRemoved(MidiDeviceListEvent e) {
1527 cbMidiDevice.removeItem(e.getMidiDeviceModel().getDeviceInfo());
1528 }
1529
1530 /**
1531 * Invoked when a new audio device is created.
1532 * @param e An <code>AudioDeviceListEvent</code>
1533 * instance providing the event information.
1534 */
1535 public void
1536 entryAdded(ListEvent<AudioDeviceModel> e) {
1537 cbAudioDevice.addItem(e.getEntry().getDeviceInfo());
1538 }
1539
1540 /**
1541 * Invoked when an audio device is removed.
1542 * @param e An <code>AudioDeviceListEvent</code>
1543 * instance providing the event information.
1544 */
1545 public void
1546 entryRemoved(ListEvent<AudioDeviceModel> e) {
1547 cbAudioDevice.removeItem(e.getEntry().getDeviceInfo());
1548 }
1549
1550 public void
1551 settingsChanged(MidiDeviceEvent e) {
1552 if(isUpdate()) {
1553 CC.getLogger().warning("Invalid update state");
1554 return;
1555 }
1556
1557 setUpdate(true);
1558 int idx = cbMidiPort.getSelectedIndex();
1559 MidiInputDevice d = e.getMidiDeviceModel().getDeviceInfo();
1560
1561 cbMidiPort.removeAllItems();
1562 for(MidiPort port : d.getMidiPorts()) cbMidiPort.addItem(port);
1563
1564 if(idx >= cbMidiPort.getModel().getSize()) idx = 0;
1565
1566 setUpdate(false);
1567
1568 if(cbMidiPort.getModel().getSize() > 0) cbMidiPort.setSelectedIndex(idx);
1569 }
1570 }
1571
1572 private class MapListListener implements ListListener<MidiInstrumentMap> {
1573 /** Invoked when a new MIDI instrument map is added to a list. */
1574 public void
1575 entryAdded(ListEvent<MidiInstrumentMap> e) {
1576 cbInstrumentMap.insertItemAt(e.getEntry(), cbInstrumentMap.getItemCount());
1577 boolean b = channel.getModel().getChannelInfo().getEngine() != null;
1578 if(b && !cbInstrumentMap.isEnabled()) cbInstrumentMap.setEnabled(true);
1579 }
1580
1581 /** Invoked when a new MIDI instrument map is removed from a list. */
1582 public void
1583 entryRemoved(ListEvent<MidiInstrumentMap> e) {
1584 cbInstrumentMap.removeItem(e.getEntry());
1585 if(cbInstrumentMap.getItemCount() == 0) { // TODO: ?
1586 cbInstrumentMap.setSelectedItem(noMap);
1587 cbInstrumentMap.setEnabled(false);
1588 }
1589 }
1590 }
1591 }

  ViewVC Help
Powered by ViewVC