/[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 1688 - (hide annotations) (download)
Thu Feb 14 16:52:36 2008 UTC (16 years, 2 months ago) by iliev
File size: 48405 byte(s)
* Implemented a backend list with option to manually choose a backend
  to connect on startup(Edit/Preferences, then click the `Backend' tab)
  and option to change the backend without restarting JSampler
  (Actions/Change Backend or Ctrl + B)

* Added confirmation messages for removing sampler channels and
  audio/MIDI devices (Edit/Preferences, then click the `View' tab)

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

  ViewVC Help
Powered by ViewVC