From 5a43b0324c6353c1541a3c1fad52e2f040ab389d Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 22 Sep 2013 15:15:03 -0700 Subject: [PATCH] Allow computer-keyboard input of accidentals, and draw accidentals. All accidentals are drawn assuming the key of C major, for now. That is, natural symbols will not be drawn, but all other accidental symbols will be drawn. No care is taken to avoid accidentals colliding with each other when drawn. --- scherzo.c | 21 ++++++++++++---- score.c | 71 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/scherzo.c b/scherzo.c index b0f2c44..b9a4633 100644 --- a/scherzo.c +++ b/scherzo.c @@ -60,9 +60,11 @@ typedef struct scherzo score_staff_t *bass; score_chord_t *chord; - /* This is for a "computer keyboard". Any "piano keyboard" key - * knows its own octave. */ + /* The word "keyboard" here is referring to a "computer + * keyboard". Any "piano keyboard" key knows its own octave and + * accidental already. */ int keyboard_octave; + score_pitch_accidental_t keyboard_accidental; int midi_fd; snd_midi_event_t *snd_midi_event; @@ -215,9 +217,17 @@ on_key_press_event (GtkWidget *widget, case GDK_KEY_space: scherzo_press_pedal (scherzo); break; + case GDK_KEY_Up: + if (scherzo->keyboard_accidental < SCORE_PITCH_ACCIDENTAL_DOUBLE_SHARP) + scherzo->keyboard_accidental++; + break; + case GDK_KEY_Down: + if (scherzo->keyboard_accidental > SCORE_PITCH_ACCIDENTAL_DOUBLE_FLAT) + scherzo->keyboard_accidental--; + break; } - pitch = SCORE_PITCH (pitch_name, SCORE_PITCH_ACCIDENTAL_NATURAL); + pitch = SCORE_PITCH (pitch_name, scherzo->keyboard_accidental); if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) || (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g)) @@ -285,7 +295,7 @@ on_key_release_event (unused (GtkWidget *widget), break; } - pitch = SCORE_PITCH (pitch_name, SCORE_PITCH_ACCIDENTAL_NATURAL); + pitch = SCORE_PITCH (pitch_name, scherzo->keyboard_accidental); if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) || (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g)) @@ -989,8 +999,9 @@ main (int argc, char *argv[]) scherzo.chord = NULL; - /* Default to octave 4 for computer keyboard keypresses. */ + /* Default to octave 4 and natural for computer keyboard keypresses. */ scherzo.keyboard_octave = 4; + scherzo.keyboard_accidental = SCORE_PITCH_ACCIDENTAL_NATURAL; note_group_init (scherzo.ctx, &scherzo.notes_pressed); note_group_init (scherzo.ctx, &scherzo.notes_pedaled); diff --git a/score.c b/score.c index ac0d346..25187ba 100644 --- a/score.c +++ b/score.c @@ -218,12 +218,13 @@ _draw_note (score_t *score, cairo_t *cr, score_staff_t *staff, score_note_t *note) { double line; - cairo_glyph_t note_glyph; + cairo_glyph_t note_glyph[2]; static double extend_factor = 0.25; + cairo_text_extents_t extents; + int num_glyphs = 0; - void _draw_ledger_line (double line, double width) { - cairo_move_to (cr, - - width * extend_factor / 2.0, + void _draw_ledger_line (double line, double offset, double width) { + cairo_move_to (cr, offset - extend_factor * width / 2.0, score->space_height * line + score->line_width / 2.0); cairo_rel_line_to (cr, (1 + extend_factor) * width, 0); cairo_stroke (cr); @@ -231,6 +232,11 @@ _draw_note (score_t *score, cairo_t *cr, cairo_save (cr); + /* Move right so that X==0 is natural position for non-displaced + * noteheads. + */ + cairo_translate (cr, score->space_height, 0); + /* Which line should the note appear on? Line 0 is the top line of * the staff and increasing downwards. (Negative values indicate a * note on a ledger line above the staff). Values half way between @@ -243,12 +249,45 @@ _draw_note (score_t *score, cairo_t *cr, /* XXX: The hard-coded glyph indices here are very ugly. We should * figure out how to lookup glyphs by name from this font. */ + switch (SCORE_PITCH_ACCIDENTAL (note->pitch)) { + case SCORE_PITCH_ACCIDENTAL_DOUBLE_FLAT: + note_glyph[num_glyphs].index = 77; + break; + case SCORE_PITCH_ACCIDENTAL_FLAT: + note_glyph[num_glyphs].index = 68; + break; + case SCORE_PITCH_ACCIDENTAL_NATURAL: + note_glyph[num_glyphs].index = 101; + break; + case SCORE_PITCH_ACCIDENTAL_SHARP: + note_glyph[num_glyphs].index = 134; + break; + case SCORE_PITCH_ACCIDENTAL_DOUBLE_SHARP: + note_glyph[num_glyphs].index = 142; + break; + } + + if (SCORE_PITCH_ACCIDENTAL (note->pitch) != SCORE_PITCH_ACCIDENTAL_NATURAL) + { + note_glyph[num_glyphs].x = 0; + + note_glyph[num_glyphs].y = score->space_height * line; + + num_glyphs++; + + cairo_glyph_extents (cr, note_glyph, num_glyphs, &extents); + +#define ACCIDENTAL_NOTE_SPACING (score->space_height * .15) + + note_glyph[0].x = - (extents.width + ACCIDENTAL_NOTE_SPACING); + } + switch (note->duration) { case SCORE_DURATION_1: - note_glyph.index = 127; + note_glyph[num_glyphs].index = 127; break; case SCORE_DURATION_2: - note_glyph.index = 85; + note_glyph[num_glyphs].index = 85; break; case SCORE_DURATION_4: case SCORE_DURATION_8: @@ -257,24 +296,28 @@ _draw_note (score_t *score, cairo_t *cr, case SCORE_DURATION_64: case SCORE_DURATION_128: default: - note_glyph.index = 84; + note_glyph[num_glyphs].index = 84; } - note_glyph.x = 0; - note_glyph.y = score->space_height * line; + note_glyph[num_glyphs].x = 0; + note_glyph[num_glyphs].y = score->space_height * line; + + num_glyphs++; if (line < 0 || line > 4) { + double offset, width; int i; - cairo_text_extents_t note_extents; - cairo_glyph_extents (cr, ¬e_glyph, 1, ¬e_extents); + cairo_glyph_extents (cr, note_glyph, num_glyphs, &extents); + offset = note_glyph[0].x + extents.x_bearing; + width = extents.width; if (line < 0) { for (i = -1; i >= line; i--) - _draw_ledger_line (i, note_extents.width); + _draw_ledger_line (i, offset, width); } else { for (i = 5; i <= line; i++) - _draw_ledger_line (i, note_extents.width); + _draw_ledger_line (i, offset, width); } } @@ -282,7 +325,7 @@ _draw_note (score_t *score, cairo_t *cr, note->color.r, note->color.g, note->color.b); - cairo_show_glyphs (cr, ¬e_glyph, 1); + cairo_show_glyphs (cr, note_glyph, num_glyphs); cairo_restore (cr); } -- 2.43.0