X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=scherzo-key.c;h=8fea502de8044cc8b6fad289f3838c5b29260b78;hb=ff7437e171dab5bc3868ce65ecacf8e77c6e8df3;hp=67d2c1e2875f7a2a4388b5726a338e38bf91ac43;hpb=45d36bd8372f38186ceebf74b48f1a67bd67c573;p=scherzo diff --git a/scherzo-key.c b/scherzo-key.c index 67d2c1e..8fea502 100644 --- a/scherzo-key.c +++ b/scherzo-key.c @@ -19,6 +19,8 @@ */ #include +#include +#include #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); +}