/[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 1540 - (hide annotations) (download)
Mon Dec 3 23:22:02 2007 UTC (16 years, 4 months ago) by iliev
File size: 48001 byte(s)
* Fantasia: by default the volume values are now shown in decibels
* Implemented support for retrieving instrument information
  from instrument files
* Some bugfixes and enhancements

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

  ViewVC Help
Powered by ViewVC