X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=scherzo.c;h=6a5f2b3176c7f441fdf097714746705a74a91a2c;hb=aae6b7f55870ab7f9cd41f95e22231e66a673aea;hp=b8dd611a0a7e9ae9cff49b08b1a1090e4518acfc;hpb=367e517451123c7c79ead28eca6d2489bfed6467;p=scherzo diff --git a/scherzo.c b/scherzo.c index b8dd611..6a5f2b3 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)) @@ -32,10 +32,11 @@ typedef struct challenge { + int active; bin_t *bin; int item_index; score_staff_t *staff; - score_note_t *note; + pitch_t pitch; int satisfied; int mistaken; @@ -152,8 +153,8 @@ on_key_press_event (GtkWidget *widget, pitch_name_t pitch_name = PITCH_NATURAL (C, 0); pitch_t pitch; - if (scherzo->challenge.note) - octave = PITCH_OCTAVE (scherzo->challenge.note->pitch); + if (scherzo->challenge.active) + octave = PITCH_OCTAVE (scherzo->challenge.pitch); else octave = scherzo->keyboard_octave; @@ -257,8 +258,8 @@ on_key_release_event (unused (GtkWidget *widget), pitch_name_t pitch_name = PITCH_NAME_C; pitch_t pitch; - if (scherzo->challenge.note) - octave = PITCH_OCTAVE (scherzo->challenge.note->pitch); + if (scherzo->challenge.active) + octave = PITCH_OCTAVE (scherzo->challenge.pitch); else octave = scherzo->keyboard_octave; @@ -410,6 +411,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 { @@ -834,7 +846,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) { @@ -846,7 +857,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++) { @@ -866,30 +877,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); @@ -897,7 +902,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. */ @@ -959,27 +964,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); } @@ -1037,6 +1031,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) { @@ -1046,6 +1056,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) @@ -1055,8 +1066,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); } @@ -1065,6 +1075,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. */ @@ -1077,8 +1092,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_str (*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++) { @@ -1092,13 +1137,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); @@ -1125,6 +1170,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 */ @@ -1137,6 +1185,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); @@ -1146,7 +1197,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; @@ -1154,15 +1205,9 @@ _select_challenge (scherzo_t *scherzo) item_t *item; challenge_t *challenge = &scherzo->challenge; pitch_name_t pitch_name; - pitch_t pitch; int octave; char *s; - if (challenge->note) { - score_remove_note (challenge->note); - challenge->note = NULL; - } - mnemon_select_item (&scherzo->mnemon, &challenge->bin, &challenge->item_index, @@ -1220,10 +1265,9 @@ _select_challenge (scherzo_t *scherzo) octave = *s - '0'; - pitch = PITCH (pitch_name, PITCH_ACCIDENTAL_NATURAL, octave); + challenge->pitch = PITCH (pitch_name, PITCH_ACCIDENTAL_NATURAL, octave); - challenge->note = score_staff_add_note (challenge->staff, pitch, - SCORE_DURATION_WHOLE); + challenge->active = 1; challenge->satisfied = 0; challenge->mistaken = 0; } @@ -1234,10 +1278,10 @@ _judge_pitch (scherzo_t *scherzo, pitch_t pitch) { challenge_t *challenge = &scherzo->challenge; - if (! challenge->note) + if (! challenge->active) return; - if (pitch == challenge->note->pitch) + if (pitch == challenge->pitch) challenge->satisfied = 1; else challenge->mistaken = 1; @@ -1250,7 +1294,7 @@ _score_challenge (scherzo_t *scherzo) { challenge_t *challenge = &scherzo->challenge; - if (! challenge->note) + if (! challenge->active) return; if (! challenge->satisfied) @@ -1369,7 +1413,7 @@ main (int argc, char *argv[]) /* XXX: Should create a default file if one cannot be loaded. */ mnemon_load_category (&scherzo.mnemon, "scherzo-notes"); - scherzo.challenge.note = NULL; + scherzo.challenge.active = 0; /* _select_challenge (&scherzo); */