summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/gtk_pianokeyboard.c372
-rw-r--r--gtk2_ardour/gtk_pianokeyboard.h14
-rw-r--r--gtk2_ardour/virtual_keyboard_window.cc103
-rw-r--r--gtk2_ardour/virtual_keyboard_window.h9
4 files changed, 400 insertions, 98 deletions
diff --git a/gtk2_ardour/gtk_pianokeyboard.c b/gtk2_ardour/gtk_pianokeyboard.c
index 07643aef29..e9212be439 100644
--- a/gtk2_ardour/gtk_pianokeyboard.c
+++ b/gtk2_ardour/gtk_pianokeyboard.c
@@ -41,6 +41,14 @@
#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
@@ -51,18 +59,23 @@ enum {
LAST_SIGNAL
};
-static guint piano_keyboard_signals[LAST_SIGNAL] = { 0 };
+static guint piano_keyboard_signals[LAST_SIGNAL] = { 0 };
static void
draw_keyboard_cue(PianoKeyboard *pk, cairo_t* cr)
{
- int w = pk->notes[0].w;
- int h = pk->notes[0].h;
+ 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;
- int first_note_in_lower_row = (pk->octave + 5) * 12;
- int last_note_in_lower_row = (pk->octave + 6) * 12 - 1;
- int first_note_in_higher_row = (pk->octave + 6) * 12;
- int last_note_in_higher_row = (pk->octave + 7) * 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);
@@ -95,23 +108,32 @@ queue_note_draw (PianoKeyboard* pk, int note)
static void
draw_note(PianoKeyboard *pk, cairo_t* cr, int note)
{
- int is_white = pk->notes[note].white;
+ if (note < pk->min_note || note > pk->max_note) {
+ return;
+ }
- int x = pk->notes[note].x;
- int w = pk->notes[note].w;
- int h = pk->notes[note].h;
+ 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.60f, 0.60f, 0.60f);
+ 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.8, 0.8, 0.8);
} else {
- cairo_set_source_rgb (cr, 0.50f, 0.50f, 0.50f);
+ cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
}
} else {
if (is_white) {
- cairo_set_source_rgb (cr, 1.0f, 1.0f, 1.0f);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
} else {
- cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
}
}
@@ -204,9 +226,8 @@ rest (PianoKeyboard* pk)
static void
stop_unsustained_notes(PianoKeyboard *pk)
{
- int i;
-
- for (i = 0; i < NNOTES; i++) {
+ 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);
@@ -218,9 +239,8 @@ stop_unsustained_notes(PianoKeyboard *pk)
static void
stop_sustained_notes(PianoKeyboard *pk)
{
- int i;
-
- for (i = 0; i < NNOTES; i++) {
+ int i;
+ for (i = 0; i < NNOTES; ++i) {
if (pk->notes[i].sustained) {
pk->notes[i].pressed = 0;
pk->notes[i].sustained = 0;
@@ -270,7 +290,7 @@ bind_keys_qwerty(PianoKeyboard *pk)
bind_key(pk, "space", 128);
/* Lower keyboard row - "zxcvbnm". */
- bind_key(pk, "z", 12); /* C0 */
+ bind_key(pk, "z", 12); /* C0 */
bind_key(pk, "s", 13);
bind_key(pk, "x", 14);
bind_key(pk, "d", 15);
@@ -323,7 +343,7 @@ bind_keys_azerty(PianoKeyboard *pk)
bind_key(pk, "space", 128);
/* Lower keyboard row - "wxcvbn,". */
- bind_key(pk, "w", 12); /* C0 */
+ bind_key(pk, "w", 12); /* C0 */
bind_key(pk, "s", 13);
bind_key(pk, "x", 14);
bind_key(pk, "d", 15);
@@ -358,14 +378,68 @@ bind_keys_azerty(PianoKeyboard *pk)
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);
+ int note;
+ char* key;
+ guint keyval;
+
+ GdkKeymapKey kk;
+ PianoKeyboard* pk = PIANO_KEYBOARD(mk);
(void) ignored;
@@ -387,7 +461,6 @@ keyboard_event_handler(GtkWidget *mk, GdkEventKey *event, gpointer ignored)
note = key_binding(pk, key);
if (note < 0) {
- /* Key was not bound. Maybe it's one of the keys handled in jack-keyboard.c. */
return FALSE;
}
@@ -414,27 +487,31 @@ keyboard_event_handler(GtkWidget *mk, GdkEventKey *event, gpointer ignored)
}
static int
-get_note_for_xy(PianoKeyboard *pk, int x, int y)
+get_note_for_xy (PianoKeyboard *pk, int x, int y)
{
- int height = GTK_WIDGET(pk)->allocation.height;
- int note;
+ int height = GTK_WIDGET(pk)->allocation.height;
+ int note;
- if (y <= height / 2) {
- for (note = 0; note < NNOTES - 1; note++) {
- if (pk->notes[note].white)
+ 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)
+ if (x >= pk->notes[note].x && x <= pk->notes[note].x + pk->notes[note].w) {
return note;
+ }
}
}
- for (note = 0; note < NNOTES - 1; note++) {
- if (!pk->notes[note].white)
+ 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)
+ if (x >= pk->notes[note].x && x <= pk->notes[note].x + pk->notes[note].w) {
return note;
+ }
}
return -1;
@@ -459,10 +536,10 @@ get_velocity_for_note_at_y(PianoKeyboard *pk, int note, int y)
static gboolean
mouse_button_event_handler(PianoKeyboard *pk, GdkEventButton *event, gpointer ignored)
{
- int x = event->x;
- int y = event->y;
+ int x = event->x;
+ int y = event->y;
- int note = get_note_for_xy(pk, x, y);
+ int note = get_note_for_xy (pk, x, y);
(void) ignored;
@@ -470,29 +547,26 @@ mouse_button_event_handler(PianoKeyboard *pk, GdkEventButton *event, gpointer ig
return TRUE;
if (event->type == GDK_BUTTON_PRESS) {
- /* This is possible when you make the window a little wider and then click
- on the grey area. */
if (note < 0) {
return TRUE;
}
- if (pk->note_being_pressed_using_mouse >= 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));
+ 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)
+ 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;
@@ -501,17 +575,17 @@ mouse_button_event_handler(PianoKeyboard *pk, GdkEventButton *event, gpointer ig
static gboolean
mouse_motion_event_handler(PianoKeyboard *pk, GdkEventMotion *event, gpointer ignored)
{
- int note;
+ int note;
(void) ignored;
if ((event->state & GDK_BUTTON1_MASK) == 0)
return TRUE;
- int x = event->x;
- int y = event->y;
+ int x = event->x;
+ int y = event->y;
- note = get_note_for_xy(pk, x, 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) {
@@ -534,7 +608,7 @@ piano_keyboard_expose(GtkWidget *widget, GdkEventExpose *event)
gdk_cairo_region (cr, event->region);
cairo_clip (cr);
- for (i = 0; i < NNOTES; i++) {
+ for (i = 0; i < NNOTES; ++i) {
GdkRectangle r;
r.x = pk->notes[i].x;
@@ -566,39 +640,82 @@ piano_keyboard_size_request(GtkWidget* w, GtkRequisition *requisition)
requisition->height = PIANO_KEYBOARD_DEFAULT_HEIGHT;
}
-static void
-recompute_dimensions(PianoKeyboard *pk)
+static int
+is_black (int key)
{
- int number_of_white_keys = (NNOTES - 1) * (7.0 / 12.0);
+ 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;
+}
- int key_width;
- int black_key_width;
- int useful_width;
+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;
+}
- int note;
- int white_key = 0;
- int note_in_octave;
+static void
+recompute_dimensions (PianoKeyboard *pk)
+{
+ int note;
+ int number_of_white_keys = 0;
+ int skipped_white_keys = 0;
- int width = GTK_WIDGET(pk)->allocation.width;
- int height = GTK_WIDGET(pk)->allocation.height;
+ 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;
+ }
+ }
- key_width = width / number_of_white_keys;
- black_key_width = key_width * 0.8;
- useful_width = number_of_white_keys * key_width;
- pk->widget_margin = (width - useful_width) / 2;
+ int width = GTK_WIDGET(pk)->allocation.width;
+ int height = GTK_WIDGET(pk)->allocation.height;
- for (note = 0, white_key = 0; note < NNOTES - 2; note++) {
- note_in_octave = note % 12;
+ 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;
- if (note_in_octave == 1 || note_in_octave == 3 || note_in_octave == 6 ||
- note_in_octave == 8 || note_in_octave == 10) {
+ 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 / 2;
+ 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 * .6;
+ pk->notes[note].h = (height * 2) / 3;
pk->notes[note].white = 0;
-
continue;
}
@@ -667,7 +784,7 @@ g_cclosure_user_marshal_VOID__INT_INT (GClosure *closure,
static void
piano_keyboard_class_init(PianoKeyboardClass *klass)
{
- GtkWidgetClass *widget_klass;
+ GtkWidgetClass* widget_klass;
/* Set up signals. */
piano_keyboard_signals[NOTE_ON_SIGNAL] = g_signal_new ("note-on",
@@ -735,9 +852,13 @@ piano_keyboard_new(void)
pk->maybe_stop_sustained_notes = 0;
pk->sustain_new_notes = 0;
- pk->enable_keyboard_cue = 0;
+ pk->enable_keyboard_cue = FALSE;
+ pk->highlight_grand_piano_range = FALSE;
pk->octave = 4;
+ pk->octave_range = 7;
pk->note_being_pressed_using_mouse = -1;
+ pk->min_note = PIANO_MIN_NOTE;
+ pk->max_note = PIANO_MAX_NOTE;
pk->last_key = 0;
pk->monophonic = FALSE;
@@ -754,9 +875,17 @@ piano_keyboard_new(void)
}
void
-piano_keyboard_set_keyboard_cue(PianoKeyboard *pk, int enabled)
+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
@@ -816,10 +945,88 @@ piano_keyboard_set_note_off(PianoKeyboard *pk, int note)
}
void
-piano_keyboard_set_octave(PianoKeyboard *pk, int octave)
+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);
+ }
+
+ printf ("Oct: %d, Range: %d MIDI %d .. %d\n", pk->octave, octave_range, pk->min_note, pk->max_note);
+
+ recompute_dimensions(pk);
gtk_widget_queue_draw(GTK_WIDGET(pk));
}
@@ -837,6 +1044,9 @@ piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout)
} else if (!g_ascii_strcasecmp(layout, "AZERTY")) {
bind_keys_azerty(pk);
+ } else if (!g_ascii_strcasecmp(layout, "DVORAK")) {
+ bind_keys_dvorak(pk);
+
} else {
/* Unknown layout name. */
return TRUE;
diff --git a/gtk2_ardour/gtk_pianokeyboard.h b/gtk2_ardour/gtk_pianokeyboard.h
index b9d3581c74..70077da508 100644
--- a/gtk2_ardour/gtk_pianokeyboard.h
+++ b/gtk2_ardour/gtk_pianokeyboard.h
@@ -35,7 +35,9 @@ G_BEGIN_DECLS
typedef struct _PianoKeyboard PianoKeyboard;
typedef struct _PianoKeyboardClass PianoKeyboardClass;
-#define NNOTES (127)
+#define NNOTES (128)
+#define PIANO_MIN_NOTE 21
+#define PIANO_MAX_NOTE 108
#define OCTAVE_MIN (-1)
#define OCTAVE_MAX (7)
@@ -55,10 +57,14 @@ struct _PianoKeyboard
GtkDrawingArea da;
int maybe_stop_sustained_notes;
int sustain_new_notes;
- int enable_keyboard_cue;
+ gboolean enable_keyboard_cue;
+ gboolean highlight_grand_piano_range;
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];
@@ -81,9 +87,11 @@ 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, int enabled);
+void piano_keyboard_set_keyboard_cue (PianoKeyboard *pk, gboolean enabled);
+void piano_keyboard_set_grand_piano_highlight (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);
gboolean 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);
diff --git a/gtk2_ardour/virtual_keyboard_window.cc b/gtk2_ardour/virtual_keyboard_window.cc
index 31bde09b72..299a380cbb 100644
--- a/gtk2_ardour/virtual_keyboard_window.cc
+++ b/gtk2_ardour/virtual_keyboard_window.cc
@@ -37,18 +37,22 @@ using namespace ArdourWidgets;
#define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
VirtualKeyboardWindow::VirtualKeyboardWindow ()
- : ArdourWindow (_("Virtual Keyboard"))
+ : ArdourWindow (_("Virtual MIDI Keyboard"))
, _piano_channel (*manage (new Adjustment (1, 1, 16, 1, 1)))
, _bank_msb (*manage (new Adjustment (0, 0, 127, 1, 16)))
, _bank_lsb (*manage (new Adjustment (0, 0, 127, 1, 16)))
, _patchpgm (*manage (new Adjustment (1, 1, 128, 1, 16)))
, _cfg_display ("Config", ArdourButton::led_default_elements)
, _pgm_display ("Bank/Patch", ArdourButton::led_default_elements)
- , _yaxis_velocity ("Y-Axis Click Velocity", ArdourButton::led_default_elements)
+ , _yaxis_velocity ("Y-Axis", ArdourButton::led_default_elements)
+ , _highlight_grand_piano ("Grand Piano", ArdourButton::led_default_elements)
+ , _highlight_key_range ("Key Bindings", ArdourButton::led_default_elements)
, _send_panic ("Panic", ArdourButton::default_elements)
, _piano_key_velocity (*manage (new Adjustment (100, 1, 127, 1, 16)))
, _piano_min_velocity (*manage (new Adjustment (1 , 1, 127, 1, 16)))
, _piano_max_velocity (*manage (new Adjustment (127, 1, 127, 1, 16)))
+ , _piano_octave_key (*manage (new Adjustment (4, -1, 7, 1, 1)))
+ , _piano_octave_range (*manage (new Adjustment (7, 2, 11, 1, 1)))
, _pitch_adjustment (8192, 0, 16383, 1, 256)
{
_piano = (PianoKeyboard*)piano_keyboard_new();
@@ -64,11 +68,15 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
sigc::bind (sigc::mem_fun (*this, &VirtualKeyboardWindow::select_keyboard_layout), 1)));
_keyboard_layout.AddMenuElem (MenuElem ("AZERTY",
sigc::bind (sigc::mem_fun (*this, &VirtualKeyboardWindow::select_keyboard_layout), 2)));
+ _keyboard_layout.AddMenuElem (MenuElem ("DVORAK",
+ sigc::bind (sigc::mem_fun (*this, &VirtualKeyboardWindow::select_keyboard_layout), 3)));
_keyboard_layout.set_active (_("QWERTY"));
_cfg_display.set_active (false);
_pgm_display.set_active (false);
_yaxis_velocity.set_active (false);
+ _highlight_grand_piano.set_active (false);
+ _highlight_key_range.set_active (false);
_pitchbend = boost::shared_ptr<VKBDControl> (new VKBDControl ("PB", 8192, 16383));
_pitch_slider = manage (new VSliderController(&_pitch_adjustment, _pitchbend, 0, PX_SCALE (15)));
@@ -78,21 +86,50 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
_pitchbend->ValueChanged.connect_same_thread (_cc_connections,
boost::bind (&VirtualKeyboardWindow::pitch_bend_event_handler, this, _1));
+ set_tooltip (_highlight_grand_piano, "Shade keys outside the range of a Grand Piano (A0-C8).");
+ set_tooltip (_highlight_key_range, "Indicate which notes can be controlled by keyboard-shortcuts.");
+ set_tooltip (_yaxis_velocity, "When enabled, mouse-click y-axis position defines the velocity.");
+
+ set_tooltip (_piano_octave_key, "The center octave, and lowest octave for keyboard control.");
+ set_tooltip (_piano_octave_range, "Available octave range, centered around the key-octave.");
+ set_tooltip (_keyboard_layout, "Keyboard layout to use for keyboard control.");
+
+ set_tooltip (_piano_key_velocity, "The default velocity to use with keyboard control, and when y-axis click-position is disabled.");
+ set_tooltip (_piano_min_velocity, "Velocity to use when clicking at the top-end of a key.");
+ set_tooltip (_piano_max_velocity, "Velocity to use when clicking at the bottom-end of a key.");
+
set_tooltip (_send_panic, "Send MIDI Panic message for current channel");
+
_pitch_slider_tooltip->set_tip ("Pitchbend: 8192");
/* config */
- HBox* cfg_box = manage (new HBox);
- cfg_box->set_spacing (4);
- cfg_box->pack_start (*manage (new Label (_("Key Velocity:"))), false, false);
- cfg_box->pack_start (_piano_key_velocity, false, false);
- cfg_box->pack_start (_yaxis_velocity, false, false, 8);
- cfg_box->pack_start (*manage (new Label (_("Min Velocity:"))), false, false);
- cfg_box->pack_start (_piano_min_velocity, false, false);
- cfg_box->pack_start (*manage (new Label (_("Max Velocity:"))), false, false);
- cfg_box->pack_start (_piano_max_velocity, false, false);
- cfg_box->pack_start (_keyboard_layout, false, false, 8);
- cfg_box->show_all ();
+ Table* cfg_tbl = manage (new Table);
+ cfg_tbl->attach (_yaxis_velocity, 0, 1, 0, 1, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (*manage (new Label (_("Velocity:"))), 0, 1, 1, 2, SHRINK, SHRINK, 4, 0);
+
+ cfg_tbl->attach (_piano_min_velocity, 1, 2, 0, 1, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (*manage (new Label (_("Min"))), 1, 2, 1, 2, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (_piano_max_velocity, 2, 3, 0, 1, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (*manage (new Label (_("Max"))), 2, 3, 1, 2, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (_piano_key_velocity, 3, 4, 0, 1, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (*manage (new Label (_("Key"))), 3, 4, 1, 2, SHRINK, SHRINK, 4, 0);
+
+ cfg_tbl->attach (*manage (new ArdourVSpacer), 4, 5, 0, 2, SHRINK, FILL, 4, 0);
+
+ cfg_tbl->attach (_piano_octave_key, 5, 6, 0, 1, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (*manage (new Label (_("Octave"))), 5, 6, 1, 2, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (_piano_octave_range, 6, 7, 0, 1, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->attach (*manage (new Label (_("Range"))), 6, 7, 1, 2, SHRINK, SHRINK, 4, 0);
+
+ cfg_tbl->attach (*manage (new ArdourVSpacer), 7, 8, 0, 2, SHRINK, FILL, 4, 0);
+
+ cfg_tbl->attach (_highlight_grand_piano, 8, 9, 0, 1, FILL, SHRINK, 4, 2);
+ cfg_tbl->attach (_highlight_key_range, 8, 9, 1, 2, FILL, SHRINK, 4, 2);
+
+ cfg_tbl->attach (*manage (new ArdourVSpacer), 9,10, 0, 2, SHRINK, FILL, 4, 0);
+
+ cfg_tbl->attach (_keyboard_layout, 10,11, 0, 2, SHRINK, SHRINK, 4, 0);
+ cfg_tbl->show_all ();
/* bank/patch */
Table* pgm_tbl = manage (new Table);
@@ -156,7 +193,7 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
box1->pack_start (*box2, false, false);
_cfg_box = manage (new HBox ());
- _cfg_box->pack_start (*cfg_box, true, false);
+ _cfg_box->pack_start (*cfg_tbl, true, false);
_cfg_box->set_no_show_all (true);
_pgm_box = manage (new HBox ());
@@ -178,9 +215,14 @@ VirtualKeyboardWindow::VirtualKeyboardWindow ()
_piano_min_velocity.signal_value_changed ().connect (sigc::bind (sigc::mem_fun (*this, &VirtualKeyboardWindow::update_velocity_settings), 1));
_piano_max_velocity.signal_value_changed ().connect (sigc::bind (sigc::mem_fun (*this, &VirtualKeyboardWindow::update_velocity_settings), 2));
+ _piano_octave_key.signal_value_changed ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::update_octave_key));
+ _piano_octave_range.signal_value_changed ().connect (sigc::mem_fun (*this, &VirtualKeyboardWindow::update_octave_range));
+
_cfg_display.signal_button_release_event().connect (sigc::mem_fun(*this, &VirtualKeyboardWindow::toggle_config), false);
_pgm_display.signal_button_release_event().connect (sigc::mem_fun(*this, &VirtualKeyboardWindow::toggle_bankpatch), false);
_yaxis_velocity.signal_button_release_event().connect (sigc::mem_fun(*this, &VirtualKeyboardWindow::toggle_yaxis_velocity), false);
+ _highlight_grand_piano.signal_button_release_event().connect (sigc::mem_fun(*this, &VirtualKeyboardWindow::toggle_highlight_piano), false);
+ _highlight_key_range.signal_button_release_event().connect (sigc::mem_fun(*this, &VirtualKeyboardWindow::toggle_highlight_key), 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);
@@ -304,6 +346,9 @@ VirtualKeyboardWindow::select_keyboard_layout (int l)
case 2:
piano_keyboard_set_keyboard_layout (_piano, "AZERTY");
break;
+ case 3:
+ piano_keyboard_set_keyboard_layout (_piano, "DVORAK");
+ break;
}
}
@@ -333,6 +378,18 @@ VirtualKeyboardWindow::toggle_bankpatch (GdkEventButton*)
return false;
}
+void
+VirtualKeyboardWindow::update_octave_key ()
+{
+ piano_keyboard_set_octave (_piano, _piano_octave_key.get_value_as_int ());
+}
+
+void
+VirtualKeyboardWindow::update_octave_range ()
+{
+ piano_keyboard_set_octave_range (_piano, _piano_octave_range.get_value_as_int ());
+}
+
bool
VirtualKeyboardWindow::toggle_yaxis_velocity (GdkEventButton*)
{
@@ -342,6 +399,24 @@ VirtualKeyboardWindow::toggle_yaxis_velocity (GdkEventButton*)
}
bool
+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);
+ return false;
+}
+
+bool
+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);
+ return false;
+}
+
+bool
VirtualKeyboardWindow::send_panic_message (GdkEventButton*)
{
uint8_t channel = _piano_channel.get_value_as_int () - 1;
diff --git a/gtk2_ardour/virtual_keyboard_window.h b/gtk2_ardour/virtual_keyboard_window.h
index 20d11562f5..44a71867c0 100644
--- a/gtk2_ardour/virtual_keyboard_window.h
+++ b/gtk2_ardour/virtual_keyboard_window.h
@@ -115,12 +115,16 @@ private:
void select_keyboard_layout (int);
void update_velocity_settings (int);
+ void update_octave_key ();
+ void update_octave_range ();
void bank_patch ();
void update_sensitivity ();
void pitch_slider_adjusted ();
bool toggle_config (GdkEventButton*);
bool toggle_bankpatch (GdkEventButton*);
bool toggle_yaxis_velocity (GdkEventButton*);
+ bool toggle_highlight_piano (GdkEventButton*);
+ bool toggle_highlight_key (GdkEventButton*);
bool send_panic_message (GdkEventButton*);
PianoKeyboard* _piano;
@@ -137,6 +141,8 @@ private:
ArdourWidgets::ArdourButton _cfg_display;
ArdourWidgets::ArdourButton _pgm_display;
ArdourWidgets::ArdourButton _yaxis_velocity;
+ ArdourWidgets::ArdourButton _highlight_grand_piano;
+ ArdourWidgets::ArdourButton _highlight_key_range;
ArdourWidgets::ArdourButton _send_panic;
ArdourWidgets::ArdourDropdown _keyboard_layout;
@@ -144,6 +150,9 @@ private:
Gtk::SpinButton _piano_min_velocity;
Gtk::SpinButton _piano_max_velocity;
+ Gtk::SpinButton _piano_octave_key;
+ Gtk::SpinButton _piano_octave_range;
+
boost::shared_ptr<VKBDControl> _pitchbend;
Gtk::Adjustment _pitch_adjustment;
ArdourWidgets::VSliderController* _pitch_slider;