summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2019-10-24 19:43:46 +0200
committerRobin Gareus <robin@gareus.org>2019-10-24 19:59:22 +0200
commit3f2f5172915973a98b550c70cabbe979553664b2 (patch)
tree7713bf254c2128d586eee0f41f7374fb1cd46a70 /gtk2_ardour
parent7664f8fd29793be09899cd1c94695a2a3880215f (diff)
Rough-in gtk-pianokeyboard C -> C++
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/generic_pluginui.cc31
-rw-r--r--gtk2_ardour/gtk_pianokeyboard.c1131
-rw-r--r--gtk2_ardour/gtk_pianokeyboard.cc994
-rw-r--r--gtk2_ardour/gtk_pianokeyboard.h166
-rw-r--r--gtk2_ardour/note_select_dialog.cc27
-rw-r--r--gtk2_ardour/note_select_dialog.h9
-rw-r--r--gtk2_ardour/patch_change_widget.cc32
-rw-r--r--gtk2_ardour/patch_change_widget.h6
-rw-r--r--gtk2_ardour/plugin_ui.h5
-rw-r--r--gtk2_ardour/step_entry.cc27
-rw-r--r--gtk2_ardour/step_entry.h10
-rw-r--r--gtk2_ardour/virtual_keyboard_window.cc74
-rw-r--r--gtk2_ardour/virtual_keyboard_window.h13
-rw-r--r--gtk2_ardour/wscript2
14 files changed, 1185 insertions, 1342 deletions
diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc
index b091840e55..1d1ee67e62 100644
--- a/gtk2_ardour/generic_pluginui.cc
+++ b/gtk2_ardour/generic_pluginui.cc
@@ -88,7 +88,6 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
, is_scrollable(scrollable)
, _plugin_pianokeyboard_expander (_("MIDI Keyboard"))
, _piano (0)
- , _pianomm (0)
, _piano_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
, _piano_channel (*manage (new Adjustment (0, 1, 16, 1, 1)))
{
@@ -140,13 +139,11 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
VBox* v1_box = manage (new VBox);
VBox* v2_box = manage (new VBox);
if (pi->is_instrument ()) {
- _piano = (PianoKeyboard*)piano_keyboard_new();
- _pianomm = Glib::wrap((GtkWidget*)_piano);
- _pianomm->set_flags(Gtk::CAN_FOCUS);
- _pianomm->add_events(Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
+ _piano = new PianoKeyboard ();
+ _piano->set_flags(Gtk::CAN_FOCUS);
- g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (GenericPluginUI::_note_on_event_handler), this);
- g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (GenericPluginUI::_note_off_event_handler), this);
+ _piano->NoteOn.connect (sigc::mem_fun (*this, &GenericPluginUI::note_on_event_handler));
+ _piano->NoteOff.connect (sigc::mem_fun (*this, &GenericPluginUI::note_off_event_handler));
HBox* box = manage (new HBox);
box->pack_start (*manage (new Label (_("Channel:"))), false, false);
@@ -159,7 +156,7 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrol
_pianobox.set_spacing (4);
_pianobox.pack_start (*box2, true, true);
- _pianobox.pack_start (*_pianomm, true, true);
+ _pianobox.pack_start (*_piano, true, true);
_plugin_pianokeyboard_expander.set_expanded(false);
_plugin_pianokeyboard_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &GenericPluginUI::toggle_pianokeyboard));
@@ -236,7 +233,7 @@ GenericPluginUI::~GenericPluginUI ()
screen_update_connection.disconnect();
}
delete automation_menu;
- delete _pianomm;
+ delete _piano;
}
void
@@ -1392,22 +1389,10 @@ GenericPluginUI::toggle_pianokeyboard ()
}
void
-GenericPluginUI::_note_on_event_handler(GtkWidget*, int note, int, gpointer arg)
-{
- ((GenericPluginUI*)arg)->note_on_event_handler(note);
-}
-
-void
-GenericPluginUI::_note_off_event_handler(GtkWidget*, int note, gpointer arg)
-{
- ((GenericPluginUI*)arg)->note_off_event_handler(note);
-}
-
-void
-GenericPluginUI::note_on_event_handler (int note)
+GenericPluginUI::note_on_event_handler (int note, int)
{
MidiTrack* mt = dynamic_cast<MidiTrack*> (insert->owner());
- _pianomm->grab_focus ();
+ _piano->grab_focus ();
uint8_t channel = _piano_channel.get_value_as_int () - 1;
uint8_t event[3];
event[0] = (MIDI_CMD_NOTE_ON | channel);
diff --git a/gtk2_ardour/gtk_pianokeyboard.c b/gtk2_ardour/gtk_pianokeyboard.c
deleted file mode 100644
index 5448b2d59b..0000000000
--- a/gtk2_ardour/gtk_pianokeyboard.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-/*-
- * Copyright (c) 2007, 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * This is piano_keyboard, piano keyboard-like GTK+ widget. It contains
- * no MIDI-specific code.
- *
- * For questions and comments, contact Edward Tomasz Napierala <trasz@FreeBSD.org>.
- */
-
-#include <assert.h>
-#include <math.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <cairo/cairo.h>
-# include <pango/pango.h>
-#include <pango/pangocairo.h>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include "gtk_pianokeyboard.h"
-
-#ifndef MIN
-# define MIN(A, B) ((A) < (B)) ? (A) : (B)
-#endif
-
-#ifndef MAX
-# define MAX(A, B) ((A) > (B)) ? (A) : (B)
-#endif
-
-#define PIANO_KEYBOARD_DEFAULT_WIDTH 730
-#define PIANO_KEYBOARD_DEFAULT_HEIGHT 70
-
-enum {
- NOTE_ON_SIGNAL,
- NOTE_OFF_SIGNAL,
- REST_SIGNAL,
- LAST_SIGNAL
-};
-
-static guint piano_keyboard_signals[LAST_SIGNAL] = { 0 };
-
-static void
-draw_keyboard_cue (PianoKeyboard* pk, cairo_t* cr, int note)
-{
-#if 0
- int w = pk->notes[0].w;
- int h = pk->notes[0].h;
-
- int first_note_in_lower_row = (pk->octave + 1) * 12;
- int last_note_in_lower_row = (pk->octave + 2) * 12 - 1;
- int first_note_in_higher_row = (pk->octave + 2) * 12;
- int last_note_in_higher_row = (pk->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, pk->notes[first_note_in_lower_row].x + 3, h - 6);
- cairo_line_to (cr, pk->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, pk->notes[first_note_in_higher_row].x + 3, h - 9);
- cairo_line_to (cr, pk->notes[last_note_in_higher_row].x + w - 3, h - 9);
- cairo_stroke (cr);
-#endif
-
- int nkey = note - pk->octave * 12;
- if (nkey < 0 || nkey >= NNOTES) {
- return;
- }
- if (!pk->note_bindings[nkey]) {
- return;
- }
-
- // TODO Cache PangoFontDescription for each expose call.
- // TODO display above note/octave label if both are visible
- int is_white = pk->notes[note].white;
- int x = pk->notes[note].x;
- int w = pk->notes[note].w;
- int h = pk->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 (pk->note_bindings[nkey]))));
- 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 (is_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);
- }
-
- if (tw < w) {
- cairo_save (cr);
- cairo_move_to (cr, x + (w - tw) / 2, h - th - 5);
- pango_cairo_show_layout (cr, pl);
- cairo_restore (cr);
- }
- g_object_unref (pl);
- pango_font_description_free (font);
-}
-
-static void
-queue_note_draw (PianoKeyboard* pk, int note)
-{
- GdkWindow* w = GTK_WIDGET (pk)->window;
-
- if (w) {
- GdkRectangle r;
-
- r.x = pk->notes[note].x;
- r.y = 0;
- r.width = pk->notes[note].w;
- r.height = pk->notes[note].h;
-
- gdk_window_invalidate_rect (w, &r, TRUE);
- }
-}
-
-static void
-draw_note (PianoKeyboard* pk, cairo_t* cr, int note)
-{
- if (note < pk->min_note || note > pk->max_note) {
- return;
- }
-
- int is_white = pk->notes[note].white;
- int x = pk->notes[note].x;
- int w = pk->notes[note].w;
- int h = pk->notes[note].h;
-
- if (pk->notes[note].pressed || pk->notes[note].sustained) {
- if (is_white) {
- cairo_set_source_rgb (cr, 0.7, 0.5, 0.5);
- } else {
- cairo_set_source_rgb (cr, 0.6, 0.4, 0.4);
- }
- } else if (pk->highlight_grand_piano_range && (note < PIANO_MIN_NOTE || note > PIANO_MAX_NOTE)) {
- if (is_white) {
- cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
- } else {
- cairo_set_source_rgb (cr, 0.3, 0.3, 0.3);
- }
- } else {
- if (is_white) {
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- } else {
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- }
- }
-
- cairo_set_line_width (cr, 1.0);
-
- cairo_rectangle (cr, x, 0, w, h);
- cairo_fill (cr);
-
- cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f); /* black outline */
- cairo_rectangle (cr, x, 0, w, h);
- cairo_stroke (cr);
-
- if (pk->enable_keyboard_cue) {
- draw_keyboard_cue (pk, cr, note);
- }
- else if (pk->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);
- }
-
- /* We need to redraw black keys that partially obscure the white one. */
- if (note < NNOTES - 2 && !pk->notes[note + 1].white) {
- draw_note (pk, cr, note + 1);
- }
-
- if (note > 0 && !pk->notes[note - 1].white) {
- draw_note (pk, cr, note - 1);
- }
-}
-
-static int
-press_key (PianoKeyboard* pk, int key, int vel)
-{
- assert (key >= 0);
- assert (key < NNOTES);
-
- pk->maybe_stop_sustained_notes = 0;
-
- /* This is for keyboard autorepeat protection. */
- if (pk->notes[key].pressed)
- return 0;
-
- if (pk->sustain_new_notes)
- pk->notes[key].sustained = 1;
- else
- pk->notes[key].sustained = 0;
-
- if (pk->monophonic && pk->last_key != key) {
- pk->notes[pk->last_key].pressed = 0;
- pk->notes[pk->last_key].sustained = 0;
- queue_note_draw (pk, pk->last_key);
- }
- pk->last_key = key;
-
- pk->notes[key].pressed = 1;
-
- g_signal_emit_by_name (GTK_WIDGET (pk), "note-on", key, vel);
- queue_note_draw (pk, key);
-
- return 1;
-}
-
-static int
-release_key (PianoKeyboard* pk, int key)
-{
- assert (key >= 0);
- assert (key < NNOTES);
-
- pk->maybe_stop_sustained_notes = 0;
-
- if (!pk->notes[key].pressed)
- return 0;
-
- if (pk->sustain_new_notes)
- pk->notes[key].sustained = 1;
-
- pk->notes[key].pressed = 0;
-
- if (pk->notes[key].sustained)
- return 0;
-
- g_signal_emit_by_name (GTK_WIDGET (pk), "note-off", key);
- queue_note_draw (pk, key);
-
- return 1;
-}
-
-static void
-rest (PianoKeyboard* pk)
-{
- g_signal_emit_by_name (GTK_WIDGET (pk), "rest");
-}
-
-static void
-stop_unsustained_notes (PianoKeyboard* pk)
-{
- int i;
- for (i = 0; i < NNOTES; ++i) {
- if (pk->notes[i].pressed && !pk->notes[i].sustained) {
- pk->notes[i].pressed = 0;
- g_signal_emit_by_name (GTK_WIDGET (pk), "note-off", i);
- queue_note_draw (pk, i);
- }
- }
-}
-
-static void
-stop_sustained_notes (PianoKeyboard* pk)
-{
- int i;
- for (i = 0; i < NNOTES; ++i) {
- if (pk->notes[i].sustained) {
- pk->notes[i].pressed = 0;
- pk->notes[i].sustained = 0;
- g_signal_emit_by_name (GTK_WIDGET (pk), "note-off", i);
- queue_note_draw (pk, i);
- }
- }
-}
-
-static int
-key_binding (PianoKeyboard* pk, const char* key)
-{
- gpointer notused, note;
- gboolean found;
-
- assert (pk->key_bindings != NULL);
-
- found = g_hash_table_lookup_extended (pk->key_bindings, key, &notused, &note);
-
- if (!found)
- return -1;
-
- return (intptr_t)note;
-}
-
-static void
-bind_key (PianoKeyboard* pk, const char* key, int note)
-{
- assert (pk->key_bindings != NULL);
-
- g_hash_table_insert (pk->key_bindings, (const gpointer)key, (gpointer) ((intptr_t)note));
- pk->note_bindings[note] = key;
-}
-
-static void
-clear_notes (PianoKeyboard* pk)
-{
- assert (pk->key_bindings != NULL);
-
- g_hash_table_remove_all (pk->key_bindings);
- memset (pk->note_bindings, 0, sizeof (pk->note_bindings));
-}
-
-static void
-bind_keys_qwerty (PianoKeyboard* pk)
-{
- clear_notes (pk);
-
- bind_key (pk, "space", 128);
-
- /* Lower keyboard row - "zxcvbnm". */
- bind_key (pk, "z", 12); /* C0 */
- bind_key (pk, "s", 13);
- bind_key (pk, "x", 14);
- bind_key (pk, "d", 15);
- bind_key (pk, "c", 16);
- bind_key (pk, "v", 17);
- bind_key (pk, "g", 18);
- bind_key (pk, "b", 19);
- bind_key (pk, "h", 20);
- bind_key (pk, "n", 21);
- bind_key (pk, "j", 22);
- bind_key (pk, "m", 23);
-
- /* Upper keyboard row, first octave - "qwertyu". */
- bind_key (pk, "q", 24);
- bind_key (pk, "2", 25);
- bind_key (pk, "w", 26);
- bind_key (pk, "3", 27);
- bind_key (pk, "e", 28);
- bind_key (pk, "r", 29);
- bind_key (pk, "5", 30);
- bind_key (pk, "t", 31);
- bind_key (pk, "6", 32);
- bind_key (pk, "y", 33);
- bind_key (pk, "7", 34);
- bind_key (pk, "u", 35);
-
- /* Upper keyboard row, the rest - "iop". */
- bind_key (pk, "i", 36);
- bind_key (pk, "9", 37);
- bind_key (pk, "o", 38);
- bind_key (pk, "0", 39);
- bind_key (pk, "p", 40);
-}
-
-static void
-bind_keys_qwertz (PianoKeyboard* pk)
-{
- bind_keys_qwerty (pk);
-
- /* The only difference between QWERTY and QWERTZ is that the "y" and "z" are swapped together. */
- bind_key (pk, "y", 12);
- bind_key (pk, "z", 33);
-}
-
-static void
-bind_keys_azerty (PianoKeyboard* pk)
-{
- clear_notes (pk);
-
- bind_key (pk, "space", 128);
-
- /* Lower keyboard row - "wxcvbn,". */
- bind_key (pk, "w", 12); /* C0 */
- bind_key (pk, "s", 13);
- bind_key (pk, "x", 14);
- bind_key (pk, "d", 15);
- bind_key (pk, "c", 16);
- bind_key (pk, "v", 17);
- bind_key (pk, "g", 18);
- bind_key (pk, "b", 19);
- bind_key (pk, "h", 20);
- bind_key (pk, "n", 21);
- bind_key (pk, "j", 22);
- bind_key (pk, "comma", 23);
-
- /* Upper keyboard row, first octave - "azertyu". */
- bind_key (pk, "a", 24);
- bind_key (pk, "eacute", 25);
- bind_key (pk, "z", 26);
- bind_key (pk, "quotedbl", 27);
- bind_key (pk, "e", 28);
- bind_key (pk, "r", 29);
- bind_key (pk, "parenleft", 30);
- bind_key (pk, "t", 31);
- bind_key (pk, "minus", 32);
- bind_key (pk, "y", 33);
- bind_key (pk, "egrave", 34);
- bind_key (pk, "u", 35);
-
- /* Upper keyboard row, the rest - "iop". */
- bind_key (pk, "i", 36);
- bind_key (pk, "ccedilla", 37);
- bind_key (pk, "o", 38);
- bind_key (pk, "agrave", 39);
- bind_key (pk, "p", 40);
-}
-
-static void
-bind_keys_dvorak (PianoKeyboard* pk)
-{
- clear_notes (pk);
-
- bind_key (pk, "space", 128);
-
- /* Lower keyboard row - ";qjkxbm". */
- bind_key (pk, "semicolon", 12); /* C0 */
- bind_key (pk, "o", 13);
- bind_key (pk, "q", 14);
- bind_key (pk, "e", 15);
- bind_key (pk, "j", 16);
- bind_key (pk, "k", 17);
- bind_key (pk, "i", 18);
- bind_key (pk, "x", 19);
- bind_key (pk, "d", 20);
- bind_key (pk, "b", 21);
- bind_key (pk, "h", 22);
- bind_key (pk, "m", 23);
- bind_key (pk, "w", 24); /* overlaps with upper row */
- bind_key (pk, "n", 25);
- bind_key (pk, "v", 26);
- bind_key (pk, "s", 27);
- bind_key (pk, "z", 28);
-
- /* Upper keyboard row, first octave - "',.pyfg". */
- bind_key (pk, "apostrophe", 24);
- bind_key (pk, "2", 25);
- bind_key (pk, "comma", 26);
- bind_key (pk, "3", 27);
- bind_key (pk, "period", 28);
- bind_key (pk, "p", 29);
- bind_key (pk, "5", 30);
- bind_key (pk, "y", 31);
- bind_key (pk, "6", 32);
- bind_key (pk, "f", 33);
- bind_key (pk, "7", 34);
- bind_key (pk, "g", 35);
-
- /* Upper keyboard row, the rest - "crl". */
- bind_key (pk, "c", 36);
- bind_key (pk, "9", 37);
- bind_key (pk, "r", 38);
- bind_key (pk, "0", 39);
- bind_key (pk, "l", 40);
-#if 0
- bind_key(pk, "slash", 41); /* extra F */
- bind_key(pk, "bracketright", 42);
- bind_key(pk, "equal", 43);
-#endif
-}
-
-static gint
-keyboard_event_handler (GtkWidget* mk, GdkEventKey* event, gpointer ignored)
-{
- int note;
- char* key;
- guint keyval;
-
- GdkKeymapKey kk;
- PianoKeyboard* pk = PIANO_KEYBOARD (mk);
-
- (void)ignored;
-
- /* We're not using event->keyval, because we need keyval with level set to 0.
- E.g. if user holds Shift and presses '7', we want to get a '7', not '&'. */
- kk.keycode = event->hardware_keycode;
- kk.level = 0;
- kk.group = 0;
-
- keyval = gdk_keymap_lookup_key (NULL, &kk);
-
- key = gdk_keyval_name (gdk_keyval_to_lower (keyval));
-
- if (key == NULL) {
- g_message ("gtk_keyval_name() returned NULL; please report this.");
- return FALSE;
- }
-
- note = key_binding (pk, key);
-
- if (note < 0) {
- return FALSE;
- }
-
- if (note == 128) {
- if (event->type == GDK_KEY_RELEASE) {
- rest (pk);
- }
-
- return TRUE;
- }
-
- note += pk->octave * 12;
-
- assert (note >= 0);
- assert (note < NNOTES);
-
- if (event->type == GDK_KEY_PRESS) {
- press_key (pk, note, pk->key_velocity);
- } else if (event->type == GDK_KEY_RELEASE) {
- release_key (pk, note);
- }
-
- return TRUE;
-}
-
-static int
-get_note_for_xy (PianoKeyboard* pk, int x, int y)
-{
- int height = GTK_WIDGET (pk)->allocation.height;
- int note;
-
- if (y <= ((height * 2) / 3)) { /* might be a black key */
- for (note = 0; note <= pk->max_note; ++note) {
- if (pk->notes[note].white) {
- continue;
- }
-
- if (x >= pk->notes[note].x && x <= pk->notes[note].x + pk->notes[note].w) {
- return note;
- }
- }
- }
-
- for (note = 0; note <= pk->max_note; ++note) {
- if (!pk->notes[note].white) {
- continue;
- }
-
- if (x >= pk->notes[note].x && x <= pk->notes[note].x + pk->notes[note].w) {
- return note;
- }
- }
-
- return -1;
-}
-
-static int
-get_velocity_for_note_at_y (PianoKeyboard* pk, int note, int y)
-{
- if (note < 0) {
- return 0;
- }
- int vel = pk->min_velocity + (pk->max_velocity - pk->min_velocity) * y / pk->notes[note].h;
-
- if (vel < 1) {
- return 1;
- } else if (vel > 127) {
- return 127;
- }
- return vel;
-}
-
-static gboolean
-mouse_button_event_handler (PianoKeyboard* pk, GdkEventButton* event, gpointer ignored)
-{
- int x = event->x;
- int y = event->y;
-
- int note = get_note_for_xy (pk, x, y);
-
- (void)ignored;
-
- if (event->button != 1)
- return TRUE;
-
- if (event->type == GDK_BUTTON_PRESS) {
- if (note < 0) {
- return TRUE;
- }
-
- if (pk->note_being_pressed_using_mouse >= 0) {
- release_key (pk, pk->note_being_pressed_using_mouse);
- }
-
- press_key (pk, note, get_velocity_for_note_at_y (pk, note, y));
- pk->note_being_pressed_using_mouse = note;
-
- } else if (event->type == GDK_BUTTON_RELEASE) {
- if (note >= 0) {
- release_key (pk, note);
- } else {
- if (pk->note_being_pressed_using_mouse >= 0) {
- release_key (pk, pk->note_being_pressed_using_mouse);
- }
- }
- pk->note_being_pressed_using_mouse = -1;
- }
-
- return TRUE;
-}
-
-static gboolean
-mouse_motion_event_handler (PianoKeyboard* pk, GdkEventMotion* event, gpointer ignored)
-{
- int note;
-
- (void)ignored;
-
- if ((event->state & GDK_BUTTON1_MASK) == 0)
- return TRUE;
-
- int x = event->x;
- int y = event->y;
-
- note = get_note_for_xy (pk, x, y);
-
- if (note != pk->note_being_pressed_using_mouse && note >= 0) {
- if (pk->note_being_pressed_using_mouse >= 0) {
- release_key (pk, pk->note_being_pressed_using_mouse);
- }
- press_key (pk, note, get_velocity_for_note_at_y (pk, note, y));
- pk->note_being_pressed_using_mouse = note;
- }
-
- return TRUE;
-}
-
-static gboolean
-piano_keyboard_expose (GtkWidget* widget, GdkEventExpose* event)
-{
- int i;
- PianoKeyboard* pk = PIANO_KEYBOARD (widget);
- cairo_t* cr = gdk_cairo_create (GDK_DRAWABLE (GTK_WIDGET (pk)->window));
-
- gdk_cairo_region (cr, event->region);
- cairo_clip (cr);
-
- for (i = 0; i < NNOTES; ++i) {
- GdkRectangle r;
-
- r.x = pk->notes[i].x;
- r.y = 0;
- r.width = pk->notes[i].w;
- r.height = pk->notes[i].h;
-
- switch (gdk_region_rect_in (event->region, &r)) {
- case GDK_OVERLAP_RECTANGLE_PART:
- case GDK_OVERLAP_RECTANGLE_IN:
- draw_note (pk, cr, i);
- break;
- default:
- break;
- }
- }
-
- cairo_destroy (cr);
-
- return TRUE;
-}
-
-static void
-piano_keyboard_size_request (GtkWidget* w, GtkRequisition* requisition)
-{
- (void)w;
-
- requisition->width = PIANO_KEYBOARD_DEFAULT_WIDTH;
- requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT;
-}
-
-static int
-is_black (int key)
-{
- int note_in_octave = key % 12;
- switch (note_in_octave) {
- case 1:
- case 3:
- case 6:
- case 8:
- case 10:
- return 1;
- default:
- return 0;
- }
- return 0;
-}
-
-static double
-black_key_left_shift (int key)
-{
- int note_in_octave = key % 12;
- switch (note_in_octave) {
- case 1:
- return 2.0 / 3.0;
- case 3:
- return 1.0 / 3.0;
- case 6:
- return 2.0 / 3.0;
- case 8:
- return 0.5;
- case 10:
- return 1.0 / 3.0;
- default:
- return 0;
- }
- return 0;
-}
-
-static void
-recompute_dimensions (PianoKeyboard* pk)
-{
- int note;
- int number_of_white_keys = 0;
- int skipped_white_keys = 0;
-
- for (note = pk->min_note; note <= pk->max_note; ++note) {
- if (!is_black (note)) {
- ++number_of_white_keys;
- }
- }
- for (note = 0; note < pk->min_note; ++note) {
- if (!is_black (note)) {
- ++skipped_white_keys;
- }
- }
-
- int width = GTK_WIDGET (pk)->allocation.width;
- int height = GTK_WIDGET (pk)->allocation.height;
-
- int key_width = width / number_of_white_keys;
- int black_key_width = key_width * 0.8;
- int useful_width = number_of_white_keys * key_width;
-
- pk->widget_margin = (width - useful_width) / 2;
-
- int white_key;
- for (note = 0, white_key = -skipped_white_keys; note < NNOTES; ++note) {
- if (is_black (note)) {
- /* This note is black key. */
- pk->notes[note].x = pk->widget_margin +
- (white_key * key_width) -
- (black_key_width * black_key_left_shift (note));
- pk->notes[note].w = black_key_width;
- pk->notes[note].h = (height * 2) / 3;
- pk->notes[note].white = 0;
- continue;
- }
-
- /* This note is white key. */
- pk->notes[note].x = pk->widget_margin + white_key * key_width;
- pk->notes[note].w = key_width;
- pk->notes[note].h = height;
- pk->notes[note].white = 1;
-
- white_key++;
- }
-}
-
-static void
-piano_keyboard_size_allocate (GtkWidget* widget, GtkAllocation* allocation)
-{
- /* XXX: Are these two needed? */
- g_return_if_fail (widget != NULL);
- g_return_if_fail (allocation != NULL);
-
- widget->allocation = *allocation;
-
- recompute_dimensions (PIANO_KEYBOARD (widget));
-
- if (GTK_WIDGET_REALIZED (widget)) {
- gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
- }
-}
-
-typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer data1,
- gint arg1,
- gint arg2,
- gpointer data2);
-static void
-g_cclosure_user_marshal_VOID__INT_INT (GClosure* closure,
- GValue* return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue* param_values,
- gpointer invocation_hint G_GNUC_UNUSED,
- gpointer marshal_data)
-{
- GCClosure* cc = (GCClosure*)closure;
- gpointer data1, data2;
- GMarshalFunc_VOID__INT_INT callback;
-
- g_return_if_fail (n_param_values == 3);
-
- if (G_CCLOSURE_SWAP_DATA (closure)) {
- data1 = closure->data;
- data2 = g_value_peek_pointer (param_values + 0);
- } else {
- data1 = g_value_peek_pointer (param_values + 0);
- data2 = closure->data;
- }
- callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback);
-
- callback (data1,
- (param_values + 1)->data[0].v_int,
- (param_values + 2)->data[0].v_int,
- data2);
-}
-
-static void
-piano_keyboard_class_init (PianoKeyboardClass* klass)
-{
- GtkWidgetClass* widget_klass;
-
- /* Set up signals. */
- piano_keyboard_signals[NOTE_ON_SIGNAL] = g_signal_new ("note-on",
- G_TYPE_FROM_CLASS (klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
- 0, NULL, NULL, g_cclosure_user_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
- piano_keyboard_signals[NOTE_OFF_SIGNAL] = g_signal_new ("note-off",
- G_TYPE_FROM_CLASS (klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
- 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
- piano_keyboard_signals[REST_SIGNAL] = g_signal_new ("rest",
- G_TYPE_FROM_CLASS (klass), (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
- 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- widget_klass = (GtkWidgetClass*)klass;
-
- widget_klass->expose_event = piano_keyboard_expose;
- widget_klass->size_request = piano_keyboard_size_request;
- widget_klass->size_allocate = piano_keyboard_size_allocate;
-}
-
-static void
-piano_keyboard_init (GtkWidget* mk)
-{
- gtk_widget_add_events (mk, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
-
- g_signal_connect (G_OBJECT (mk), "button-press-event", G_CALLBACK (mouse_button_event_handler), NULL);
- g_signal_connect (G_OBJECT (mk), "button-release-event", G_CALLBACK (mouse_button_event_handler), NULL);
- g_signal_connect (G_OBJECT (mk), "motion-notify-event", G_CALLBACK (mouse_motion_event_handler), NULL);
- g_signal_connect (G_OBJECT (mk), "key-press-event", G_CALLBACK (keyboard_event_handler), NULL);
- g_signal_connect (G_OBJECT (mk), "key-release-event", G_CALLBACK (keyboard_event_handler), NULL);
-}
-
-GType
-piano_keyboard_get_type (void)
-{
- static GType mk_type = 0;
-
- if (!mk_type) {
- static const GTypeInfo mk_info = {
- sizeof (PianoKeyboardClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc)piano_keyboard_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (PianoKeyboard),
- 0, /* n_preallocs */
- (GInstanceInitFunc)piano_keyboard_init,
- 0, /* value_table */
- };
-
- mk_type = g_type_register_static (GTK_TYPE_DRAWING_AREA, "PianoKeyboard", &mk_info, (GTypeFlags)0);
- }
-
- return mk_type;
-}
-
-GtkWidget*
-piano_keyboard_new (void)
-{
- GtkWidget* widget = (GtkWidget*)gtk_type_new (piano_keyboard_get_type ());
-
- PianoKeyboard* pk = PIANO_KEYBOARD (widget);
-
- pk->maybe_stop_sustained_notes = 0;
- pk->sustain_new_notes = 0;
- pk->enable_keyboard_cue = FALSE;
- pk->highlight_grand_piano_range = FALSE;
- pk->print_note_label = FALSE;
- pk->octave = 4;
- pk->octave_range = 7;
- pk->note_being_pressed_using_mouse = -1;
- pk->min_note = 0;
- pk->max_note = 127;
- pk->last_key = 0;
- pk->monophonic = FALSE;
-
- pk->min_velocity = 1;
- pk->max_velocity = 127;
- pk->key_velocity = 100;
-
- memset ((void*)pk->notes, 0, sizeof (struct PKNote) * NNOTES);
-
- pk->key_bindings = g_hash_table_new (g_str_hash, g_str_equal);
- bind_keys_qwerty (pk);
-
- return widget;
-}
-
-void
-piano_keyboard_set_keyboard_cue (PianoKeyboard* pk, gboolean enabled)
-{
- pk->enable_keyboard_cue = enabled;
- gtk_widget_queue_draw (GTK_WIDGET (pk));
-}
-
-void
-piano_keyboard_set_grand_piano_highlight (PianoKeyboard* pk, gboolean enabled)
-{
- pk->highlight_grand_piano_range = enabled;
- gtk_widget_queue_draw (GTK_WIDGET (pk));
-}
-
-void
-piano_keyboard_show_note_label (PianoKeyboard* pk, gboolean enabled)
-{
- pk->print_note_label = enabled;
- gtk_widget_queue_draw (GTK_WIDGET (pk));
-}
-
-void
-piano_keyboard_set_monophonic (PianoKeyboard* pk, gboolean monophonic)
-{
- pk->monophonic = monophonic;
-}
-
-void
-piano_keyboard_set_velocities (PianoKeyboard* pk, int min_vel, int max_vel, int key_vel)
-{
- if (min_vel <= max_vel && min_vel > 0 && max_vel < 128) {
- pk->min_velocity = min_vel;
- pk->max_velocity = max_vel;
- }
-
- if (key_vel > 0 && key_vel < 128) {
- pk->key_velocity = key_vel;
- }
-}
-
-void
-piano_keyboard_sustain_press (PianoKeyboard* pk)
-{
- if (!pk->sustain_new_notes) {
- pk->sustain_new_notes = 1;
- pk->maybe_stop_sustained_notes = 1;
- }
-}
-
-void
-piano_keyboard_sustain_release (PianoKeyboard* pk)
-{
- if (pk->maybe_stop_sustained_notes)
- stop_sustained_notes (pk);
-
- pk->sustain_new_notes = 0;
-}
-
-void
-piano_keyboard_set_note_on (PianoKeyboard* pk, int note)
-{
- if (pk->notes[note].pressed == 0) {
- pk->notes[note].pressed = 1;
- queue_note_draw (pk, note);
- }
-}
-
-void
-piano_keyboard_set_note_off (PianoKeyboard* pk, int note)
-{
- if (pk->notes[note].pressed || pk->notes[note].sustained) {
- pk->notes[note].pressed = 0;
- pk->notes[note].sustained = 0;
- queue_note_draw (pk, note);
- }
-}
-
-void
-piano_keyboard_set_octave (PianoKeyboard* pk, int octave)
-{
- stop_unsustained_notes (pk);
-
- if (pk->octave < -1) {
- pk->octave = -1;
- } else if (pk->octave > 7) {
- pk->octave = 7;
- }
-
- pk->octave = octave;
- piano_keyboard_set_octave_range (pk, pk->octave_range);
- gtk_widget_queue_draw (GTK_WIDGET (pk));
-}
-
-void
-piano_keyboard_set_octave_range (PianoKeyboard* pk, int octave_range)
-{
- stop_unsustained_notes (pk);
-
- if (octave_range < 2) {
- octave_range = 2;
- }
- if (octave_range > 11) {
- octave_range = 11;
- }
-
- pk->octave_range = octave_range;
-
- /* -1 <= pk->octave <= 7
- * key-bindings are at offset 12 .. 40
- * default piano range: octave = 4, range = 7 -> note 21..108
- */
-
- switch (octave_range) {
- default:
- assert (0);
- break;
- case 2:
- case 3:
- pk->min_note = (pk->octave + 1) * 12;
- break;
- case 4:
- case 5:
- pk->min_note = (pk->octave + 0) * 12;
- break;
- case 6:
- pk->min_note = (pk->octave - 1) * 12;
- break;
- case 7:
- case 8:
- pk->min_note = (pk->octave - 2) * 12;
- break;
- case 9:
- case 10:
- pk->min_note = (pk->octave - 3) * 12;
- break;
- case 11:
- pk->min_note = (pk->octave - 4) * 12;
- break;
- }
-
- int upper_offset = 0;
-
- if (pk->min_note < 3) {
- upper_offset = 0;
- pk->min_note = 0;
- } else if (octave_range > 5) {
- /* extend down to A */
- upper_offset = 3;
- pk->min_note -= 3;
- }
-
- pk->max_note = MIN (127, upper_offset + pk->min_note + octave_range * 12);
-
- if (pk->max_note == 127) {
- pk->min_note = MAX (0, pk->max_note - octave_range * 12);
- }
-
- recompute_dimensions (pk);
- gtk_widget_queue_draw (GTK_WIDGET (pk));
-}
-
-void
-piano_keyboard_set_keyboard_layout (PianoKeyboard* pk, const char* layout)
-{
- assert (layout);
-
- if (!g_ascii_strcasecmp (layout, "QWERTY")) {
- bind_keys_qwerty (pk);
-
- } else if (!g_ascii_strcasecmp (layout, "QWERTZ")) {
- bind_keys_qwertz (pk);
-
- } else if (!g_ascii_strcasecmp (layout, "AZERTY")) {
- bind_keys_azerty (pk);
-
- } else if (!g_ascii_strcasecmp (layout, "DVORAK")) {
- bind_keys_dvorak (pk);
- } else {
- assert (0);
- }
- gtk_widget_queue_draw (GTK_WIDGET (pk));
-}
diff --git a/gtk2_ardour/gtk_pianokeyboard.cc b/gtk2_ardour/gtk_pianokeyboard.cc
new file mode 100644
index 0000000000..35c356735d
--- /dev/null
+++ b/gtk2_ardour/gtk_pianokeyboard.cc
@@ -0,0 +1,994 @@
+/*-
+ * Copyright (c) 2007, 2008 Edward Tomasz NapieraƂa <trasz@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This is piano_keyboard, piano keyboard-like GTK+ widget. It contains
+ * no MIDI-specific code.
+ *
+ * For questions and comments, contact Edward Tomasz Napierala <trasz@FreeBSD.org>.
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <cairo/cairo.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "gtk_pianokeyboard.h"
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+#ifndef MIN
+# define MIN(A, B) ((A) < (B)) ? (A) : (B)
+#endif
+
+#ifndef MAX
+# define MAX(A, B) ((A) > (B)) ? (A) : (B)
+#endif
+
+#define PIANO_KEYBOARD_DEFAULT_WIDTH 730
+#define PIANO_KEYBOARD_DEFAULT_HEIGHT 70
+
+void
+PianoKeyboard::draw_keyboard_cue (cairo_t* cr, int note)
+{
+#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;
+ }
+ if (_note_bindings.find (nkey) == _note_bindings.end()) {
+ 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 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()))));
+ 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 (is_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);
+ }
+
+ if (tw < w) {
+ cairo_save (cr);
+ cairo_move_to (cr, x + (w - tw) / 2, h - th - 5);
+ 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)
+{
+ Gdk::Rectangle rect;
+ Glib::RefPtr<Gdk::Window> win = get_window();
+
+ rect.set_x (_notes[note].x);
+ rect.set_y (0);
+ rect.set_width (_notes[note].w);
+ rect.set_height (_notes[note].h);
+
+ win->invalidate_rect(rect, true); // -> queue_draw_area ()
+}
+
+void
+PianoKeyboard::draw_note (cairo_t* cr, int note)
+{
+ if (note < _min_note || note > _max_note) {
+ return;
+ }
+
+ int is_white = _notes[note].white;
+ int x = _notes[note].x;
+ int w = _notes[note].w;
+ int h = _notes[note].h;
+
+ if (_notes[note].pressed || _notes[note].sustained) {
+ if (is_white) {
+ cairo_set_source_rgb (cr, 0.7, 0.5, 0.5);
+ } else {
+ cairo_set_source_rgb (cr, 0.6, 0.4, 0.4);
+ }
+ } else if (_highlight_grand_piano_range && (note < PIANO_MIN_NOTE || note > PIANO_MAX_NOTE)) {
+ if (is_white) {
+ cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
+ } else {
+ cairo_set_source_rgb (cr, 0.3, 0.3, 0.3);
+ }
+ } else {
+ if (is_white) {
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ } else {
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ }
+ }
+
+ cairo_set_line_width (cr, 1.0);
+
+ cairo_rectangle (cr, x, 0, w, h);
+ cairo_fill (cr);
+
+ cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f); /* black outline */
+ cairo_rectangle (cr, x, 0, w, h);
+ cairo_stroke (cr);
+
+ 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);
+ }
+
+ /* We need to redraw black keys that partially obscure the white one. */
+ if (note < NNOTES - 2 && !_notes[note + 1].white) {
+ draw_note (cr, note + 1);
+ }
+
+ if (note > 0 && !_notes[note - 1].white) {
+ draw_note (cr, note - 1);
+ }
+}
+
+int
+PianoKeyboard::press_key (int key, int vel)
+{
+ assert (key >= 0);
+ assert (key < NNOTES);
+
+ _maybe_stop_sustained_notes = false;
+
+ /* This is for keyboard autorepeat protection. */
+ if (_notes[key].pressed)
+ return 0;
+
+ if (_sustain_new_notes) {
+ _notes[key].sustained = 1;
+ } else {
+ _notes[key].sustained = 0;
+ }
+
+ if (_monophonic && _last_key != key) {
+ _notes[_last_key].pressed = 0;
+ _notes[_last_key].sustained = 0;
+ queue_note_draw (_last_key);
+ }
+ _last_key = key;
+
+ _notes[key].pressed = 1;
+
+ NoteOn (key, vel); /* EMIT SIGNAL */
+ queue_note_draw (key);
+
+ return 1;
+}
+
+int
+PianoKeyboard::release_key (int key)
+{
+ assert (key >= 0);
+ assert (key < NNOTES);
+
+ _maybe_stop_sustained_notes = false;
+
+ if (!_notes[key].pressed)
+ return 0;
+
+ if (_sustain_new_notes) {
+ _notes[key].sustained = 1;
+ }
+
+ _notes[key].pressed = 0;
+
+ if (_notes[key].sustained)
+ return 0;
+
+ NoteOff (key); /* EMIT SIGNAL */
+ queue_note_draw (key);
+
+ return 1;
+}
+
+void
+PianoKeyboard::stop_unsustained_notes ()
+{
+ int i;
+ for (i = 0; i < NNOTES; ++i) {
+ if (_notes[i].pressed && !_notes[i].sustained) {
+ _notes[i].pressed = 0;
+ NoteOff (i); /* EMIT SIGNAL */
+ queue_note_draw (i);
+ }
+ }
+}
+
+void
+PianoKeyboard::stop_sustained_notes ()
+{
+ int i;
+ for (i = 0; i < NNOTES; ++i) {
+ if (_notes[i].sustained) {
+ _notes[i].pressed = 0;
+ _notes[i].sustained = 0;
+ NoteOff (i); /* EMIT SIGNAL */
+ queue_note_draw (i);
+ }
+ }
+}
+
+int
+PianoKeyboard::key_binding (const char* key)
+{
+ if (_key_bindings.find (key) != _key_bindings.end()) {
+ return _key_bindings.at (key);
+ }
+ return -1;
+}
+
+void
+PianoKeyboard::bind_key (const char* key, int note)
+{
+ _key_bindings[key] = note;
+ _note_bindings[note] = key;
+}
+
+void
+PianoKeyboard::clear_notes ()
+{
+ _key_bindings.clear ();
+ _note_bindings.clear ();
+}
+
+void
+PianoKeyboard::bind_keys_qwerty ()
+{
+ clear_notes ();
+
+ bind_key ("space", 128);
+
+ /* Lower keyboard row - "zxcvbnm". */
+ bind_key ("z", 12); /* C0 */
+ bind_key ("s", 13);
+ bind_key ("x", 14);
+ bind_key ("d", 15);
+ bind_key ("c", 16);
+ bind_key ("v", 17);
+ bind_key ("g", 18);
+ bind_key ("b", 19);
+ bind_key ("h", 20);
+ bind_key ("n", 21);
+ bind_key ("j", 22);
+ bind_key ("m", 23);
+
+ /* Upper keyboard row, first octave - "qwertyu". */
+ bind_key ("q", 24);
+ bind_key ("2", 25);
+ bind_key ("w", 26);
+ bind_key ("3", 27);
+ bind_key ("e", 28);
+ bind_key ("r", 29);
+ bind_key ("5", 30);
+ bind_key ("t", 31);
+ bind_key ("6", 32);
+ bind_key ("y", 33);
+ bind_key ("7", 34);
+ bind_key ("u", 35);
+
+ /* Upper keyboard row, the rest - "iop". */
+ bind_key ("i", 36);
+ bind_key ("9", 37);
+ bind_key ("o", 38);
+ bind_key ("0", 39);
+ bind_key ("p", 40);
+}
+
+void
+PianoKeyboard::bind_keys_qwertz ()
+{
+ bind_keys_qwerty ();
+
+ /* The only difference between QWERTY and QWERTZ is that the "y" and "z" are swapped together. */
+ bind_key ("y", 12);
+ bind_key ("z", 33);
+}
+
+void
+PianoKeyboard::bind_keys_azerty ()
+{
+ clear_notes ();
+
+ bind_key ("space", 128);
+
+ /* Lower keyboard row - "wxcvbn,". */
+ bind_key ("w", 12); /* C0 */
+ bind_key ("s", 13);
+ bind_key ("x", 14);
+ bind_key ("d", 15);
+ bind_key ("c", 16);
+ bind_key ("v", 17);
+ bind_key ("g", 18);
+ bind_key ("b", 19);
+ bind_key ("h", 20);
+ bind_key ("n", 21);
+ bind_key ("j", 22);
+ bind_key ("comma", 23);
+
+ /* Upper keyboard row, first octave - "azertyu". */
+ bind_key ("a", 24);
+ bind_key ("eacute", 25);
+ bind_key ("z", 26);
+ bind_key ("quotedbl", 27);
+ bind_key ("e", 28);
+ bind_key ("r", 29);
+ bind_key ("parenleft", 30);
+ bind_key ("t", 31);
+ bind_key ("minus", 32);
+ bind_key ("y", 33);
+ bind_key ("egrave", 34);
+ bind_key ("u", 35);
+
+ /* Upper keyboard row, the rest - "iop". */
+ bind_key ("i", 36);
+ bind_key ("ccedilla", 37);
+ bind_key ("o", 38);
+ bind_key ("agrave", 39);
+ bind_key ("p", 40);
+}
+
+void
+PianoKeyboard::bind_keys_dvorak ()
+{
+ clear_notes ();
+
+ bind_key ("space", 128);
+
+ /* Lower keyboard row - ";qjkxbm". */
+ bind_key ("semicolon", 12); /* C0 */
+ bind_key ("o", 13);
+ bind_key ("q", 14);
+ bind_key ("e", 15);
+ bind_key ("j", 16);
+ bind_key ("k", 17);
+ bind_key ("i", 18);
+ bind_key ("x", 19);
+ bind_key ("d", 20);
+ bind_key ("b", 21);
+ bind_key ("h", 22);
+ bind_key ("m", 23);
+ bind_key ("w", 24); /* overlaps with upper row */
+ bind_key ("n", 25);
+ bind_key ("v", 26);
+ bind_key ("s", 27);
+ bind_key ("z", 28);
+
+ /* Upper keyboard row, first octave - "',.pyfg". */
+ bind_key ("apostrophe", 24);
+ bind_key ("2", 25);
+ bind_key ("comma", 26);
+ bind_key ("3", 27);
+ bind_key ("period", 28);
+ bind_key ("p", 29);
+ bind_key ("5", 30);
+ bind_key ("y", 31);
+ bind_key ("6", 32);
+ bind_key ("f", 33);
+ bind_key ("7", 34);
+ bind_key ("g", 35);
+
+ /* Upper keyboard row, the rest - "crl". */
+ bind_key ("c", 36);
+ bind_key ("9", 37);
+ bind_key ("r", 38);
+ bind_key ("0", 39);
+ bind_key ("l", 40);
+#if 0
+ bind_key("slash", 41); /* extra F */
+ bind_key("bracketright", 42);
+ bind_key("equal", 43);
+#endif
+}
+
+bool
+PianoKeyboard::on_key_press_event (GdkEventKey* event)
+{
+ int note;
+ char* key;
+ guint keyval;
+
+ GdkKeymapKey kk;
+
+ /* We're not using event->keyval, because we need keyval with level set to 0.
+ E.g. if user holds Shift and presses '7', we want to get a '7', not '&'. */
+ kk.keycode = event->hardware_keycode;
+ kk.level = 0;
+ kk.group = 0;
+
+ keyval = gdk_keymap_lookup_key (NULL, &kk);
+
+ key = gdk_keyval_name (gdk_keyval_to_lower (keyval));
+
+ if (key == NULL) {
+ g_message ("gtk_keyval_name() returned NULL; please report this.");
+ return false;
+ }
+
+ note = key_binding (key);
+
+ if (note < 0) {
+ return false;
+ }
+
+ if (note == 128) {
+ if (event->type == GDK_KEY_RELEASE) {
+ Rest (); /* EMIT SIGNAL */
+ }
+
+ return true;
+ }
+
+ note += _octave * 12;
+
+ assert (note >= 0);
+ assert (note < NNOTES);
+
+ if (event->type == GDK_KEY_PRESS) {
+ press_key (note, _key_velocity);
+ } else if (event->type == GDK_KEY_RELEASE) {
+ release_key (note);
+ }
+
+ return true;
+}
+
+bool
+PianoKeyboard::on_key_release_event (GdkEventKey* event)
+{
+ return on_key_press_event (event);
+}
+
+int
+PianoKeyboard::get_note_for_xy (int x, int y) const
+{
+ int height = get_height ();
+ int note;
+
+ if (y <= ((height * 2) / 3)) { /* might be a black key */
+ for (note = 0; note <= _max_note; ++note) {
+ if (_notes[note].white) {
+ continue;
+ }
+
+ if (x >= _notes[note].x && x <= _notes[note].x + _notes[note].w) {
+ return note;
+ }
+ }
+ }
+
+ for (note = 0; note <= _max_note; ++note) {
+ if (!_notes[note].white) {
+ continue;
+ }
+
+ if (x >= _notes[note].x && x <= _notes[note].x + _notes[note].w) {
+ return note;
+ }
+ }
+
+ return -1;
+}
+
+int
+PianoKeyboard::get_velocity_for_note_at_y (int note, int y) const
+{
+ if (note < 0) {
+ return 0;
+ }
+ int vel = _min_velocity + (_max_velocity - _min_velocity) * y / _notes[note].h;
+
+ if (vel < 1) {
+ return 1;
+ } else if (vel > 127) {
+ return 127;
+ }
+ return vel;
+}
+
+bool
+PianoKeyboard::on_button_press_event (GdkEventButton* event)
+{
+ int x = event->x;
+ int y = event->y;
+
+ int note = get_note_for_xy (x, y);
+
+ if (event->button != 1)
+ return true;
+
+ if (event->type == GDK_BUTTON_PRESS) {
+ if (note < 0) {
+ return true;
+ }
+
+ if (_note_being_pressed_using_mouse >= 0) {
+ release_key (_note_being_pressed_using_mouse);
+ }
+
+ press_key (note, get_velocity_for_note_at_y ( note, y));
+ _note_being_pressed_using_mouse = note;
+
+ } else if (event->type == GDK_BUTTON_RELEASE) {
+ if (note >= 0) {
+ release_key (note);
+ } else {
+ if (_note_being_pressed_using_mouse >= 0) {
+ release_key (_note_being_pressed_using_mouse);
+ }
+ }
+ _note_being_pressed_using_mouse = -1;
+ }
+
+ return true;
+}
+
+bool
+PianoKeyboard::on_button_release_event (GdkEventButton* event)
+{
+ return on_button_press_event (event);
+}
+
+bool
+PianoKeyboard::on_motion_notify_event (GdkEventMotion* event)
+{
+ int note;
+
+ if ((event->state & GDK_BUTTON1_MASK) == 0)
+ return true;
+
+ int x = event->x;
+ int y = event->y;
+
+ note = get_note_for_xy (x, y);
+
+ if (note != _note_being_pressed_using_mouse && note >= 0) {
+ if (_note_being_pressed_using_mouse >= 0) {
+ release_key (_note_being_pressed_using_mouse);
+ }
+ press_key (note, get_velocity_for_note_at_y (note, y));
+ _note_being_pressed_using_mouse = note;
+ }
+
+ return true;
+}
+
+bool
+PianoKeyboard::on_expose_event (GdkEventExpose* event)
+{
+ cairo_t* cr = gdk_cairo_create (GDK_DRAWABLE (get_window ()->gobj ()));
+ cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
+ cairo_clip (cr);
+
+ for (int i = 0; i < NNOTES; ++i) {
+ GdkRectangle r;
+
+ r.x = _notes[i].x;
+ r.y = 0;
+ r.width = _notes[i].w;
+ r.height = _notes[i].h;
+
+ switch (gdk_region_rect_in (event->region, &r)) {
+ case GDK_OVERLAP_RECTANGLE_PART:
+ case GDK_OVERLAP_RECTANGLE_IN:
+ draw_note (cr, i);
+ break;
+ default:
+ break;
+ }
+ }
+
+ cairo_destroy (cr);
+ return true;
+}
+
+void
+PianoKeyboard::on_size_request (Gtk::Requisition* requisition)
+{
+ requisition->width = PIANO_KEYBOARD_DEFAULT_WIDTH;
+ requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT;
+}
+
+int
+PianoKeyboard::is_black (int key) const
+{
+ int note_in_octave = key % 12;
+ switch (note_in_octave) {
+ case 1:
+ case 3:
+ case 6:
+ case 8:
+ case 10:
+ return 1;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+double
+PianoKeyboard::black_key_left_shift (int key) const
+{
+ int note_in_octave = key % 12;
+ switch (note_in_octave) {
+ case 1:
+ return 2.0 / 3.0;
+ case 3:
+ return 1.0 / 3.0;
+ case 6:
+ return 2.0 / 3.0;
+ case 8:
+ return 0.5;
+ case 10:
+ return 1.0 / 3.0;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+void
+PianoKeyboard::recompute_dimensions ()
+{
+ int note;
+ int number_of_white_keys = 0;
+ int skipped_white_keys = 0;
+
+ for (note = _min_note; note <= _max_note; ++note) {
+ if (!is_black (note)) {
+ ++number_of_white_keys;
+ }
+ }
+ for (note = 0; note < _min_note; ++note) {
+ if (!is_black (note)) {
+ ++skipped_white_keys;
+ }
+ }
+
+ int width = get_width ();
+ int height = get_height ();
+
+ int key_width = width / number_of_white_keys;
+ int black_key_width = key_width * 0.8;
+ int useful_width = number_of_white_keys * key_width;
+
+ int widget_margin = (width - useful_width) / 2;
+
+ int white_key;
+ for (note = 0, white_key = -skipped_white_keys; note < NNOTES; ++note) {
+ if (is_black (note)) {
+ /* This note is black key. */
+ _notes[note].x = widget_margin +
+ (white_key * key_width) -
+ (black_key_width * black_key_left_shift (note));
+ _notes[note].w = black_key_width;
+ _notes[note].h = (height * 2) / 3;
+ _notes[note].white = 0;
+ continue;
+ }
+
+ /* This note is white key. */
+ _notes[note].x = widget_margin + white_key * key_width;
+ _notes[note].w = key_width;
+ _notes[note].h = height;
+ _notes[note].white = 1;
+
+ white_key++;
+ }
+}
+
+void
+PianoKeyboard::on_size_allocate (Gtk::Allocation& allocation)
+{
+ DrawingArea::on_size_allocate (allocation);
+ recompute_dimensions ();
+}
+
+PianoKeyboard::PianoKeyboard ()
+{
+ using namespace Gdk;
+ add_events (KEY_PRESS_MASK|KEY_RELEASE_MASK|BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|POINTER_MOTION_MASK|POINTER_MOTION_HINT_MASK);
+
+ _maybe_stop_sustained_notes = false;
+ _sustain_new_notes = false;
+ _enable_keyboard_cue = false;
+ _highlight_grand_piano_range = false;
+ _print_note_label = false;
+ _octave = 4;
+ _octave_range = 7;
+ _note_being_pressed_using_mouse = -1;
+ _min_note = 0;
+ _max_note = 127;
+ _last_key = 0;
+ _monophonic = false;
+
+ _min_velocity = 1;
+ _max_velocity = 127;
+ _key_velocity = 100;
+
+ bind_keys_qwerty ();
+}
+
+PianoKeyboard::~PianoKeyboard ()
+{
+}
+
+void
+PianoKeyboard::set_keyboard_cue (bool enabled)
+{
+ _enable_keyboard_cue = enabled;
+ queue_draw ();
+}
+
+void
+PianoKeyboard::set_grand_piano_highlight (bool enabled)
+{
+ _highlight_grand_piano_range = enabled;
+ queue_draw ();
+}
+
+void
+PianoKeyboard::show_note_label (bool enabled)
+{
+ _print_note_label = enabled;
+ queue_draw ();
+}
+
+void
+PianoKeyboard::set_monophonic (bool monophonic)
+{
+ _monophonic = monophonic;
+}
+
+void
+PianoKeyboard::set_velocities (int min_vel, int max_vel, int key_vel)
+{
+ if (min_vel <= max_vel && min_vel > 0 && max_vel < 128) {
+ _min_velocity = min_vel;
+ _max_velocity = max_vel;
+ }
+
+ if (key_vel > 0 && key_vel < 128) {
+ _key_velocity = key_vel;
+ }
+}
+
+void
+PianoKeyboard::sustain_press ()
+{
+ if (!_sustain_new_notes) {
+ _sustain_new_notes = true;
+ _maybe_stop_sustained_notes = true;
+ }
+}
+
+void
+PianoKeyboard::sustain_release ()
+{
+ if (_maybe_stop_sustained_notes) {
+ stop_sustained_notes ();
+ }
+ _sustain_new_notes = false;
+}
+
+void
+PianoKeyboard::set_note_on (int note)
+{
+ if (_notes[note].pressed == 0) {
+ _notes[note].pressed = 1;
+ queue_note_draw (note);
+ }
+}
+
+void
+PianoKeyboard::set_note_off (int note)
+{
+ if (_notes[note].pressed || _notes[note].sustained) {
+ _notes[note].pressed = 0;
+ _notes[note].sustained = 0;
+ queue_note_draw (note);
+ }
+}
+
+void
+PianoKeyboard::set_octave (int octave)
+{
+ stop_unsustained_notes ();
+
+ if (octave < -1) {
+ octave = -1;
+ } else if (octave > 7) {
+ octave = 7;
+ }
+
+ _octave = octave;
+ set_octave_range (_octave_range);
+}
+
+void
+PianoKeyboard::set_octave_range (int octave_range)
+{
+ stop_unsustained_notes ();
+
+ if (octave_range < 2) {
+ octave_range = 2;
+ }
+ if (octave_range > 11) {
+ octave_range = 11;
+ }
+
+ _octave_range = octave_range;
+
+ /* -1 <= _octave <= 7
+ * key-bindings are at offset 12 .. 40
+ * default piano range: _octave = 4, range = 7 -> note 21..108
+ */
+
+ switch (_octave_range) {
+ default:
+ assert (0);
+ break;
+ case 2:
+ case 3:
+ _min_note = (_octave + 1) * 12;
+ break;
+ case 4:
+ case 5:
+ _min_note = (_octave + 0) * 12;
+ break;
+ case 6:
+ _min_note = (_octave - 1) * 12;
+ break;
+ case 7:
+ case 8:
+ _min_note = (_octave - 2) * 12;
+ break;
+ case 9:
+ case 10:
+ _min_note = (_octave - 3) * 12;
+ break;
+ case 11:
+ _min_note = (_octave - 4) * 12;
+ break;
+ }
+
+ int upper_offset = 0;
+
+ if (_min_note < 3) {
+ upper_offset = 0;
+ _min_note = 0;
+ } else if (_octave_range > 5) {
+ /* extend down to A */
+ upper_offset = 3;
+ _min_note -= 3;
+ }
+
+ _max_note = MIN (127, upper_offset + _min_note + _octave_range * 12);
+
+ if (_max_note == 127) {
+ _min_note = MAX (0, _max_note - _octave_range * 12);
+ }
+
+ recompute_dimensions ();
+ queue_draw ();
+}
+
+void
+PianoKeyboard::set_keyboard_layout (Layout layout)
+{
+ switch (layout) {
+ case QWERTY:
+ bind_keys_qwerty ();
+ break;
+ case QWERTZ:
+ bind_keys_qwertz ();
+ break;
+ case AZERTY:
+ bind_keys_azerty ();
+ break;
+ case DVORAK:
+ bind_keys_dvorak ();
+ break;
+
+ }
+ queue_draw ();
+}
diff --git a/gtk2_ardour/gtk_pianokeyboard.h b/gtk2_ardour/gtk_pianokeyboard.h
index 535b143db3..bba08187b1 100644
--- a/gtk2_ardour/gtk_pianokeyboard.h
+++ b/gtk2_ardour/gtk_pianokeyboard.h
@@ -20,20 +20,10 @@
#ifndef __PIANO_KEYBOARD_H__
#define __PIANO_KEYBOARD_H__
-#include <glib.h>
-#include <gtk/gtkdrawingarea.h>
-
-G_BEGIN_DECLS
-
-#define TYPE_PIANO_KEYBOARD (piano_keyboard_get_type ())
-#define PIANO_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PIANO_KEYBOARD, PianoKeyboard))
-#define PIANO_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PIANO_KEYBOARD, PianoKeyboardClass))
-#define IS_PIANO_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PIANO_KEYBOARD))
-#define IS_PIANO_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PIANO_KEYBOARD))
-#define PIANO_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PIANO_KEYBOARD, PianoKeyboardClass))
+#include <map>
-typedef struct _PianoKeyboard PianoKeyboard;
-typedef struct _PianoKeyboardClass PianoKeyboardClass;
+#include <glib.h>
+#include <gtkmm/drawingarea.h>
#define NNOTES (128)
#define PIANO_MIN_NOTE 21
@@ -42,59 +32,111 @@ typedef struct _PianoKeyboardClass PianoKeyboardClass;
#define OCTAVE_MIN (-1)
#define OCTAVE_MAX (7)
-struct PKNote {
- int pressed; /* 1 if key is in pressed down state. */
- int sustained; /* 1 if note is sustained. */
- int x; /* Distance between the left edge of the key
- * and the left edge of the widget, in pixels. */
- int w; /* Width of the key, in pixels. */
- int h; /* Height of the key, in pixels. */
- int white; /* 1 if key is white; 0 otherwise. */
-};
+class PianoKeyboard : public Gtk::DrawingArea
+{
+public:
+ PianoKeyboard ();
+ ~PianoKeyboard ();
-struct _PianoKeyboard {
- GtkDrawingArea da;
- int maybe_stop_sustained_notes;
- int sustain_new_notes;
- gboolean enable_keyboard_cue;
- gboolean highlight_grand_piano_range;
- gboolean print_note_label;
- int octave;
- int octave_range;
- int widget_margin;
- int note_being_pressed_using_mouse;
- int min_note;
- int max_note;
- int last_key;
- gboolean monophonic;
- struct PKNote notes[NNOTES];
- GHashTable* key_bindings; /**< Table used to translate from PC keyboard character to MIDI note number. */
- char* note_bindings[NNOTES]; /**< Table to translate from MIDI note number to PC keyboard character. */
- int min_velocity;
- int max_velocity;
- int key_velocity;
-};
+ sigc::signal<void, int, int> NoteOn;
+ sigc::signal<void, int> NoteOff;
+ sigc::signal<void > Rest;
-struct _PianoKeyboardClass {
- GtkDrawingAreaClass parent_class;
-};
+ enum Layout {
+ QWERTY,
+ QWERTZ,
+ AZERTY,
+ DVORAK
+ };
+
+ 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);
+ void set_keyboard_layout (Layout layout);
+ void set_velocities (int min_vel, int max_vel, int key_vel);
+
+protected:
+ bool on_key_press_event (GdkEventKey *);
+ bool on_key_release_event (GdkEventKey *);
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ bool on_motion_notify_event (GdkEventMotion*);
+ bool on_expose_event (GdkEventExpose*);
-GType piano_keyboard_get_type (void) G_GNUC_CONST;
-GtkWidget* piano_keyboard_new (void);
+ void on_size_request (Gtk::Requisition*);
+ void on_size_allocate (Gtk::Allocation&);
-void piano_keyboard_sustain_press (PianoKeyboard* pk);
-void piano_keyboard_sustain_release (PianoKeyboard* pk);
-void piano_keyboard_set_note_on (PianoKeyboard* pk, int note);
-void piano_keyboard_set_note_off (PianoKeyboard* pk, int note);
-void piano_keyboard_set_keyboard_cue (PianoKeyboard* pk, gboolean enabled);
-void piano_keyboard_set_grand_piano_highlight (PianoKeyboard* pk, gboolean enabled);
-void piano_keyboard_show_note_label (PianoKeyboard* pk, gboolean enabled);
-void piano_keyboard_set_monophonic (PianoKeyboard* pk, gboolean monophonic);
-void piano_keyboard_set_octave (PianoKeyboard* pk, int octave);
-void piano_keyboard_set_octave_range (PianoKeyboard* pk, int octave_range);
-void piano_keyboard_set_keyboard_layout (PianoKeyboard* pk, const char* layout);
-void piano_keyboard_set_velocities (PianoKeyboard* pk, int min_vel, int max_vel, int key_vel);
+private:
-G_END_DECLS
+ void draw_keyboard_cue (cairo_t* cr, int note);
+ 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 stop_sustained_notes ();
+ int key_binding (const char* key);
+ void bind_key (const char* key, int note);
+ void clear_notes ();
+ void bind_keys_qwerty ();
+ void bind_keys_qwertz ();
+ void bind_keys_azerty ();
+ void bind_keys_dvorak ();
+
+ int get_note_for_xy (int x, int y) const;
+ int get_velocity_for_note_at_y (int note, int y) const;
+
+ int is_black (int key) const;
+ double black_key_left_shift (int key) const;
+
+ void recompute_dimensions ();
+
+ struct PKNote {
+ PKNote ()
+ : pressed (false)
+ , sustained (false)
+ , white (false)
+ , x (0)
+ , w (0)
+ , h (0)
+ {}
+
+ bool pressed; /* 1 if key is in pressed down state. */
+ bool sustained; /* 1 if note is sustained. */
+ bool white; /* 1 if key is white; 0 otherwise. */
+ int x; /* Distance between the left edge of the key * and the left edge of the widget, in pixels. */
+ int w; /* Width of the key, in pixels. */
+ int h; /* Height of the key, in pixels. */
+ };
+
+ bool _maybe_stop_sustained_notes;
+ bool _sustain_new_notes;
+ bool _enable_keyboard_cue;
+ bool _highlight_grand_piano_range;
+ bool _print_note_label;
+ int _octave;
+ int _octave_range;
+ int _note_being_pressed_using_mouse;
+ int _min_note;
+ int _max_note;
+ int _last_key;
+ bool _monophonic;
+ int _min_velocity;
+ int _max_velocity;
+ int _key_velocity;
+
+ PKNote _notes[NNOTES];
+
+ std::map<std::string, int> _key_bindings; /**< Table used to translate from PC keyboard character to MIDI note number. */
+ std::map<int, std::string> _note_bindings; /**< Table to translate from MIDI note number to PC keyboard character. */
+};
#endif /* __PIANO_KEYBOARD_H__ */
diff --git a/gtk2_ardour/note_select_dialog.cc b/gtk2_ardour/note_select_dialog.cc
index 3a9dfa35e7..36aae45db6 100644
--- a/gtk2_ardour/note_select_dialog.cc
+++ b/gtk2_ardour/note_select_dialog.cc
@@ -23,33 +23,26 @@
#include "pbd/i18n.h"
-static void
-_note_on_event_handler(GtkWidget* /*widget*/, int note, int, gpointer arg)
-{
- ((NoteSelectDialog*)arg)->note_on_event_handler(note);
-}
-
-NoteSelectDialog::NoteSelectDialog()
+NoteSelectDialog::NoteSelectDialog ()
: ArdourDialog (_("Select Note"))
- , _piano((PianoKeyboard*)piano_keyboard_new())
- , _pianomm(Glib::wrap((GtkWidget*)_piano))
, _note_number(60)
{
- _pianomm->set_flags(Gtk::CAN_FOCUS);
- _pianomm->show();
- g_signal_connect(G_OBJECT(_piano), "note-on", G_CALLBACK(_note_on_event_handler), this);
- piano_keyboard_set_monophonic(_piano, TRUE);
- piano_keyboard_sustain_press(_piano);
+ _piano.set_flags(Gtk::CAN_FOCUS);
+ _piano.show();
+ _piano.NoteOn.connect (sigc::mem_fun (*this, &NoteSelectDialog::note_on_event_handler));
+
+ _piano.set_monophonic (true);
+ _piano.sustain_press ();
+
+ get_vbox()->pack_start(_piano);
- get_vbox()->pack_start(*_pianomm);
add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
set_default_response(Gtk::RESPONSE_ACCEPT);
}
void
-NoteSelectDialog::note_on_event_handler(int note)
+NoteSelectDialog::note_on_event_handler(int note, int)
{
- printf("NOTE: %d\n", note);
_note_number = note;
}
diff --git a/gtk2_ardour/note_select_dialog.h b/gtk2_ardour/note_select_dialog.h
index 3970095317..893952e60d 100644
--- a/gtk2_ardour/note_select_dialog.h
+++ b/gtk2_ardour/note_select_dialog.h
@@ -31,12 +31,11 @@ public:
uint8_t note_number() const { return _note_number; }
- void note_on_event_handler(int note);
-
private:
- PianoKeyboard* _piano;
- Gtk::Widget* _pianomm;
- uint8_t _note_number;
+ PianoKeyboard _piano;
+ uint8_t _note_number;
+
+ void note_on_event_handler(int, int);
};
#endif /* __gtk2_ardour_note_select_dialog_h__ */
diff --git a/gtk2_ardour/patch_change_widget.cc b/gtk2_ardour/patch_change_widget.cc
index 0e5ad911ab..51cae03f7e 100644
--- a/gtk2_ardour/patch_change_widget.cc
+++ b/gtk2_ardour/patch_change_widget.cc
@@ -57,8 +57,6 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
, _audition_end_spin (*manage (new Adjustment (60, 0, 127, 1, 16)))
, _audition_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
, _audition_note_on (false)
- , _piano ((PianoKeyboard*)piano_keyboard_new())
- , _pianomm (Glib::wrap((GtkWidget*)_piano))
{
Box* box;
box = manage (new HBox ());
@@ -114,11 +112,12 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
_channel_select.AddMenuElem (MenuElemNoMnemonic (buf, sigc::bind (sigc::mem_fun (*this, &PatchChangeWidget::select_channel), chn)));
}
- piano_keyboard_set_monophonic (_piano, TRUE);
- g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (PatchChangeWidget::_note_on_event_handler), this);
- g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (PatchChangeWidget::_note_off_event_handler), this);
- _pianomm->set_flags(Gtk::CAN_FOCUS);
- pack_start (*_pianomm, false, false);
+ _piano.set_monophonic (true);
+ _piano.NoteOn.connect (sigc::mem_fun (*this, &PatchChangeWidget::_note_on_event_handler));
+ _piano.NoteOff.connect (sigc::mem_fun (*this, &PatchChangeWidget::note_off_event_handler));
+
+ _piano.set_flags(Gtk::CAN_FOCUS);
+ pack_start (_piano, false, false);
_audition_start_spin.set_sensitive (false);
_audition_end_spin.set_sensitive (false);
@@ -145,7 +144,6 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
PatchChangeWidget::~PatchChangeWidget ()
{
cancel_audition ();
- delete _pianomm;
}
void
@@ -434,7 +432,7 @@ PatchChangeWidget::cancel_audition ()
if (_audition_note_on) {
note_off_event_handler (_audition_note_num);
- piano_keyboard_set_note_off (_piano, _audition_note_num);
+ _piano.set_note_off (_audition_note_num);
}
}
@@ -467,25 +465,19 @@ PatchChangeWidget::audition_next ()
{
if (_audition_note_on) {
note_off_event_handler (_audition_note_num);
- piano_keyboard_set_note_off (_piano, _audition_note_num);
+ _piano.set_note_off (_audition_note_num);
return ++_audition_note_num <= _audition_end_spin.get_value_as_int() && _audition_enable.get_active ();
} else {
note_on_event_handler (_audition_note_num, true);
- piano_keyboard_set_note_on (_piano, _audition_note_num);
+ _piano.set_note_on (_audition_note_num);
return true;
}
}
void
-PatchChangeWidget::_note_on_event_handler(GtkWidget*, int note, int, gpointer arg)
-{
- ((PatchChangeWidget*)arg)->note_on_event_handler(note, false);
-}
-
-void
-PatchChangeWidget::_note_off_event_handler(GtkWidget*, int note, gpointer arg)
+PatchChangeWidget::_note_on_event_handler (int note, int)
{
- ((PatchChangeWidget*)arg)->note_off_event_handler(note);
+ note_on_event_handler(note, false);
}
void
@@ -493,7 +485,7 @@ PatchChangeWidget::note_on_event_handler (int note, bool for_audition)
{
if (!for_audition) {
cancel_audition ();
- _pianomm->grab_focus ();
+ _piano.grab_focus ();
}
uint8_t event[3];
event[0] = (MIDI_CMD_NOTE_ON | _channel);
diff --git a/gtk2_ardour/patch_change_widget.h b/gtk2_ardour/patch_change_widget.h
index ae9af56d45..860c02026f 100644
--- a/gtk2_ardour/patch_change_widget.h
+++ b/gtk2_ardour/patch_change_widget.h
@@ -99,11 +99,9 @@ private:
uint8_t _audition_note_num;
bool _audition_note_on;
- PianoKeyboard* _piano;
- Gtk::Widget* _pianomm;
+ PianoKeyboard _piano;
- static void _note_on_event_handler (GtkWidget*, int, int, gpointer);
- static void _note_off_event_handler (GtkWidget*, int, gpointer);
+ void _note_on_event_handler (int, int);
void note_on_event_handler (int, bool for_audition);
void note_off_event_handler (int);
};
diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h
index 044a52e3bb..57951ae914 100644
--- a/gtk2_ardour/plugin_ui.h
+++ b/gtk2_ardour/plugin_ui.h
@@ -319,14 +319,11 @@ private:
Gtk::Expander _plugin_pianokeyboard_expander;
PianoKeyboard* _piano;
- Gtk::Widget* _pianomm;
Gtk::VBox _pianobox;
Gtk::SpinButton _piano_velocity;
Gtk::SpinButton _piano_channel;
- static void _note_on_event_handler (GtkWidget*, int, int, gpointer);
- static void _note_off_event_handler (GtkWidget*, int, gpointer);
- void note_on_event_handler (int);
+ void note_on_event_handler (int, int);
void note_off_event_handler (int);
void toggle_pianokeyboard ();
diff --git a/gtk2_ardour/step_entry.cc b/gtk2_ardour/step_entry.cc
index ec38782a10..374791627e 100644
--- a/gtk2_ardour/step_entry.cc
+++ b/gtk2_ardour/step_entry.cc
@@ -50,18 +50,6 @@ using namespace ArdourWidgets;
Gtkmm2ext::Bindings* StepEntry::bindings = 0;
StepEntry* StepEntry::_instance = 0;
-static void
-_note_off_event_handler (GtkWidget* /*widget*/, int note, gpointer arg)
-{
- ((StepEntry*)arg)->note_off_event_handler (note);
-}
-
-static void
-_rest_event_handler (GtkWidget* /*widget*/, gpointer arg)
-{
- ((StepEntry*)arg)->rest_event_handler ();
-}
-
StepEntry&
StepEntry::instance()
{
@@ -99,8 +87,6 @@ StepEntry::StepEntry ()
, program_adjustment (0, 0.0, 127.0, 1.0, 4.0)
, program_spinner (program_adjustment)
, program_button (_("+"))
- , _piano (0)
- , piano (0)
, se (0)
{
set_data ("ardour-bindings", bindings);
@@ -436,13 +422,10 @@ StepEntry::StepEntry ()
length_divisor_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::length_value_change));
dot_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::dot_value_change));
- _piano = (PianoKeyboard*) piano_keyboard_new ();
- piano = wrap ((GtkWidget*) _piano);
-
- piano->set_flags (Gtk::CAN_FOCUS);
+ _piano.set_flags (Gtk::CAN_FOCUS);
- g_signal_connect(G_OBJECT(_piano), "note-off", G_CALLBACK(_note_off_event_handler), this);
- g_signal_connect(G_OBJECT(_piano), "rest", G_CALLBACK(_rest_event_handler), this);
+ _piano.NoteOff.connect (sigc::mem_fun (*this, &StepEntry::note_off_event_handler));
+ _piano.Rest.connect (sigc::mem_fun (*this, &StepEntry::rest_event_handler));
program_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::program_click));
bank_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::bank_click));
@@ -453,7 +436,7 @@ StepEntry::StepEntry ()
packer.set_spacing (6);
packer.pack_start (upper_box, false, false);
- packer.pack_start (*piano, false, false);
+ packer.pack_start (_piano, false, false);
packer.show_all ();
add (packer);
@@ -592,7 +575,7 @@ void
StepEntry::on_show ()
{
ArdourWindow::on_show ();
- //piano->grab_focus ();
+ //_piano->grab_focus ();
}
void
diff --git a/gtk2_ardour/step_entry.h b/gtk2_ardour/step_entry.h
index b257b824b4..36e1884652 100644
--- a/gtk2_ardour/step_entry.h
+++ b/gtk2_ardour/step_entry.h
@@ -51,9 +51,6 @@ class StepEntry : public ArdourWindow
void set_step_editor (StepEditor*);
- void note_off_event_handler (int note);
- void rest_event_handler ();
-
Temporal::Beats note_length();
uint8_t note_velocity() const;
uint8_t note_channel() const;
@@ -66,6 +63,9 @@ class StepEntry : public ArdourWindow
static StepEntry* _instance;
StepEntry ();
+ void note_off_event_handler (int note);
+ void rest_event_handler ();
+
Temporal::Beats _current_note_length;
uint8_t _current_note_velocity;
@@ -140,8 +140,8 @@ class StepEntry : public ArdourWindow
void velocity_value_change ();
void length_value_change ();
- PianoKeyboard* _piano;
- Gtk::Widget* piano;
+ PianoKeyboard _piano;
+
StepEditor* se;
void bank_click ();
diff --git a/gtk2_ardour/virtual_keyboard_window.cc b/gtk2_ardour/virtual_keyboard_window.cc
index 61b6759fad..24dad70cf2 100644
--- a/gtk2_ardour/virtual_keyboard_window.cc
+++ b/gtk2_ardour/virtual_keyboard_window.cc
@@ -57,12 +57,10 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
, _piano_octave_range (*manage (new Adjustment (7, 2, 11, 1, 1)))
, _pitch_adjustment (8192, 0, 16383, 1, 256)
{
- _piano = (PianoKeyboard*)piano_keyboard_new ();
- _pianomm = Glib::wrap ((GtkWidget*)_piano);
- _pianomm->set_flags (Gtk::CAN_FOCUS);
- _pianomm->add_events (Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
- piano_keyboard_set_keyboard_layout (_piano, "QWERTY");
- piano_keyboard_show_note_label (_piano, true);
+ _piano.set_flags (Gtk::CAN_FOCUS);
+
+ _piano.set_keyboard_layout(PianoKeyboard::QWERTY);
+ _piano.show_note_label (true);
using namespace Menu_Helpers;
_keyboard_layout.AddMenuElem (MenuElem ("QWERTY",
@@ -218,7 +216,7 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
vbox->pack_start (*box1, false, false, 4);
vbox->pack_start (*_pgm_box, false, false, 4);
vbox->pack_start (*_cfg_box, false, false, 4);
- vbox->pack_start (*_pianomm, true, true);
+ vbox->pack_start (_piano, true, true);
add (*vbox);
_bank_msb.signal_value_changed ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::bank_patch));
@@ -240,8 +238,9 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
_show_note_label.signal_button_release_event ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::toggle_note_label), false);
_send_panic.signal_button_release_event ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::send_panic_message), false);
- g_signal_connect (G_OBJECT (_piano), "note-on", G_CALLBACK (VirtualKeyboardWindow::_note_on_event_handler), this);
- g_signal_connect (G_OBJECT (_piano), "note-off", G_CALLBACK (VirtualKeyboardWindow::_note_off_event_handler), this);
+
+ _piano.NoteOn.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::note_on_event_handler));
+ _piano.NoteOff.connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::note_off_event_handler));
update_velocity_settings (0);
update_octave_range ();
@@ -252,7 +251,6 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
VirtualKeyboardWindow::~VirtualKeyboardWindow ()
{
- delete _pianomm;
delete _pitch_slider_tooltip;
}
@@ -306,8 +304,7 @@ VirtualKeyboardWindow::set_state (const XMLNode& root)
std::string layout;
if (node->get_property (X_("Layout"), layout)) {
- piano_keyboard_set_keyboard_layout (_piano, layout.c_str ());
- _keyboard_layout.set_active (layout);
+ select_keyboard_layout (layout);
}
for (int i = 0; i < VKBD_NCTRLS; ++i) {
@@ -325,15 +322,15 @@ VirtualKeyboardWindow::set_state (const XMLNode& root)
}
if (node->get_property (X_("HighlightGrandPiano"), a)) {
_highlight_grand_piano.set_active (a);
- piano_keyboard_set_grand_piano_highlight (_piano, a);
+ _piano.set_grand_piano_highlight (a);
}
if (node->get_property (X_("HighlightKeyRange"), a)) {
_highlight_key_range.set_active (a);
- piano_keyboard_set_keyboard_cue (_piano, a);
+ _piano.set_keyboard_cue (a);
}
if (node->get_property (X_("ShowNoteLabel"), a)) {
_show_note_label.set_active (a);
- piano_keyboard_show_note_label (_piano, a);
+ _piano.show_note_label (a);
}
int v;
@@ -367,7 +364,7 @@ VirtualKeyboardWindow::set_state (const XMLNode& root)
bool
VirtualKeyboardWindow::on_focus_in_event (GdkEventFocus *ev)
{
- _pianomm->grab_focus ();
+ _piano.grab_focus ();
return ArdourWindow::on_focus_in_event(ev);
}
@@ -381,15 +378,22 @@ VirtualKeyboardWindow::on_unmap ()
bool
VirtualKeyboardWindow::on_key_press_event (GdkEventKey* ev)
{
- _pianomm->grab_focus ();
+ _piano.grab_focus ();
return ARDOUR_UI_UTILS::relay_key_press (ev, this);
}
void
VirtualKeyboardWindow::select_keyboard_layout (std::string const& l)
{
- piano_keyboard_set_keyboard_layout (_piano, l.c_str ());
- _keyboard_layout.set_active (l);
+ if (l == "QWERTY") {
+ _piano.set_keyboard_layout (PianoKeyboard::QWERTY);
+ } else if (l == "QWERTZ") {
+ _piano.set_keyboard_layout (PianoKeyboard::QWERTZ);
+ } else if (l == "AZERTY") {
+ _piano.set_keyboard_layout (PianoKeyboard::AZERTY);
+ } else if (l == "DVORAK") {
+ _piano.set_keyboard_layout (PianoKeyboard::DVORAK);
+ }
}
bool
@@ -421,15 +425,15 @@ VirtualKeyboardWindow::toggle_bankpatch (GdkEventButton*)
void
VirtualKeyboardWindow::update_octave_key ()
{
- piano_keyboard_set_octave (_piano, _piano_octave_key.get_value_as_int ());
- _pianomm->grab_focus ();
+ _piano.set_octave (_piano_octave_key.get_value_as_int ());
+ _piano.grab_focus ();
}
void
VirtualKeyboardWindow::update_octave_range ()
{
- piano_keyboard_set_octave_range (_piano, _piano_octave_range.get_value_as_int ());
- _pianomm->grab_focus ();
+ _piano.set_octave_range (_piano_octave_range.get_value_as_int ());
+ _piano.grab_focus ();
}
bool
@@ -445,7 +449,7 @@ VirtualKeyboardWindow::toggle_highlight_piano (GdkEventButton*)
{
bool a = !_highlight_grand_piano.get_active ();
_highlight_grand_piano.set_active (a);
- piano_keyboard_set_grand_piano_highlight (_piano, a);
+ _piano.set_grand_piano_highlight (a);
return false;
}
@@ -454,7 +458,7 @@ VirtualKeyboardWindow::toggle_highlight_key (GdkEventButton*)
{
bool a = !_highlight_key_range.get_active ();
_highlight_key_range.set_active (a);
- piano_keyboard_set_keyboard_cue (_piano, a);
+ _piano.set_keyboard_cue (a);
return false;
}
@@ -463,7 +467,7 @@ VirtualKeyboardWindow::toggle_note_label (GdkEventButton*)
{
bool a = !_show_note_label.get_active ();
_show_note_label.set_active (a);
- piano_keyboard_show_note_label (_piano, a);
+ _piano.show_note_label (a);
return false;
}
@@ -518,15 +522,13 @@ VirtualKeyboardWindow::update_velocity_settings (int ctrl)
}
if (_yaxis_velocity.get_active ()) {
- piano_keyboard_set_velocities (_piano,
- _piano_min_velocity.get_value_as_int (),
- _piano_max_velocity.get_value_as_int (),
- _piano_key_velocity.get_value_as_int ());
+ _piano.set_velocities (_piano_min_velocity.get_value_as_int (),
+ _piano_max_velocity.get_value_as_int (),
+ _piano_key_velocity.get_value_as_int ());
} else {
- piano_keyboard_set_velocities (_piano,
- _piano_key_velocity.get_value_as_int (),
- _piano_key_velocity.get_value_as_int (),
- _piano_key_velocity.get_value_as_int ());
+ _piano.set_velocities (_piano_key_velocity.get_value_as_int (),
+ _piano_key_velocity.get_value_as_int (),
+ _piano_key_velocity.get_value_as_int ());
}
update_sensitivity ();
}
@@ -537,7 +539,7 @@ VirtualKeyboardWindow::update_sensitivity ()
bool c = _yaxis_velocity.get_active ();
_piano_min_velocity.set_sensitive (c);
_piano_max_velocity.set_sensitive (c);
- _pianomm->grab_focus ();
+ _piano.grab_focus ();
}
void
@@ -552,7 +554,7 @@ VirtualKeyboardWindow::pitch_slider_adjusted ()
void
VirtualKeyboardWindow::note_on_event_handler (int note, int velocity)
{
- _pianomm->grab_focus ();
+ _piano.grab_focus ();
if (!_session) {
return;
}
diff --git a/gtk2_ardour/virtual_keyboard_window.h b/gtk2_ardour/virtual_keyboard_window.h
index 1f561c802d..2094d7696f 100644
--- a/gtk2_ardour/virtual_keyboard_window.h
+++ b/gtk2_ardour/virtual_keyboard_window.h
@@ -96,16 +96,6 @@ protected:
bool on_focus_in_event (GdkEventFocus*);
private:
- static void _note_on_event_handler (GtkWidget*, int note, int vel, gpointer arg)
- {
- static_cast<VirtualKeyboardWindow*> (arg)->note_on_event_handler (note, vel);
- }
-
- static void _note_off_event_handler (GtkWidget*, int note, gpointer arg)
- {
- static_cast<VirtualKeyboardWindow*> (arg)->note_off_event_handler (note);
- }
-
void on_unmap ();
bool on_key_press_event (GdkEventKey*);
@@ -129,8 +119,7 @@ private:
bool toggle_note_label (GdkEventButton*);
bool send_panic_message (GdkEventButton*);
- PianoKeyboard* _piano;
- Gtk::Widget* _pianomm;
+ PianoKeyboard _piano;
Gtk::SpinButton _piano_channel;
Gtk::SpinButton _transpose_output;
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 0845013f75..ff6dd3b9db 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -125,7 +125,7 @@ gtk2_ardour_sources = [
'ghostregion.cc',
'global_port_matrix.cc',
'group_tabs.cc',
- 'gtk_pianokeyboard.c',
+ 'gtk_pianokeyboard.cc',
'gui_object.cc',
'idleometer.cc',
'insert_remove_time_dialog.cc',