/[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 1864 - (show annotations) (download)
Sat Mar 14 20:44:58 2009 UTC (15 years, 1 month ago) by iliev
File size: 25330 byte(s)
* Fixed bug in the parameter table when editing
  string list parameters with no possibilities
* Mac OS integration, work in progress:
* ant: added new target build-fantasia-osx
* Moved the menu bar on top of the screen
* Use custom application icon
* Register LSCP scripts to be opened with Fantasia
* Changed shortcut keys (use command key instead of ctrl key)

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

  ViewVC Help
Powered by ViewVC