From 61f32339ef00f59befa864b9a0dd58c9a9fd54b2 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 25 Oct 2019 18:05:28 +0200 Subject: Continue C++ification of PianoKeyboard --- gtk2_ardour/gtk_pianokeyboard.cc | 210 ++++++++++++++++++++------------------- gtk2_ardour/gtk_pianokeyboard.h | 31 +++--- 2 files changed, 125 insertions(+), 116 deletions(-) (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/gtk_pianokeyboard.cc b/gtk2_ardour/gtk_pianokeyboard.cc index 222bd78e9e..9646e774a2 100644 --- a/gtk2_ardour/gtk_pianokeyboard.cc +++ b/gtk2_ardour/gtk_pianokeyboard.cc @@ -60,35 +60,16 @@ #define PIANO_KEYBOARD_DEFAULT_WIDTH 730 #define PIANO_KEYBOARD_DEFAULT_HEIGHT 70 +#define PIANO_MIN_NOTE 21 +#define PIANO_MAX_NOTE 108 +#define OCTAVE_MIN (-1) +#define OCTAVE_MAX (7) + void -PianoKeyboard::draw_keyboard_cue (cairo_t* cr, int note) +PianoKeyboard::annotate_layout (cairo_t* cr, int note) const { -#if 0 - int w = _notes[0].w; - int h = _notes[0].h; - - int first_note_in_lower_row = (_octave + 1) * 12; - int last_note_in_lower_row = (_octave + 2) * 12 - 1; - int first_note_in_higher_row = (_octave + 2) * 12; - int last_note_in_higher_row = (_octave + 3) * 12 + 4; - - first_note_in_lower_row = MIN (127, MAX (0, first_note_in_lower_row)); - last_note_in_lower_row = MIN (127, MAX (0, last_note_in_lower_row)); - first_note_in_higher_row = MIN (127, MAX (0, first_note_in_higher_row)); - last_note_in_higher_row = MIN (127, MAX (0, last_note_in_higher_row)); - - cairo_set_source_rgb (cr, 1.0f, 0.0f, 0.0f); - cairo_move_to (cr, _notes[first_note_in_lower_row].x + 3, h - 6); - cairo_line_to (cr, _notes[last_note_in_lower_row].x + w - 3, h - 6); - cairo_stroke (cr); - - cairo_set_source_rgb (cr, 0.0f, 0.0f, 1.0f); - cairo_move_to (cr, _notes[first_note_in_higher_row].x + 3, h - 9); - cairo_line_to (cr, _notes[last_note_in_higher_row].x + w - 3, h - 9); - cairo_stroke (cr); -#endif - int nkey = note - _octave * 12; + if (nkey < 0 || nkey >= NNOTES) { return; } @@ -96,25 +77,21 @@ PianoKeyboard::draw_keyboard_cue (cairo_t* cr, int note) return; } - // TODO Cache PangoFontDescription for each expose call. - // TODO display above note/octave label if both are visible - int is_white = _notes[note].white; - int x = _notes[note].x; - int w = _notes[note].w; - int h = _notes[note].h; + int x = _notes[note].x; + int w = _notes[note].w; + int h = _notes[note].h; int tw, th; char buf[32]; - sprintf (buf, "ArdourMono %dpx", MAX (8, MIN (20, w / 2 + 3))); - PangoFontDescription* font = pango_font_description_from_string (buf); - snprintf (buf, 16, "%lc", gdk_keyval_to_unicode (gdk_keyval_to_upper (gdk_keyval_from_name (_note_bindings[nkey].c_str ())))); + snprintf (buf, 16, "%lc", + gdk_keyval_to_unicode (gdk_keyval_to_upper (gdk_keyval_from_name (_note_bindings.at(nkey).c_str ())))); PangoLayout* pl = pango_cairo_create_layout (cr); - pango_layout_set_font_description (pl, font); + pango_layout_set_font_description (pl, _font_cue); pango_layout_set_text (pl, buf, -1); pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT); pango_layout_get_pixel_size (pl, &tw, &th); - if (is_white) { + if (_notes[note].white) { cairo_set_source_rgba (cr, 0.0, 0.0, 0.5, 1.0); } else { cairo_set_source_rgba (cr, 1.0, 1.0, 0.5, 1.0); @@ -122,30 +99,60 @@ PianoKeyboard::draw_keyboard_cue (cairo_t* cr, int note) if (tw < w) { cairo_save (cr); - cairo_move_to (cr, x + (w - tw) / 2, h - th - 5); + if (_notes[note].white) { + cairo_move_to (cr, x + (w - tw) / 2, h * 2 / 3 + 3); + } else { + cairo_move_to (cr, x + (w - tw) / 2, h - th - 3); + } pango_cairo_show_layout (cr, pl); cairo_restore (cr); } g_object_unref (pl); - pango_font_description_free (font); } void -PianoKeyboard::queue_note_draw (int note) +PianoKeyboard::annotate_note (cairo_t* cr, int note) const { - Gdk::Rectangle rect; - Glib::RefPtr win = get_window (); + assert ((note % 12) == 0); - rect.set_x (_notes[note].x); - rect.set_y (0); - rect.set_width (_notes[note].w); - rect.set_height (_notes[note].h); + int x = _notes[note].x; + int w = _notes[note].w; + int h = _notes[note].h; - win->invalidate_rect (rect, true); // -> queue_draw_area () + int tw, th; + char buf[32]; + sprintf (buf, "C%2d", (note / 12) - 1); + PangoLayout* pl = pango_cairo_create_layout (cr); + pango_layout_set_font_description (pl, _font_octave); + pango_layout_set_text (pl, buf, -1); + pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT); + pango_layout_get_pixel_size (pl, &tw, &th); + + if (th < w && tw < h * .3) { + cairo_save (cr); + cairo_move_to (cr, x + (w - th) / 2, h - 3); + cairo_rotate (cr, M_PI / -2.0); + + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgba (cr, 0, 0, 0, 1.0); + pango_cairo_show_layout (cr, pl); + +#if 0 + cairo_rel_move_to (cr, -.5, -.5); + pango_cairo_update_layout (cr, pl); + cairo_set_source_rgba (cr, 1, 1, 1, 0.3); + pango_cairo_layout_path (cr, pl); + cairo_set_line_width (cr, 1.5); + cairo_stroke (cr); +#endif + + cairo_restore (cr); + } + g_object_unref (pl); } void -PianoKeyboard::draw_note (cairo_t* cr, int note) +PianoKeyboard::draw_note (cairo_t* cr, int note) const { if (note < _min_note || note > _max_note) { return; @@ -185,30 +192,12 @@ PianoKeyboard::draw_note (cairo_t* cr, int note) cairo_rectangle (cr, x, 0, w, h); cairo_stroke (cr); + if (_print_note_label && (note % 12) == 0) { + annotate_note (cr, note); + } + if (_enable_keyboard_cue) { - draw_keyboard_cue (cr, note); - } else if (_print_note_label && (note % 12) == 0) { - int tw, th; - char buf[32]; - sprintf (buf, "ArdourMono %dpx", MAX (10, MIN (20, MIN (w / 2 + 3, h / 7)))); - PangoFontDescription* font = pango_font_description_from_string (buf); - sprintf (buf, "C%2d", (note / 12) - 1); - PangoLayout* pl = pango_cairo_create_layout (cr); - pango_layout_set_font_description (pl, font); - pango_layout_set_text (pl, buf, -1); - pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT); - pango_layout_get_pixel_size (pl, &tw, &th); - - if (th < w && tw < h * .3) { - cairo_save (cr); - cairo_move_to (cr, x + (w - th) / 2, h - 3); - cairo_rotate (cr, M_PI / -2.0); - cairo_set_source_rgba (cr, .0, .0, .0, 1.0); - pango_cairo_show_layout (cr, pl); - cairo_restore (cr); - } - g_object_unref (pl); - pango_font_description_free (font); + annotate_layout (cr, note); } /* We need to redraw black keys that partially obscure the white one. */ @@ -221,7 +210,13 @@ PianoKeyboard::draw_note (cairo_t* cr, int note) } } -int +void +PianoKeyboard::queue_note_draw (int note) +{ + queue_draw_area (_notes[note].x, 0, _notes[note].w, _notes[note].h); +} + +void PianoKeyboard::press_key (int key, int vel) { assert (key >= 0); @@ -230,31 +225,34 @@ PianoKeyboard::press_key (int key, int vel) _maybe_stop_sustained_notes = false; /* This is for keyboard autorepeat protection. */ - if (_notes[key].pressed) - return 0; + if (_notes[key].pressed) { + return; + } if (_sustain_new_notes) { - _notes[key].sustained = 1; + _notes[key].sustained = true; } else { - _notes[key].sustained = 0; + _notes[key].sustained = false; } if (_monophonic && _last_key != key) { - _notes[_last_key].pressed = 0; - _notes[_last_key].sustained = 0; + bool signal_off = _notes[_last_key].pressed || _notes[_last_key].sustained; + _notes[_last_key].pressed = false; + _notes[_last_key].sustained = false; + if (signal_off) { + NoteOff (_last_key); /* EMIT SIGNAL */ + } queue_note_draw (_last_key); } _last_key = key; - _notes[key].pressed = 1; + _notes[key].pressed = true; NoteOn (key, vel); /* EMIT SIGNAL */ queue_note_draw (key); - - return 1; } -int +void PianoKeyboard::release_key (int key) { assert (key >= 0); @@ -262,31 +260,30 @@ PianoKeyboard::release_key (int key) _maybe_stop_sustained_notes = false; - if (!_notes[key].pressed) - return 0; + if (!_notes[key].pressed) { + return; + } if (_sustain_new_notes) { - _notes[key].sustained = 1; + _notes[key].sustained = true; } - _notes[key].pressed = 0; + _notes[key].pressed = false; - if (_notes[key].sustained) - return 0; + if (_notes[key].sustained) { + return; + } NoteOff (key); /* EMIT SIGNAL */ queue_note_draw (key); - - return 1; } void PianoKeyboard::stop_unsustained_notes () { - int i; - for (i = 0; i < NNOTES; ++i) { + for (int i = 0; i < NNOTES; ++i) { if (_notes[i].pressed && !_notes[i].sustained) { - _notes[i].pressed = 0; + _notes[i].pressed = false; NoteOff (i); /* EMIT SIGNAL */ queue_note_draw (i); } @@ -296,11 +293,10 @@ PianoKeyboard::stop_unsustained_notes () void PianoKeyboard::stop_sustained_notes () { - int i; - for (i = 0; i < NNOTES; ++i) { + for (int i = 0; i < NNOTES; ++i) { if (_notes[i].sustained) { - _notes[i].pressed = 0; - _notes[i].sustained = 0; + _notes[i].pressed = false; + _notes[i].sustained = false; NoteOff (i); /* EMIT SIGNAL */ queue_note_draw (i); } @@ -308,7 +304,7 @@ PianoKeyboard::stop_sustained_notes () } int -PianoKeyboard::key_binding (const char* key) +PianoKeyboard::key_binding (const char* key) const { if (_key_bindings.find (key) != _key_bindings.end ()) { return _key_bindings.at (key); @@ -658,6 +654,12 @@ PianoKeyboard::on_expose_event (GdkEventExpose* event) cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height); cairo_clip (cr); + char buf[32]; + sprintf (buf, "ArdourMono %dpx", MAX (8, MIN (20, _notes[1].w / 2 + 3))); + _font_cue = pango_font_description_from_string (buf); + sprintf (buf, "ArdourMono %dpx", MAX (10, MIN (20, MIN (_notes[0].w / 2 + 3, _notes[0].h / 7)))); + _font_octave = pango_font_description_from_string (buf); + for (int i = 0; i < NNOTES; ++i) { GdkRectangle r; @@ -676,6 +678,9 @@ PianoKeyboard::on_expose_event (GdkEventExpose* event) } } + pango_font_description_free (_font_cue); + pango_font_description_free (_font_octave); + cairo_destroy (cr); return true; } @@ -835,6 +840,7 @@ PianoKeyboard::show_note_label (bool enabled) void PianoKeyboard::set_monophonic (bool monophonic) { + _monophonic = monophonic; } @@ -872,8 +878,8 @@ PianoKeyboard::sustain_release () void PianoKeyboard::set_note_on (int note) { - if (_notes[note].pressed == 0) { - _notes[note].pressed = 1; + if (!_notes[note].pressed) { + _notes[note].pressed = true; queue_note_draw (note); } } @@ -882,8 +888,8 @@ void PianoKeyboard::set_note_off (int note) { if (_notes[note].pressed || _notes[note].sustained) { - _notes[note].pressed = 0; - _notes[note].sustained = 0; + _notes[note].pressed = false; + _notes[note].sustained = false; queue_note_draw (note); } } diff --git a/gtk2_ardour/gtk_pianokeyboard.h b/gtk2_ardour/gtk_pianokeyboard.h index 030a3bc221..fd54d8c551 100644 --- a/gtk2_ardour/gtk_pianokeyboard.h +++ b/gtk2_ardour/gtk_pianokeyboard.h @@ -21,16 +21,9 @@ #define __PIANO_KEYBOARD_H__ #include - -#include #include #define NNOTES (128) -#define PIANO_MIN_NOTE 21 -#define PIANO_MAX_NOTE 108 - -#define OCTAVE_MIN (-1) -#define OCTAVE_MAX (7) class PianoKeyboard : public Gtk::DrawingArea { @@ -51,11 +44,14 @@ public: void sustain_press (); void sustain_release (); + void set_note_on (int note); void set_note_off (int note); + void set_keyboard_cue (bool enabled); void set_grand_piano_highlight (bool enabled); void show_note_label (bool enabled); + void set_monophonic (bool monophonic); void set_octave (int octave); void set_octave_range (int octave_range); @@ -74,15 +70,18 @@ protected: void on_size_allocate (Gtk::Allocation&); private: - void draw_keyboard_cue (cairo_t* cr, int note); + void annotate_layout (cairo_t* cr, int note) const; + void annotate_note (cairo_t* cr, int note) const; + void draw_note (cairo_t* cr, int note) const; + void queue_note_draw (int note); - void draw_note (cairo_t* cr, int note); - int press_key (int key, int vel); - int release_key (int key); - void release_key (); - void stop_unsustained_notes (); + + void press_key (int key, int vel); + void release_key (int key); void stop_sustained_notes (); - int key_binding (const char* key); + void stop_unsustained_notes (); + + int key_binding (const char* key) const; void bind_key (const char* key, int note); void clear_notes (); @@ -137,5 +136,9 @@ private: std::map _key_bindings; /**< Table used to translate from PC keyboard character to MIDI note number. */ std::map _note_bindings; /**< Table to translate from MIDI note number to PC keyboard character. */ + + /* these are only valid during expose/draw */ + PangoFontDescription* _font_cue; + PangoFontDescription* _font_octave; }; #endif /* __PIANO_KEYBOARD_H__ */ -- cgit v1.2.3