]> git.cworth.org Git - scherzo/commitdiff
Respect the key when drawing notes.
authorCarl Worth <cworth@cworth.org>
Tue, 1 Oct 2013 16:41:42 +0000 (09:41 -0700)
committerCarl Worth <cworth@cworth.org>
Tue, 1 Oct 2013 16:41:42 +0000 (09:41 -0700)
Don't print accidentals when they are already in the key, and add
naturals when needed because of they key.

score.c

diff --git a/score.c b/score.c
index 0a6016bcb706785db4460460a37ebdde235a8563..e93042a0b2dd435db07f3ba89acf69334552d695 100644 (file)
--- 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);