From fbfb0b3acfebeb22fae538588557f523ee539617 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 1 Oct 2013 08:47:34 -0700 Subject: [PATCH] Rework computer keyboard input to be mapped piano keyboard Instead of using computer keyboard letter names for piano note names, (which allowed only entering natural notes), we now map the piano keyboard onto the computer keyboard. The naturals are on the home row, (middle C is on 'A' and the next higher C is on 'K'), and the sharps map onto the top row in the obvious position, (C# on 'W, D# on 'E', etc.). --- pitch.h | 2 + scherzo.c | 197 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 140 insertions(+), 59 deletions(-) diff --git a/pitch.h b/pitch.h index 4467aa8..3d1dd2e 100644 --- a/pitch.h +++ b/pitch.h @@ -60,6 +60,8 @@ typedef uint32_t pitch_t; #define PITCH_CLASS_LITERAL(literal_name, literal_accidental) \ PITCH_LITERAL(literal_name, literal_accidental, 0) +#define PITCH_NOT_A_PITCH ((pitch_t) -1) + typedef enum pitch_accidental { PITCH_ACCIDENTAL_DOUBLE_FLAT, diff --git a/scherzo.c b/scherzo.c index e8d0d27..e57ccbe 100644 --- a/scherzo.c +++ b/scherzo.c @@ -66,7 +66,6 @@ typedef struct scherzo * keyboard". Any "piano keyboard" key knows its own octave and * accidental already. */ int keyboard_octave; - pitch_accidental_t keyboard_accidental; int midi_fd; snd_midi_event_t *snd_midi_event; @@ -151,9 +150,7 @@ on_key_press_event (GtkWidget *widget, { scherzo_t *scherzo = user_data; int octave; - /* Initialize to keep the compiler quiet. */ - pitch_name_t pitch_name = PITCH_NATURAL (C, 0); - pitch_t pitch; + pitch_t pitch = PITCH_NOT_A_PITCH; if (scherzo->challenge.active) octave = PITCH_OCTAVE (scherzo->challenge.pitch); @@ -175,38 +172,89 @@ on_key_press_event (GtkWidget *widget, gtk_widget_queue_draw (widget); return TRUE; break; - case GDK_KEY_q: - case GDK_KEY_Q: case GDK_KEY_Escape: gtk_main_quit (); return FALSE; - case GDK_KEY_c: - case GDK_KEY_C: - pitch_name = PITCH_NAME_C; + /* Map a piano keyboard onto the computer keyboard with white keys + * along the home row, (piano C on computer A, up to next octave + * higher C on computer K). Black keys are in the expected + * positions, (C# is W, D# is E, etc.). + */ + case GDK_KEY_a: + case GDK_KEY_A: + pitch = PITCH_LITERAL (C, NATURAL, octave); + break; + case GDK_KEY_s: + case GDK_KEY_S: + pitch = PITCH_LITERAL (D, NATURAL, octave); break; case GDK_KEY_d: case GDK_KEY_D: - pitch_name = PITCH_NAME_D; - break; - case GDK_KEY_e: - case GDK_KEY_E: - pitch_name = PITCH_NAME_E; + pitch = PITCH_LITERAL (E, NATURAL, octave); break; case GDK_KEY_f: case GDK_KEY_F: - pitch_name = PITCH_NAME_F; + pitch = PITCH_LITERAL (F, NATURAL, octave); break; case GDK_KEY_g: case GDK_KEY_G: - pitch_name = PITCH_NAME_G; + pitch = PITCH_LITERAL (G, NATURAL, octave); break; - case GDK_KEY_a: - case GDK_KEY_A: - pitch_name = PITCH_NAME_A; + case GDK_KEY_h: + case GDK_KEY_H: + pitch = PITCH_LITERAL (A, NATURAL, octave); break; - case GDK_KEY_b: - case GDK_KEY_B: - pitch_name = PITCH_NAME_B; + case GDK_KEY_j: + case GDK_KEY_J: + pitch = PITCH_LITERAL (B, NATURAL, octave); + break; + case GDK_KEY_k: + case GDK_KEY_K: + pitch = PITCH_LITERAL (C, NATURAL, octave + 1); + break; + case GDK_KEY_l: + case GDK_KEY_L: + pitch = PITCH_LITERAL (D, NATURAL, octave + 1); + break; + case GDK_KEY_semicolon: + case GDK_KEY_colon: + pitch = PITCH_LITERAL (E, NATURAL, octave + 1); + break; + case GDK_KEY_apostrophe: + case GDK_KEY_quotedbl: + pitch = PITCH_LITERAL (F, NATURAL, octave + 1); + break; + case GDK_KEY_w: + case GDK_KEY_W: + pitch = PITCH_LITERAL (C, SHARP, octave); + break; + case GDK_KEY_e: + case GDK_KEY_E: + pitch = PITCH_LITERAL (D, SHARP, octave); + break; + case GDK_KEY_t: + case GDK_KEY_T: + pitch = PITCH_LITERAL (F, SHARP, octave); + break; + case GDK_KEY_y: + case GDK_KEY_Y: + pitch = PITCH_LITERAL (G, SHARP, octave); + break; + case GDK_KEY_u: + case GDK_KEY_U: + pitch = PITCH_LITERAL (A, SHARP, octave); + break; + case GDK_KEY_o: + case GDK_KEY_O: + pitch = PITCH_LITERAL (C, SHARP, octave + 1); + break; + case GDK_KEY_p: + case GDK_KEY_P: + pitch = PITCH_LITERAL (D, SHARP, octave + 1); + break; + case GDK_KEY_bracketright: + case GDK_KEY_braceright: + pitch = PITCH_LITERAL (F, SHARP, octave + 1); break; case GDK_KEY_0: case GDK_KEY_1: @@ -222,20 +270,9 @@ on_key_press_event (GtkWidget *widget, case GDK_KEY_space: scherzo_press_pedal (scherzo); break; - case GDK_KEY_Up: - if (scherzo->keyboard_accidental < PITCH_ACCIDENTAL_DOUBLE_SHARP) - scherzo->keyboard_accidental++; - break; - case GDK_KEY_Down: - if (scherzo->keyboard_accidental > PITCH_ACCIDENTAL_DOUBLE_FLAT) - scherzo->keyboard_accidental--; - break; } - pitch = PITCH (pitch_name, scherzo->keyboard_accidental, octave); - - if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) || - (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g)) + if (pitch != PITCH_NOT_A_PITCH) { scherzo_press_note (scherzo, pitch); _judge_pitch (scherzo, pitch); @@ -256,9 +293,7 @@ on_key_release_event (unused (GtkWidget *widget), { scherzo_t *scherzo = user_data; int octave; - /* Initialize to keep the compiler quiet. */ - pitch_name_t pitch_name = PITCH_NAME_C; - pitch_t pitch; + pitch_t pitch = PITCH_NOT_A_PITCH; if (scherzo->challenge.active) octave = PITCH_OCTAVE (scherzo->challenge.pitch); @@ -266,43 +301,88 @@ on_key_release_event (unused (GtkWidget *widget), octave = scherzo->keyboard_octave; switch (key->keyval) { - case GDK_KEY_c: - case GDK_KEY_C: - pitch_name = PITCH_NAME_C; + case GDK_KEY_a: + case GDK_KEY_A: + pitch = PITCH_LITERAL (C, NATURAL, octave); + break; + case GDK_KEY_s: + case GDK_KEY_S: + pitch = PITCH_LITERAL (D, NATURAL, octave); break; case GDK_KEY_d: case GDK_KEY_D: - pitch_name = PITCH_NAME_D; - break; - case GDK_KEY_e: - case GDK_KEY_E: - pitch_name = PITCH_NAME_E; + pitch = PITCH_LITERAL (E, NATURAL, octave); break; case GDK_KEY_f: case GDK_KEY_F: - pitch_name = PITCH_NAME_F; + pitch = PITCH_LITERAL (F, NATURAL, octave); break; case GDK_KEY_g: case GDK_KEY_G: - pitch_name = PITCH_NAME_G; + pitch = PITCH_LITERAL (G, NATURAL, octave); break; - case GDK_KEY_a: - case GDK_KEY_A: - pitch_name = PITCH_NAME_A; + case GDK_KEY_h: + case GDK_KEY_H: + pitch = PITCH_LITERAL (A, NATURAL, octave); break; - case GDK_KEY_b: - case GDK_KEY_B: - pitch_name = PITCH_NAME_B; + case GDK_KEY_j: + case GDK_KEY_J: + pitch = PITCH_LITERAL (B, NATURAL, octave); + break; + case GDK_KEY_k: + case GDK_KEY_K: + pitch = PITCH_LITERAL (C, NATURAL, octave + 1); + break; + case GDK_KEY_l: + case GDK_KEY_L: + pitch = PITCH_LITERAL (D, NATURAL, octave + 1); + break; + case GDK_KEY_semicolon: + case GDK_KEY_colon: + pitch = PITCH_LITERAL (E, NATURAL, octave + 1); + break; + case GDK_KEY_apostrophe: + case GDK_KEY_quotedbl: + pitch = PITCH_LITERAL (F, NATURAL, octave + 1); + break; + case GDK_KEY_w: + case GDK_KEY_W: + pitch = PITCH_LITERAL (C, SHARP, octave); + break; + case GDK_KEY_e: + case GDK_KEY_E: + pitch = PITCH_LITERAL (D, SHARP, octave); + break; + case GDK_KEY_t: + case GDK_KEY_T: + pitch = PITCH_LITERAL (F, SHARP, octave); + break; + case GDK_KEY_y: + case GDK_KEY_Y: + pitch = PITCH_LITERAL (G, SHARP, octave); + break; + case GDK_KEY_u: + case GDK_KEY_U: + pitch = PITCH_LITERAL (A, SHARP, octave); + break; + case GDK_KEY_o: + case GDK_KEY_O: + pitch = PITCH_LITERAL (C, SHARP, octave + 1); + break; + case GDK_KEY_p: + case GDK_KEY_P: + pitch = PITCH_LITERAL (D, SHARP, octave + 1); + break; + case GDK_KEY_bracketright: + case GDK_KEY_braceright: + pitch = PITCH_LITERAL (F, SHARP, octave + 1); break; case GDK_KEY_space: scherzo_release_pedal (scherzo); break; } - pitch = PITCH (pitch_name, scherzo->keyboard_accidental, octave); - - if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) || - (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g)) + if (pitch != PITCH_NOT_A_PITCH) { scherzo_release_note (scherzo, pitch); _score_challenge (scherzo); @@ -1347,9 +1427,8 @@ main (int argc, char *argv[]) scherzo.chord = NULL; - /* Default to octave 4 and natural for computer keyboard keypresses. */ + /* Default to octave 4 for computer keyboard keypresses. */ scherzo.keyboard_octave = 4; - scherzo.keyboard_accidental = PITCH_ACCIDENTAL_NATURAL; pitch_group_init (scherzo.ctx, &scherzo.notes_pressed); pitch_group_init (scherzo.ctx, &scherzo.notes_pedaled); -- 2.43.0