]> git.cworth.org Git - scherzo/blobdiff - scherzo-key.c
Fix high octave numbers (8+) to not be interpreted as 0.
[scherzo] / scherzo-key.c
index 67d2c1e2875f7a2a4388b5726a338e38bf91ac43..8fea502de8044cc8b6fad289f3838c5b29260b78 100644 (file)
@@ -19,6 +19,8 @@
  */
 
 #include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "scherzo-key.h"
 
@@ -29,17 +31,6 @@ scherzo_key_init (scherzo_key_t *key, pitch_t pitch)
 {
     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),
@@ -51,17 +42,66 @@ scherzo_key_init (scherzo_key_t *key, pitch_t pitch)
        PITCH_CLASS_LITERAL (C, FLAT)
     };
 
-    key->pitch = PITCH_CLASS (PITCH_NAME (pitch), PITCH_ACCIDENTAL (pitch));
+    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),
+    };
+
+    /* Remove octave from 'pitch' */
+    pitch = PITCH_CLASS (pitch);
 
     key->num_sharps = 0;
-    for (i = 0; i < ARRAY_SIZE (sharp_keys); i++)
-       if (sharp_keys[i] == key->pitch)
+    key->num_flats = 0;
+
+    /* First, look for a key that exactly matches the specified pitch. */
+    for (i = 0; i < ARRAY_SIZE (flat_keys); i++) {
+       if (flat_keys[i] == pitch) {
+           key->pitch = flat_keys[i];
+           key->num_flats = i;
+           return;
+       }
+    }
+
+    for (i = 0; i < ARRAY_SIZE (sharp_keys); i++) {
+       if (sharp_keys[i] == pitch) {
+           key->pitch = sharp_keys[i];
            key->num_sharps = i;
+           return;
+       }
+    }
 
-    key->num_flats = 0;
-    for (i = 0; i < ARRAY_SIZE (flat_keys); i++)
-       if (flat_keys[i] == key->pitch)
+    /* Second, if we haven't found a key, look for something enharmonic. */
+    for (i = 0; i < ARRAY_SIZE (flat_keys); i++) {
+       if (pitch_enharmonic_to (flat_keys[i], pitch)) {
+           key->pitch = flat_keys[i];
            key->num_flats = i;
+           return;
+       }
+    }
+
+    for (i = 0; i < ARRAY_SIZE (sharp_keys); i++) {
+       if (pitch_enharmonic_to (sharp_keys[i], pitch)) {
+           key->pitch = sharp_keys[i];
+           key->num_sharps = i;
+           return;
+       }
+    }
+
+    /* The pitch_enharmonic_to function won't catch this wraparound. */
+    if (pitch == PITCH_CLASS_LITERAL (B, SHARP)) {
+       key->pitch = PITCH_CLASS_LITERAL (C, NATURAL);
+       return;
+    }
+
+    fprintf (stderr, "Interal error: Failed to find a key for %s.\n",
+            pitch_string (pitch));
+    exit (1);
 }
 
 bool
@@ -135,3 +175,30 @@ scherzo_key_contains_pitch (scherzo_key_t *key, pitch_t pitch)
     else
        return false;
 }
+
+pitch_t
+scherzo_key_spell_pitch (scherzo_key_t *key, pitch_t pitch)
+{
+    pitch_t root = key->pitch;
+    int half_steps = pitch_from_root_in_half_steps (pitch, root);
+    pitch_name_t new_pitch_name;
+    int i;
+    int half_steps_per_degree[] = {
+       0, 2, 4, 5, 7, 9, 11
+    };
+
+    for (i = 0; i < ARRAY_SIZE (half_steps_per_degree); i++)
+       if (half_steps_per_degree[i] == half_steps)
+           goto WITHIN_SCALE;
+
+    return pitch;
+
+WITHIN_SCALE:
+    new_pitch_name = (PITCH_NAME (root) + i) % 7;
+
+    /* Original pitch is spelled correctly. Return it as is. */
+    if (new_pitch_name == PITCH_NAME (pitch))
+       return pitch;
+
+    return pitch_spell_as_degree (pitch, root, i + 1);
+}