37 #include <cairo/cairo.h>
40 #include <gdk/gdkkeysyms.h>
44 #define PIANO_KEYBOARD_DEFAULT_WIDTH 730
45 #define PIANO_KEYBOARD_DEFAULT_HEIGHT 70
62 int first_note_in_lower_row = (pk->
octave + 5) * 12;
63 int last_note_in_lower_row = (pk->
octave + 6) * 12 - 1;
64 int first_note_in_higher_row = (pk->
octave + 6) * 12;
65 int last_note_in_higher_row = (pk->
octave + 7) * 12 + 4;
67 cairo_set_source_rgb (cr, 1.0
f, 0.0
f, 0.0
f);
68 cairo_move_to (cr, pk->
notes[first_note_in_lower_row].
x + 3, h - 6);
69 cairo_line_to (cr, pk->
notes[last_note_in_lower_row].
x + w - 3, h - 6);
72 cairo_set_source_rgb (cr, 0.0
f, 0.0
f, 1.0
f);
73 cairo_move_to (cr, pk->
notes[first_note_in_higher_row].
x + 3, h - 9);
74 cairo_line_to (cr, pk->
notes[last_note_in_higher_row].
x + w - 3, h - 9);
81 GdkWindow* w = GTK_WIDGET(pk)->window;
88 r.width = pk->
notes[note].
w;
89 r.height = pk->
notes[note].
h;
91 gdk_window_invalidate_rect (w, &r, TRUE);
100 int x = pk->
notes[note].
x;
101 int w = pk->
notes[note].
w;
102 int h = pk->
notes[note].
h;
106 cairo_set_source_rgb (cr, 0.60
f, 0.60
f, 0.60
f);
108 cairo_set_source_rgb (cr, 0.50
f, 0.50
f, 0.50
f);
112 cairo_set_source_rgb (cr, 1.0
f, 1.0
f, 1.0
f);
114 cairo_set_source_rgb (cr, 0.0
f, 0.0
f, 0.0
f);
118 cairo_set_line_width (cr, 1.0);
120 cairo_rectangle (cr, x, 0, w, h);
123 cairo_set_source_rgb(cr, 0.0
f, 0.0
f, 0.0
f);
124 cairo_rectangle (cr, x, 0, w, h);
132 if (note < NNOTES - 2 && !pk->notes[note + 1].white) {
167 g_signal_emit_by_name(GTK_WIDGET(pk),
"note-on", key);
192 g_signal_emit_by_name(GTK_WIDGET(pk),
"note-off", key);
201 g_signal_emit_by_name(GTK_WIDGET(pk),
"rest");
209 for (i = 0; i <
NNOTES; i++) {
212 g_signal_emit_by_name(GTK_WIDGET(pk),
"note-off", i);
223 for (i = 0; i <
NNOTES; i++) {
227 g_signal_emit_by_name(GTK_WIDGET(pk),
"note-off", i);
236 gpointer notused, note;
241 found = g_hash_table_lookup_extended(pk->
key_bindings, key, ¬used, ¬e);
374 kk.keycode =
event->hardware_keycode;
378 keyval = gdk_keymap_lookup_key(NULL, &kk);
380 key = gdk_keyval_name(gdk_keyval_to_lower(keyval));
383 g_message(
"gtk_keyval_name() returned NULL; please report this.");
395 if (event->type == GDK_KEY_RELEASE) {
407 if (event->type == GDK_KEY_PRESS) {
410 }
else if (event->type == GDK_KEY_RELEASE) {
420 int height = GTK_WIDGET(pk)->allocation.height;
423 if (y <= height / 2) {
424 for (note = 0; note <
NNOTES - 1; note++) {
428 if (x >= pk->
notes[note].
x && x <= pk->notes[note].x + pk->
notes[note].
w)
433 for (note = 0; note <
NNOTES - 1; note++) {
437 if (x >= pk->
notes[note].
x && x <= pk->notes[note].x + pk->
notes[note].
w)
454 if (event->button != 1)
457 if (event->type == GDK_BUTTON_PRESS) {
470 }
else if (event->type == GDK_BUTTON_RELEASE) {
493 if ((event->state & GDK_BUTTON1_MASK) == 0)
514 cairo_t* cr = gdk_cairo_create (GDK_DRAWABLE (GTK_WIDGET(pk)->window));
516 gdk_cairo_region (cr, event->region);
519 for (i = 0; i <
NNOTES; i++) {
525 r.height = pk->
notes[i].
h;
527 switch (gdk_region_rect_in (event->region, &r)) {
528 case GDK_OVERLAP_RECTANGLE_PART:
529 case GDK_OVERLAP_RECTANGLE_IN:
554 int number_of_white_keys = (
NNOTES - 1) * (7.0 / 12.0);
564 int width = GTK_WIDGET(pk)->allocation.width;
565 int height = GTK_WIDGET(pk)->allocation.height;
567 key_width = width / number_of_white_keys;
568 black_key_width = key_width * 0.8;
569 useful_width = number_of_white_keys * key_width;
572 for (note = 0, white_key = 0; note <
NNOTES - 2; note++) {
573 note_in_octave = note % 12;
575 if (note_in_octave == 1 || note_in_octave == 3 || note_in_octave == 6 ||
576 note_in_octave == 8 || note_in_octave == 10) {
580 pk->
notes[note].
w = black_key_width;
581 pk->
notes[note].
h = height / 2;
589 pk->
notes[note].
w = key_width;
590 pk->
notes[note].
h = height;
601 g_return_if_fail(widget != NULL);
602 g_return_if_fail(allocation != NULL);
604 widget->allocation = *allocation;
608 if (GTK_WIDGET_REALIZED(widget)) {
609 gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height);
616 GtkWidgetClass *widget_klass;
620 G_TYPE_FROM_CLASS (klass), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
621 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
624 G_TYPE_FROM_CLASS (klass), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
625 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
628 G_TYPE_FROM_CLASS (klass), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
629 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
631 widget_klass = (GtkWidgetClass*) klass;
641 gtk_widget_add_events(mk, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
653 static GType mk_type = 0;
656 static const GTypeInfo mk_info = {
669 mk_type = g_type_register_static(GTK_TYPE_DRAWING_AREA,
"PianoKeyboard", &mk_info, (GTypeFlags)0);
690 pk->
key_bindings = g_hash_table_new(g_str_hash, g_str_equal);
750 gtk_widget_queue_draw(GTK_WIDGET(pk));
758 if (!g_ascii_strcasecmp(layout,
"QWERTY")) {
761 }
else if (!g_ascii_strcasecmp(layout,
"QWERTZ")) {
764 }
else if (!g_ascii_strcasecmp(layout,
"AZERTY")) {
static void stop_unsustained_notes(PianoKeyboard *pk)
static void clear_notes(PianoKeyboard *pk)
static void piano_keyboard_class_init(PianoKeyboardClass *klass)
static int key_binding(PianoKeyboard *pk, const char *key)
void piano_keyboard_sustain_release(PianoKeyboard *pk)
void piano_keyboard_set_monophonic(PianoKeyboard *pk, gboolean monophonic)
static void stop_sustained_notes(PianoKeyboard *pk)
static gboolean mouse_button_event_handler(PianoKeyboard *pk, GdkEventButton *event, gpointer ignored)
static guint piano_keyboard_signals[LAST_SIGNAL]
int maybe_stop_sustained_notes
gboolean piano_keyboard_set_keyboard_layout(PianoKeyboard *pk, const char *layout)
GtkWidget * piano_keyboard_new(void)
static void rest(PianoKeyboard *pk)
static void piano_keyboard_init(GtkWidget *mk)
static void draw_keyboard_cue(PianoKeyboard *pk, cairo_t *cr)
#define PIANO_KEYBOARD(obj)
GHashTable * key_bindings
#define PIANO_KEYBOARD_DEFAULT_HEIGHT
void piano_keyboard_set_note_off(PianoKeyboard *pk, int note)
static void bind_keys_qwerty(PianoKeyboard *pk)
static gint keyboard_event_handler(GtkWidget *mk, GdkEventKey *event, gpointer ignored)
static int get_note_for_xy(PianoKeyboard *pk, int x, int y)
struct _PianoKeyboardClass PianoKeyboardClass
struct _PianoKeyboard PianoKeyboard
static void bind_keys_azerty(PianoKeyboard *pk)
static void bind_keys_qwertz(PianoKeyboard *pk)
static void bind_key(PianoKeyboard *pk, const char *key, int note)
void piano_keyboard_set_note_on(PianoKeyboard *pk, int note)
void piano_keyboard_sustain_press(PianoKeyboard *pk)
#define PIANO_KEYBOARD_DEFAULT_WIDTH
GType piano_keyboard_get_type(void)
static void draw_note(PianoKeyboard *pk, cairo_t *cr, int note)
static void queue_note_draw(PianoKeyboard *pk, int note)
static gboolean piano_keyboard_expose(GtkWidget *widget, GdkEventExpose *event)
static int release_key(PianoKeyboard *pk, int key)
static void piano_keyboard_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
static gboolean mouse_motion_event_handler(PianoKeyboard *pk, GdkEventMotion *event, gpointer ignored)
static int press_key(PianoKeyboard *pk, int key)
static void piano_keyboard_size_request(GtkWidget *w, GtkRequisition *requisition)
void piano_keyboard_set_keyboard_cue(PianoKeyboard *pk, int enabled)
void piano_keyboard_set_octave(PianoKeyboard *pk, int octave)
static void recompute_dimensions(PianoKeyboard *pk)
volatile struct PKNote notes[NNOTES]
int note_being_pressed_using_mouse