return midi_note;
}
+/* octave can optionally by NULL */
static void
_midi_to_score_pitch_and_octave (unsigned char midi_note,
score_pitch_t *pitch,
int *octave)
{
- *octave = midi_note / 12 - 1;
+ if (octave)
+ *octave = midi_note / 12 - 1;
switch (midi_note % 12)
{
scale_degree = (scale_degree % 8) + 1;
/* Number of half steps from root to specified degree within a
- * diatonic scaled. */
+ * diatonic scale. */
switch (scale_degree) {
case 1:
half_steps = 0;
return half_steps + degree->modification;
}
+/* Number of half steps from 'root' up to 'pitch' (that is, counting
+ * the steps up a chromatic scale). */
+static int
+_pitch_from_root_in_half_steps (score_pitch_t pitch, score_pitch_t root)
+{
+ int root_midi = _score_pitch_and_octave_to_midi (root, 0);
+ int pitch_midi = _score_pitch_and_octave_to_midi (pitch, 0);
+
+ if (pitch_midi < root_midi)
+ pitch_midi += 12;
+
+ if (pitch_midi < root_midi) {
+ fprintf (stderr, "Internal error: midi values differ by more than expected.\n");
+ exit (1);
+ }
+
+ return (pitch_midi - root_midi) % 12;
+}
+
static int
_chord_signature_matches (analyzed_note_t *notes,
int num_notes,
{ 2, {{1, 0}, {7, 0}}, "M7" },
/* Triads */
- { 3, {{1, 0}, {3, +1}, {5, 0}}, "sus" },
+ { 3, {{1, 0}, {4, 0}, {5, 0}}, "sus" },
{ 3, {{1, 0}, {3, 0}, {5, +1}}, SUP "+" PUS },
{ 3, {{1, 0}, {3, 0}, {5, 0}}, "" },
{ 3, {{1, 0}, {3, -1}, {5, 0}}, "m" },
{ 6, {{1, 0}, {9, -1}, {3, -1}, {11, -1}, {5, -1}, {7, -2}}, "°" SUP "11" PUS }
};
+static void
+scherzo_adjust_note_to_match_modified_degree (score_note_t *note,
+ score_pitch_t root,
+ modified_degree_t *degree)
+{
+ score_pitch_name_t name = SCORE_PITCH_NAME (note->pitch);
+ score_pitch_accidental_t accidental = SCORE_PITCH_ACCIDENTAL (note->pitch);
+ int degree_zero_based = (degree->degree - 1) % 7;
+ int degree_delta;
+
+ int note_degree_zero_based = name - SCORE_PITCH_NAME (root);
+ if (note_degree_zero_based < 0)
+ note_degree_zero_based += 7;
+
+ if (note_degree_zero_based == degree_zero_based)
+ return;
+
+ degree_delta = note_degree_zero_based - degree_zero_based;
+ if (degree_delta > 3)
+ degree_delta = - (7 - degree_delta);
+ if (degree_delta < -3)
+ degree_delta = - (-7 - degree_delta);
+
+ if (abs (degree_delta) != 1) {
+ fprintf (stderr, "Internal error: Cannot adjust a note more than one degree (%d vs. %d).\n", note_degree_zero_based + 1, degree->degree);
+ exit (1);
+ }
+
+ if (degree_delta == -1) {
+ if (name == SCORE_PITCH_NAME_B) {
+ name = SCORE_PITCH_NAME_C;
+ note->octave++;
+ } else {
+ name++;
+ }
+ switch (name) {
+ case SCORE_PITCH_NAME_D:
+ case SCORE_PITCH_NAME_E:
+ case SCORE_PITCH_NAME_G:
+ case SCORE_PITCH_NAME_A:
+ case SCORE_PITCH_NAME_B:
+ accidental -= 2;
+ break;
+ case SCORE_PITCH_NAME_C:
+ case SCORE_PITCH_NAME_F:
+ accidental -= 1;
+ break;
+ }
+ }
+
+ if (degree_delta == +1) {
+ if (name == SCORE_PITCH_NAME_C) {
+ name = SCORE_PITCH_NAME_B;
+ note->octave--;
+ } else {
+ name--;
+ }
+ switch (name) {
+ case SCORE_PITCH_NAME_C:
+ case SCORE_PITCH_NAME_D:
+ case SCORE_PITCH_NAME_F:
+ case SCORE_PITCH_NAME_G:
+ case SCORE_PITCH_NAME_A:
+ accidental += 2;
+ break;
+ case SCORE_PITCH_NAME_E:
+ case SCORE_PITCH_NAME_B:
+ accidental += 1;
+ }
+ }
+
+ if (accidental < 0 || accidental > SCORE_PITCH_ACCIDENTAL_DOUBLE_SHARP) {
+ fprintf (stderr, "Internal error: Trying to adjust an accidental out of range (degree_delta == %d (%d - %d), new accidental == %d).\n", degree_delta, note_degree_zero_based, degree_zero_based, accidental);
+ exit (1);
+ }
+
+ note->pitch = SCORE_PITCH (name, accidental);
+}
+
+static void
+_spell_chord_by_signature (note_group_t *chord,
+ int num_notes,
+ chord_signature_t *signature,
+ score_pitch_t root)
+{
+ int i, degree, note_half_steps, degree_half_steps;
+ int root_midi;
+
+ /* Sanitize root to eliminate things like double-flats,
+ * double-sharps, Cb, E#, etc. */
+ root_midi = _score_pitch_and_octave_to_midi (root, 0);
+ _midi_to_score_pitch_and_octave (root_midi, &root, NULL);
+
+ for (i = 0; i < num_notes; i++) {
+ note_half_steps = _pitch_from_root_in_half_steps (chord->notes[i]->pitch,
+ root);
+ for (degree = 0; degree < signature->num_degrees; degree++) {
+ degree_half_steps = _modified_degree_to_half_steps (&signature->degrees[degree]);
+ if (note_half_steps == degree_half_steps) {
+ scherzo_adjust_note_to_match_modified_degree (chord->notes[i],
+ root,
+ &signature->degrees[degree]);
+ break;
+ }
+ }
+ if (note_half_steps != degree_half_steps) {
+ fprintf (stderr, "Internal error: Chord and degree mis-match\n");
+ exit (1);
+ }
+ }
+}
+
static void
scherzo_analyze_chord (scherzo_t *scherzo)
{
unsigned i, j, num_notes;
int bass_pitch, inversion;
score_pitch_t root;
- const char *chord_name = NULL;
+ chord_signature_t *match = NULL;
+ char *chord_name;
if (scherzo->pedal_pressed)
note_group = &scherzo->notes_pedaled;
signatures[i].num_degrees,
inversion, &root))
{
- chord_name = signatures[i].name;
- goto CHORD_NAME_KNOWN;
+ match = &signatures[i];
+ goto HAVE_MATCH;
}
}
}
- CHORD_NAME_KNOWN:
+HAVE_MATCH:
+
+ chord_name = (char *) signatures[i].name;
- if (chord_name) {
+ if (match) {
/* Don't print root pitch for octaves and inversions,
* (since a pitch name alone looks like a major triad) */
if (num_notes < 3) {
_pitch_str (root),
chord_name);
}
+
+ _spell_chord_by_signature (note_group, num_notes,
+ match, root);
} else {
chord_name = talloc_strdup (local, "Unknown chord");
}
score_note_t *note;
int i;
int found = 0;
+ int target_midi = _score_pitch_and_octave_to_midi (pitch, octave);
+ int note_midi;
for (i = scherzo->notes_pressed.num_notes - 1; i >=0; i--) {
note = scherzo->notes_pressed.notes[i];
- if (note->pitch == pitch && note->octave == octave) {
+ note_midi = _score_pitch_and_octave_to_midi (note->pitch, note->octave);
+ if (note_midi == target_midi) {
found = 1;
if (! scherzo->pedal_pressed)
score_remove_note (note);