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

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

  ViewVC Help
Powered by ViewVC