X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=scherzo.c;h=e8d0d274231e42d0adf1da3d8b3d91ad171c5f7b;hb=54d2b1cb13bf52df22c93e58377a00b757644b94;hp=109de6d06b2ccce29e193686f0cd0f9f35059561;hpb=e5ec7a294da3e46c83d858f711405febbad2651b;p=scherzo diff --git a/scherzo.c b/scherzo.c index 109de6d..e8d0d27 100644 --- a/scherzo.c +++ b/scherzo.c @@ -24,7 +24,7 @@ #include "score.h" #include "mnemon.h" -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#define ARRAY_SIZE(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) #define unused(foo) foo __attribute__((unused)) @@ -78,6 +78,8 @@ typedef struct scherzo pitch_group_t notes_pedaled; int pedal_pressed; + + pitch_t key; } scherzo_t; /* Forward declarations. */ @@ -411,6 +413,17 @@ _midi_to_pitch (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. */ +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 { @@ -550,61 +563,6 @@ _chord_signature_matches (analyzed_pitch_t *pitches, return 1; } -static const char * -_pitch_str (pitch_t pitch) -{ - static char double_flat[] = "X𝄫"; - static char flat[] = "X♭"; - static char natural[] = "X"; - static char sharp[] = "X♯"; - static char double_sharp[] = "X𝄪"; - char *ret; - - switch (PITCH_ACCIDENTAL (pitch)) { - case PITCH_ACCIDENTAL_DOUBLE_FLAT: - ret = double_flat; - break; - case PITCH_ACCIDENTAL_FLAT: - ret = flat; - break; - case PITCH_ACCIDENTAL_NATURAL: - ret = natural; - break; - case PITCH_ACCIDENTAL_SHARP: - ret = sharp; - break; - case PITCH_ACCIDENTAL_DOUBLE_SHARP: - ret = double_sharp; - break; - } - - switch (PITCH_NAME(pitch)) { - case PITCH_NAME_C: - ret[0] = 'C'; - break; - case PITCH_NAME_D: - ret[0] = 'D'; - break; - case PITCH_NAME_E: - ret[0] = 'E'; - break; - case PITCH_NAME_F: - ret[0] = 'F'; - break; - case PITCH_NAME_G: - ret[0] = 'G'; - break; - case PITCH_NAME_A: - ret[0] = 'A'; - break; - case PITCH_NAME_B: - ret[0] = 'B'; - break; - } - - return ret; -} - typedef struct chord_signature { int num_degrees; @@ -835,7 +793,6 @@ scherzo_adjust_pitch_to_match_modified_degree (pitch_t *pitch, static void _spell_chord_by_signature (pitch_group_t *chord, - int num_notes, chord_signature_t *signature, pitch_t root) { @@ -847,7 +804,7 @@ _spell_chord_by_signature (pitch_group_t *chord, root_midi = _pitch_to_midi (root); root = _midi_to_pitch (root_midi); - for (i = 0; i < num_notes; i++) { + for (i = 0; i < chord->num_pitches; i++) { note_half_steps = _pitch_from_root_in_half_steps (chord->pitches[i], root); for (degree = 0; degree < signature->num_degrees; degree++) { @@ -867,30 +824,24 @@ _spell_chord_by_signature (pitch_group_t *chord, } static void -scherzo_analyze_chord (scherzo_t *scherzo) +_analyze_chord (pitch_group_t *chord, + chord_signature_t **signature_ret, + pitch_t **root_ret) { void *local = talloc_new (NULL); analyzed_pitch_t *pitches; - pitch_group_t *pitch_group; - unsigned i, j, num_pitches; + int i, j, num_pitches; int bass_pitch, inversion; pitch_t root; chord_signature_t *match = NULL; - char *chord_name; - if (scherzo->pedal_pressed) - pitch_group = &scherzo->notes_pedaled; - else - pitch_group = &scherzo->notes_pressed; + /* Default to no-match for any early return */ + *signature_ret = NULL; + *root_ret = NULL; - num_pitches = pitch_group->num_pitches; + num_pitches = chord->num_pitches; - if (scherzo->chord) { - score_remove_chord (scherzo->chord); - scherzo->chord = NULL; - } - - if (num_pitches <= 1) + if (chord->num_pitches <= 1) goto DONE; pitches = talloc_array (local, analyzed_pitch_t, num_pitches); @@ -898,7 +849,7 @@ scherzo_analyze_chord (scherzo_t *scherzo) goto DONE; for (i = 0; i < num_pitches; i++) { - pitch_t pitch = pitch_group->pitches[i]; + pitch_t pitch = chord->pitches[i]; pitches[i].pitch = pitch; pitches[i].midi_pitch = _pitch_to_midi (pitch); /* Relative pitch will be filled in after sorting. */ @@ -960,27 +911,16 @@ scherzo_analyze_chord (scherzo_t *scherzo) } HAVE_MATCH: - chord_name = (char *) signatures[i].name; - if (match) { - /* Don't print root pitch for octaves and inversions, - * (since a pitch name alone looks like a major triad) */ - if (num_pitches < 3) { - chord_name = talloc_strdup (local, chord_name); - } else { - chord_name = talloc_asprintf (local, "%s%s", - _pitch_str (root), - chord_name); + *signature_ret = match; + for (i = 0; i < chord->num_pitches; i++) { + if (chord->pitches[i] == root) { + *root_ret = &chord->pitches[i]; + break; + } } - - _spell_chord_by_signature (pitch_group, num_pitches, - match, root); - } else { - chord_name = talloc_strdup (local, "?"); } - scherzo->chord = score_add_chord (scherzo->treble, chord_name); - DONE: talloc_free (local); } @@ -1038,6 +978,22 @@ pitch_group_remove_pitch_at (pitch_group_t *group, int i) group->num_pitches--; } +/* Remove a 'pitch' from 'group', (including any enharmonic pitch) + * See also: pitch_group_remove_pitch + */ +static void +pitch_group_remove_pitch_enharmonic (pitch_group_t *group, pitch_t pitch) +{ + int i; + + for (i = 0; i < group->num_pitches; i++) + if (_pitches_are_enharmonic (group->pitches[i], pitch)) + pitch_group_remove_pitch_at (group, i); +} + +/* Remove an exactly-matching pitch from 'group' + * See also: pitch_group_remove_pitch_enharmonic + * static void pitch_group_remove_pitch (pitch_group_t *group, pitch_t pitch) { @@ -1047,6 +1003,7 @@ pitch_group_remove_pitch (pitch_group_t *group, pitch_t pitch) if (group->pitches[i] == pitch) pitch_group_remove_pitch_at (group, i); } +*/ static void scherzo_update_notes_and_chord (scherzo_t *scherzo) @@ -1056,8 +1013,7 @@ scherzo_update_notes_and_chord (scherzo_t *scherzo) { score_remove_notes (scherzo->score); - if (scherzo->chord) - score_remove_chord (scherzo->chord); + score_remove_chords (scherzo->score); gtk_widget_queue_draw (scherzo->window); } @@ -1066,6 +1022,11 @@ scherzo_update_notes_and_chord (scherzo_t *scherzo) static void scherzo_press_note (scherzo_t *scherzo, pitch_t pitch) { + void *local = talloc_new (NULL); + pitch_group_t *chord; + chord_signature_t *signature; + char *chord_name = NULL; + pitch_t *root; int i; /* Do nothing if this note is already pressed. */ @@ -1078,8 +1039,38 @@ scherzo_press_note (scherzo_t *scherzo, pitch_t pitch) if (scherzo->pedal_pressed) pitch_group_add_pitch (&scherzo->notes_pedaled, pitch); - /* Remove all notes from score, then add current notes. */ + /* Remove all notes/chords from score, then add current notes. */ score_remove_notes (scherzo->score); + score_remove_chords (scherzo->score); + + if (scherzo->pedal_pressed) + chord = &scherzo->notes_pedaled; + else + chord = &scherzo->notes_pressed; + + _analyze_chord (chord, &signature, &root); + + if (signature) { + /* Don't print root pitch for octaves and inversions, + * (since a pitch name alone looks like a major triad) */ + if (signature->num_degrees < 3) { + chord_name = talloc_strdup (local, signature->name); + } else { + _spell_chord_by_signature (&scherzo->notes_pressed, + signature, *root); + _spell_chord_by_signature (&scherzo->notes_pedaled, + signature, *root); + + chord_name = talloc_asprintf (local, "%s%s", + pitch_string (*root), + signature->name); + } + } else if (chord->num_pitches > 2) { + chord_name = talloc_strdup (local, "?"); + } + + if (chord_name) + scherzo->chord = score_add_chord (scherzo->treble, chord_name); for (i = 0; i < scherzo->notes_pressed.num_pitches; i++) { @@ -1093,13 +1084,13 @@ scherzo_press_note (scherzo_t *scherzo, pitch_t pitch) SCORE_DURATION_WHOLE); } - scherzo_analyze_chord (scherzo); + talloc_free (local); } static void scherzo_release_note (scherzo_t *scherzo, pitch_t pitch) { - pitch_group_remove_pitch (&scherzo->notes_pressed, pitch); + pitch_group_remove_pitch_enharmonic (&scherzo->notes_pressed, pitch); if (scherzo->notes_pressed.num_pitches == 0) scherzo_update_notes_and_chord (scherzo); @@ -1126,6 +1117,9 @@ scherzo_press_pedal (scherzo_t *scherzo) { int i; + if (scherzo->pedal_pressed) + return; + scherzo->pedal_pressed = 1; /* Copy all pressed notes to pedaled notes */ @@ -1138,6 +1132,9 @@ scherzo_release_pedal (scherzo_t *scherzo) { int i; + if (! scherzo->pedal_pressed) + return; + /* Remove all previously pedaled notes. */ for (i = scherzo->notes_pedaled.num_pitches - 1; i >=0; i--) pitch_group_remove_pitch_at (&scherzo->notes_pedaled, i); @@ -1147,7 +1144,7 @@ scherzo_release_pedal (scherzo_t *scherzo) scherzo_update_notes_and_chord (scherzo); } -void +static void _select_challenge (scherzo_t *scherzo) { category_t *category_unused; @@ -1359,6 +1356,9 @@ main (int argc, char *argv[]) scherzo.pedal_pressed = 0; + scherzo.key = PITCH_CLASS_LITERAL (C, NATURAL); + score_set_key (scherzo.score, scherzo.key); + mnemon_init (&scherzo.mnemon); /* XXX: Should create a default file if one cannot be loaded. */ mnemon_load_category (&scherzo.mnemon, "scherzo-notes");