]> git.cworth.org Git - scherzo/commitdiff
Fix key signature setting to accept an enharmonic pitch
authorCarl Worth <cworth@cworth.org>
Tue, 1 Oct 2013 19:06:31 +0000 (12:06 -0700)
committerCarl Worth <cworth@cworth.org>
Thu, 3 Oct 2013 17:50:55 +0000 (10:50 -0700)
If the user asks for a key with a specific, real, name such a Cb or B,
then the user will get that key.

But if the user asks for a key that is not a real name, (such as B#),
then the user will get a real key that is enharmonic, (such as C in
this case).

pitch.c
pitch.h
scherzo-key.c
scherzo.c

diff --git a/pitch.c b/pitch.c
index 211e68c1aeb1252ff60c62b1d214475ffe5d5ce9..03eb48100e56efd011206928d391b3ffa5eaba65 100644 (file)
--- a/pitch.c
+++ b/pitch.c
@@ -18,6 +18,7 @@
  * along with this program.  If not, see http://www.gnu.org/licenses/ .
  */
 
  * along with this program.  If not, see http://www.gnu.org/licenses/ .
  */
 
+#include <stdio.h>
 #include <stdlib.h>
 
 #include "pitch.h"
 #include <stdlib.h>
 
 #include "pitch.h"
@@ -288,3 +289,9 @@ pitch_from_midi (unsigned char midi_note)
        break;
     }
 }
        break;
     }
 }
+
+int
+pitch_enharmonic_to (pitch_t a, pitch_t b)
+{
+    return pitch_to_midi (a) == pitch_to_midi (b);
+}
diff --git a/pitch.h b/pitch.h
index ffe9782c54b50cac05ba3470477f079afe31ddd6..d376a2217f3bb0cd225fc42ac92ad9a7c7e8870b 100644 (file)
--- a/pitch.h
+++ b/pitch.h
@@ -55,7 +55,7 @@ typedef uint32_t pitch_t;
     PITCH_LITERAL(literal_name, NATURAL, octave)
 
 /* PITCH_CLASS is useful for comparing pitches while ignoring any octave. */
     PITCH_LITERAL(literal_name, NATURAL, octave)
 
 /* PITCH_CLASS is useful for comparing pitches while ignoring any octave. */
-#define PITCH_CLASS(name, accidental) PITCH(name, accidental, 0)
+#define PITCH_CLASS(pitch) PITCH(PITCH_NAME(pitch), PITCH_ACCIDENTAL(pitch), 0)
 
 #define PITCH_CLASS_LITERAL(literal_name, literal_accidental) \
     PITCH_LITERAL(literal_name, literal_accidental, 0)
 
 #define PITCH_CLASS_LITERAL(literal_name, literal_accidental) \
     PITCH_LITERAL(literal_name, literal_accidental, 0)
@@ -132,4 +132,12 @@ pitch_to_midi (pitch_t pitch);
 pitch_t
 pitch_from_midi (unsigned char midi_note);
 
 pitch_t
 pitch_from_midi (unsigned char midi_note);
 
+/* Return true if 'a' and 'b' sound identical, (even if spelled differently)
+ *
+ * This comparison considers octaves as significant. So Bb and A# in
+ * the same octave are considered enharmonic, but Bb and A# in
+ * different octaves are not. */
+int
+pitch_enharmonic_to (pitch_t a, pitch_t b);
+
 #endif /* PITCH_H */
 #endif /* PITCH_H */
index 18cd261f6d5823e6727978b19397a415af23c592..8fea502de8044cc8b6fad289f3838c5b29260b78 100644 (file)
@@ -19,6 +19,8 @@
  */
 
 #include <stdbool.h>
  */
 
 #include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "scherzo-key.h"
 
 
 #include "scherzo-key.h"
 
@@ -29,17 +31,6 @@ scherzo_key_init (scherzo_key_t *key, pitch_t pitch)
 {
     int i;
 
 {
     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_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)
     };
 
        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;
 
     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;
            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;
            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
 }
 
 bool
index dacefa8e8e8e186ec9fa6f20b9f79f05ab34e420..bdd1a0fe5c7dbe86e97cf1c2a219e17815b9873e 100644 (file)
--- a/scherzo.c
+++ b/scherzo.c
@@ -397,17 +397,6 @@ on_key_release_event (unused (GtkWidget *widget),
     return FALSE;
 }
 
     return FALSE;
 }
 
-/* Return true if 'a' and 'b' sound identical, (even if spelled differently)
- *
- * This comparison considers octaves as significant. So Bb and A# in
- * the same octave are considered enharmonic, but Bb and A# in
- * different octaves are not. */
-static int
-_pitches_are_enharmonic (pitch_t a, pitch_t b)
-{
-    return pitch_to_midi (a) == pitch_to_midi (b);
-}
-
 /* Determine a chord name (if any) from the current notes pressed */
 
 typedef struct analyzed_pitch {
 /* Determine a chord name (if any) from the current notes pressed */
 
 typedef struct analyzed_pitch {
@@ -871,7 +860,7 @@ pitch_group_remove_pitch_enharmonic (pitch_group_t *group, pitch_t pitch)
     int i;
 
     for (i = 0; i < group->num_pitches; i++)
     int i;
 
     for (i = 0; i < group->num_pitches; i++)
-       if (_pitches_are_enharmonic (group->pitches[i], pitch))
+       if (pitch_enharmonic_to (group->pitches[i], pitch))
            pitch_group_remove_pitch_at (group, i);
 }
 
            pitch_group_remove_pitch_at (group, i);
 }