From b588ae80ff8009695f7ed299fd27e3f16de01e9e Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 1 Oct 2013 09:41:42 -0700 Subject: [PATCH] Respect the key when drawing notes. Don't print accidentals when they are already in the key, and add naturals when needed because of they key. --- score.c | 222 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 144 insertions(+), 78 deletions(-) diff --git a/score.c b/score.c index 0a6016b..e93042a 100644 --- a/score.c +++ b/score.c @@ -64,6 +64,16 @@ typedef struct score_brace int num_staves; } score_brace_t; +typedef struct score_key +{ + /* Pitch class (diatonic) */ + pitch_t pitch; + + /* Number of sharps/flats in key (if any) */ + int num_sharps; + int num_flats; +} score_key_t; + struct score { /* Nominal height of a single staff (ledger lines may make it larger) */ @@ -78,8 +88,8 @@ struct score /* Full width of staff */ int width; - /* the pitch class of the current (diatonic) key */ - pitch_t key; + /* Current (diatonic) key */ + score_key_t key; score_brace_t **braces; int num_braces; @@ -105,7 +115,9 @@ score_create (void *ctx) score->width = 1000; /* Default to C, of course */ - score->key = PITCH_CLASS_LITERAL (C, NATURAL); + score->key.pitch = PITCH_CLASS_LITERAL (C, NATURAL); + score->key.num_sharps = 0; + score->key.num_flats = 0; score->braces = NULL; score->num_braces = 0; @@ -138,7 +150,113 @@ score_set_width (score_t *score, int width) void score_set_key (score_t *score, pitch_t key) { - score->key = key; + int i; + + pitch_t sharp_keys[] = { + PITCH_CLASS_LITERAL (C, NATURAL), + PITCH_CLASS_LITERAL (G, NATURAL), + PITCH_CLASS_LITERAL (D, NATURAL), + PITCH_CLASS_LITERAL (A, NATURAL), + PITCH_CLASS_LITERAL (E, NATURAL), + PITCH_CLASS_LITERAL (B, NATURAL), + PITCH_CLASS_LITERAL (F, SHARP), + PITCH_CLASS_LITERAL (C, SHARP), + }; + + pitch_t flat_keys[] = { + PITCH_CLASS_LITERAL (C, NATURAL), + PITCH_CLASS_LITERAL (F, NATURAL), + PITCH_CLASS_LITERAL (B, FLAT), + PITCH_CLASS_LITERAL (E, FLAT), + PITCH_CLASS_LITERAL (A, FLAT), + PITCH_CLASS_LITERAL (D, FLAT), + PITCH_CLASS_LITERAL (G, FLAT), + PITCH_CLASS_LITERAL (C, FLAT) + }; + + score->key.pitch = PITCH_CLASS (PITCH_NAME (key), PITCH_ACCIDENTAL (key)); + + score->key.num_sharps = 0; + for (i = 0; i < ARRAY_SIZE (sharp_keys); i++) + if (sharp_keys[i] == score->key.pitch) + score->key.num_sharps = i; + + score->key.num_flats = 0; + for (i = 0; i < ARRAY_SIZE (flat_keys); i++) + if (flat_keys[i] == score->key.pitch) + score->key.num_flats = i; +} + +static int +score_key_contains_pitch (score_key_t *key, pitch_t pitch) +{ + pitch_accidental_t accidental = PITCH_ACCIDENTAL (pitch); + int i; + + pitch_name_t sharps_order[] = { + PITCH_NAME_F, + PITCH_NAME_C, + PITCH_NAME_G, + PITCH_NAME_D, + PITCH_NAME_A, + PITCH_NAME_E, + PITCH_NAME_B + }; + + pitch_name_t flats_order[] = { + PITCH_NAME_B, + PITCH_NAME_E, + PITCH_NAME_A, + PITCH_NAME_D, + PITCH_NAME_G, + PITCH_NAME_C, + PITCH_NAME_F + }; + + if (accidental == PITCH_ACCIDENTAL_DOUBLE_SHARP || + accidental == PITCH_ACCIDENTAL_DOUBLE_FLAT) + { + return 0; + } + + if (key->num_sharps) { + if (accidental == PITCH_ACCIDENTAL_FLAT) + return 0; + for (i = 0; i < key->num_sharps; i++) { + if (sharps_order[i] == PITCH_NAME (pitch)) { + if (accidental == PITCH_ACCIDENTAL_SHARP) + return 1; + else + return 0; + } + } + if (accidental == PITCH_ACCIDENTAL_SHARP) + return 0; + else + return 1; + } + + if (key->num_flats) { + if (accidental == PITCH_ACCIDENTAL_SHARP) + return 0; + for (i = 0; i < key->num_flats; i++) { + if (flats_order[i] == PITCH_NAME (pitch)) { + if (accidental == PITCH_ACCIDENTAL_FLAT) + return 1; + else + return 0; + } + } + if (accidental == PITCH_ACCIDENTAL_FLAT) + return 0; + else + return 1; + } + + if (accidental == PITCH_ACCIDENTAL_NATURAL) + return 1; + else + return 0; } /* Returns in brace_width the width of the brace */ @@ -269,8 +387,13 @@ _draw_chord (score_t *score, cairo_t *cr, cairo_restore (cr); } -/* Draw 'note' with accidental (if not NATURAL) at its correct - * position on 'staff'. +/* Draw 'note' at its correct position on 'staff'. + * If the accidental of 'note' is not contained within the current + * key, then draw the accidental as well. + * + * As a special case, if the note's duration is 0, draw the accidental + * alone, regardless of the key. This is useful for drawing the + * accidentals of the key signature. * * Returns the width of the drawn glyphs. */ @@ -328,7 +451,8 @@ _draw_note (score_t *score, cairo_t *cr, break; } - if (PITCH_ACCIDENTAL (note->pitch) != PITCH_ACCIDENTAL_NATURAL) + if (note->duration == 0 || + ! score_key_contains_pitch (&score->key, note->pitch)) { note_glyph[num_glyphs].x = 0; @@ -425,8 +549,8 @@ _draw_accidental (score_t *score, } static void -_draw_sharps_key_signature (score_t *score, cairo_t *cr, - score_staff_t *staff, int num_sharps) +_draw_key_signature (score_t *score, cairo_t *cr, + score_staff_t *staff) { pitch_t pitch; double width; @@ -445,31 +569,7 @@ _draw_sharps_key_signature (score_t *score, cairo_t *cr, PITCH_LITERAL (B, SHARP, 4) }; - for (i = 0; i < num_sharps; i++) { - pitch = sharps_order[i]; - - if (staff->clef == SCORE_CLEF_BASS) - pitch = pitch_lower_by_octaves (pitch, 2); - - width = _draw_accidental (score, cr, staff, pitch); - -#define KEY_SIGNATURE_ACCIDENTAL_SPACING (score->space_height * .15) - cairo_translate (cr, ceil (width + KEY_SIGNATURE_ACCIDENTAL_SPACING), 0); - } -} - -static void -_draw_flats_key_signature (score_t *score, cairo_t *cr, - score_staff_t *staff, int num_flats) -{ - pitch_t pitch; - double width; - int i; - - /* These octave numbers are correct for treble clef. For bass - * clef, subtract two. - */ - pitch_name_t flats_order[] = { + pitch_t flats_order[] = { PITCH_LITERAL (B, FLAT, 4), PITCH_LITERAL (E, FLAT, 5), PITCH_LITERAL (A, FLAT, 4), @@ -479,62 +579,28 @@ _draw_flats_key_signature (score_t *score, cairo_t *cr, PITCH_LITERAL (F, FLAT, 4), }; - for (i = 0; i < num_flats; i++) { - pitch = flats_order[i]; + for (i = 0; i < score->key.num_sharps; i++) { + pitch = sharps_order[i]; if (staff->clef == SCORE_CLEF_BASS) pitch = pitch_lower_by_octaves (pitch, 2); width = _draw_accidental (score, cr, staff, pitch); +#define KEY_SIGNATURE_ACCIDENTAL_SPACING (score->space_height * .15) cairo_translate (cr, ceil (width + KEY_SIGNATURE_ACCIDENTAL_SPACING), 0); } -} - -static void -_draw_key_signature (score_t *score, cairo_t *cr, - score_staff_t *staff, pitch_t key) -{ - int i; - pitch_t sharp_keys[] = { - PITCH_CLASS_LITERAL (C, NATURAL), - PITCH_CLASS_LITERAL (G, NATURAL), - PITCH_CLASS_LITERAL (D, NATURAL), - PITCH_CLASS_LITERAL (A, NATURAL), - PITCH_CLASS_LITERAL (E, NATURAL), - PITCH_CLASS_LITERAL (B, NATURAL), - PITCH_CLASS_LITERAL (F, SHARP), - PITCH_CLASS_LITERAL (C, SHARP), - }; + for (i = 0; i < score->key.num_flats; i++) { + pitch = flats_order[i]; - pitch_t flat_keys[] = { - PITCH_CLASS_LITERAL (C, NATURAL), - PITCH_CLASS_LITERAL (F, NATURAL), - PITCH_CLASS_LITERAL (B, FLAT), - PITCH_CLASS_LITERAL (E, FLAT), - PITCH_CLASS_LITERAL (A, FLAT), - PITCH_CLASS_LITERAL (D, FLAT), - PITCH_CLASS_LITERAL (G, FLAT), - PITCH_CLASS_LITERAL (C, FLAT) - }; + if (staff->clef == SCORE_CLEF_BASS) + pitch = pitch_lower_by_octaves (pitch, 2); - for (i = 0; i < ARRAY_SIZE (sharp_keys); i++) { - if (sharp_keys[i] == key) { - _draw_sharps_key_signature (score, cr, staff, i); - return; - } - } + width = _draw_accidental (score, cr, staff, pitch); - for (i = 0; i < ARRAY_SIZE (flat_keys); i++) { - if (flat_keys[i] == key) { - _draw_flats_key_signature (score, cr, staff, i); - return; - } + cairo_translate (cr, ceil (width + KEY_SIGNATURE_ACCIDENTAL_SPACING), 0); } - - fprintf (stderr, "Internal error: Not a key: %s\n", pitch_string (key)); - exit (1); } static void @@ -593,7 +659,7 @@ _draw_staff (score_t *score, cairo_t *cr, CLEF_KEY_SIGNATURE_SPACING), 0); /* Draw the key signature */ - _draw_key_signature (score, cr, staff, score->key); + _draw_key_signature (score, cr, staff); /* Draw chord symbols */ cairo_save (cr); -- 2.43.0