_chord_signature_matches (analyzed_note_t *notes,
int num_notes,
modified_degree_t *degrees,
- int num_degrees)
+ int num_degrees,
+ int *inversion_ret)
{
#define MAX_DEGREES 4
int relative_pitches[MAX_DEGREES];
+ int inversion, max_inversions;
int i;
assert (num_degrees <= MAX_DEGREES);
if (num_notes != num_degrees)
return 0;
- for (i = 0; i < num_degrees; i++)
- relative_pitches[i] = _modified_degree_to_half_steps (°rees[i]);
+ max_inversions = num_degrees;
- for (i = 0; i < num_notes; i++)
- if (notes[i].relative_pitch != relative_pitches[i])
- return 0;
+ /* We never spell simple intervals as inversions. */
+ if (num_degrees == 2)
+ max_inversions = 1;
+
+ for (inversion = 0; inversion < max_inversions; inversion++) {
+ for (i = 0; i < num_degrees; i++) {
+ /* The num_degrees is in the addition just to ensure all
+ * inputs to the modulus operator remain positive. */
+ int index = (i + num_degrees - inversion) % num_degrees;
+
+ /* Again, adding a 12 to keep things positive. */
+ relative_pitches[index] =
+ (12 +
+ _modified_degree_to_half_steps (°rees[i]) -
+ _modified_degree_to_half_steps (°rees[inversion])) % 12;
+
+ }
+
+ for (i = 0; i < num_notes; i++)
+ if (notes[i].relative_pitch != relative_pitches[i])
+ goto NEXT_INVERSION;
+
+ *inversion_ret = inversion;
- return 1;
+ return 1;
+
+ NEXT_INVERSION:
+ ;
+ }
+
+ return 0;
}
static void
analyzed_note_t *notes;
note_group_t *note_group;
unsigned i, j, num_notes;
- int bass_pitch;
+ int bass_pitch, inversion;
const char *chord_name = NULL;
if (scherzo->pedal_pressed)
num_notes = note_group->num_notes;
struct { modified_degree_t degrees[1]; const char *name; } octaves[] = {
- { {{0, 0}}, "Octave"}
+ { {{1, 0}}, "Octave"}
};
struct { modified_degree_t degrees[2]; const char *name; } intervals[] = {
case 1:
for (i = 0; i < ARRAY_SIZE (octaves); i++) {
if (_chord_signature_matches (notes, num_notes,
- octaves[i].degrees, 1))
+ octaves[i].degrees, 1, &inversion))
+ {
chord_name = octaves[i].name;
+ break;
+ }
}
break;
case 2:
for (i = 0; i < ARRAY_SIZE (intervals); i++) {
if (_chord_signature_matches (notes, num_notes,
- intervals[i].degrees, 2))
+ intervals[i].degrees, 2, &inversion))
+ {
chord_name = intervals[i].name;
+ break;
+ }
}
break;
case 3:
for (i = 0; i < ARRAY_SIZE (triads); i++) {
if (_chord_signature_matches (notes, num_notes,
- triads[i].degrees, 3))
+ triads[i].degrees, 3, &inversion))
+ {
chord_name = triads[i].name;
+ break;
+ }
}
break;
case 4:
for (i = 0; i < ARRAY_SIZE(sevenths); i++) {
if (_chord_signature_matches (notes, num_notes,
- sevenths[i].degrees, 4))
+ sevenths[i].degrees, 4, &inversion))
+ {
chord_name = sevenths[i].name;
+ break;
+ }
}
break;
}
- if (chord_name)
- scherzo->chord = score_add_chord (scherzo->treble, chord_name);
- else
- scherzo->chord = score_add_chord (scherzo->treble, "Unknown or not a chord");
+ if (chord_name) {
+ if (inversion) {
+ const char *inversion_str;
+ switch (inversion) {
+ case 1:
+ inversion_str = "1st inversion";
+ break;
+ case 2:
+ inversion_str = "2nd inversion";
+ break;
+ case 3:
+ inversion_str = "3rd inversion";
+ break;
+ default:
+ fprintf (stderr, "Internal error: Unexpected inversion: %d\n",
+ inversion);
+ exit(1);
+ }
+ chord_name = talloc_asprintf (local, "%s %s",
+ chord_name, inversion_str);
+ } else {
+ chord_name = talloc_strdup (local, chord_name);
+ }
+ } else {
+ chord_name = talloc_strdup (local, "Unknown chord");
+ }
+
+ scherzo->chord = score_add_chord (scherzo->treble, chord_name);
DONE:
talloc_free (local);