VKeybd: Pass on primary (Ctrl/Cmd) shortcuts
[ardour.git] / gtk2_ardour / pianokeyboard.cc
1 /* Piano-keyboard based on jack-keyboard
2  *
3  * Copyright (C) 2019 Robin Gareus <robin@gareus.org>
4  * Copyright (c) 2007, 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <assert.h>
22 #include <math.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include <cairo/cairo.h>
27 #include <pango/pango.h>
28 #include <pango/pangocairo.h>
29
30 #include <gdk/gdkkeysyms.h>
31 #include <gtk/gtk.h>
32
33 #include "gtkmm2ext/keyboard.h"
34
35 #include "pianokeyboard.h"
36
37 #ifndef M_PI
38 #  define M_PI 3.14159265358979323846
39 #endif
40
41 #ifndef MIN
42 #  define MIN(A, B) ((A) < (B)) ? (A) : (B)
43 #endif
44
45 #ifndef MAX
46 #  define MAX(A, B) ((A) > (B)) ? (A) : (B)
47 #endif
48
49 #define PIANO_KEYBOARD_DEFAULT_WIDTH 730
50 #define PIANO_KEYBOARD_DEFAULT_HEIGHT 70
51
52 #define PIANO_MIN_NOTE 21
53 #define PIANO_MAX_NOTE 108
54 #define OCTAVE_MIN (-1)
55 #define OCTAVE_MAX (7)
56
57 void
58 APianoKeyboard::annotate_layout (cairo_t* cr, int note) const
59 {
60         int nkey = note - _octave * 12;
61
62         if (nkey < 0 || nkey >= NNOTES) {
63                 return;
64         }
65
66         std::map<int, std::string>::const_iterator kv = _note_bindings.find (nkey);
67         if (kv == _note_bindings.end ()) {
68                 return;
69         }
70
71         int x = _notes[note].x;
72         int w = _notes[note].w;
73         int h = _notes[note].h;
74
75         int  tw, th;
76         char buf[32];
77         snprintf (buf, 16, "%lc",
78                         gdk_keyval_to_unicode (gdk_keyval_to_upper (gdk_keyval_from_name (kv->second.c_str ()))));
79         PangoLayout* pl = pango_cairo_create_layout (cr);
80         pango_layout_set_font_description (pl, _font_cue);
81         pango_layout_set_text (pl, buf, -1);
82         pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
83         pango_layout_get_pixel_size (pl, &tw, &th);
84
85         if (_notes[note].white) {
86                 cairo_set_source_rgba (cr, 0.0, 0.0, 0.5, 1.0);
87         } else {
88                 cairo_set_source_rgba (cr, 1.0, 1.0, 0.5, 1.0);
89         }
90
91         if (tw < w) {
92                 cairo_save (cr);
93                 if (_notes[note].white) {
94                         cairo_move_to (cr, x + (w - tw) / 2, h * 2 / 3 + 3);
95                 } else {
96                         cairo_move_to (cr, x + (w - tw) / 2, h - th - 3);
97                 }
98                 pango_cairo_show_layout (cr, pl);
99                 cairo_restore (cr);
100         }
101         g_object_unref (pl);
102 }
103
104 void
105 APianoKeyboard::annotate_note (cairo_t* cr, int note) const
106 {
107         assert ((note % 12) == 0);
108
109         int x = _notes[note].x;
110         int w = _notes[note].w;
111         int h = _notes[note].h;
112
113         int  tw, th;
114         char buf[32];
115         sprintf (buf, "C%d", (note / 12) - 1);
116         PangoLayout* pl = pango_cairo_create_layout (cr);
117         pango_layout_set_font_description (pl, _font_octave);
118         pango_layout_set_text (pl, buf, -1);
119         pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
120         pango_layout_get_pixel_size (pl, &tw, &th);
121
122         if (th < w && tw < h * .3) {
123                 cairo_save (cr);
124                 cairo_move_to (cr, x + (w - th) / 2, h - 3);
125                 cairo_rotate (cr, M_PI / -2.0);
126
127                 cairo_set_line_width (cr, 1.0);
128                 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
129                 pango_cairo_show_layout (cr, pl);
130
131 #if 0
132                 cairo_rel_move_to (cr, -.5, -.5);
133                 pango_cairo_update_layout (cr, pl);
134                 cairo_set_source_rgba (cr, 1, 1, 1, 0.3);
135                 pango_cairo_layout_path (cr, pl);
136                 cairo_set_line_width (cr, 1.5);
137                 cairo_stroke (cr);
138 #endif
139
140                 cairo_restore (cr);
141         }
142         g_object_unref (pl);
143 }
144
145 void
146 APianoKeyboard::draw_note (cairo_t* cr, int note) const
147 {
148         if (note < _min_note || note > _max_note) {
149                 return;
150         }
151
152         int is_white = _notes[note].white;
153         int x        = _notes[note].x;
154         int w        = _notes[note].w;
155         int h        = _notes[note].h;
156
157         if (_notes[note].pressed || _notes[note].sustained) {
158                 if (is_white) {
159                         cairo_set_source_rgb (cr, 0.7, 0.5, 0.5);
160                 } else {
161                         cairo_set_source_rgb (cr, 0.6, 0.4, 0.4);
162                 }
163         } else if (_highlight_grand_piano_range && (note < PIANO_MIN_NOTE || note > PIANO_MAX_NOTE)) {
164                 if (is_white) {
165                         cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
166                 } else {
167                         cairo_set_source_rgb (cr, 0.3, 0.3, 0.3);
168                 }
169         } else {
170                 if (is_white) {
171                         cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
172                 } else {
173                         cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
174                 }
175         }
176
177         cairo_set_line_width (cr, 1.0);
178
179         cairo_rectangle (cr, x, 0, w, h);
180         cairo_fill (cr);
181
182         cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f); /* black outline */
183         cairo_rectangle (cr, x, 0, w, h);
184         cairo_stroke (cr);
185
186         if (_annotate_octave && (note % 12) == 0) {
187                 annotate_note (cr, note);
188         }
189
190         if (_annotate_layout) {
191                 annotate_layout (cr, note);
192         }
193
194         /* We need to redraw black keys that partially obscure the white one. */
195         if (note < NNOTES - 2 && !_notes[note + 1].white) {
196                 draw_note (cr, note + 1);
197         }
198
199         if (note > 0 && !_notes[note - 1].white) {
200                 draw_note (cr, note - 1);
201         }
202 }
203
204 void
205 APianoKeyboard::queue_note_draw (int note)
206 {
207         queue_draw_area (_notes[note].x, 0, _notes[note].w, _notes[note].h);
208 }
209
210 void
211 APianoKeyboard::press_key (int key, int vel)
212 {
213         assert (key >= 0);
214         assert (key < NNOTES);
215
216         /* This is for keyboard autorepeat protection. */
217         if (_notes[key].pressed) {
218                 return;
219         }
220
221         if (_sustain_new_notes) {
222                 _notes[key].sustained = true;
223         } else {
224                 _notes[key].sustained = false;
225         }
226
227         if (_monophonic && _last_key != key) {
228                 bool signal_off = _notes[_last_key].pressed || _notes[_last_key].sustained;
229                 _notes[_last_key].pressed = false;
230                 _notes[_last_key].sustained = false;
231                 if (signal_off) {
232                         NoteOff (_last_key); /* EMIT SIGNAL */
233                 }
234                 queue_note_draw (_last_key);
235         }
236         _last_key = key;
237
238         _notes[key].pressed = true;
239
240         NoteOn (key, vel); /* EMIT SIGNAL */
241         queue_note_draw (key);
242 }
243
244 void
245 APianoKeyboard::release_key (int key)
246 {
247         assert (key >= 0);
248         assert (key < NNOTES);
249
250         if (!_notes[key].pressed) {
251                 return;
252         }
253
254         if (_sustain_new_notes) {
255                 _notes[key].sustained = true;
256         }
257
258         _notes[key].pressed = false;
259
260         if (_notes[key].sustained) {
261                 return;
262         }
263
264         NoteOff (key); /* EMIT SIGNAL */
265         queue_note_draw (key);
266 }
267
268 void
269 APianoKeyboard::stop_unsustained_notes ()
270 {
271         for (int i = 0; i < NNOTES; ++i) {
272                 if (_notes[i].pressed && !_notes[i].sustained) {
273                         _notes[i].pressed = false;
274                         NoteOff (i); /* EMIT SIGNAL */
275                         queue_note_draw (i);
276                 }
277         }
278 }
279
280 void
281 APianoKeyboard::stop_sustained_notes ()
282 {
283         for (int i = 0; i < NNOTES; ++i) {
284                 if (_notes[i].sustained) {
285                         _notes[i].sustained = false;
286                         if (_notes[i].pressed) {
287                                 continue;
288                         }
289                         NoteOff (i); /* EMIT SIGNAL */
290                         queue_note_draw (i);
291                 }
292         }
293 }
294
295 int
296 APianoKeyboard::key_binding (const char* key) const
297 {
298         std::map<std::string, int>::const_iterator kv;
299         if (key && (kv = _key_bindings.find (key)) != _key_bindings.end ()) {
300                 return kv->second;
301         }
302         return -1;
303 }
304
305 void
306 APianoKeyboard::bind_key (const char* key, int note)
307 {
308         _key_bindings[key]   = note;
309         _note_bindings[note] = key;
310 }
311
312 void
313 APianoKeyboard::clear_notes ()
314 {
315         _key_bindings.clear ();
316         _note_bindings.clear ();
317 }
318
319 void
320 APianoKeyboard::bind_keys_qwerty ()
321 {
322         clear_notes ();
323
324         bind_key ("space", 128);
325         bind_key ("Tab", 129);
326
327         /* Lower keyboard row - "zxcvbnm". */
328         bind_key ("z", 12); /* C0 */
329         bind_key ("s", 13);
330         bind_key ("x", 14);
331         bind_key ("d", 15);
332         bind_key ("c", 16);
333         bind_key ("v", 17);
334         bind_key ("g", 18);
335         bind_key ("b", 19);
336         bind_key ("h", 20);
337         bind_key ("n", 21);
338         bind_key ("j", 22);
339         bind_key ("m", 23);
340
341         /* Upper keyboard row, first octave - "qwertyu". */
342         bind_key ("q", 24);
343         bind_key ("2", 25);
344         bind_key ("w", 26);
345         bind_key ("3", 27);
346         bind_key ("e", 28);
347         bind_key ("r", 29);
348         bind_key ("5", 30);
349         bind_key ("t", 31);
350         bind_key ("6", 32);
351         bind_key ("y", 33);
352         bind_key ("7", 34);
353         bind_key ("u", 35);
354
355         /* Upper keyboard row, the rest - "iop". */
356         bind_key ("i", 36);
357         bind_key ("9", 37);
358         bind_key ("o", 38);
359         bind_key ("0", 39);
360         bind_key ("p", 40);
361
362         /* ignore */
363         bind_key ("a", -2);
364         bind_key ("f", -3);
365         bind_key ("1", -4);
366         bind_key ("4", -5);
367         bind_key ("8", -6);
368 }
369
370 void
371 APianoKeyboard::bind_keys_qwertz ()
372 {
373         bind_keys_qwerty ();
374
375         /* The only difference between QWERTY and QWERTZ is that the "y" and "z" are swapped together. */
376         bind_key ("y", 12);
377         bind_key ("z", 33);
378 }
379
380 void
381 APianoKeyboard::bind_keys_azerty ()
382 {
383         clear_notes ();
384
385         bind_key ("space", 128);
386         bind_key ("Tab", 129);
387
388         /* Lower keyboard row - "wxcvbn,". */
389         bind_key ("w", 12); /* C0 */
390         bind_key ("s", 13);
391         bind_key ("x", 14);
392         bind_key ("d", 15);
393         bind_key ("c", 16);
394         bind_key ("v", 17);
395         bind_key ("g", 18);
396         bind_key ("b", 19);
397         bind_key ("h", 20);
398         bind_key ("n", 21);
399         bind_key ("j", 22);
400         bind_key ("comma", 23);
401
402         /* Upper keyboard row, first octave - "azertyu". */
403         bind_key ("a", 24);
404         bind_key ("eacute", 25);
405         bind_key ("z", 26);
406         bind_key ("quotedbl", 27);
407         bind_key ("e", 28);
408         bind_key ("r", 29);
409         bind_key ("parenleft", 30);
410         bind_key ("t", 31);
411         bind_key ("minus", 32);
412         bind_key ("y", 33);
413         bind_key ("egrave", 34);
414         bind_key ("u", 35);
415
416         /* Upper keyboard row, the rest - "iop". */
417         bind_key ("i", 36);
418         bind_key ("ccedilla", 37);
419         bind_key ("o", 38);
420         bind_key ("agrave", 39);
421         bind_key ("p", 40);
422 }
423
424 void
425 APianoKeyboard::bind_keys_dvorak ()
426 {
427         clear_notes ();
428
429         bind_key ("space", 128);
430         bind_key ("Tab", 129);
431
432         /* Lower keyboard row - ";qjkxbm". */
433         bind_key ("semicolon", 12); /* C0 */
434         bind_key ("o", 13);
435         bind_key ("q", 14);
436         bind_key ("e", 15);
437         bind_key ("j", 16);
438         bind_key ("k", 17);
439         bind_key ("i", 18);
440         bind_key ("x", 19);
441         bind_key ("d", 20);
442         bind_key ("b", 21);
443         bind_key ("h", 22);
444         bind_key ("m", 23);
445         bind_key ("w", 24); /* overlaps with upper row */
446         bind_key ("n", 25);
447         bind_key ("v", 26);
448         bind_key ("s", 27);
449         bind_key ("z", 28);
450
451         /* Upper keyboard row, first octave - "',.pyfg". */
452         bind_key ("apostrophe", 24);
453         bind_key ("2", 25);
454         bind_key ("comma", 26);
455         bind_key ("3", 27);
456         bind_key ("period", 28);
457         bind_key ("p", 29);
458         bind_key ("5", 30);
459         bind_key ("y", 31);
460         bind_key ("6", 32);
461         bind_key ("f", 33);
462         bind_key ("7", 34);
463         bind_key ("g", 35);
464
465         /* Upper keyboard row, the rest - "crl". */
466         bind_key ("c", 36);
467         bind_key ("9", 37);
468         bind_key ("r", 38);
469         bind_key ("0", 39);
470         bind_key ("l", 40);
471 #if 0
472         bind_key("slash", 41); /* extra F */
473         bind_key("bracketright", 42);
474         bind_key("equal", 43);
475 #endif
476 }
477
478 void
479 APianoKeyboard::bind_keys_basic_qwerty ()
480 {
481         clear_notes ();
482
483         bind_key ("space", 128);
484         bind_key ("Tab", 129);
485
486         /* simple - middle rows only */
487         bind_key ("a", 12); /* C0 */
488         bind_key ("w", 13);
489         bind_key ("s", 14);
490         bind_key ("e", 15);
491         bind_key ("d", 16);
492         bind_key ("f", 17);
493         bind_key ("t", 18);
494         bind_key ("g", 19);
495         bind_key ("y", 20);
496         bind_key ("h", 21);
497         bind_key ("u", 22);
498         bind_key ("j", 23);
499
500         bind_key ("k", 24); /* C1 */
501         bind_key ("o", 25);
502         bind_key ("l", 26);
503         bind_key ("p", 27);
504         bind_key ("semicolon", 28);
505         bind_key ("apostrophe", 29);
506 }
507
508 void
509 APianoKeyboard::bind_keys_basic_qwertz ()
510 {
511         clear_notes ();
512
513         bind_key ("space", 128);
514         bind_key ("Tab", 129);
515
516         /* simple - middle rows only */
517         bind_key ("a", 12); /* C0 */
518         bind_key ("w", 13);
519         bind_key ("s", 14);
520         bind_key ("e", 15);
521         bind_key ("d", 16);
522         bind_key ("f", 17);
523         bind_key ("t", 18);
524         bind_key ("g", 19);
525         bind_key ("z", 20);
526         bind_key ("h", 21);
527         bind_key ("u", 22);
528         bind_key ("j", 23);
529
530         bind_key ("k", 24); /* C1 */
531         bind_key ("o", 25);
532         bind_key ("l", 26);
533         bind_key ("p", 27);
534         bind_key ("semicolon", 28);
535         bind_key ("apostrophe", 29);
536 }
537
538 static const char*
539 get_keycode (GdkEventKey* event)
540 {
541         /* We're not using event->keyval, because we need keyval with level set to 0.
542            E.g. if user holds Shift and presses '7', we want to get a '7', not '&'. */
543
544 #ifdef __APPLE__
545         /* gdkkeys-quartz.c does not implement gdk_keymap_lookup_key */
546         guint keyval;
547         gdk_keymap_translate_keyboard_state (NULL, event->hardware_keycode,
548                                              (GdkModifierType)0, 0,
549                                              &keyval, NULL, NULL, NULL);
550 #else
551         GdkKeymapKey kk;
552         kk.keycode = event->hardware_keycode;
553         kk.level   = 0;
554         kk.group   = 0;
555
556         guint keyval = gdk_keymap_lookup_key (NULL, &kk);
557 #endif
558         return gdk_keyval_name (gdk_keyval_to_lower (keyval));
559 }
560
561 bool
562 APianoKeyboard::on_key_press_event (GdkEventKey* event)
563 {
564          if (Gtkmm2ext::Keyboard::modifier_state_contains (event->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
565                  return false;
566          }
567
568         char const* key = get_keycode (event);
569         int note = key_binding (key);
570
571         if (note < -1) {
572                 return true;
573         }
574         else if (note < 0) {
575                 return false;
576         }
577
578         if (note == 128) {
579                 /* Rest is used on release */
580                 return false;
581         }
582         if (note == 129) {
583                 sustain_press ();
584                 return true;
585         }
586
587         note += _octave * 12;
588
589         assert (key);
590         assert (note >= 0);
591         assert (note < NNOTES);
592
593         _note_stack[key] = note;
594
595         press_key (note, _key_velocity);
596
597         return true;
598 }
599
600 bool
601 APianoKeyboard::on_key_release_event (GdkEventKey* event)
602 {
603          if (Gtkmm2ext::Keyboard::modifier_state_contains (event->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
604                  return false;
605          }
606         char const* key = get_keycode (event);
607
608         if (!key) {
609                 return false;
610         }
611
612         int note = key_binding (key);
613
614         if (note == 128) {
615                 Rest (); /* EMIT SIGNAL */
616                 return true;
617         }
618         if (note == 129) {
619                 sustain_release ();
620                 return true;
621         }
622         if (note < -1) {
623                 return true;
624         }
625
626         std::map<std::string, int>::const_iterator kv = _note_stack.find (key);
627         if (kv == _note_stack.end ()) {
628                 return note != -1;
629         }
630
631         release_key (kv->second);
632         _note_stack.erase (key);
633
634         return true;
635 }
636
637 int
638 APianoKeyboard::get_note_for_xy (int x, int y) const
639 {
640         int height = get_height ();
641         int note;
642
643         if (y <= ((height * 2) / 3)) { /* might be a black key */
644                 for (note = 0; note <= _max_note; ++note) {
645                         if (_notes[note].white) {
646                                 continue;
647                         }
648
649                         if (x >= _notes[note].x && x <= _notes[note].x + _notes[note].w) {
650                                 return note;
651                         }
652                 }
653         }
654
655         for (note = 0; note <= _max_note; ++note) {
656                 if (!_notes[note].white) {
657                         continue;
658                 }
659
660                 if (x >= _notes[note].x && x <= _notes[note].x + _notes[note].w) {
661                         return note;
662                 }
663         }
664
665         return -1;
666 }
667
668 int
669 APianoKeyboard::get_velocity_for_note_at_y (int note, int y) const
670 {
671         if (note < 0) {
672                 return 0;
673         }
674         int vel = _min_velocity + (_max_velocity - _min_velocity) * y / _notes[note].h;
675
676         if (vel < 1) {
677                 return 1;
678         } else if (vel > 127) {
679                 return 127;
680         }
681         return vel;
682 }
683
684 bool
685 APianoKeyboard::on_button_press_event (GdkEventButton* event)
686 {
687         int x = event->x;
688         int y = event->y;
689
690         int note = get_note_for_xy (x, y);
691
692         if (event->button != 1)
693                 return true;
694
695         if (event->type == GDK_BUTTON_PRESS) {
696                 if (note < 0) {
697                         return true;
698                 }
699
700                 if (_note_being_pressed_using_mouse >= 0) {
701                         release_key (_note_being_pressed_using_mouse);
702                 }
703
704                 press_key (note, get_velocity_for_note_at_y (note, y));
705                 _note_being_pressed_using_mouse = note;
706
707         } else if (event->type == GDK_BUTTON_RELEASE) {
708                 if (note >= 0) {
709                         release_key (note);
710                 } else {
711                         if (_note_being_pressed_using_mouse >= 0) {
712                                 release_key (_note_being_pressed_using_mouse);
713                         }
714                 }
715                 _note_being_pressed_using_mouse = -1;
716         }
717
718         return true;
719 }
720
721 bool
722 APianoKeyboard::on_button_release_event (GdkEventButton* event)
723 {
724         return on_button_press_event (event);
725 }
726
727 bool
728 APianoKeyboard::on_motion_notify_event (GdkEventMotion* event)
729 {
730         int note;
731
732         if ((event->state & GDK_BUTTON1_MASK) == 0)
733                 return true;
734
735         int x = event->x;
736         int y = event->y;
737
738         note = get_note_for_xy (x, y);
739
740         if (note != _note_being_pressed_using_mouse && note >= 0) {
741                 if (_note_being_pressed_using_mouse >= 0) {
742                         release_key (_note_being_pressed_using_mouse);
743                 }
744                 press_key (note, get_velocity_for_note_at_y (note, y));
745                 _note_being_pressed_using_mouse = note;
746         }
747
748         return true;
749 }
750
751 bool
752 APianoKeyboard::on_expose_event (GdkEventExpose* event)
753 {
754         cairo_t* cr = gdk_cairo_create (GDK_DRAWABLE (get_window ()->gobj ()));
755         cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
756         cairo_clip (cr);
757
758         char buf[32];
759         sprintf (buf, "ArdourMono %dpx", MAX (8, MIN (20, _notes[1].w / 2 + 3)));
760         _font_cue = pango_font_description_from_string (buf);
761         sprintf (buf, "ArdourMono %dpx", MAX (8, MIN (20, MIN (_notes[0].w * 11 / 15 , _notes[0].h / 7))));
762         _font_octave = pango_font_description_from_string (buf);
763
764         for (int i = 0; i < NNOTES; ++i) {
765                 GdkRectangle r;
766
767                 r.x      = _notes[i].x;
768                 r.y      = 0;
769                 r.width  = _notes[i].w;
770                 r.height = _notes[i].h;
771
772                 switch (gdk_region_rect_in (event->region, &r)) {
773                         case GDK_OVERLAP_RECTANGLE_PART:
774                         case GDK_OVERLAP_RECTANGLE_IN:
775                                 draw_note (cr, i);
776                                 break;
777                         default:
778                                 break;
779                 }
780         }
781
782         pango_font_description_free (_font_cue);
783         pango_font_description_free (_font_octave);
784
785         cairo_destroy (cr);
786         return true;
787 }
788
789 void
790 APianoKeyboard::on_size_request (Gtk::Requisition* requisition)
791 {
792         requisition->width  = PIANO_KEYBOARD_DEFAULT_WIDTH;
793         requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT;
794         if (_annotate_layout) {
795                 requisition->height += 16;
796         }
797         if (_annotate_octave) {
798                 requisition->height += 24;
799         }
800 }
801
802 int
803 APianoKeyboard::is_black (int key) const
804 {
805         int note_in_octave = key % 12;
806         switch (note_in_octave) {
807                 case 1:
808                 case 3:
809                 case 6:
810                 case 8:
811                 case 10:
812                         return 1;
813                 default:
814                         return 0;
815         }
816         return 0;
817 }
818
819 double
820 APianoKeyboard::black_key_left_shift (int key) const
821 {
822         int note_in_octave = key % 12;
823         switch (note_in_octave) {
824                 case 1:
825                         return 2.0 / 3.0;
826                 case 3:
827                         return 1.0 / 3.0;
828                 case 6:
829                         return 2.0 / 3.0;
830                 case 8:
831                         return 0.5;
832                 case 10:
833                         return 1.0 / 3.0;
834                 default:
835                         return 0;
836         }
837         return 0;
838 }
839
840 void
841 APianoKeyboard::recompute_dimensions ()
842 {
843         int note;
844         int number_of_white_keys = 0;
845         int skipped_white_keys   = 0;
846
847         for (note = _min_note; note <= _max_note; ++note) {
848                 if (!is_black (note)) {
849                         ++number_of_white_keys;
850                 }
851         }
852         for (note = 0; note < _min_note; ++note) {
853                 if (!is_black (note)) {
854                         ++skipped_white_keys;
855                 }
856         }
857
858         int width  = get_width ();
859         int height = get_height ();
860
861         int key_width       = width / number_of_white_keys;
862         int black_key_width = key_width * 0.8;
863         int useful_width    = number_of_white_keys * key_width;
864
865         int widget_margin = (width - useful_width) / 2;
866
867         int white_key;
868         for (note = 0, white_key = -skipped_white_keys; note < NNOTES; ++note) {
869                 if (is_black (note)) {
870                         /* This note is black key. */
871                         _notes[note].x = widget_margin +
872                                          (white_key * key_width) -
873                                          (black_key_width * black_key_left_shift (note));
874                         _notes[note].w     = black_key_width;
875                         _notes[note].h     = (height * 2) / 3;
876                         _notes[note].white = 0;
877                         continue;
878                 }
879
880                 /* This note is white key. */
881                 _notes[note].x     = widget_margin + white_key * key_width;
882                 _notes[note].w     = key_width;
883                 _notes[note].h     = height;
884                 _notes[note].white = 1;
885
886                 white_key++;
887         }
888 }
889
890 void
891 APianoKeyboard::on_size_allocate (Gtk::Allocation& allocation)
892 {
893         DrawingArea::on_size_allocate (allocation);
894         recompute_dimensions ();
895 }
896
897 APianoKeyboard::APianoKeyboard ()
898 {
899         using namespace Gdk;
900         add_events (KEY_PRESS_MASK | KEY_RELEASE_MASK | BUTTON_PRESS_MASK | BUTTON_RELEASE_MASK | POINTER_MOTION_MASK | POINTER_MOTION_HINT_MASK);
901
902         _sustain_new_notes              = false;
903         _highlight_grand_piano_range    = true;
904         _annotate_layout                = false;
905         _annotate_octave                = false;
906         _octave                         = 4;
907         _octave_range                   = 7;
908         _note_being_pressed_using_mouse = -1;
909         _min_note                       = 0;
910         _max_note                       = 127;
911         _last_key                       = 0;
912         _monophonic                     = false;
913
914         _min_velocity = 1;
915         _max_velocity = 127;
916         _key_velocity = 100;
917
918         bind_keys_qwerty ();
919 }
920
921 APianoKeyboard::~APianoKeyboard ()
922 {
923 }
924
925 void
926 APianoKeyboard::set_grand_piano_highlight (bool enabled)
927 {
928         _highlight_grand_piano_range = enabled;
929         queue_draw ();
930 }
931
932 void
933 APianoKeyboard::set_annotate_layout (bool enabled)
934 {
935         _annotate_layout = enabled;
936         queue_draw ();
937 }
938
939 void
940 APianoKeyboard::set_annotate_octave (bool enabled)
941 {
942         _annotate_octave = enabled;
943         queue_draw ();
944 }
945
946 void
947 APianoKeyboard::set_monophonic (bool monophonic)
948 {
949         _monophonic = monophonic;
950 }
951
952 void
953 APianoKeyboard::set_velocities (int min_vel, int max_vel, int key_vel)
954 {
955         if (min_vel <= max_vel && min_vel > 0 && max_vel < 128) {
956                 _min_velocity = min_vel;
957                 _max_velocity = max_vel;
958         }
959
960         if (key_vel > 0 && key_vel < 128) {
961                 _key_velocity = key_vel;
962         }
963 }
964
965 void
966 APianoKeyboard::sustain_press ()
967 {
968         if (_sustain_new_notes) {
969                 return;
970         }
971         _sustain_new_notes = true;
972         SustainChanged (true); /* EMIT SIGNAL */
973 }
974
975 void
976 APianoKeyboard::sustain_release ()
977 {
978         stop_sustained_notes ();
979         if (_sustain_new_notes) {
980                 _sustain_new_notes = false;
981                 SustainChanged (false); /* EMIT SIGNAL */
982         }
983 }
984
985 void
986 APianoKeyboard::set_note_on (int note)
987 {
988         if (!_notes[note].pressed) {
989                 _notes[note].pressed = true;
990                 queue_note_draw (note);
991         }
992 }
993
994 void
995 APianoKeyboard::set_note_off (int note)
996 {
997         if (_notes[note].pressed || _notes[note].sustained) {
998                 _notes[note].pressed   = false;
999                 _notes[note].sustained = false;
1000                 queue_note_draw (note);
1001         }
1002 }
1003
1004 void
1005 APianoKeyboard::set_octave (int octave)
1006 {
1007         if (octave < -1) {
1008                 octave = -1;
1009         } else if (octave > 7) {
1010                 octave = 7;
1011         }
1012
1013         _octave = octave;
1014         set_octave_range (_octave_range);
1015 }
1016
1017 void
1018 APianoKeyboard::set_octave_range (int octave_range)
1019 {
1020         if (octave_range < 2) {
1021                 octave_range = 2;
1022         }
1023         if (octave_range > 11) {
1024                 octave_range = 11;
1025         }
1026
1027         _octave_range = octave_range;
1028
1029         /* -1 <= _octave <= 7
1030          * key-bindings are at offset 12 .. 40
1031          * default piano range: _octave = 4, range = 7 -> note 21..108
1032          */
1033
1034         switch (_octave_range) {
1035                 default:
1036                         assert (0);
1037                         break;
1038                 case 2:
1039                 case 3:
1040                         _min_note = (_octave + 1) * 12;
1041                         break;
1042                 case 4:
1043                 case 5:
1044                         _min_note = (_octave + 0) * 12;
1045                         break;
1046                 case 6:
1047                         _min_note = (_octave - 1) * 12;
1048                         break;
1049                 case 7:
1050                 case 8:
1051                         _min_note = (_octave - 2) * 12;
1052                         break;
1053                 case 9:
1054                 case 10:
1055                         _min_note = (_octave - 3) * 12;
1056                         break;
1057                 case 11:
1058                         _min_note = (_octave - 4) * 12;
1059                         break;
1060         }
1061
1062         int upper_offset = 0;
1063
1064         if (_min_note < 3) {
1065                 upper_offset = 0;
1066                 _min_note    = 0;
1067         } else if (_octave_range > 5) {
1068                 /* extend down to A */
1069                 upper_offset = 3;
1070                 _min_note -= 3;
1071         }
1072
1073         _max_note = MIN (127, upper_offset + _min_note + _octave_range * 12);
1074
1075         if (_max_note == 127) {
1076                 _min_note = MAX (0, _max_note - _octave_range * 12);
1077         }
1078
1079         recompute_dimensions ();
1080         queue_draw ();
1081 }
1082
1083 void
1084 APianoKeyboard::set_keyboard_layout (Layout layout)
1085 {
1086         switch (layout) {
1087                 case QWERTY:
1088                         bind_keys_qwerty ();
1089                         break;
1090                 case QWERTZ:
1091                         bind_keys_qwertz ();
1092                         break;
1093                 case AZERTY:
1094                         bind_keys_azerty ();
1095                         break;
1096                 case DVORAK:
1097                         bind_keys_dvorak ();
1098                         break;
1099                 case S_QWERTY:
1100                         bind_keys_basic_qwerty ();
1101                         break;
1102                 case S_QWERTZ:
1103                         bind_keys_basic_qwertz ();
1104                         break;
1105         }
1106         queue_draw ();
1107 }