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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1341 - (hide 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 iliev 912 /*
2     * JSampler - a java front-end for LinuxSampler
3     *
4 iliev 1285 * Copyright (C) 2005-2007 Grigor Iliev <grigor@grigoriliev.com>
5 iliev 912 *
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 iliev 1285 import java.awt.Graphics;
28 iliev 912 import java.awt.Insets;
29    
30     import java.awt.event.ActionEvent;
31     import java.awt.event.ActionListener;
32 iliev 1341 import java.awt.event.HierarchyEvent;
33     import java.awt.event.HierarchyListener;
34 iliev 912 import java.awt.event.MouseAdapter;
35     import java.awt.event.MouseEvent;
36    
37 iliev 1285 import java.beans.PropertyChangeEvent;
38     import java.beans.PropertyChangeListener;
39    
40 iliev 912 import java.util.logging.Level;
41    
42 iliev 1285 import javax.swing.Action;
43 iliev 912 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 iliev 1285 import javax.swing.JMenuItem;
51 iliev 912 import javax.swing.JPanel;
52 iliev 1285 import javax.swing.JPopupMenu;
53 iliev 912 import javax.swing.JToggleButton;
54 iliev 1285 import javax.swing.JToolBar;
55 iliev 912 import javax.swing.SwingConstants;
56 iliev 1341 import javax.swing.Timer;
57 iliev 912
58     import javax.swing.event.ChangeEvent;
59     import javax.swing.event.ChangeListener;
60    
61     import net.sf.juife.Dial;
62 iliev 1285 import net.sf.juife.InformationDialog;
63 iliev 912 import net.sf.juife.JuifeUtils;
64     import net.sf.juife.TitleBar;
65    
66 iliev 1285 import org.jdesktop.swingx.JXCollapsiblePane;
67    
68 iliev 912 import org.jsampler.AudioDeviceModel;
69     import org.jsampler.CC;
70     import org.jsampler.MidiDeviceModel;
71 iliev 1285 import org.jsampler.MidiInstrumentMap;
72 iliev 912 import org.jsampler.SamplerChannelModel;
73     import org.jsampler.SamplerModel;
74    
75 iliev 1143 import org.jsampler.event.ListEvent;
76     import org.jsampler.event.ListListener;
77 iliev 1285 import org.jsampler.event.MidiDeviceEvent;
78 iliev 912 import org.jsampler.event.MidiDeviceListEvent;
79     import org.jsampler.event.MidiDeviceListListener;
80 iliev 1285 import org.jsampler.event.MidiDeviceListener;
81     import org.jsampler.event.SamplerAdapter;
82 iliev 912 import org.jsampler.event.SamplerChannelAdapter;
83     import org.jsampler.event.SamplerChannelEvent;
84 iliev 1285 import org.jsampler.event.SamplerChannelListEvent;
85     import org.jsampler.event.SamplerChannelListListener;
86 iliev 912 import org.jsampler.event.SamplerChannelListener;
87 iliev 1285 import org.jsampler.event.SamplerEvent;
88     import org.jsampler.event.SamplerListener;
89 iliev 912
90 iliev 1285 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 iliev 912 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 iliev 1285 import static org.jsampler.view.fantasia.FantasiaPrefs.*;
108 iliev 912
109    
110     /**
111     *
112     * @author Grigor Iliev
113     */
114     public class Channel extends org.jsampler.view.JSChannel {
115 iliev 1285 private final JXCollapsiblePane mainPane;
116 iliev 912 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 iliev 1318 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 iliev 912 super(model);
150    
151     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
152 iliev 1285 ChannelPane p = new ChannelPane();
153 iliev 912 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 iliev 1285 JPanel tb = new JPanel();
160 iliev 912 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 iliev 1285 p2.add(new JLabel(Res.gfxMuteTitle));
192 iliev 912 p2.add(btnMute);
193 iliev 1285 p2.add(new JLabel(Res.gfxSoloTitle));
194 iliev 912 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 iliev 1285 JLabel l = new JLabel(Res.gfxVolumeTitle);
206 iliev 912 l.setAlignmentX(JPanel.CENTER_ALIGNMENT);
207     l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
208     p2.add(l);
209 iliev 1285 dialVolume.setDialPixmap(Res.gfxVolumeDial, 30, 330);
210 iliev 912 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 iliev 1285 l = new JLabel(Res.gfxOptionsTitle);
222 iliev 912 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 iliev 1285 mainPane = new JXCollapsiblePane();
242     mainPane.getContentPane().setLayout (
243     new BoxLayout(mainPane.getContentPane(), BoxLayout.Y_AXIS)
244     );
245 iliev 912
246 iliev 1285 mainPane.add(p);
247     mainPane.add(optionsPane);
248    
249     setOpaque(false);
250    
251 iliev 912 getModel().addSamplerChannelListener(getHandler());
252    
253     updateChannelInfo();
254 iliev 1285
255     add(mainPane);
256    
257 iliev 1318 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 iliev 1285 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 iliev 1318
282     if(listener != null) {
283     javax.swing.SwingUtilities.invokeLater(new Runnable() {
284     public void
285     run() { listener.actionPerformed(null); }
286     });
287     }
288 iliev 1341
289     CC.getSamplerModel().addSamplerChannelListListener(getHandler());
290 iliev 912 }
291    
292     private JPanel
293     createVSeparator() {
294 iliev 1285 PixmapPane p = new PixmapPane(Res.gfxVLine);
295 iliev 912 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 iliev 1285 expandChannel() { expandChannel(optionsPane.isAnimated()); }
323 iliev 912
324 iliev 1285 /** 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 iliev 912
335 iliev 1285
336 iliev 912 /** 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 iliev 1143 getModel().setBackendVolume(volume);
356 iliev 912 }
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 iliev 1285 if(sc.isSoloChannel()) btnSolo.setIcon(Res.gfxSoloOn);
370     else btnSolo.setIcon(Res.gfxSoloOff);
371 iliev 912
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 iliev 1285 if(channel.isMutedBySolo()) btnMute.setIcon(Res.gfxMutedBySolo);
389     else if(channel.isMuted()) btnMute.setIcon(Res.gfxMuteOn);
390     else btnMute.setIcon(Res.gfxMuteOff);
391 iliev 912 }
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 iliev 1341 protected void
422     onDestroy() {
423     CC.getSamplerModel().removeSamplerChannelListListener(getHandler());
424    
425     screen.onDestroy();
426     optionsPane.onDestroy();
427     }
428    
429 iliev 912 private final EventHandler eventHandler = new EventHandler();
430    
431     private EventHandler
432     getHandler() { return eventHandler; }
433    
434 iliev 1341 private class EventHandler implements SamplerChannelListener, SamplerChannelListListener {
435 iliev 912 /**
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 iliev 1341
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 iliev 912 }
484    
485    
486 iliev 1285 private class PowerButton extends PixmapToggleButton
487     implements ActionListener, PropertyChangeListener {
488    
489 iliev 912 PowerButton() {
490 iliev 1285 super(Res.gfxPowerOff, Res.gfxPowerOn);
491 iliev 912
492     setSelected(true);
493     addActionListener(this);
494     }
495    
496     public void
497     actionPerformed(ActionEvent e) {
498 iliev 1285 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 iliev 912 }
507    
508 iliev 1285 public void
509     propertyChange(PropertyChangeEvent e) {
510     if(e.getNewValue() == "collapsed") {
511     CC.getSamplerModel().removeBackendChannel(getChannelId());
512     }
513     }
514    
515 iliev 912 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 iliev 1285 super(Res.gfxMuteOff);
522     //setDisabledIcon(Res.gfxMuteSoloDisabled);
523     setDisabledIcon (
524     SubstanceImageCreator.makeTransparent(this, Res.gfxMuteOff, 0.4)
525     );
526 iliev 912 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 iliev 1285 if(sc.isSoloChannel() || !hasSolo) setIcon(Res.gfxMuteOff);
543     else setIcon(Res.gfxMutedBySolo);
544     } else setIcon(Res.gfxMuteOn);
545 iliev 912
546 iliev 1143 Channel.this.getModel().setBackendMute(b);
547 iliev 912 }
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 iliev 1285 super(Res.gfxSoloOff);
556     //setDisabledIcon(Res.gfxMuteSoloDisabled);
557     setDisabledIcon (
558     SubstanceImageCreator.makeTransparent(this, Res.gfxSoloOff, 0.4)
559     );
560 iliev 912 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 iliev 1285 setIcon(Res.gfxSoloOn);
574     if(sc.isMutedBySolo()) btnMute.setIcon(Res.gfxMuteOff);
575 iliev 912 } else {
576 iliev 1285 setIcon(Res.gfxSoloOff);
577 iliev 912 if(!sc.isMuted() && CC.getSamplerModel().getSoloChannelCount() > 1)
578 iliev 1285 btnMute.setIcon(Res.gfxMutedBySolo);
579 iliev 912 }
580    
581 iliev 1143 Channel.this.getModel().setBackendSolo(b);
582 iliev 912 }
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 iliev 1285 super(Res.gfxOptionsOff, Res.gfxOptionsOn);
591     setRolloverIcon(Res.gfxOptionsOffRO);
592     this.setRolloverSelectedIcon(Res.gfxOptionsOnRO);
593 iliev 912 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 iliev 1285 optionsPane.setCollapsed(!show);
610 iliev 912 }
611    
612     public boolean
613 iliev 1143 contains(int x, int y) { return super.contains(x, y) & y < 13; }
614 iliev 912 }
615     }
616    
617 iliev 1285 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 iliev 912 private final Channel channel;
626 iliev 1341
627     private final InstrumentPane instrumentPane;
628 iliev 912 private JButton btnInstr = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnInstr"));
629    
630 iliev 1341 private final JButton btnEditInstr =
631     new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnEditInstr"));
632     private final ScreenButtonBg sbbEditInstr = new ScreenButtonBg(btnEditInstr);
633    
634 iliev 1285 private final JButton btnFxSends =
635     new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnFxSends"));
636 iliev 912
637 iliev 1285 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 iliev 1341 private Timer timer;
651    
652 iliev 1285 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 iliev 912 this.channel = channel;
668    
669 iliev 1285 setOpaque(false);
670 iliev 912
671     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
672    
673     btnInstr.setAlignmentX(CENTER_ALIGNMENT);
674 iliev 1285 btnInstr.setRolloverEnabled(false);
675     btnInstr.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
676 iliev 912
677 iliev 1341 instrumentPane = new InstrumentPane();
678     add(instrumentPane);
679 iliev 912
680     JPanel p = new JPanel();
681     p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
682     p.setAlignmentX(CENTER_ALIGNMENT);
683 iliev 1285 p.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
684 iliev 912
685 iliev 1285 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 iliev 912
703 iliev 1285 p.add(btnFxSends);
704    
705 iliev 912 p.add(Box.createRigidArea(new Dimension(6, 0)));
706    
707 iliev 1285 btnEngine.setIcon(Res.iconEngine12);
708     p.add(btnEngine);
709     //p.add(new Label("|"));
710 iliev 912
711 iliev 1285 //p.add(Box.createRigidArea(new Dimension(6, 0)));
712 iliev 912
713 iliev 1285 //p.add(btnReset);
714 iliev 912
715     p.add(Box.createGlue());
716    
717     p.add(lStreams);
718 iliev 1285 p.add(new Label("/"));
719 iliev 912 p.add(lVoices);
720    
721     p.add(Box.createRigidArea(new Dimension(12, 0)));
722    
723 iliev 1285 lVolume.setIcon(Res.iconVolume14);
724 iliev 912 lVolume.setAlignmentX(RIGHT_ALIGNMENT);
725 iliev 1285 updateVolumeInfo(100);
726     dimVolume = lVolume.getPreferredSize();
727 iliev 912 p.add(lVolume);
728     p.setPreferredSize(new Dimension(250, p.getPreferredSize().height));
729     p.setMinimumSize(p.getPreferredSize());
730     p.setMaximumSize(p.getPreferredSize());
731    
732 iliev 1285 //btnInstr.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
733     p.setOpaque(false);
734 iliev 912 add(p);
735    
736    
737     setPreferredSize(new Dimension(270, 48));
738     setMinimumSize(getPreferredSize());
739     setMaximumSize(getPreferredSize());
740    
741 iliev 1285 createEngineMenu();
742 iliev 912 installListeners();
743     }
744    
745 iliev 1341 protected void
746     onDestroy() { timer.stop(); }
747    
748 iliev 912 private void
749 iliev 1285 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 iliev 912 installListeners() {
766     btnInstr.addActionListener(new ActionListener() {
767     public void
768     actionPerformed(ActionEvent e) { loadInstrument(); }
769     });
770    
771 iliev 1341 btnEditInstr.addActionListener(new ActionListener() {
772     public void
773     actionPerformed(ActionEvent e) {
774     CC.getSamplerModel().editBackendInstrument(channel.getChannelId());
775     }
776     });
777    
778 iliev 1285 btnEngine.addActionListener(new ActionListener() {
779 iliev 912 public void
780 iliev 1143 actionPerformed(ActionEvent e) {
781 iliev 1285 int y = btnEngine.getHeight() + 1;
782     menuEngines.show(btnEngine, 0, y);
783 iliev 1143 }
784 iliev 912 });
785 iliev 1341
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 iliev 912 }
802 iliev 1285
803 iliev 912 private void
804     loadInstrument() {
805 iliev 1285 JSInstrumentChooser dlg = new JSInstrumentChooser(CC.getMainFrame());
806 iliev 912 dlg.setVisible(true);
807    
808     if(!dlg.isCancelled()) {
809     SamplerChannelModel m = channel.getModel();
810 iliev 1285 m.loadBackendInstrument(dlg.getInstrumentFile(), dlg.getInstrumentIndex());
811 iliev 912 }
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 iliev 1341
828     instrumentPane.update();
829 iliev 912
830 iliev 1285 if(sc.getEngine() != null) {
831     String s = sc.getEngine().getDescription();
832     if(!s.equals(btnEngine.getText())) btnEngine.setText(s);
833     }
834 iliev 912
835     }
836    
837     protected void
838     updateVolumeInfo(int volume) {
839     lVolume.setText(i18n.getLabel("ChannelScreen.volume", volume));
840 iliev 1285 lVolume.setMinimumSize(dimVolume);
841     lVolume.setPreferredSize(dimVolume);
842 iliev 912
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 iliev 1341 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 iliev 1285 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 iliev 912 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 iliev 1285
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 iliev 912 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
969 iliev 1285 setFont(Res.fontScreen);
970     setForeground(new java.awt.Color(0xFFA300));
971 iliev 912 }
972     }
973 iliev 1341
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 iliev 912 }
1023    
1024 iliev 1285 class ChannelOptions extends JXCollapsiblePane {
1025 iliev 912 private final Channel channel;
1026 iliev 1285 private MidiDeviceModel midiDevice = null;
1027 iliev 912
1028 iliev 1285 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 iliev 912
1034 iliev 1285 private final PixmapButton btnChannelRouting;
1035    
1036 iliev 912 private boolean update = false;
1037    
1038 iliev 1285 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 iliev 912 this.channel = channel;
1071    
1072 iliev 1285 bgp.setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 4));
1073     bgp.setLayout(new BoxLayout(bgp, BoxLayout.X_AXIS));
1074 iliev 912
1075 iliev 1285 bgp.setPreferredSize(new Dimension(420, 44));
1076     bgp.setMinimumSize(getPreferredSize());
1077     bgp.setMaximumSize(getPreferredSize());
1078 iliev 912
1079     JPanel p = new JPanel();
1080     p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1081     p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1082 iliev 1285 JLabel l = new JLabel(Res.gfxMidiInputTitle);
1083 iliev 912 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 iliev 1285 cbMidiPort.setPreferredSize(new Dimension(62, 18));
1104 iliev 912 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 iliev 1285 p2.setOpaque(false);
1122 iliev 912 p.add(p2);
1123 iliev 1285 p.setBackground(new java.awt.Color(0x818181));
1124 iliev 912
1125 iliev 1285 bgp.add(p);
1126 iliev 912
1127 iliev 1285 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
1128 iliev 912
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 iliev 1285 l = new JLabel(Res.gfxInstrumentMapTitle);
1134 iliev 912 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 iliev 1285 //o = cbInstrumentMap.getRenderer();
1141     //if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1142 iliev 912
1143 iliev 1285 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 iliev 912
1151 iliev 1285 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
1152 iliev 912
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 iliev 1285 l = new JLabel(Res.gfxAudioOutputTitle);
1158 iliev 912 l.setAlignmentX(LEFT_ALIGNMENT);
1159     p.add(l);
1160    
1161 iliev 1285 //p.add(Box.createRigidArea(new Dimension(0, 3)));
1162 iliev 912
1163 iliev 1285 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 iliev 912 o = cbAudioDevice.getRenderer();
1170     if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.RIGHT);
1171    
1172 iliev 1285 cbAudioDevice.setPreferredSize(new Dimension(40, 18));
1173 iliev 912 cbAudioDevice.setMinimumSize(cbAudioDevice.getPreferredSize());
1174     cbAudioDevice.setMaximumSize(cbAudioDevice.getPreferredSize());
1175    
1176 iliev 1285 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 iliev 912
1183 iliev 1285 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 iliev 912 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 iliev 1285 samplerListener = new SamplerAdapter() {
1219     /** Invoked when the default MIDI instrument map is changed. */
1220 iliev 912 public void
1221 iliev 1285 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 iliev 912 });
1254    
1255 iliev 1285 CC.getSamplerModel().addMidiInstrumentMapListListener(mapListListener);
1256    
1257 iliev 912 cbAudioDevice.addActionListener(new ActionListener() {
1258     public void
1259 iliev 1143 actionPerformed(ActionEvent e) { setBackendAudioDevice(); }
1260 iliev 912 });
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 iliev 1204 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1285     AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1286 iliev 912
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 iliev 1285 btnChannelRouting.setEnabled(am != null);
1296 iliev 912 } catch(Exception x) {
1297     CC.getLogger().log(Level.WARNING, "Unkown error", x);
1298     }
1299    
1300 iliev 1285 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 iliev 912 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 iliev 1204 for(MidiDeviceModel m : sm.getMidiDevices())
1333 iliev 912 cbMidiDevice.addItem(m.getDeviceInfo());
1334    
1335 iliev 1204 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1336 iliev 912 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 iliev 1285
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 iliev 912 /**
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 iliev 1204 for(AudioDeviceModel m : sm.getAudioDevices())
1393 iliev 912 cbAudioDevice.addItem(m.getDeviceInfo());
1394    
1395 iliev 1204 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1396 iliev 912 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 iliev 1143 if(mid != null) {
1410     channel.getModel().setBackendMidiInputDevice(mid.getDeviceId());
1411     }
1412    
1413 iliev 912 return;
1414     }
1415    
1416 iliev 1285 if(midiDevice != null) midiDevice.removeMidiDeviceListener(getHandler());
1417    
1418 iliev 912 cbMidiPort.removeAllItems();
1419    
1420     if(mid == null) {
1421 iliev 1285 midiDevice = null;
1422 iliev 912 cbMidiPort.setEnabled(false);
1423    
1424     cbMidiChannel.setSelectedItem(null);
1425     cbMidiChannel.setEnabled(false);
1426     } else {
1427 iliev 1285 midiDevice = CC.getSamplerModel().getMidiDeviceById(mid.getDeviceId());
1428     if(midiDevice != null) midiDevice.addMidiDeviceListener(getHandler());
1429    
1430 iliev 912 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 iliev 1143 channel.getModel().setBackendMidiInputPort(cbMidiPort.getSelectedIndex());
1449 iliev 912 }
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 iliev 1143 channel.getModel().setBackendMidiInputChannel(c);
1462 iliev 912 }
1463    
1464     private void
1465 iliev 1143 setBackendAudioDevice() {
1466 iliev 912 if(isUpdate()) return;
1467     AudioOutputDevice dev = (AudioOutputDevice)cbAudioDevice.getSelectedItem();
1468 iliev 1143 if(dev != null) channel.getModel().setBackendAudioOutputDevice(dev.getDeviceId());
1469 iliev 912 }
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 iliev 1341 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 iliev 912 private final Handler handler = new Handler();
1503    
1504     private Handler
1505     getHandler() { return handler; }
1506    
1507 iliev 1285 private class Handler implements MidiDeviceListListener, ListListener<AudioDeviceModel>,
1508 iliev 1341 MidiDeviceListener {
1509 iliev 912 /**
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 iliev 1143 entryAdded(ListEvent<AudioDeviceModel> e) {
1536     cbAudioDevice.addItem(e.getEntry().getDeviceInfo());
1537 iliev 912 }
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 iliev 1143 entryRemoved(ListEvent<AudioDeviceModel> e) {
1546     cbAudioDevice.removeItem(e.getEntry().getDeviceInfo());
1547 iliev 912 }
1548 iliev 1285
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 iliev 912 }
1570 iliev 1285
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 iliev 912 }

  ViewVC Help
Powered by ViewVC