/[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 1357 - (hide annotations) (download)
Sat Sep 22 17:27:06 2007 UTC (16 years, 7 months ago) by iliev
File size: 46225 byte(s)
* Added options for setting the maximum master and channel volume
  (choose Edit/Preferences)
* Fantasia: Edit instrument button is now shown on the channel
  screen only when there is loaded instrument on that channel
* Fantasia: Added options for showing additional device parameters in
  audio/MIDI device panes (Edit/Preferences, then click the `View' tab)
* Fantasia: Master volume is now fully implemented

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

  ViewVC Help
Powered by ViewVC