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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1778 - (hide annotations) (download)
Sun Sep 28 20:38:36 2008 UTC (15 years, 7 months ago) by iliev
File size: 16032 byte(s)
* Fantasia: Improved look and feel
* Fantasia: Added buttons for increasing/decreasing the key number
  of the MIDI keyboard (Ctrl+Up Arrow/Ctrl+Down Arrow)
* Fantasia: Added buttons for scrolling left/right on the MIDI keyboard
  (Ctrl+Left Arrow/Ctrl+Right Arrow)
* Added key bindings for triggering MIDI notes using the computer keyboard
  (from a to ' for the white keys and from 0 to 7 for changing the octaves)
* Notes are now triggered when dragging the mouse over the MIDI keyboard

1 iliev 1776 /*
2     * JSampler - a java front-end for LinuxSampler
3     *
4     * Copyright (C) 2005-2008 Grigor Iliev <grigor@grigoriliev.com>
5     *
6     * This file is part of JSampler.
7     *
8     * JSampler is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License version 2
10     * as published by the Free Software Foundation.
11     *
12     * JSampler is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with JSampler; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20     * MA 02111-1307 USA
21     */
22    
23     package org.jsampler.view.fantasia;
24    
25 iliev 1778 import java.awt.AlphaComposite;
26     import java.awt.Color;
27     import java.awt.Composite;
28     import java.awt.Dimension;
29     import java.awt.GradientPaint;
30     import java.awt.Graphics;
31     import java.awt.Graphics2D;
32     import java.awt.GridBagConstraints;
33     import java.awt.GridBagLayout;
34 iliev 1776 import java.awt.Insets;
35 iliev 1778 import java.awt.Paint;
36     import java.awt.RenderingHints;
37 iliev 1776
38 iliev 1778 import java.awt.event.ActionEvent;
39     import java.awt.event.ActionListener;
40     import java.awt.event.FocusEvent;
41     import java.awt.event.FocusListener;
42     import java.awt.event.MouseEvent;
43     import java.awt.event.MouseAdapter;
44    
45     import java.awt.geom.Line2D;
46     import java.awt.geom.Rectangle2D;
47    
48 iliev 1776 import java.beans.PropertyChangeEvent;
49     import java.beans.PropertyChangeListener;
50    
51     import javax.swing.BorderFactory;
52 iliev 1778 import javax.swing.Box;
53     import javax.swing.BoxLayout;
54     import javax.swing.ImageIcon;
55     import javax.swing.JButton;
56     import javax.swing.JPanel;
57     import javax.swing.JToggleButton;
58 iliev 1776
59     import javax.swing.event.ListSelectionEvent;
60     import javax.swing.event.ListSelectionListener;
61    
62     import net.sf.juife.event.TaskEvent;
63     import net.sf.juife.event.TaskListener;
64    
65     import org.jsampler.CC;
66     import org.jsampler.SamplerChannelModel;
67    
68     import org.jsampler.event.SamplerChannelAdapter;
69     import org.jsampler.event.SamplerChannelEvent;
70     import org.jsampler.event.SamplerChannelListListener;
71     import org.jsampler.event.SamplerChannelListEvent;
72    
73     import org.jsampler.view.JSChannel;
74     import org.jsampler.view.std.JSPianoRoll;
75    
76     import org.linuxsampler.lscp.Instrument;
77 iliev 1778 import org.linuxsampler.lscp.SamplerChannel;
78 iliev 1776
79     import org.linuxsampler.lscp.event.MidiDataEvent;
80     import org.linuxsampler.lscp.event.MidiDataListener;
81    
82 iliev 1778 import static javax.swing.Action.SMALL_ICON;
83 iliev 1776 import static org.jsampler.task.Global.GetFileInstrument;
84 iliev 1778 import static org.jsampler.view.fantasia.FantasiaI18n.i18n;
85 iliev 1776
86     /**
87     *
88     * @author Grigor Iliev
89     */
90 iliev 1778 public class PianoKeyboardPane extends FantasiaPanel
91 iliev 1776 implements ListSelectionListener, SamplerChannelListListener {
92    
93 iliev 1778 protected final JToggleButton btnPower = new PowerButton();
94     private final FantasiaLabel lDisplay = new FantasiaLabel(" ", true);
95 iliev 1776 private final JSPianoRoll pianoRoll = new JSPianoRoll();
96     private SamplerChannelModel channel = null;
97    
98     private String file = null;
99     private int index = -1;
100    
101     public
102     PianoKeyboardPane() {
103 iliev 1778 pianoRoll.actionDecreaseKeyNumber.putValue(SMALL_ICON, Res.gfxBtnDecrease);
104     pianoRoll.actionIncreaseKeyNumber.putValue(SMALL_ICON, Res.gfxBtnIncrease);
105     pianoRoll.actionScrollLeft.putValue(SMALL_ICON, Res.gfxBtnScrollLeft);
106     pianoRoll.actionScrollRight.putValue(SMALL_ICON, Res.gfxBtnScrollRight);
107    
108 iliev 1776 setOpaque(false);
109    
110 iliev 1778 GridBagLayout gridbag = new GridBagLayout();
111     GridBagConstraints c = new GridBagConstraints();
112 iliev 1776
113 iliev 1778 setLayout(gridbag);
114 iliev 1776
115 iliev 1778 setBorder(BorderFactory.createEmptyBorder(0, 3, 5, 3));
116    
117     c.fill = GridBagConstraints.NONE;
118    
119     c.gridx = 0;
120     c.gridy = 0;
121     c.anchor = GridBagConstraints.NORTHWEST;
122     c.insets = new Insets(3, 3, 3, 3);
123     gridbag.setConstraints(btnPower, c);
124     add(btnPower);
125    
126     JPanel p = createVSeparator();
127     c.gridx = 1;
128     c.gridy = 0;
129     c.gridheight = 2;
130     c.insets = new Insets(3, 0, 5, 3);
131     c.fill = GridBagConstraints.VERTICAL;
132     c.weighty = 1.0;
133     gridbag.setConstraints(p, c);
134     add(p);
135    
136     p = new KeyRangePropsPane();
137    
138     c.gridx = 2;
139     c.gridy = 0;
140     c.gridheight = 1;
141     c.insets = new Insets(0, 0, 0, 0);
142     c.fill = GridBagConstraints.NONE;
143     c.weighty = 0.0;
144     c.anchor = GridBagConstraints.WEST;
145     gridbag.setConstraints(p, c);
146     add(p);
147    
148     p = new KeyRangePropsPane();
149    
150     c.gridx = 6;
151     c.gridy = 0;
152     c.anchor = GridBagConstraints.EAST;
153     c.insets = new Insets(0, 0, 0, 10);
154     gridbag.setConstraints(p, c);
155     add(p);
156    
157     lDisplay.setPreferredSize(new Dimension(300, lDisplay.getPreferredSize().height));
158    
159     c.gridx = 4;
160     c.gridy = 0;
161     c.insets = new Insets(3, 3, 3, 12);
162     c.fill = GridBagConstraints.NONE;
163     c.weightx = 0.0;
164     gridbag.setConstraints(lDisplay, c);
165     add(lDisplay);
166    
167     p = new JPanel();
168     p.setOpaque(false);
169     c.gridx = 3;
170     c.gridy = 0;
171     c.insets = new Insets(0, 0, 0, 0);
172     c.fill = GridBagConstraints.HORIZONTAL;
173     c.weightx = 1.0;
174     gridbag.setConstraints(p, c);
175     add(p);
176    
177     p = new JPanel();
178     p.setOpaque(false);
179     c.gridx = 5;
180     c.gridy = 0;
181     gridbag.setConstraints(p, c);
182     add(p);
183    
184     pianoRoll.setFocusable(false);
185     pianoRoll.setBackground(new Color(0x2e2e2e));
186     //pianoRoll.setOpaque(false);
187    
188 iliev 1776 disablePianoRoll();
189    
190 iliev 1778 c.gridx = 2;
191     c.gridy = 1;
192     c.gridwidth = 5;
193     c.insets = new Insets(0, 3, 0, 12);
194     c.fill = GridBagConstraints.BOTH;
195     c.weightx = 1.0;
196     c.weighty = 1.0;
197     gridbag.setConstraints(pianoRoll, c);
198     add(pianoRoll);
199    
200 iliev 1776 CC.getSamplerModel().addSamplerChannelListListener(this);
201     pianoRoll.addMidiDataListener(getHandler());
202    
203     updateKeyRange();
204    
205     PropertyChangeListener l = new PropertyChangeListener() {
206     public void
207     propertyChange(PropertyChangeEvent e) {
208     updateKeyRange();
209     }
210     };
211    
212     CC.preferences().addPropertyChangeListener("midiKeyboard.firstKey", l);
213     CC.preferences().addPropertyChangeListener("midiKeyboard.lastKey", l);
214 iliev 1778
215     addFocusListener(getHandler());
216    
217     MouseAdapter l2 = new MouseAdapter() {
218     public void
219     mouseClicked(MouseEvent e) { requestFocusInWindow(); }
220     };
221    
222     addKeyListener(pianoRoll.getKeyListener());
223     pianoRoll.registerKeys(this);
224    
225     addMouseListener(l2);
226     pianoRoll.addMouseListener(l2);
227     lDisplay.addMouseListener(l2);
228 iliev 1776 }
229    
230     public JSPianoRoll
231     getPianoRoll() { return pianoRoll; }
232    
233     private void
234     updateKeyRange() {
235     int firstKey = CC.preferences().getIntProperty("midiKeyboard.firstKey");
236     int lastKey = CC.preferences().getIntProperty("midiKeyboard.lastKey");
237     pianoRoll.setKeyRange(firstKey, lastKey);
238     }
239    
240     @Override public void
241     valueChanged(ListSelectionEvent e) {
242     if(e.getValueIsAdjusting()) return;
243    
244     JSChannel[] chnS = CC.getMainFrame().getChannelsPane(0).getSelectedChannels();
245     if(chnS == null || chnS.length == 0) {
246     disconnectChannel();
247     return;
248     }
249    
250     if(chnS[0].getModel() == channel) return;
251     disconnectChannel();
252     connectChannel(chnS[0].getModel());
253     }
254    
255     private void
256     updateInstrumentInfo() {
257     final GetFileInstrument i = new GetFileInstrument(file, index);
258    
259     i.addTaskListener(new TaskListener() {
260     public void
261     taskPerformed(TaskEvent e) {
262     if(i.doneWithErrors()) return;
263     updatePianoKeyboard(i.getResult());
264     }
265     });
266    
267     CC.getTaskQueue().add(i);
268     }
269    
270     private void
271     disablePianoRoll() {
272     pianoRoll.reset(true);
273     pianoRoll.setPlayingEnabled(false);
274     }
275    
276     private void
277     updatePianoKeyboard(Instrument instr) {
278     // The selected channel may have changed before this update
279     // due to concurency, so also checking whether file is null
280     if(instr == null || file == null) {
281     disablePianoRoll();
282     return;
283     }
284    
285     pianoRoll.setPlayingEnabled(true);
286    
287     pianoRoll.setShouldRepaint(false);
288     pianoRoll.reset(true);
289     pianoRoll.setDisabled(instr.getKeyMapping(), false);
290     pianoRoll.setKeyswitches(instr.getKeyswitchMapping(), true);
291     pianoRoll.setShouldRepaint(true);
292     pianoRoll.repaint();
293     }
294    
295     private void
296     connectChannel(SamplerChannelModel chn) {
297     channel = chn;
298     channel.addMidiDataListener(pianoRoll);
299     channel.addSamplerChannelListener(getHandler());
300    
301 iliev 1778 updateDisplay();
302    
303 iliev 1776 file = channel.getChannelInfo().getInstrumentFile();
304     if(file == null) {
305     disablePianoRoll();
306     return;
307     }
308     index = channel.getChannelInfo().getInstrumentIndex();
309     updateInstrumentInfo();
310     }
311    
312     private void
313     disconnectChannel() {
314     if(channel != null) {
315     channel.removeMidiDataListener(pianoRoll);
316     channel.removeSamplerChannelListener(getHandler());
317     channel = null;
318     file = null;
319     index = -1;
320     disablePianoRoll();
321     }
322 iliev 1778
323     updateDisplay();
324 iliev 1776 }
325    
326     @Override public void
327 iliev 1778 channelAdded(SamplerChannelListEvent e) {
328     updateDisplay();
329     }
330 iliev 1776
331     @Override public void
332     channelRemoved(SamplerChannelListEvent e) {
333     if(e.getChannelModel() == channel) {
334     disconnectChannel();
335     }
336 iliev 1778
337     updateDisplay();
338 iliev 1776 }
339    
340 iliev 1778 private JPanel
341     createVSeparator() {
342     PixmapPane p = new PixmapPane(Res.gfxVLine);
343     p.setAlignmentY(JPanel.TOP_ALIGNMENT);
344     p.setPreferredSize(new Dimension(2, 60));
345     p.setMaximumSize(new Dimension(2, Short.MAX_VALUE));
346     return p;
347     }
348    
349     private Color color1 = new Color(0x7a7a7a);
350     private Color color2 = new Color(0x5e5e5e);
351     private Color color3 = new Color(0x2e2e2e);
352    
353     @Override
354     public void
355     paintComponent(Graphics g) {
356     Graphics2D g2 = (Graphics2D)g;
357    
358     Paint oldPaint = g2.getPaint();
359     Composite oldComposite = g2.getComposite();
360    
361     Insets insets = this.getInsets();
362     double x1 = insets.left;
363     double y1 = insets.top;
364    
365     double w = getSize().getWidth();
366     double x2 = w - insets.right - 1;
367     double h = getSize().getHeight();
368     double y2 = h - insets.bottom - 1;
369    
370     FantasiaPainter.paintGradient(g2, x1, y1, x2, y2 - 10, color1, color2);
371    
372     g2.setRenderingHint (
373     RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF
374     );
375    
376     double y3 = y2 - 10;
377     if(y3 < 0) y3 = 0;
378    
379     Rectangle2D.Double rect = new Rectangle2D.Double(x1, y3, x2 - x1 + 1, 11);
380    
381     GradientPaint gr = new GradientPaint (
382     0.0f, (float)y3, color2,
383     0.0f, (float)h, color3
384     );
385    
386     g2.setPaint(gr);
387     g2.fill(rect);
388    
389     drawOutBorder(g2, x1, y1, x2, y2);
390    
391     double prX = pianoRoll.getLocation().getX();
392     double prY = pianoRoll.getLocation().getY();
393     drawInBorder (
394     g2, prX - 2, prY - 2,
395     prX + pianoRoll.getSize().getWidth() + 1, prY + pianoRoll.getSize().getHeight() - 3
396     );
397    
398     g2.setPaint(oldPaint);
399     g2.setComposite(oldComposite);
400     }
401    
402     private void
403     drawOutBorder(Graphics2D g2, double x1, double y1, double x2, double y2) {
404     AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.40f);
405     g2.setComposite(ac);
406    
407     g2.setPaint(Color.WHITE);
408     Line2D.Double l = new Line2D.Double(x1, y1, x2, y1);
409     g2.draw(l);
410    
411     g2.setComposite(ac.derive(0.20f));
412     l = new Line2D.Double(x1, y1 + 1, x2, y1 + 1);
413     g2.draw(l);
414    
415     g2.setComposite(ac.derive(0.255f));
416    
417     l = new Line2D.Double(x1, y1, x1, y2);
418     g2.draw(l);
419    
420     g2.setComposite(ac.derive(0.40f));
421     g2.setPaint(Color.BLACK);
422    
423     //l = new Line2D.Double(x1, y2, x2, y2);
424     //g2.draw(l);
425    
426     g2.setComposite(ac.derive(0.20f));
427    
428     l = new Line2D.Double(x2, y1, x2, y2);
429     g2.draw(l);
430     }
431    
432     private void
433     drawInBorder(Graphics2D g2, double x1, double y1, double x2, double y2) {
434     AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.40f);
435     g2.setComposite(ac);
436    
437     g2.setPaint(Color.WHITE);
438     Line2D.Double l = new Line2D.Double(x1, y2, x2, y2);
439     //g2.draw(l);
440    
441     g2.setComposite(ac.derive(0.255f));
442    
443     l = new Line2D.Double(x2 - 1, y1 + 1, x2 - 1, y2 + 1);
444     g2.draw(l);
445    
446     g2.setComposite(ac.derive(0.13f));
447    
448     l = new Line2D.Double(x2, y1, x2, y2);
449     g2.draw(l);
450    
451     g2.setComposite(ac.derive(0.20f));
452     g2.setPaint(Color.BLACK);
453    
454     l = new Line2D.Double(x1, y1, x2, y1);
455     g2.draw(l);
456    
457     g2.setComposite(ac.derive(0.40f));
458     g2.setPaint(Color.BLACK);
459    
460     l = new Line2D.Double(x1 + 1, y1 + 1, x2 - 1, y1 + 1);
461     g2.draw(l);
462    
463     g2.setComposite(ac.derive(0.20f));
464    
465     l = new Line2D.Double(x1, y1, x1, y2);
466     g2.draw(l);
467    
468     g2.setComposite(ac.derive(0.40f));
469    
470     l = new Line2D.Double(x1 + 1, y1 + 1, x1 + 1, y2 + 1);
471     g2.draw(l);
472     }
473    
474     private void
475     updateDisplay() {
476     // TODO: called too often?
477     if(channel == null) {
478     lDisplay.setText(i18n.getLabel("PianoKeyboardPane.noChannel"));
479     return;
480     }
481    
482     SamplerChannel sc = channel.getChannelInfo();
483     int i = CC.getSamplerModel().getChannelIndex(channel) + 1;
484    
485     StringBuffer sb = new StringBuffer();
486     sb.append(i18n.getLabel("PianoKeyboardPane.channel", i)).append(" - ");
487    
488     int status = sc.getInstrumentStatus();
489     if(status >= 0 && status < 100) {
490     sb.append(i18n.getLabel("ChannelScreen.loadingInstrument", status));
491     } else if(status == -1) {
492     sb.append(i18n.getLabel("PianoKeyboardPane.noInstrument"));
493     } else if(status < -1) {
494     sb.append(i18n.getLabel("ChannelScreen.errorLoadingInstrument"));
495     } else {
496     if(sc.getInstrumentName() != null) sb.append(sc.getInstrumentName());
497     }
498    
499     lDisplay.setText(sb.toString());
500     }
501    
502    
503     class KeyRangePropsPane extends JPanel {
504     private final JButton btnIncrease =
505     new PixmapButton(pianoRoll.actionIncreaseKeyNumber, Res.gfxBtnIncrease);
506    
507     private final JButton btnDecrease =
508     new PixmapButton(pianoRoll.actionDecreaseKeyNumber, Res.gfxBtnDecrease);
509    
510     private final JButton btnScrollLeft =
511     new PixmapButton(pianoRoll.actionScrollLeft, Res.gfxBtnScrollLeft);
512    
513     private final JButton btnScrollRight =
514     new PixmapButton(pianoRoll.actionScrollRight, Res.gfxBtnScrollRight);
515    
516     KeyRangePropsPane() {
517     setOpaque(false);
518     setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
519    
520     btnIncrease.setFocusable(false);
521     btnDecrease.setFocusable(false);
522     btnScrollLeft.setFocusable(false);
523     btnScrollRight.setFocusable(false);
524    
525    
526     btnDecrease.setPressedIcon(Res.gfxBtnDecreaseRO);
527     add(btnDecrease);
528    
529     btnIncrease.setPressedIcon(Res.gfxBtnIncreaseRO);
530     add(btnIncrease);
531    
532     add(Box.createRigidArea(new Dimension(6, 0)));
533    
534     btnScrollLeft.setPressedIcon(Res.gfxBtnScrollLeftRO);
535     add(btnScrollLeft);
536    
537     btnScrollRight.setPressedIcon(Res.gfxBtnScrollRightRO);
538     add(btnScrollRight);
539     }
540     }
541    
542    
543     public static class PowerButton extends PixmapToggleButton implements ActionListener {
544     PowerButton() {
545     this(Res.gfxPowerOff, Res.gfxPowerOn);
546     }
547    
548     PowerButton(ImageIcon defaultIcon, ImageIcon selectedIcon) {
549     super(defaultIcon, selectedIcon);
550    
551     setSelected(true);
552     addActionListener(this);
553     }
554    
555     @Override
556     public void
557     actionPerformed(ActionEvent e) {
558     boolean b = isSelected();
559     MainFrame frm = (MainFrame)CC.getMainFrame();
560     if(frm == null) return;
561     frm.setMidiKeyboardVisible(b);
562     }
563    
564     @Override
565     public boolean
566     contains(int x, int y) { return (x - 11)*(x - 11) + (y - 11)*(y - 11) < 71; }
567     }
568    
569 iliev 1776 private final Handler handler = new Handler();
570    
571     private Handler
572     getHandler() { return handler; }
573    
574 iliev 1778 private class Handler extends SamplerChannelAdapter implements FocusListener, MidiDataListener {
575     @Override
576 iliev 1776 public void
577     midiDataArrived(MidiDataEvent e) {
578     if(channel == null) return;
579     channel.sendBackendMidiData(e);
580     }
581    
582 iliev 1778 @Override
583 iliev 1776 public void
584     channelChanged(SamplerChannelEvent e) {
585 iliev 1778 updateDisplay();
586    
587 iliev 1776 String newFile = channel.getChannelInfo().getInstrumentFile();
588     int newIndex = channel.getChannelInfo().getInstrumentIndex();
589    
590     if(channel.getChannelInfo().getInstrumentStatus() != 100) {
591     //don't use disablePianoRoll because of unnecessary repainting
592     pianoRoll.setAllKeysPressed(false);
593     pianoRoll.removeAllKeyswitches();
594     pianoRoll.setAllKeysDisabled(true);
595     pianoRoll.setPlayingEnabled(false);
596     return;
597     }
598    
599     if(newFile == null) {
600     if(file != null) disablePianoRoll();
601     file = null;
602     index = -1;
603     return;
604     }
605    
606     if(newFile.equals(file) && newIndex == index) return;
607    
608     file = newFile;
609     index = newIndex;
610     updateInstrumentInfo();
611     }
612 iliev 1778
613     @Override
614     public void
615     focusGained(FocusEvent e) {
616    
617     }
618    
619     @Override
620     public void
621     focusLost(FocusEvent e) {
622    
623     }
624 iliev 1776 }
625     }

  ViewVC Help
Powered by ViewVC