]> git.cworth.org Git - scherzo/commitdiff
Fix scherzo to use pitch_t rather than score_note_t for computation
authorCarl Worth <cworth@cworth.org>
Sun, 29 Sep 2013 21:56:47 +0000 (14:56 -0700)
committerCarl Worth <cworth@cworth.org>
Sun, 29 Sep 2013 21:56:47 +0000 (14:56 -0700)
The score_note_t type is constructed as a side effect of performing
drawing. This is a poor fit for scherzo's computation and reasoning
since it often wants to perform analysis on notes that it has never
drawn.

Meanwhile, the new pitch_t is a simple integer, making it very easy
for scherzo to use pitch_t in all of its calculations.

The goal is for no functional changes with this commit, but we know
that some bugs have likely been changed or moved around.

scherzo.c
score.c
score.h

index 0192c0c1a4dee0ca60fdc68d2ead86336aeaad24..b8dd611a0a7e9ae9cff49b08b1a1090e4518acfc 100644 (file)
--- a/scherzo.c
+++ b/scherzo.c
@@ -41,13 +41,13 @@ typedef struct challenge
     int mistaken;
 } challenge_t;
 
     int mistaken;
 } challenge_t;
 
-typedef struct note_group
+typedef struct pitch_group
 {
     void *ctx;
 {
     void *ctx;
-    score_note_t **notes;
+    pitch_t *pitches;
     int size;
     int size;
-    int num_notes;
-} note_group_t;
+    int num_pitches;
+} pitch_group_t;
 
 typedef struct scherzo
 {
 
 typedef struct scherzo
 {
@@ -56,6 +56,7 @@ typedef struct scherzo
     GtkWidget *window;
     score_t *score;
     int staff_height;
     GtkWidget *window;
     score_t *score;
     int staff_height;
+
     score_staff_t *treble;
     score_staff_t *bass;
     score_chord_t *chord;
     score_staff_t *treble;
     score_staff_t *bass;
     score_chord_t *chord;
@@ -72,14 +73,14 @@ typedef struct scherzo
     mnemon_t mnemon;
     challenge_t challenge;
 
     mnemon_t mnemon;
     challenge_t challenge;
 
-    note_group_t notes_pressed;
-    note_group_t notes_pedaled;
+    pitch_group_t notes_pressed;
+    pitch_group_t notes_pedaled;
 
     int pedal_pressed;
 } scherzo_t;
 
 /* Forward declarations. */
 
     int pedal_pressed;
 } scherzo_t;
 
 /* Forward declarations. */
-static score_note_t *
+static void
 scherzo_press_note (scherzo_t *scherzo, pitch_t pitch);
 
 static void
 scherzo_press_note (scherzo_t *scherzo, pitch_t pitch);
 
 static void
@@ -92,7 +93,7 @@ static void
 scherzo_release_pedal (scherzo_t *scherzo);
 
 static void
 scherzo_release_pedal (scherzo_t *scherzo);
 
 static void
-_judge_note (scherzo_t *scherzo, score_note_t *note);
+_judge_pitch (scherzo_t *scherzo, pitch_t pitch);
 
 static void
 _score_challenge (scherzo_t *scherzo);
 
 static void
 _score_challenge (scherzo_t *scherzo);
@@ -233,10 +234,8 @@ on_key_press_event (GtkWidget *widget,
     if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) ||
        (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g))
     {
     if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) ||
        (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g))
     {
-       score_note_t *note;
-
-       note = scherzo_press_note (scherzo, pitch);
-       _judge_note (scherzo, note);
+       scherzo_press_note (scherzo, pitch);
+       _judge_pitch (scherzo, pitch);
        gtk_widget_queue_draw (scherzo->window);
 
        return TRUE;
        gtk_widget_queue_draw (scherzo->window);
 
        return TRUE;
@@ -413,29 +412,29 @@ _midi_to_pitch (unsigned char midi_note)
 
 /* Determine a chord name (if any) from the current notes pressed */
 
 
 /* Determine a chord name (if any) from the current notes pressed */
 
-typedef struct analyzed_note {
+typedef struct analyzed_pitch {
     /* Original note being analzyed. */
     /* Original note being analzyed. */
-    score_note_t *note;
+    pitch_t pitch;
 
     /* Absolute pitch (expressed as midi number). */
     int midi_pitch;
 
     /* Pitch relative to bass note. */
     int relative_pitch;
 
     /* Absolute pitch (expressed as midi number). */
     int midi_pitch;
 
     /* Pitch relative to bass note. */
     int relative_pitch;
-} analyzed_note_t;
+} analyzed_pitch_t;
 
 static int
 
 static int
-_compare_analyzed_note_by_midi_pitch (const void *va, const void *vb)
+_compare_analyzed_pitch_by_midi_pitch (const void *va, const void *vb)
 {
 {
-    const analyzed_note_t *a = va, *b = vb;
+    const analyzed_pitch_t *a = va, *b = vb;
 
     return a->midi_pitch - b->midi_pitch;
 }
 
 static int
 
     return a->midi_pitch - b->midi_pitch;
 }
 
 static int
-_compare_analyzed_note_by_relative_pitch (const void *va, const void *vb)
+_compare_analyzed_pitch_by_relative_pitch (const void *va, const void *vb)
 {
 {
-    const analyzed_note_t *a = va, *b = vb;
+    const analyzed_pitch_t *a = va, *b = vb;
 
     return a->relative_pitch - b->relative_pitch;
 }
 
     return a->relative_pitch - b->relative_pitch;
 }
@@ -504,8 +503,8 @@ _pitch_from_root_in_half_steps (pitch_t pitch, pitch_t root)
 }
 
 static int
 }
 
 static int
-_chord_signature_matches (analyzed_note_t *notes,
-                         int num_notes,
+_chord_signature_matches (analyzed_pitch_t *pitches,
+                         int num_pitches,
                          modified_degree_t *degrees,
                          int num_degrees,
                          int inversion,
                          modified_degree_t *degrees,
                          int num_degrees,
                          int inversion,
@@ -517,7 +516,7 @@ _chord_signature_matches (analyzed_note_t *notes,
 
     assert (num_degrees <= MAX_DEGREES);
 
 
     assert (num_degrees <= MAX_DEGREES);
 
-    if (num_notes != num_degrees)
+    if (num_pitches != num_degrees)
        return 0;
 
     if (inversion >= num_degrees)
        return 0;
 
     if (inversion >= num_degrees)
@@ -540,12 +539,12 @@ _chord_signature_matches (analyzed_note_t *notes,
                
     }
 
                
     }
 
-    for (i = 0; i < num_notes; i++)
-       if (notes[i].relative_pitch != relative_pitches[i])
+    for (i = 0; i < num_pitches; i++)
+       if (pitches[i].relative_pitch != relative_pitches[i])
            return 0;
 
            return 0;
 
-    root_index = (num_notes - inversion) % num_notes;
-    *root = notes[root_index].note->pitch;
+    root_index = (num_pitches - inversion) % num_pitches;
+    *root = pitches[root_index].pitch;
 
     return 1;
 }
 
     return 1;
 }
@@ -754,13 +753,13 @@ chord_signature_t signatures[] = {
 };
 
 static void
 };
 
 static void
-scherzo_adjust_note_to_match_modified_degree (score_note_t *note,
-                                             pitch_t root,
-                                             modified_degree_t *degree)
+scherzo_adjust_pitch_to_match_modified_degree (pitch_t *pitch,
+                                              pitch_t root,
+                                              modified_degree_t *degree)
 {
 {
-    pitch_name_t name = PITCH_NAME (note->pitch);
-    pitch_accidental_t accidental = PITCH_ACCIDENTAL (note->pitch);
-    int octave = PITCH_OCTAVE (note->pitch);
+    pitch_name_t name = PITCH_NAME (*pitch);
+    pitch_accidental_t accidental = PITCH_ACCIDENTAL (*pitch);
+    int octave = PITCH_OCTAVE (*pitch);
     int degree_zero_based = (degree->degree - 1) % 7;
     int degree_delta;
 
     int degree_zero_based = (degree->degree - 1) % 7;
     int degree_delta;
 
@@ -830,11 +829,11 @@ scherzo_adjust_note_to_match_modified_degree (score_note_t *note,
        exit (1);
     }
 
        exit (1);
     }
 
-    note->pitch = PITCH (name, accidental, octave);
+    *pitch = PITCH (name, accidental, octave);
 }
 
 static void
 }
 
 static void
-_spell_chord_by_signature (note_group_t *chord,
+_spell_chord_by_signature (pitch_group_t *chord,
                           int num_notes,
                           chord_signature_t *signature,
                           pitch_t root)
                           int num_notes,
                           chord_signature_t *signature,
                           pitch_t root)
@@ -848,14 +847,14 @@ _spell_chord_by_signature (note_group_t *chord,
     root = _midi_to_pitch (root_midi);
     
     for (i = 0; i < num_notes; i++) {
     root = _midi_to_pitch (root_midi);
     
     for (i = 0; i < num_notes; i++) {
-       note_half_steps = _pitch_from_root_in_half_steps (chord->notes[i]->pitch,
+       note_half_steps = _pitch_from_root_in_half_steps (chord->pitches[i],
                                                          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) {
                                                          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]);
+               scherzo_adjust_pitch_to_match_modified_degree (&chord->pitches[i],
+                                                              root,
+                                                              &signature->degrees[degree]);
                break;
            }
        }
                break;
            }
        }
@@ -870,64 +869,64 @@ static void
 scherzo_analyze_chord (scherzo_t *scherzo)
 {
     void *local = talloc_new (NULL);
 scherzo_analyze_chord (scherzo_t *scherzo)
 {
     void *local = talloc_new (NULL);
-    analyzed_note_t *notes;
-    note_group_t *note_group;
-    unsigned i, j, num_notes;
+    analyzed_pitch_t *pitches;
+    pitch_group_t *pitch_group;
+    unsigned i, j, num_pitches;
     int bass_pitch, inversion;
     pitch_t root;
     chord_signature_t *match = NULL;
     char *chord_name;
 
     if (scherzo->pedal_pressed)
     int bass_pitch, inversion;
     pitch_t root;
     chord_signature_t *match = NULL;
     char *chord_name;
 
     if (scherzo->pedal_pressed)
-       note_group = &scherzo->notes_pedaled;
+       pitch_group = &scherzo->notes_pedaled;
     else
     else
-       note_group = &scherzo->notes_pressed;
+       pitch_group = &scherzo->notes_pressed;
 
 
-    num_notes = note_group->num_notes;
+    num_pitches = pitch_group->num_pitches;
 
     if (scherzo->chord) {
        score_remove_chord (scherzo->chord);
        scherzo->chord = NULL;
     }
 
 
     if (scherzo->chord) {
        score_remove_chord (scherzo->chord);
        scherzo->chord = NULL;
     }
 
-    if (num_notes <= 1)
+    if (num_pitches <= 1)
        goto DONE;
 
        goto DONE;
 
-    notes = talloc_array (local, analyzed_note_t, num_notes);
-    if (notes == NULL)
+    pitches = talloc_array (local, analyzed_pitch_t, num_pitches);
+    if (pitches == NULL)
        goto DONE;
 
        goto DONE;
 
-    for (i = 0; i < num_notes; i++) {
-       score_note_t *note = note_group->notes[i];
-       notes[i].note = note;
-       notes[i].midi_pitch = _pitch_to_midi (note->pitch);
+    for (i = 0; i < num_pitches; i++) {
+       pitch_t pitch = pitch_group->pitches[i];
+       pitches[i].pitch = pitch;
+       pitches[i].midi_pitch = _pitch_to_midi (pitch);
        /* Relative pitch will be filled in after sorting. */
        /* Relative pitch will be filled in after sorting. */
-       notes[i].relative_pitch = 0;
+       pitches[i].relative_pitch = 0;
     }
 
     /* First, sort by midi pitch to find the bass note. */
     }
 
     /* First, sort by midi pitch to find the bass note. */
-    qsort (notes, num_notes, sizeof (analyzed_note_t),
-          _compare_analyzed_note_by_midi_pitch);
+    qsort (pitches, num_pitches, sizeof (analyzed_pitch_t),
+          _compare_analyzed_pitch_by_midi_pitch);
     
     
-    bass_pitch = notes[0].midi_pitch;
+    bass_pitch = pitches[0].midi_pitch;
 
     /* With the bass note identified, we can find all relative pitches. */
 
     /* With the bass note identified, we can find all relative pitches. */
-    for (i = 0; i < num_notes; i++) {
-       notes[i].relative_pitch = notes[i].midi_pitch - bass_pitch;
-       while (notes[i].relative_pitch >= 12)
-           notes[i].relative_pitch -= 12;
+    for (i = 0; i < num_pitches; i++) {
+       pitches[i].relative_pitch = pitches[i].midi_pitch - bass_pitch;
+       while (pitches[i].relative_pitch >= 12)
+           pitches[i].relative_pitch -= 12;
     }
 
     /* Now, sort again by relative pitch. */
     }
 
     /* Now, sort again by relative pitch. */
-    qsort (notes, num_notes, sizeof (analyzed_note_t),
-          _compare_analyzed_note_by_relative_pitch);
+    qsort (pitches, num_pitches, sizeof (analyzed_pitch_t),
+          _compare_analyzed_pitch_by_relative_pitch);
 
     /* Finally, eliminate all duplicate notes. */
 
     /* Finally, eliminate all duplicate notes. */
-    for (i = 0; i < num_notes - 1; i++) {
-           if (notes[i+1].relative_pitch == notes[i].relative_pitch) {
+    for (i = 0; i < num_pitches - 1; i++) {
+           if (pitches[i+1].relative_pitch == pitches[i].relative_pitch) {
                    j = i+1;
                    j = i+1;
-                   while (j < num_notes &&
-                          notes[j].relative_pitch == notes[i].relative_pitch)
+                   while (j < num_pitches &&
+                          pitches[j].relative_pitch == pitches[i].relative_pitch)
                    {
                            j++;
                    }
                    {
                            j++;
                    }
@@ -937,18 +936,18 @@ scherzo_analyze_chord (scherzo_t *scherzo)
                     * the array bounds).*/
                    j--;
 
                     * the array bounds).*/
                    j--;
 
-                   if (j < num_notes - 1) {
-                           memmove (&notes[i+1], &notes[j+1],
-                                    (num_notes - j) * sizeof (analyzed_note_t));
+                   if (j < num_pitches - 1) {
+                           memmove (&pitches[i+1], &pitches[j+1],
+                                    (num_pitches - j) * sizeof (analyzed_pitch_t));
                    }
 
                    }
 
-                   num_notes -= (j - i);
+                   num_pitches -= (j - i);
            }
     }
 
     for (inversion = 0; inversion < 4; inversion++) {
        for (i = 0; i < ARRAY_SIZE (signatures); i++) {
            }
     }
 
     for (inversion = 0; inversion < 4; inversion++) {
        for (i = 0; i < ARRAY_SIZE (signatures); i++) {
-           if (_chord_signature_matches (notes, num_notes,
+           if (_chord_signature_matches (pitches, num_pitches,
                                          signatures[i].degrees,
                                          signatures[i].num_degrees,
                                          inversion, &root))
                                          signatures[i].degrees,
                                          signatures[i].num_degrees,
                                          inversion, &root))
@@ -965,7 +964,7 @@ HAVE_MATCH:
     if (match) {
        /* Don't print root pitch for octaves and inversions,
         * (since a pitch name alone looks like a major triad) */
     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) {
+       if (num_pitches < 3) {
            chord_name = talloc_strdup (local, chord_name);
        } else {
            chord_name = talloc_asprintf (local, "%s%s",
            chord_name = talloc_strdup (local, chord_name);
        } else {
            chord_name = talloc_asprintf (local, "%s%s",
@@ -973,7 +972,7 @@ HAVE_MATCH:
                                          chord_name);
        }
 
                                          chord_name);
        }
 
-       _spell_chord_by_signature (note_group, num_notes,
+       _spell_chord_by_signature (pitch_group, num_pitches,
                                   match, root);
     } else {
        chord_name = talloc_strdup (local, "?");
                                   match, root);
     } else {
        chord_name = talloc_strdup (local, "?");
@@ -986,118 +985,133 @@ DONE:
 }
 
 static void
 }
 
 static void
-note_group_init (void *ctx, note_group_t *group)
+pitch_group_init (void *ctx, pitch_group_t *group)
 {
     group->ctx = ctx;
 {
     group->ctx = ctx;
-    group->notes = NULL;
+    group->pitches = NULL;
     group->size = 0;
     group->size = 0;
-    group->num_notes = 0;
+    group->num_pitches = 0;
 }
 
 static void
 }
 
 static void
-note_group_add_note (note_group_t *group, score_note_t *note)
+pitch_group_add_pitch (pitch_group_t *group, pitch_t pitch)
 {
     int i;
 
 {
     int i;
 
-    /* Do nothing if note is already in group. */
-    for (i = 0; i < group->num_notes; i++)
-       if (group->notes[i]->pitch == note->pitch)
+    /* Do nothing if pitch is already in group. */
+    for (i = 0; i < group->num_pitches; i++)
+       if (group->pitches[i] == pitch)
            return;
 
            return;
 
-    group->num_notes++;
+    group->num_pitches++;
 
 
-    if (group->num_notes > group->size) {
+    if (group->num_pitches > group->size) {
        group->size++;
        group->size++;
-       group->notes = talloc_realloc (group->ctx, group->notes,
-                                      score_note_t*, group->size);
+       group->pitches = talloc_realloc (group->ctx, group->pitches,
+                                        pitch_t, group->size);
 
 
-       if (group->notes == NULL) {
+       if (group->pitches == NULL) {
            fprintf (stderr, "Out of memory.\n");
            exit (1);
        }
     }
 
            fprintf (stderr, "Out of memory.\n");
            exit (1);
        }
     }
 
-    group->notes[group->num_notes - 1] = note;
+    group->pitches[group->num_pitches - 1] = pitch;
 }
 
 static void
 }
 
 static void
-note_group_remove_note_at (note_group_t *group, int i)
+pitch_group_remove_pitch_at (pitch_group_t *group, int i)
 {
 {
-    if (i >= group->num_notes) {
-       fprintf (stderr, "Internal error: No note to remove at index %d\n", i);
+    if (i > group->num_pitches) {
+       fprintf (stderr, "Internal error: Cannot remove pitch %d from group with only %d %s\n",
+                i, group->num_pitches,
+                group->num_pitches == 1 ? "pitch" : "pitches");
        exit (1);
     }
 
        exit (1);
     }
 
-    if (i < group->num_notes - 1) {
-       memmove (group->notes + i, group->notes + i + 1,
-                (group->num_notes - 1 - i) * sizeof (score_note_t*));
+    if (i < group->num_pitches - 1) {
+       memmove (group->pitches + i, group->pitches + i + 1,
+                (group->num_pitches - 1 - i) * sizeof (pitch_t));
     }
     }
-    group->num_notes--;
+
+    group->num_pitches--;
 }
 
 }
 
-static score_note_t *
-scherzo_press_note (scherzo_t *scherzo, pitch_t pitch)
+static void
+pitch_group_remove_pitch (pitch_group_t *group, pitch_t pitch)
 {
 {
-    score_staff_t *staff;
-    score_note_t *note;
     int i;
 
     int i;
 
-    if (scherzo->challenge.note) {
-       staff = scherzo->challenge.staff;
-    } else if (PITCH_OCTAVE (pitch) >= 4) {
-       staff = scherzo->treble;
-    } else {
-       staff = scherzo->bass;
+    for (i = 0; i < group->num_pitches; i++)
+       if (group->pitches[i] == pitch)
+           pitch_group_remove_pitch_at (group, i);
+}
+
+static void
+scherzo_update_notes_and_chord (scherzo_t *scherzo)
+{
+    if (scherzo->notes_pressed.num_pitches == 0 &&
+       scherzo->notes_pedaled.num_pitches == 0)
+    {
+       score_remove_notes (scherzo->score);
+
+       if (scherzo->chord)
+           score_remove_chord (scherzo->chord);
+
+       gtk_widget_queue_draw (scherzo->window);
     }
     }
+}
 
 
-    /* Do nothing if this note is already pressed. */
-    for (i = 0; i < scherzo->notes_pressed.num_notes; i++)
-       if (scherzo->notes_pressed.notes[i]->pitch == pitch)
-           return scherzo->notes_pressed.notes[i];
+static void
+scherzo_press_note (scherzo_t *scherzo, pitch_t pitch)
+{
+    int i;
 
 
-    note = score_add_note (staff, pitch, SCORE_DURATION_WHOLE);
+    /* Do nothing if this note is already pressed. */
+    for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
+       if (scherzo->notes_pressed.pitches[i] == pitch)
+           return;
 
 
-    note_group_add_note (&scherzo->notes_pressed, note);
+    pitch_group_add_pitch (&scherzo->notes_pressed, pitch);
 
     if (scherzo->pedal_pressed)
 
     if (scherzo->pedal_pressed)
-       note_group_add_note (&scherzo->notes_pedaled, note);
+       pitch_group_add_pitch (&scherzo->notes_pedaled, pitch);
 
 
-    scherzo_analyze_chord (scherzo);
+    /* Remove all notes from score, then add current notes. */
+    score_remove_notes (scherzo->score);
 
 
-    return note;
+    for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
+    {
+       score_add_note (scherzo->score, scherzo->notes_pressed.pitches[i],
+                       SCORE_DURATION_WHOLE);
+    }
+
+    for (i = 0; i < scherzo->notes_pedaled.num_pitches; i++)
+    {
+       score_add_note (scherzo->score, scherzo->notes_pedaled.pitches[i],
+                       SCORE_DURATION_WHOLE);
+    }
+
+    scherzo_analyze_chord (scherzo);
 }
 
 static void
 scherzo_release_note (scherzo_t *scherzo, pitch_t pitch)
 {
 }
 
 static void
 scherzo_release_note (scherzo_t *scherzo, pitch_t pitch)
 {
-    score_note_t *note;
-    int i;
-    int found = 0;
-    int target_midi = _pitch_to_midi (pitch);
-    int note_midi;
-
-    for (i = scherzo->notes_pressed.num_notes - 1; i >=0; i--) {
-       note = scherzo->notes_pressed.notes[i];
-       note_midi = _pitch_to_midi (note->pitch);
-       if (note_midi == target_midi) {
-           found = 1;
-           if (! scherzo->pedal_pressed)
-               score_remove_note (note);
-           note_group_remove_note_at (&scherzo->notes_pressed, i);
-       }
-    }
+    pitch_group_remove_pitch (&scherzo->notes_pressed, pitch);
 
 
-    if (found == 0) {
-       fprintf (stderr, "Internal error: Failed to find note to release.\n");
-    }
-
-    scherzo_analyze_chord (scherzo);
+    if (scherzo->notes_pressed.num_pitches == 0)
+       scherzo_update_notes_and_chord (scherzo);
 }
 
 }
 
-static score_note_t *
+static pitch_t
 scherzo_press_note_midi (scherzo_t *scherzo, unsigned char midi_note)
 {
 scherzo_press_note_midi (scherzo_t *scherzo, unsigned char midi_note)
 {
-    return scherzo_press_note (scherzo, _midi_to_pitch (midi_note));
+    pitch_t pitch = _midi_to_pitch (midi_note);
+
+    scherzo_press_note (scherzo, pitch);
+
+    return pitch;
 }
 
 static void
 }
 
 static void
@@ -1114,35 +1128,22 @@ scherzo_press_pedal (scherzo_t *scherzo)
     scherzo->pedal_pressed = 1;
 
     /* Copy all pressed notes to pedaled notes */
     scherzo->pedal_pressed = 1;
 
     /* Copy all pressed notes to pedaled notes */
-    for (i = 0; i < scherzo->notes_pressed.num_notes; i++)
-       note_group_add_note (&scherzo->notes_pedaled, scherzo->notes_pressed.notes[i]);
+    for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
+       pitch_group_add_pitch (&scherzo->notes_pedaled, scherzo->notes_pressed.pitches[i]);
 }
 
 static void
 scherzo_release_pedal (scherzo_t *scherzo)
 {
 }
 
 static void
 scherzo_release_pedal (scherzo_t *scherzo)
 {
-    score_note_t *note, *new_note;
     int i;
 
     int i;
 
-    /* Make new notes in score for all pressed notes. */
-    for (i = 0; i < scherzo->notes_pressed.num_notes; i++) {
-       note = scherzo->notes_pressed.notes[i];
-       new_note = score_add_note (note->staff, note->pitch, note->duration);
-       scherzo->notes_pressed.notes[i] = new_note;
-    }
-
-    /* Then remove all previously pedaled notes from the score. */
-    for (i = scherzo->notes_pedaled.num_notes - 1; i >=0; i--) {
-       note = scherzo->notes_pedaled.notes[i];
-       score_remove_note (note);
-       note_group_remove_note_at (&scherzo->notes_pedaled, i);
-    }
+    /* 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);
 
     scherzo->pedal_pressed = 0;
 
 
     scherzo->pedal_pressed = 0;
 
-    scherzo_analyze_chord (scherzo);
-
-    gtk_widget_queue_draw (scherzo->window);
+    scherzo_update_notes_and_chord (scherzo);
 }
 
 void
 }
 
 void
@@ -1221,33 +1222,25 @@ _select_challenge (scherzo_t *scherzo)
 
     pitch = PITCH (pitch_name, PITCH_ACCIDENTAL_NATURAL, octave);
 
 
     pitch = PITCH (pitch_name, PITCH_ACCIDENTAL_NATURAL, octave);
 
-    challenge->note = score_add_note (challenge->staff, pitch,
-                                     SCORE_DURATION_WHOLE);
+    challenge->note = score_staff_add_note (challenge->staff, pitch,
+                                           SCORE_DURATION_WHOLE);
     challenge->satisfied = 0;
     challenge->mistaken = 0;
 }
 
 /* Determine whether the user hit the correct note. */
 static void
     challenge->satisfied = 0;
     challenge->mistaken = 0;
 }
 
 /* Determine whether the user hit the correct note. */
 static void
-_judge_note (scherzo_t *scherzo, score_note_t *note)
+_judge_pitch (scherzo_t *scherzo, pitch_t pitch)
 {
     challenge_t *challenge = &scherzo->challenge;
 
 {
     challenge_t *challenge = &scherzo->challenge;
 
-    if (! scherzo->challenge.note) {
-       score_set_note_color_rgb (note, 0.0, 0.0, 0.0); /* black */
+    if (! challenge->note)
        return;
        return;
-    }
 
 
-    if (note->pitch == challenge->note->pitch)
-    {
+    if (pitch == challenge->note->pitch)
        challenge->satisfied = 1;
        challenge->satisfied = 1;
-       score_set_note_color_rgb (note, 18/256., 130/256., 28/256.); /* green */
-    }
     else
     else
-    {
        challenge->mistaken = 1;
        challenge->mistaken = 1;
-       score_set_note_color_rgb (note, 184/256., 4/256., 22/256.); /* red */
-    }
 }
 
 /* If the user got the right note (eventually), then score it in
 }
 
 /* If the user got the right note (eventually), then score it in
@@ -1278,7 +1271,7 @@ on_midi_input (unused (GIOChannel *channel),
     scherzo_t *scherzo = user_data;
     ssize_t remaining;
     snd_seq_event_t event;
     scherzo_t *scherzo = user_data;
     ssize_t remaining;
     snd_seq_event_t event;
-    score_note_t *note;
+    pitch_t pitch;
     int need_redraw = FALSE;
 
     remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
     int need_redraw = FALSE;
 
     remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
@@ -1298,8 +1291,8 @@ on_midi_input (unused (GIOChannel *channel),
            /* Incomplete event. Nothing to do. */
            break;
        case SND_SEQ_EVENT_NOTEON:
            /* Incomplete event. Nothing to do. */
            break;
        case SND_SEQ_EVENT_NOTEON:
-           note = scherzo_press_note_midi (scherzo, event.data.note.note);
-           _judge_note (scherzo, note);
+           pitch = scherzo_press_note_midi (scherzo, event.data.note.note);
+           _judge_pitch (scherzo, pitch);
            need_redraw = TRUE;
            break;
        case SND_SEQ_EVENT_NOTEOFF:
            need_redraw = TRUE;
            break;
        case SND_SEQ_EVENT_NOTEOFF:
@@ -1367,8 +1360,8 @@ main (int argc, char *argv[])
     scherzo.keyboard_octave = 4;
     scherzo.keyboard_accidental = PITCH_ACCIDENTAL_NATURAL;
 
     scherzo.keyboard_octave = 4;
     scherzo.keyboard_accidental = PITCH_ACCIDENTAL_NATURAL;
 
-    note_group_init (scherzo.ctx, &scherzo.notes_pressed);
-    note_group_init (scherzo.ctx, &scherzo.notes_pedaled);
+    pitch_group_init (scherzo.ctx, &scherzo.notes_pressed);
+    pitch_group_init (scherzo.ctx, &scherzo.notes_pedaled);
 
     scherzo.pedal_pressed = 0;
 
 
     scherzo.pedal_pressed = 0;
 
diff --git a/score.c b/score.c
index 0c868c6f4a255b93787533db9cb6a80a6ff85919..ba27844fb02e9fc6835188f1409cd36e0442b5d2 100644 (file)
--- a/score.c
+++ b/score.c
@@ -21,6 +21,7 @@
 #include <pango/pangocairo.h>
 
 #include <string.h>
 #include <pango/pangocairo.h>
 
 #include <string.h>
+#include <math.h>
 
 #include "score.h"
 
 
 #include "score.h"
 
@@ -174,11 +175,22 @@ _score_clef_c_line (score_clef_t clef)
     }
 }
 
     }
 }
 
+/* On which line would 'pitch' appear on 'staff'.
+ *
+ * Lines are numbered with line 0 as the top full line of the staff
+ * and increasing downward. So line values less than 0 will appear as
+ * ledger lines above the staff while line values greater than 4 will
+ * appear on ledger lines below the staff.
+ *
+ * A line value of 2 will be centered verticall on the staff.
+ *
+ * For notes appearing on a space, the line value will be half-way
+ * between two integers. */
 static double
 static double
-_score_note_to_line (score_staff_t *staff, score_note_t *note)
+_score_staff_pitch_to_line (score_staff_t *staff, pitch_t pitch)
 {
 {
-    pitch_name_t name = PITCH_NAME (note->pitch);
-    int octave = PITCH_OCTAVE (note->pitch);
+    pitch_name_t name = PITCH_NAME (pitch);
+    int octave = PITCH_OCTAVE (pitch);
     int c_line = _score_clef_c_line (staff->clef);
 
     return c_line - (name - PITCH_NAME_C) / 2.0 - 3.5 * (octave - 4);
     int c_line = _score_clef_c_line (staff->clef);
 
     return c_line - (name - PITCH_NAME_C) / 2.0 - 3.5 * (octave - 4);
@@ -259,7 +271,7 @@ _draw_note (score_t *score, cairo_t *cr,
      * note on a ledger line above the staff). Values half way between
      * integers indicate notes appearing on a space between two staff
      * lines (or ledger lines). */
      * note on a ledger line above the staff). Values half way between
      * integers indicate notes appearing on a space between two staff
      * lines (or ledger lines). */
-    line = _score_note_to_line (staff, note);
+    line = _score_staff_pitch_to_line (staff, note->pitch);
 
     cairo_select_font_face (cr, "Gonville-26", 0, 0);
     cairo_set_font_size (cr, score->staff_height);
 
     cairo_select_font_face (cr, "Gonville-26", 0, 0);
     cairo_set_font_size (cr, score->staff_height);
@@ -594,9 +606,9 @@ score_remove_chord (score_chord_t *chord)
 }
 
 score_note_t *
 }
 
 score_note_t *
-score_add_note (score_staff_t *staff,
-               pitch_t pitch,
-               score_duration_t duration)
+score_staff_add_note (score_staff_t *staff,
+                     pitch_t pitch,
+                     score_duration_t duration)
 {
     score_note_t *note;
     double line;
 {
     score_note_t *note;
     double line;
@@ -624,7 +636,7 @@ score_add_note (score_staff_t *staff,
     note->color.g = 0.0;
     note->color.b = 0.0;
 
     note->color.g = 0.0;
     note->color.b = 0.0;
 
-    line = _score_note_to_line (staff, note);
+    line = _score_staff_pitch_to_line (staff, note->pitch);
     if (line < 0) {
        int lines = (int) (- line);
        if (lines > staff->upper_ledger_lines)
     if (line < 0) {
        int lines = (int) (- line);
        if (lines > staff->upper_ledger_lines)
@@ -650,6 +662,31 @@ score_add_note (score_staff_t *staff,
     return note;
 }
 
     return note;
 }
 
+score_note_t *
+score_add_note (score_t *score, pitch_t pitch, score_duration_t duration)
+{
+    score_staff_t *staff, *nearest_staff = NULL;
+    double distance, nearest_distance = 0.0;
+    int i;
+
+    /* Nothing to do if we have no staff, (there's no place to add a note) . */
+    if (score->num_staves == 0)
+       return NULL;
+
+    /* Find the staff where the note will be closest to the center of
+     * the staff. */
+    for (i = 0; i < score->num_staves; i++) {
+       staff = score->staves[i];
+       distance = fabs (_score_staff_pitch_to_line (staff, pitch) - 2.0);
+       if (nearest_staff == NULL || distance < nearest_distance) {
+           nearest_staff = staff;
+           nearest_distance = distance;
+       }
+    }
+
+    return score_staff_add_note (nearest_staff, pitch, duration);
+}
+
 void
 score_remove_note (score_note_t *note)
 {
 void
 score_remove_note (score_note_t *note)
 {
@@ -678,6 +715,23 @@ score_remove_note (score_note_t *note)
     }
 }
 
     }
 }
 
+void
+score_staff_remove_notes (score_staff_t *staff)
+{
+    talloc_free (staff->notes);
+    staff->notes = NULL;
+    staff->num_notes = 0;
+}
+
+void
+score_remove_notes (score_t *score)
+{
+    int i;
+
+    for (i = 0; i < score->num_staves; i++)
+       score_staff_remove_notes (score->staves[i]);
+}
+
 void
 score_set_note_color_rgb (score_note_t *note,
                          double r,
 void
 score_set_note_color_rgb (score_note_t *note,
                          double r,
diff --git a/score.h b/score.h
index d5391012bb428e26f901a8432535ce797f3c8700..b8791f67f1caa5f8dd0ab9257efa9997d312fb46 100644 (file)
--- a/score.h
+++ b/score.h
@@ -115,9 +115,14 @@ score_add_staff (score_t *score, score_clef_t clef);
  * QUARTER=4, EIGHTH=8, etc.)
  */
 score_note_t *
  * QUARTER=4, EIGHTH=8, etc.)
  */
 score_note_t *
-score_add_note (score_staff_t *staff,
-               pitch_t pitch,
-               score_duration_t);
+score_staff_add_note (score_staff_t *staff,
+                     pitch_t pitch,
+                     score_duration_t duration);
+
+/* Add a note to the score, (automatically selecting the nearest
+ * staff) */
+score_note_t *
+score_add_note (score_t *score, pitch_t pitch, score_duration_t duration);
 
 /* Add a chord symbol of 'name' to a staff.
  *
 
 /* Add a chord symbol of 'name' to a staff.
  *
@@ -138,6 +143,14 @@ score_remove_chord (score_chord_t *chord);
 void
 score_remove_note (score_note_t *note);
 
 void
 score_remove_note (score_note_t *note);
 
+/* Remove all notes from the given staff. */
+void
+score_staff_remove_notes (score_staff_t *staff);
+
+/* Remove all notes from the score. */
+void
+score_remove_notes (score_t *score);
+
 void
 score_set_note_color_rgb (score_note_t *note,
                          double r,
 void
 score_set_note_color_rgb (score_note_t *note,
                          double r,