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

Contents of /jsampler/trunk/src/org/jsampler/view/std/PianoRoll.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1778 - (show 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 /*
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 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.KeyEvent;
31 import java.awt.event.KeyListener;
32 import java.awt.event.MouseEvent;
33 import java.awt.event.MouseAdapter;
34
35 import java.util.HashMap;
36 import java.util.Vector;
37
38 import javax.swing.Action;
39 import javax.swing.AbstractAction;
40 import javax.swing.JComponent;
41 import javax.swing.JPanel;
42 import javax.swing.KeyStroke;
43 import javax.swing.SwingUtilities;
44 import javax.swing.Timer;
45
46 import org.jsampler.CC;
47
48 import org.linuxsampler.lscp.event.MidiDataEvent;
49 import org.linuxsampler.lscp.event.MidiDataListener;
50
51 import static org.jsampler.view.std.StdI18n.i18n;
52
53 /**
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 private Integer[] enabledKeys = null;
101 private Integer[] disabledKeys = null;
102 private Integer[] keyswitches = null;
103 private Integer[] notKeyswitches = null;
104
105 private int currentOctave = 3;
106 private int constantVelocity = 80;
107 private HashMap<Integer, Integer> keyMap = new HashMap<Integer, Integer>();
108
109 private final Vector<MidiDataListener> listeners = new Vector<MidiDataListener>();
110
111 private boolean shouldRepaint = true;
112
113 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 /**
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 setPainter(new BasicPianoRollPainter(this));
146
147 setKeyRange(0, 127);
148
149 installListeneres();
150 }
151
152 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 /**
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 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 /**
265 * 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 * 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 if(getShouldRepaint()) repaint(painter.getKeyRectangle(key));
335 }
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 if(getShouldRepaint()) repaint(painter.getKeyRectangle(key));
349 }
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 * Keys outside the keyboard range are remembered and
389 * applied if needed when the key range is changed.
390 * @param keys List of keys
391 */
392 public void
393 setKeyswitches(Integer[] keys, boolean b) {
394 if(b) keyswitches = keys;
395 else notKeyswitches = keys;
396 if(keys == null) return;
397
398 boolean changed = false;
399 for(int k : keys) {
400 if(!hasKey(k)) continue;
401 if(getKey(k).isKeyswitch() != b) {
402 getKey(k).setKeyswitch(b);
403 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 * Disabled keys outside the keyboard range are remembered and
422 * applied if needed when the key range is changed.
423 * @param keys List of keys
424 */
425 public void
426 setDisabled(Integer[] keys, boolean disable) {
427 if(disable) disabledKeys = keys;
428 else enabledKeys = keys;
429
430 if(keys == null) return;
431
432 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 boolean b = getShouldRepaint();
486 setShouldRepaint(false);
487
488 reset(true, false);
489 setDisabled(enabledKeys, false);
490 setDisabled(disabledKeys, true);
491 setKeyswitches(keyswitches, true);
492 setKeyswitches(notKeyswitches, false);
493
494 setShouldRepaint(b);
495 if(getShouldRepaint()) repaint();
496 }
497
498 public int
499 getFirstKey() { return firstKey; }
500
501 public int
502 getLastKey() { return lastKey; }
503
504 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 public static int
519 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 /**
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 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 /** Gets the number of white keys in the piano roll. */
547 public int
548 getWhiteKeyCount() { return whiteKeyCount; }
549
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 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 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 @Override public void
624 paint(Graphics g) {
625 super.paint(g);
626 painter.paint(this, (Graphics2D)g);
627 }
628
629 @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 }
639
640
641 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 }
663
664
665 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
673 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 }
686 }
687
688 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
696 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 }
709 }
710
711 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
719 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
727 setKeyRange(k, k2);
728 CC.preferences().setIntProperty("midiKeyboard.firstKey", k);
729 CC.preferences().setIntProperty("midiKeyboard.lastKey", k2);
730
731 }
732 }
733
734 private class ActionChangeCurrentOctave extends AbstractAction {
735 private int octave;
736
737 ActionChangeCurrentOctave(int octave) {
738 super("");
739 this.octave = octave;
740 }
741
742 public void
743 actionPerformed(ActionEvent e) {
744 setCurrentOctave(octave);
745 }
746 }
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
758 int offset = (getCurrentOctave() + 2) * 12;
759
760 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 }
798 }
799
800 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 }
827 }
828
829 private final Handler handler = new Handler();
830
831 private Handler
832 getHandler() { return handler; }
833
834 private class Handler extends MouseAdapter implements KeyListener {
835 @Override
836 public void
837 mouseClicked(MouseEvent e) { requestFocusInWindow(); }
838
839 private int pressedKey = -1;
840
841 @Override
842 public void
843 mousePressed(MouseEvent e) {
844 if(!isPlayingEnabled()) return;
845 if(e.getButton() != MouseEvent.BUTTON1) return;
846
847 int key = painter.getKeyByPoint(e.getPoint());
848 if(key == -1) return;
849 pressedKey = key;
850 setKeyPressed(key, true);
851 int velocity = painter.getVelocity(e.getPoint(), key);
852
853 fireNoteOn(key, velocity);
854 }
855
856 @Override
857 public void
858 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 int velocity = painter.getVelocity(e.getPoint(), pressedKey);
866 MidiDataEvent evt = new MidiDataEvent (
867 PianoRoll.this, MidiDataEvent.Type.NOTE_OFF, pressedKey, velocity
868 );
869
870 pressedKey = -1;
871
872 fireMidiDataEvent(evt);
873 }
874
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 }
932
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 }

  ViewVC Help
Powered by ViewVC