/[svn]/jsampler/trunk/src/org/jsampler/view/std/PianoRoll.java
ViewVC logotype

Annotation of /jsampler/trunk/src/org/jsampler/view/std/PianoRoll.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: 25323 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.std;
24    
25     import java.awt.Graphics;
26     import java.awt.Graphics2D;
27    
28 iliev 1778 import java.awt.event.ActionEvent;
29     import java.awt.event.ActionListener;
30     import java.awt.event.KeyEvent;
31     import java.awt.event.KeyListener;
32 iliev 1776 import java.awt.event.MouseEvent;
33     import java.awt.event.MouseAdapter;
34    
35 iliev 1778 import java.util.HashMap;
36 iliev 1776 import java.util.Vector;
37    
38 iliev 1778 import javax.swing.Action;
39     import javax.swing.AbstractAction;
40     import javax.swing.JComponent;
41 iliev 1776 import javax.swing.JPanel;
42 iliev 1778 import javax.swing.KeyStroke;
43     import javax.swing.SwingUtilities;
44     import javax.swing.Timer;
45 iliev 1776
46 iliev 1778 import org.jsampler.CC;
47    
48 iliev 1776 import org.linuxsampler.lscp.event.MidiDataEvent;
49     import org.linuxsampler.lscp.event.MidiDataListener;
50    
51 iliev 1778 import static org.jsampler.view.std.StdI18n.i18n;
52    
53 iliev 1776 /**
54     *
55     * @author Grigor Iliev
56     */
57     public class PianoRoll extends JPanel implements MidiDataListener {
58     public class Key {
59     private boolean disabled = false;
60     private boolean pressed = false;
61     private boolean keyswitch = false;
62    
63     public
64     Key() {
65    
66     }
67    
68     public boolean
69     isDisabled() { return disabled; }
70    
71     public void
72     setDisabled(boolean b) { disabled = b; }
73    
74     public boolean
75     isPressed() { return pressed; }
76    
77     public void
78     setPressed(boolean b) { pressed = b; }
79    
80     public boolean
81     isKeyswitch() { return keyswitch; }
82    
83     public void
84     setKeyswitch(boolean b) { keyswitch = b; }
85    
86     }
87    
88    
89     private final Vector<Key> keys = new Vector<Key>();
90    
91     private boolean vertical;
92     private boolean mirror;
93     private boolean octaveLabelsVisible = true;
94     private boolean playingEnabled = true;
95    
96     private int firstKey = -1;
97     private int lastKey = -1;
98     private int whiteKeyCount = 68;
99    
100 iliev 1778 private Integer[] enabledKeys = null;
101     private Integer[] disabledKeys = null;
102     private Integer[] keyswitches = null;
103     private Integer[] notKeyswitches = null;
104 iliev 1776
105 iliev 1778 private int currentOctave = 3;
106     private int constantVelocity = 80;
107     private HashMap<Integer, Integer> keyMap = new HashMap<Integer, Integer>();
108    
109 iliev 1776 private final Vector<MidiDataListener> listeners = new Vector<MidiDataListener>();
110    
111 iliev 1778 private boolean shouldRepaint = true;
112 iliev 1776
113 iliev 1778 private PianoRollPainter painter;
114    
115     public final Action actionScrollLeft = new ActionScrollLeft();
116     public final Action actionScrollRight = new ActionScrollRight();
117     public final Action actionIncreaseKeyNumber = new ActionIncreaseKeyNumber();
118     public final Action actionDecreaseKeyNumber = new ActionDecreaseKeyNumber();
119    
120 iliev 1776 /**
121     * Creates a new horizontal, not mirrored <code>PianoRoll</code>.
122     */
123     public
124     PianoRoll() { this(false); }
125    
126     /**
127     * Creates a new not mirrored <code>PianoRoll</code>.
128     * @param vertical Specifies whether the piano roll
129     * should be vertical or horizontal
130     */
131     public
132     PianoRoll(boolean vertical) { this(vertical, false); }
133    
134     /**
135     * Creates a new instance of <code>PianoRoll</code>.
136     * @param vertical Specifies whether the piano roll
137     * should be vertical or horizontal.
138     * @param mirror Specifies whether to mirror the piano roll.
139     */
140     public
141     PianoRoll(boolean vertical, boolean mirror) {
142     this.vertical = vertical;
143     this.mirror = mirror;
144    
145 iliev 1778 setPainter(new BasicPianoRollPainter(this));
146    
147 iliev 1776 setKeyRange(0, 127);
148 iliev 1778
149     installListeneres();
150 iliev 1776 }
151    
152 iliev 1778 private void
153     installListeneres() {
154     addMouseListener(getHandler());
155     addMouseMotionListener(getHandler());
156     addKeyListener(getHandler());
157    
158     registerKeys(this);
159    
160    
161     }
162    
163     public KeyListener
164     getKeyListener() { return getHandler(); }
165    
166     public void
167     registerKeys(JComponent c) {
168     KeyStroke k = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_MASK);
169     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "scrollLeft");
170     c.getActionMap().put("scrollLeft", actionScrollLeft);
171    
172     k = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_MASK);
173     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "scrollRight");
174     c.getActionMap().put("scrollRight", actionScrollRight);
175    
176     k = KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.CTRL_MASK);
177     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "increaseKeyRange");
178     c.getActionMap().put("increaseKeyRange", actionIncreaseKeyNumber);
179    
180     k = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.CTRL_MASK);
181     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "decreaseKeyRange");
182     c.getActionMap().put("decreaseKeyRange", actionDecreaseKeyNumber);
183    
184     k = KeyStroke.getKeyStroke(KeyEvent.VK_0, 0);
185     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave0");
186     c.getActionMap().put("changeCurrentOctave0", new ActionChangeCurrentOctave(0));
187    
188     k = KeyStroke.getKeyStroke(KeyEvent.VK_1, 0);
189     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave1");
190     c.getActionMap().put("changeCurrentOctave1", new ActionChangeCurrentOctave(1));
191    
192     k = KeyStroke.getKeyStroke(KeyEvent.VK_2, 0);
193     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave2");
194     c.getActionMap().put("changeCurrentOctave2", new ActionChangeCurrentOctave(2));
195    
196     k = KeyStroke.getKeyStroke(KeyEvent.VK_3, 0);
197     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave3");
198     c.getActionMap().put("changeCurrentOctave3", new ActionChangeCurrentOctave(3));
199    
200     k = KeyStroke.getKeyStroke(KeyEvent.VK_4, 0);
201     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave4");
202     c.getActionMap().put("changeCurrentOctave4", new ActionChangeCurrentOctave(4));
203    
204     k = KeyStroke.getKeyStroke(KeyEvent.VK_5, 0);
205     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave5");
206     c.getActionMap().put("changeCurrentOctave5", new ActionChangeCurrentOctave(5));
207    
208     k = KeyStroke.getKeyStroke(KeyEvent.VK_6, 0);
209     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave6");
210     c.getActionMap().put("changeCurrentOctave6", new ActionChangeCurrentOctave(6));
211    
212     k = KeyStroke.getKeyStroke(KeyEvent.VK_7, 0);
213     c.getInputMap(JComponent.WHEN_FOCUSED).put(k, "changeCurrentOctave7");
214     c.getActionMap().put("changeCurrentOctave7", new ActionChangeCurrentOctave(7));
215     }
216    
217     public PianoRollPainter
218     getPainter() { return painter; }
219    
220     public void
221     setPainter(PianoRollPainter painter) {
222     if(painter == null) painter = new BasicPianoRollPainter(this);
223     this.painter = painter;
224     }
225    
226 iliev 1776 /**
227     * Registers the specified listener to be notified when
228     * MIDI event occurs due to user input.
229     * @param l The <code>MidiDataListener</code> to register.
230     */
231     public void
232     addMidiDataListener(MidiDataListener l) { listeners.add(l); }
233    
234     /**
235     * Removes the specified listener.
236     * @param l The <code>MidiDataListener</code> to remove.
237     */
238     public void
239     removeMidiDataListener(MidiDataListener l) { listeners.remove(l); }
240    
241     private void
242     fireMidiDataEvent(MidiDataEvent e) {
243     for(MidiDataListener l : listeners) l.midiDataArrived(e);
244     }
245    
246 iliev 1778 private void
247     fireNoteOn(int key, int velocity) {
248     MidiDataEvent evt = new MidiDataEvent (
249     PianoRoll.this, MidiDataEvent.Type.NOTE_ON, key, velocity
250     );
251    
252     fireMidiDataEvent(evt);
253     }
254    
255     private void
256     fireNoteOff(int key, int velocity) {
257     MidiDataEvent evt = new MidiDataEvent (
258     PianoRoll.this, MidiDataEvent.Type.NOTE_OFF, key, velocity
259     );
260    
261     fireMidiDataEvent(evt);
262     }
263    
264 iliev 1776 /**
265 iliev 1778 * Used to determine which note to play when using
266     * the computer keyboard's key bindings.
267     * @return
268     */
269     public int
270     getCurrentOctave() { return currentOctave; }
271    
272     /**
273     * @see #getCurrentOctave
274     * @param octave Specifies the octave to be used as current.
275     */
276     public void
277     setCurrentOctave(int octave) { currentOctave = octave; }
278    
279     public int
280     getConstantVelocity() { return constantVelocity; }
281    
282     public void
283     setConstantVelocity(int velocity) { constantVelocity = velocity; }
284    
285     /**
286 iliev 1776 * Determines whether the user input is processed
287     * and respective MIDI data events are sent.
288     */
289     public boolean
290     isPlayingEnabled() { return playingEnabled; }
291    
292     /**
293     * Sets whether the user input should be processed
294     * and respective MIDI data events should be sent.
295     * @see #isPlayingEnabled
296     */
297     public void
298     setPlayingEnabled(boolean b) { playingEnabled = b; }
299    
300     public boolean
301     hasKey(int key) {
302     if(key >= firstKey && key <= lastKey) return true;
303     return false;
304     }
305    
306     public Key
307     getKey(int key) { return keys.get(key - firstKey); }
308    
309     public boolean
310     isKeyDisabled(int key) {
311     return getKey(key).isDisabled();
312     }
313    
314     public void
315     setKeyDisabled(int key, boolean disable) {
316     Key k = getKey(key);
317     if(k.isDisabled() == disable) return;
318    
319     getKey(key).setDisabled(disable);
320     if(getShouldRepaint()) repaint();
321     }
322    
323     public boolean
324     isKeyPressed(int key) {
325     return getKey(key).isPressed();
326     }
327    
328     public void
329     setKeyPressed(int key, boolean press) {
330     Key k = getKey(key);
331     if(k.isPressed() == press) return;
332    
333     getKey(key).setPressed(press);
334 iliev 1778 if(getShouldRepaint()) repaint(painter.getKeyRectangle(key));
335 iliev 1776 }
336    
337     public boolean
338     isKeyswitch(int key) {
339     return getKey(key).isKeyswitch();
340     }
341    
342     public void
343     setKeyswitch(int key, boolean keyswitch) {
344     Key k = getKey(key);
345     if(k.isKeyswitch() == keyswitch) return;
346    
347     getKey(key).setKeyswitch(keyswitch);
348 iliev 1778 if(getShouldRepaint()) repaint(painter.getKeyRectangle(key));
349 iliev 1776 }
350    
351     public void
352     setAllKeysPressed(boolean b) {
353     boolean changed = false;
354     for(Key key : keys) {
355     if(key.isPressed() != b) {
356     key.setPressed(b);
357     changed = true;
358     }
359     }
360    
361     if(changed && getShouldRepaint()) repaint();
362     }
363    
364     public void
365     setAllKeysDisabled(boolean b) {
366     boolean changed = false;
367     for(Key key : keys) {
368     if(key.isDisabled() != b) {
369     key.setDisabled(b);
370     changed = true;
371     }
372     }
373    
374     if(changed && getShouldRepaint()) repaint();
375     }
376    
377     public Integer[]
378     getKeyswitches() {
379     Vector<Integer> v = new Vector<Integer>();
380     for(int i = 0; i < keys.size(); i++) {
381     if(keys.get(i).isKeyswitch()) v.add(firstKey + i);
382     }
383    
384     return v.toArray(new Integer[v.size()]);
385     }
386    
387     /**
388 iliev 1778 * Keys outside the keyboard range are remembered and
389     * applied if needed when the key range is changed.
390 iliev 1776 * @param keys List of keys
391     */
392     public void
393 iliev 1778 setKeyswitches(Integer[] keys, boolean b) {
394     if(b) keyswitches = keys;
395     else notKeyswitches = keys;
396     if(keys == null) return;
397    
398 iliev 1776 boolean changed = false;
399     for(int k : keys) {
400     if(!hasKey(k)) continue;
401 iliev 1778 if(getKey(k).isKeyswitch() != b) {
402     getKey(k).setKeyswitch(b);
403 iliev 1776 changed = true;
404     }
405     }
406     if(changed && getShouldRepaint()) repaint();
407     }
408    
409     public Integer[]
410     getEnabledKeys() {
411     Vector<Integer> v = new Vector<Integer>();
412     for(int i = 0; i < keys.size(); i++) {
413     if(!keys.get(i).isDisabled()) v.add(firstKey + i);
414     }
415    
416     return v.toArray(new Integer[v.size()]);
417     }
418    
419     /**
420     * Enables or disables the specified list of keys.
421 iliev 1778 * Disabled keys outside the keyboard range are remembered and
422     * applied if needed when the key range is changed.
423 iliev 1776 * @param keys List of keys
424     */
425     public void
426     setDisabled(Integer[] keys, boolean disable) {
427 iliev 1778 if(disable) disabledKeys = keys;
428     else enabledKeys = keys;
429    
430     if(keys == null) return;
431    
432 iliev 1776 boolean changed = false;
433     for(int k : keys) {
434     if(!hasKey(k)) continue;
435     if(getKey(k).isDisabled() != disable) {
436     getKey(k).setDisabled(disable);
437     changed = true;
438     }
439     }
440     if(changed && getShouldRepaint()) repaint();
441     }
442    
443     public void
444     removeAllKeyswitches() {
445     boolean changed = false;
446     for(Key key : keys) {
447     if(key.isKeyswitch()) {
448     key.setKeyswitch(false);
449     changed = true;
450     }
451     }
452     if(changed && getShouldRepaint()) repaint();
453     }
454    
455     /**
456     * Sets the piano key range which this piano roll will provide.
457     * Note that the specified last key is also included in the piano roll.
458     * Also, the first and the last key should be white keys. If the first key
459     * and/or the last key are not white keys then the range is extended automatically.
460     * @param firstKey Number between 0 and 127 (inclusive) as specified in the MIDI standard.
461     * @param lastKey Number between 0 and 127 (inclusive) as specified in the MIDI standard.
462     * @throws IllegalArgumentException if the specified range is invalid.
463     */
464     public void
465     setKeyRange(int firstKey, int lastKey) {
466     if(this.firstKey == firstKey && this.lastKey == lastKey) return;
467    
468     if(firstKey < 0 || firstKey > 127 || lastKey < 0 || lastKey > 127 || firstKey >= lastKey) {
469     throw new IllegalArgumentException("Invalid range: " + firstKey + "-" + lastKey);
470     }
471    
472     /*Integer[] enabledKeys = getEnabledKeys();
473     Integer[] keyswitches = getKeyswitches();*/
474    
475     if(!isWhiteKey(firstKey)) firstKey--;
476     if(!isWhiteKey(lastKey)) lastKey++;
477     this.firstKey = firstKey;
478     this.lastKey = lastKey;
479    
480     keys.removeAllElements();
481     for(int i = 0; i <= lastKey - firstKey; i++) keys.add(new Key());
482    
483     whiteKeyCount = getWhiteKeyCount(firstKey, lastKey);
484    
485 iliev 1778 boolean b = getShouldRepaint();
486     setShouldRepaint(false);
487    
488     reset(true, false);
489 iliev 1776 setDisabled(enabledKeys, false);
490 iliev 1778 setDisabled(disabledKeys, true);
491     setKeyswitches(keyswitches, true);
492     setKeyswitches(notKeyswitches, false);
493 iliev 1776
494 iliev 1778 setShouldRepaint(b);
495 iliev 1776 if(getShouldRepaint()) repaint();
496     }
497    
498 iliev 1778 public int
499     getFirstKey() { return firstKey; }
500    
501     public int
502     getLastKey() { return lastKey; }
503    
504 iliev 1776 public boolean
505     getOctaveLabelsVisible() {
506     return octaveLabelsVisible;
507     }
508    
509     public void
510     setOctaveLabelsVisible(boolean b) {
511     octaveLabelsVisible = b;
512     }
513    
514     /**
515     * Gets the number of white keys int the specified range (inclusive).
516     * @see #setKeyRange
517     */
518 iliev 1778 public static int
519 iliev 1776 getWhiteKeyCount(int firstKey, int lastKey) {
520     int count = 0;
521     for(int j = firstKey; j <= lastKey; j++) { // FIXME: Stupid but works
522     if(isWhiteKey(j)) count++;
523     }
524    
525     return count;
526     }
527    
528 iliev 1778 /**
529     * Gets the MIDI note number of the specified white key position.
530     * @param whiteKey The white key position on the keyboard (zero-based)
531     * @return The MIDI number of the note
532     */
533     public int
534 iliev 1776 getWhiteKeyByNumber(int whiteKey) {
535     int count = 0;
536     for(int j = firstKey; j <= lastKey; j++) { // FIXME: Stupid but works
537     if(isWhiteKey(j)) {
538     if(whiteKey == count) return j;
539     count++;
540     }
541     }
542    
543     return -1;
544     }
545    
546 iliev 1778 /** Gets the number of white keys in the piano roll. */
547     public int
548     getWhiteKeyCount() { return whiteKeyCount; }
549 iliev 1776
550     /**
551     * Determines whether the specified key is a white key.
552     * @param key Number between 0 and 127 (inclusive) as specified in the MIDI standard.
553     */
554     public static boolean
555     isWhiteKey(int key) {
556     if(key < 0 || key > 127) return false;
557    
558     int k = key % 12;
559     if(k == 1 || k == 3 || k == 6 || k == 8 || k == 10) {
560     return false;
561     }
562    
563     return true;
564     }
565    
566     /**
567     * Returns the position (zero-based) of the specified white key in the octave.
568     * @param whiteKey Number between 0 and 127 (inclusive) as specified in the MIDI standard.
569     * @return Number between 0 and 6 (inclusive) and -1 if the
570     * specified key is not a white key.
571     */
572     public static int
573     getKeyOctaveIndex(int whiteKey) {
574     if(whiteKey < 0 || whiteKey > 127) return -1;
575    
576     int k = whiteKey % 12;
577     if(k == 1 || k == 3 || k == 6 || k == 8 || k == 10) {
578     return -1;
579     }
580    
581     return getWhiteKeyCount(0, k) - 1;
582     }
583    
584     /**
585     * Releases all pressed keys, enables all keys and removes all keyswitches.
586     */
587     public void
588     reset() { reset(false); }
589    
590     /**
591     * Releases all pressed keys, enables/disables all keys and removes all keyswitches.
592     * @param dissable Specifies whether all keys should be enabled or disabled
593     */
594     public void
595     reset(boolean dissableAllKeys) {
596 iliev 1778 reset(dissableAllKeys, true);
597     }
598    
599     private void
600     reset(boolean dissableAllKeys, boolean clear) {
601     if(clear) {
602     enabledKeys = null;
603     disabledKeys = null;
604     keyswitches = null;
605     notKeyswitches = null;
606     }
607    
608 iliev 1776 boolean b = getShouldRepaint();
609     setShouldRepaint(false);
610     setAllKeysPressed(false);
611     removeAllKeyswitches();
612     setAllKeysDisabled(dissableAllKeys);
613     setShouldRepaint(b);
614     if(getShouldRepaint()) repaint();
615     }
616    
617     public boolean
618     getShouldRepaint() { return shouldRepaint; }
619    
620     public void
621     setShouldRepaint(boolean b) { shouldRepaint = b; }
622    
623 iliev 1778 @Override public void
624     paint(Graphics g) {
625     super.paint(g);
626     painter.paint(this, (Graphics2D)g);
627 iliev 1776 }
628    
629 iliev 1778 @Override public void
630     midiDataArrived(MidiDataEvent e) {
631     switch(e.getType()) {
632     case NOTE_ON:
633     setKeyPressed(e.getNote(), true);
634     break;
635     case NOTE_OFF:
636     setKeyPressed(e.getNote(), false);
637     }
638 iliev 1776 }
639    
640    
641 iliev 1778 private class ActionScrollLeft extends AbstractAction {
642     ActionScrollLeft() {
643     super(i18n.getLabel("PianoRoll.scrollLeft"));
644    
645     String s = i18n.getLabel("PianoRoll.scrollLeft");
646     putValue(SHORT_DESCRIPTION, s);
647     }
648    
649     public void
650     actionPerformed(ActionEvent e) {
651     if(getFirstKey() == 0) return;
652     int k = getFirstKey() - 1;
653     if(!isWhiteKey(k)) k--;
654     int k2 = getLastKey() - 1;
655     if(!isWhiteKey(k2)) k2--;
656    
657     setKeyRange(k, k2);
658     CC.preferences().setIntProperty("midiKeyboard.firstKey", k);
659     CC.preferences().setIntProperty("midiKeyboard.lastKey", k2);
660    
661     }
662 iliev 1776 }
663    
664    
665 iliev 1778 private class ActionScrollRight extends AbstractAction {
666     ActionScrollRight() {
667     super(i18n.getLabel("PianoRoll.scrollRight"));
668    
669     String s = i18n.getLabel("PianoRoll.scrollRight");
670     putValue(SHORT_DESCRIPTION, s);
671     }
672 iliev 1776
673 iliev 1778 public void
674     actionPerformed(ActionEvent e) {
675     if(getLastKey() == 127) return;
676     int k = getFirstKey() + 1;
677     if(!isWhiteKey(k)) k++;
678     int k2 = getLastKey() + 1;
679     if(!isWhiteKey(k2)) k2++;
680    
681     setKeyRange(k, k2);
682     CC.preferences().setIntProperty("midiKeyboard.firstKey", k);
683     CC.preferences().setIntProperty("midiKeyboard.lastKey", k2);
684    
685 iliev 1776 }
686     }
687    
688 iliev 1778 private class ActionIncreaseKeyNumber extends AbstractAction {
689     ActionIncreaseKeyNumber() {
690     super(i18n.getLabel("PianoRoll.increaseKeyNumber"));
691    
692     String s = i18n.getLabel("PianoRoll.increaseKeyNumber");
693     putValue(SHORT_DESCRIPTION, s);
694     }
695 iliev 1776
696 iliev 1778 public void
697     actionPerformed(ActionEvent e) {
698     if(getFirstKey() == 0 && getLastKey() == 127) return;
699     int k = getFirstKey() == 0 ? 0 : getFirstKey() - 1;
700     if(!isWhiteKey(k)) k--;
701     int k2 = getLastKey() == 127 ? 127 : getLastKey() + 1;
702     if(!isWhiteKey(k2)) k2++;
703    
704     setKeyRange(k, k2);
705     CC.preferences().setIntProperty("midiKeyboard.firstKey", k);
706     CC.preferences().setIntProperty("midiKeyboard.lastKey", k2);
707    
708 iliev 1776 }
709     }
710    
711 iliev 1778 private class ActionDecreaseKeyNumber extends AbstractAction {
712     ActionDecreaseKeyNumber() {
713     super(i18n.getLabel("PianoRoll.decreaseKeyNumber"));
714    
715     String s = i18n.getLabel("PianoRoll.decreaseKeyNumber");
716     putValue(SHORT_DESCRIPTION, s);
717     }
718 iliev 1776
719 iliev 1778 public void
720     actionPerformed(ActionEvent e) {
721     if(getLastKey() - getFirstKey() < 31) return;
722     int k = getFirstKey() + 1;
723     if(!isWhiteKey(k)) k++;
724     int k2 = getLastKey() - 1;
725     if(!isWhiteKey(k2)) k2--;
726 iliev 1776
727 iliev 1778 setKeyRange(k, k2);
728     CC.preferences().setIntProperty("midiKeyboard.firstKey", k);
729     CC.preferences().setIntProperty("midiKeyboard.lastKey", k2);
730 iliev 1776
731     }
732 iliev 1778 }
733    
734     private class ActionChangeCurrentOctave extends AbstractAction {
735     private int octave;
736 iliev 1776
737 iliev 1778 ActionChangeCurrentOctave(int octave) {
738     super("");
739     this.octave = octave;
740     }
741 iliev 1776
742 iliev 1778 public void
743     actionPerformed(ActionEvent e) {
744     setCurrentOctave(octave);
745 iliev 1776 }
746 iliev 1778 }
747    
748     private void
749     keyPressed(int keyCode, int note) {
750     fireNoteOn(note, getConstantVelocity());
751     keyMap.put(keyCode, note);
752     }
753    
754     private void
755     keyPressed(int keyCode) {
756     if(!isPlayingEnabled()) return;
757 iliev 1776
758 iliev 1778 int offset = (getCurrentOctave() + 2) * 12;
759 iliev 1776
760 iliev 1778 switch(keyCode) {
761     case KeyEvent.VK_A:
762     keyPressed(keyCode, offset); break;
763     case KeyEvent.VK_W:
764     keyPressed(keyCode, offset + 1); break;
765     case KeyEvent.VK_S:
766     keyPressed(keyCode, offset + 2); break;
767     case KeyEvent.VK_E:
768     keyPressed(keyCode, offset + 3); break;
769     case KeyEvent.VK_D:
770     keyPressed(keyCode, offset + 4); break;
771     case KeyEvent.VK_F:
772     keyPressed(keyCode, offset + 5); break;
773     case KeyEvent.VK_T:
774     keyPressed(keyCode, offset + 6); break;
775     case KeyEvent.VK_G:
776     keyPressed(keyCode, offset + 7); break;
777     case KeyEvent.VK_Y:
778     keyPressed(keyCode, offset + 8); break;
779     case KeyEvent.VK_H:
780     keyPressed(keyCode, offset + 9); break;
781     case KeyEvent.VK_U:
782     keyPressed(keyCode, offset + 10); break;
783     case KeyEvent.VK_J:
784     keyPressed(keyCode, offset + 11); break;
785     case KeyEvent.VK_K:
786     keyPressed(keyCode, offset + 12); break;
787     case KeyEvent.VK_O:
788     keyPressed(keyCode, offset + 13); break;
789     case KeyEvent.VK_L:
790     keyPressed(keyCode, offset + 14); break;
791     case KeyEvent.VK_P:
792     keyPressed(keyCode, offset + 15); break;
793     case KeyEvent.VK_SEMICOLON:
794     keyPressed(keyCode, offset + 16); break;
795     case KeyEvent.VK_QUOTE:
796     keyPressed(keyCode, offset + 17); break;
797 iliev 1776 }
798     }
799    
800 iliev 1778 public void
801     keyReleased(int keyCode) {
802     if(!isPlayingEnabled()) return;
803    
804     switch(keyCode) {
805     case KeyEvent.VK_A:
806     case KeyEvent.VK_W:
807     case KeyEvent.VK_S:
808     case KeyEvent.VK_E:
809     case KeyEvent.VK_D:
810     case KeyEvent.VK_F:
811     case KeyEvent.VK_T:
812     case KeyEvent.VK_G:
813     case KeyEvent.VK_Y:
814     case KeyEvent.VK_H:
815     case KeyEvent.VK_U:
816     case KeyEvent.VK_J:
817     case KeyEvent.VK_K:
818     case KeyEvent.VK_O:
819     case KeyEvent.VK_L:
820     case KeyEvent.VK_P:
821     case KeyEvent.VK_SEMICOLON:
822     case KeyEvent.VK_QUOTE:
823     if(keyMap.get(keyCode) == null) return;
824     fireNoteOff(keyMap.get(keyCode), getConstantVelocity());
825     keyMap.remove(keyCode);
826 iliev 1776 }
827     }
828    
829     private final Handler handler = new Handler();
830    
831     private Handler
832     getHandler() { return handler; }
833    
834 iliev 1778 private class Handler extends MouseAdapter implements KeyListener {
835     @Override
836     public void
837     mouseClicked(MouseEvent e) { requestFocusInWindow(); }
838    
839 iliev 1776 private int pressedKey = -1;
840    
841 iliev 1778 @Override
842     public void
843 iliev 1776 mousePressed(MouseEvent e) {
844     if(!isPlayingEnabled()) return;
845     if(e.getButton() != MouseEvent.BUTTON1) return;
846    
847 iliev 1778 int key = painter.getKeyByPoint(e.getPoint());
848 iliev 1776 if(key == -1) return;
849     pressedKey = key;
850     setKeyPressed(key, true);
851 iliev 1778 int velocity = painter.getVelocity(e.getPoint(), key);
852 iliev 1776
853 iliev 1778 fireNoteOn(key, velocity);
854 iliev 1776 }
855    
856 iliev 1778 @Override
857     public void
858 iliev 1776 mouseReleased(MouseEvent e) {
859     if(!isPlayingEnabled()) return;
860     if(e.getButton() != MouseEvent.BUTTON1) return;
861    
862     if(pressedKey == -1) return;
863     setKeyPressed(pressedKey, false);
864    
865 iliev 1778 int velocity = painter.getVelocity(e.getPoint(), pressedKey);
866 iliev 1776 MidiDataEvent evt = new MidiDataEvent (
867     PianoRoll.this, MidiDataEvent.Type.NOTE_OFF, pressedKey, velocity
868     );
869    
870     pressedKey = -1;
871    
872     fireMidiDataEvent(evt);
873     }
874 iliev 1778
875     @Override
876     public void
877     mouseDragged(MouseEvent e) {
878     if(!isPlayingEnabled()) return;
879     //if(e.getButton() != MouseEvent.BUTTON1) return;
880    
881     if(pressedKey == -1) return;
882     int key = painter.getKeyByPoint(e.getPoint());
883     if(key == pressedKey) return;
884     setKeyPressed(pressedKey, false);
885    
886     int velocity = painter.getVelocity(e.getPoint(), pressedKey);
887     fireNoteOff(pressedKey, velocity);
888    
889     pressedKey = key;
890     if(pressedKey == -1) return;
891    
892     setKeyPressed(key, true);
893     velocity = painter.getVelocity(e.getPoint(), key);
894    
895     fireNoteOn(key, velocity);
896     }
897    
898     private HashMap<Integer, Long> pressedKeysMap = new HashMap<Integer, Long>();
899    
900     public void
901     keyPressed(KeyEvent e) {
902     // Ugly fix for bug 4153069
903     if(pressedKeysMap.get(e.getKeyCode()) == null) {
904     keyPressedNoAutoRepeat(e);
905     }
906    
907     pressedKeysMap.put(e.getKeyCode(), e.getWhen());
908     }
909    
910     public void
911     keyPressedNoAutoRepeat(KeyEvent e) {
912     //System.out.println("Pressed: " + e.getKeyCode() + " " + e.getWhen());
913     if(e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown());
914     else PianoRoll.this.keyPressed(e.getKeyCode());
915     }
916    
917     public void
918     keyReleased(final KeyEvent e) {
919     // Ugly fix for bug 4153069
920     SwingUtilities.invokeLater(new Fix4153069(e));
921     }
922    
923     public void
924     keyReleasedNoAutoRepeat(KeyEvent e) {
925     //System.out.println("Released: " + e.getKeyCode() + " " + e.getWhen());
926     PianoRoll.this.keyReleased(e.getKeyCode());
927     }
928    
929     public void
930     keyTyped(KeyEvent e) { }
931 iliev 1776 }
932 iliev 1778
933     class Fix4153069 implements Runnable, ActionListener {
934     KeyEvent e;
935     int count = 0;
936    
937     Fix4153069(KeyEvent e) {
938     this.e = e;
939     }
940    
941     public void
942     actionPerformed(ActionEvent e) { run(); }
943    
944     public void
945     run() {
946     Long l = getHandler().pressedKeysMap.get(e.getKeyCode());
947     if(l == null || l.longValue() < e.getWhen()) {
948     if(l != null) {
949     if(delay()) return;
950     }
951     getHandler().pressedKeysMap.remove(e.getKeyCode());
952     getHandler().keyReleasedNoAutoRepeat(e);
953     }
954    
955     }
956    
957     private boolean
958     delay() {
959     if(count < 1) {
960     //System.out.println("Delaying...");
961     count++;
962    
963     Timer t = new Timer(4, this);
964     t.setRepeats(false);
965     t.start();
966     return true;
967     }
968    
969     return false;
970     }
971     }
972 iliev 1776 }

  ViewVC Help
Powered by ViewVC