]> git.cworth.org Git - scherzo/blob - scherzo.c
Rework computer keyboard input to be mapped piano keyboard
[scherzo] / scherzo.c
1 /* scherzo - Music notation training
2  *
3  * Copyright © 2010 Carl Worth
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see http://www.gnu.org/licenses/ .
17  */
18
19 #include <gtk/gtk.h>
20 #include <gdk/gdkkeysyms.h>
21
22 #include <asoundlib.h>
23
24 #include "score.h"
25 #include "mnemon.h"
26
27 #define ARRAY_SIZE(arr) ((int) (sizeof(arr) / sizeof(arr[0])))
28
29 #define unused(foo) foo __attribute__((unused))
30
31 #define MIDI_BUF_SIZE 4096
32
33 typedef struct challenge
34 {
35     int active;
36     bin_t *bin;
37     int item_index;
38     score_staff_t *staff;
39     pitch_t pitch;
40
41     int satisfied;
42     int mistaken;
43 } challenge_t;
44
45 typedef struct pitch_group
46 {
47     void *ctx;
48     pitch_t *pitches;
49     int size;
50     int num_pitches;
51 } pitch_group_t;
52
53 typedef struct scherzo
54 {
55     void *ctx;
56
57     GtkWidget *window;
58     score_t *score;
59     int staff_height;
60
61     score_staff_t *treble;
62     score_staff_t *bass;
63     score_chord_t *chord;
64
65     /* The word "keyboard" here is referring to a "computer
66      * keyboard". Any "piano keyboard" key knows its own octave and
67      * accidental already. */
68     int keyboard_octave;
69
70     int midi_fd;
71     snd_midi_event_t *snd_midi_event;
72
73     mnemon_t mnemon;
74     challenge_t challenge;
75
76     pitch_group_t notes_pressed;
77     pitch_group_t notes_pedaled;
78
79     int pedal_pressed;
80
81     pitch_t key;
82 } scherzo_t;
83
84 /* Forward declarations. */
85 static void
86 scherzo_press_note (scherzo_t *scherzo, pitch_t pitch);
87
88 static void
89 scherzo_release_note (scherzo_t *scherzo, pitch_t pitch);
90
91 static void
92 scherzo_press_pedal (scherzo_t *scherzo);
93
94 static void
95 scherzo_release_pedal (scherzo_t *scherzo);
96
97 static void
98 _judge_pitch (scherzo_t *scherzo, pitch_t pitch);
99
100 static void
101 _score_challenge (scherzo_t *scherzo);
102
103 static int
104 on_delete_event_quit (unused (GtkWidget *widget),
105                       unused (GdkEvent *event),
106                       unused (gpointer user_data))
107 {
108     gtk_main_quit ();
109
110     /* Returning FALSE allows the default handler for delete-event
111      * to proceed to cleanup the widget. */
112     return FALSE;
113 }
114
115 static int
116 on_expose_event_draw (GtkWidget *widget,
117                       unused (GdkEventExpose *expose),
118                       void * user_data)
119 {
120     scherzo_t *scherzo = user_data;
121     score_t *score = scherzo->score;
122     cairo_t *cr;
123     GtkAllocation allocation;
124     static const int pad = 10;
125     int widget_width;
126
127     gtk_widget_get_allocation (widget, &allocation);
128     widget_width = allocation.width;
129
130     cr = gdk_cairo_create (widget->window);
131
132     /* White background */
133     cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
134     cairo_paint (cr);
135
136     /* Add some padding on the sides and top */
137     cairo_translate (cr, pad, scherzo->staff_height);
138     score_set_staff_height (score, scherzo->staff_height);
139     score_set_width (score, widget_width - 2 * pad);
140
141     score_draw (score, cr);
142  
143     return TRUE;
144 }
145
146 static int
147 on_key_press_event (GtkWidget *widget,
148                     GdkEventKey *key,
149                     void *user_data)
150 {
151     scherzo_t *scherzo = user_data;
152     int octave;
153     pitch_t pitch = PITCH_NOT_A_PITCH;
154
155     if (scherzo->challenge.active)
156         octave = PITCH_OCTAVE (scherzo->challenge.pitch);
157     else
158         octave = scherzo->keyboard_octave;
159
160     switch (key->keyval) {
161     case GDK_KEY_plus:
162     case GDK_KEY_KP_Add:
163     case GDK_KEY_equal:
164     case GDK_KEY_KP_Equal:
165         scherzo->staff_height += 4;
166         gtk_widget_queue_draw (widget);
167         return TRUE;
168         break;
169     case GDK_KEY_minus:
170     case GDK_KEY_KP_Subtract:
171         scherzo->staff_height -= 4;
172         gtk_widget_queue_draw (widget);
173         return TRUE;
174         break;
175     case GDK_KEY_Escape:
176         gtk_main_quit ();
177         return FALSE;
178     /* Map a piano keyboard onto the computer keyboard with white keys
179      * along the home row, (piano C on computer A, up to next octave
180      * higher C on computer K). Black keys are in the expected
181      * positions, (C# is W, D# is E, etc.).
182      */
183     case GDK_KEY_a:
184     case GDK_KEY_A:
185         pitch = PITCH_LITERAL (C, NATURAL, octave);
186         break;
187     case GDK_KEY_s:
188     case GDK_KEY_S:
189         pitch = PITCH_LITERAL (D, NATURAL, octave);
190         break;
191     case GDK_KEY_d:
192     case GDK_KEY_D:
193         pitch = PITCH_LITERAL (E, NATURAL, octave);
194         break;
195     case GDK_KEY_f:
196     case GDK_KEY_F:
197         pitch = PITCH_LITERAL (F, NATURAL, octave);
198         break;
199     case GDK_KEY_g:
200     case GDK_KEY_G:
201         pitch = PITCH_LITERAL (G, NATURAL, octave);
202         break;
203     case GDK_KEY_h:
204     case GDK_KEY_H:
205         pitch = PITCH_LITERAL (A, NATURAL, octave);
206         break;
207     case GDK_KEY_j:
208     case GDK_KEY_J:
209         pitch = PITCH_LITERAL (B, NATURAL, octave);
210         break;
211     case GDK_KEY_k:
212     case GDK_KEY_K:
213         pitch = PITCH_LITERAL (C, NATURAL, octave + 1);
214         break;
215     case GDK_KEY_l:
216     case GDK_KEY_L:
217         pitch = PITCH_LITERAL (D, NATURAL, octave + 1);
218         break;
219     case GDK_KEY_semicolon:
220     case GDK_KEY_colon:
221         pitch = PITCH_LITERAL (E, NATURAL, octave + 1);
222         break;
223     case GDK_KEY_apostrophe:
224     case GDK_KEY_quotedbl:
225         pitch = PITCH_LITERAL (F, NATURAL, octave + 1);
226         break;
227     case GDK_KEY_w:
228     case GDK_KEY_W:
229         pitch = PITCH_LITERAL (C, SHARP, octave);
230         break;
231     case GDK_KEY_e:
232     case GDK_KEY_E:
233         pitch = PITCH_LITERAL (D, SHARP, octave);
234         break;
235     case GDK_KEY_t:
236     case GDK_KEY_T:
237         pitch = PITCH_LITERAL (F, SHARP, octave);
238         break;
239     case GDK_KEY_y:
240     case GDK_KEY_Y:
241         pitch = PITCH_LITERAL (G, SHARP, octave);
242         break;
243     case GDK_KEY_u:
244     case GDK_KEY_U:
245         pitch = PITCH_LITERAL (A, SHARP, octave);
246         break;
247     case GDK_KEY_o:
248     case GDK_KEY_O:
249         pitch = PITCH_LITERAL (C, SHARP, octave + 1);
250         break;
251     case GDK_KEY_p:
252     case GDK_KEY_P:
253         pitch = PITCH_LITERAL (D, SHARP, octave + 1);
254         break;
255     case GDK_KEY_bracketright:
256     case GDK_KEY_braceright:
257         pitch = PITCH_LITERAL (F, SHARP, octave + 1);
258         break;
259     case GDK_KEY_0:
260     case GDK_KEY_1:
261     case GDK_KEY_2:
262     case GDK_KEY_3:
263     case GDK_KEY_4:
264     case GDK_KEY_5:
265     case GDK_KEY_6:
266     case GDK_KEY_7:
267     case GDK_KEY_8:
268         scherzo->keyboard_octave = key->keyval - GDK_KEY_0;
269         break;
270     case GDK_KEY_space:
271         scherzo_press_pedal (scherzo);
272         break;
273     }
274
275     if (pitch != PITCH_NOT_A_PITCH) 
276     {
277         scherzo_press_note (scherzo, pitch);
278         _judge_pitch (scherzo, pitch);
279         gtk_widget_queue_draw (scherzo->window);
280
281         return TRUE;
282     }
283
284
285     /* Allow an unhandled event to propagate to other handlers. */
286     return FALSE;
287 }
288
289 static int
290 on_key_release_event (unused (GtkWidget *widget),
291                       GdkEventKey *key,
292                       void *user_data)
293 {
294     scherzo_t *scherzo = user_data;
295     int octave;
296     pitch_t pitch = PITCH_NOT_A_PITCH;
297
298     if (scherzo->challenge.active)
299         octave = PITCH_OCTAVE (scherzo->challenge.pitch);
300     else
301         octave = scherzo->keyboard_octave;
302
303     switch (key->keyval) {
304     case GDK_KEY_a:
305     case GDK_KEY_A:
306         pitch = PITCH_LITERAL (C, NATURAL, octave);
307         break;
308     case GDK_KEY_s:
309     case GDK_KEY_S:
310         pitch = PITCH_LITERAL (D, NATURAL, octave);
311         break;
312     case GDK_KEY_d:
313     case GDK_KEY_D:
314         pitch = PITCH_LITERAL (E, NATURAL, octave);
315         break;
316     case GDK_KEY_f:
317     case GDK_KEY_F:
318         pitch = PITCH_LITERAL (F, NATURAL, octave);
319         break;
320     case GDK_KEY_g:
321     case GDK_KEY_G:
322         pitch = PITCH_LITERAL (G, NATURAL, octave);
323         break;
324     case GDK_KEY_h:
325     case GDK_KEY_H:
326         pitch = PITCH_LITERAL (A, NATURAL, octave);
327         break;
328     case GDK_KEY_j:
329     case GDK_KEY_J:
330         pitch = PITCH_LITERAL (B, NATURAL, octave);
331         break;
332     case GDK_KEY_k:
333     case GDK_KEY_K:
334         pitch = PITCH_LITERAL (C, NATURAL, octave + 1);
335         break;
336     case GDK_KEY_l:
337     case GDK_KEY_L:
338         pitch = PITCH_LITERAL (D, NATURAL, octave + 1);
339         break;
340     case GDK_KEY_semicolon:
341     case GDK_KEY_colon:
342         pitch = PITCH_LITERAL (E, NATURAL, octave + 1);
343         break;
344     case GDK_KEY_apostrophe:
345     case GDK_KEY_quotedbl:
346         pitch = PITCH_LITERAL (F, NATURAL, octave + 1);
347         break;
348     case GDK_KEY_w:
349     case GDK_KEY_W:
350         pitch = PITCH_LITERAL (C, SHARP, octave);
351         break;
352     case GDK_KEY_e:
353     case GDK_KEY_E:
354         pitch = PITCH_LITERAL (D, SHARP, octave);
355         break;
356     case GDK_KEY_t:
357     case GDK_KEY_T:
358         pitch = PITCH_LITERAL (F, SHARP, octave);
359         break;
360     case GDK_KEY_y:
361     case GDK_KEY_Y:
362         pitch = PITCH_LITERAL (G, SHARP, octave);
363         break;
364     case GDK_KEY_u:
365     case GDK_KEY_U:
366         pitch = PITCH_LITERAL (A, SHARP, octave);
367         break;
368     case GDK_KEY_o:
369     case GDK_KEY_O:
370         pitch = PITCH_LITERAL (C, SHARP, octave + 1);
371         break;
372     case GDK_KEY_p:
373     case GDK_KEY_P:
374         pitch = PITCH_LITERAL (D, SHARP, octave + 1);
375         break;
376     case GDK_KEY_bracketright:
377     case GDK_KEY_braceright:
378         pitch = PITCH_LITERAL (F, SHARP, octave + 1);
379         break;
380     case GDK_KEY_space:
381         scherzo_release_pedal (scherzo);
382         break;
383     }
384
385     if (pitch != PITCH_NOT_A_PITCH)
386     {
387         scherzo_release_note (scherzo, pitch);
388         _score_challenge (scherzo);
389         gtk_widget_queue_draw (scherzo->window);
390
391         return TRUE;
392     }
393
394
395     /* Allow an unhandled event to propagate to other handlers. */
396     return FALSE;
397 }
398
399 static unsigned char
400 _pitch_to_midi (pitch_t pitch)
401 {
402     int octave = PITCH_OCTAVE (pitch);
403     unsigned char midi_note = 12 * (octave + 1);
404
405     switch (PITCH_NAME (pitch)) {
406     case PITCH_NAME_C:
407         break;
408     case PITCH_NAME_D:
409         midi_note += 2;
410         break;
411     case PITCH_NAME_E:
412         midi_note += 4;
413         break;
414     case PITCH_NAME_F:
415         midi_note += 5;
416         break;
417     case PITCH_NAME_G:
418         midi_note += 7;
419         break;
420     case PITCH_NAME_A:
421         midi_note += 9;
422         break;
423     case PITCH_NAME_B:
424         midi_note += 11;
425         break;
426     }
427
428     switch (PITCH_ACCIDENTAL (pitch)) {
429     case PITCH_ACCIDENTAL_DOUBLE_FLAT:
430         midi_note -= 2;
431         break;
432     case PITCH_ACCIDENTAL_FLAT:
433         midi_note -= 1;
434         break;
435     case PITCH_ACCIDENTAL_NATURAL:
436         break;
437     case PITCH_ACCIDENTAL_SHARP:
438         midi_note += 1;
439         break;
440     case PITCH_ACCIDENTAL_DOUBLE_SHARP:
441         midi_note += 2;
442         break;
443     }
444
445     return midi_note;
446 }
447
448 /* octave can optionally by NULL */
449 static pitch_t
450 _midi_to_pitch (unsigned char midi_note)
451 {
452     int octave = octave = midi_note / 12 - 1;
453
454     switch (midi_note % 12)
455     {
456     default:
457     case 0:
458         return PITCH_LITERAL (C, NATURAL, octave);
459         break;
460     case 1:
461         return PITCH_LITERAL (C, SHARP, octave);
462         break;
463     case 2:
464         return PITCH_LITERAL (D, NATURAL, octave);
465         break;
466     case 3:
467         return PITCH_LITERAL (D, SHARP, octave);
468         break;
469     case 4:
470         return PITCH_LITERAL (E, NATURAL, octave);
471         break;
472     case 5:
473         return PITCH_LITERAL (F, NATURAL, octave);
474         break;
475     case 6:
476         return PITCH_LITERAL (F, SHARP, octave);
477         break;
478     case 7:
479         return PITCH_LITERAL (G, NATURAL, octave);
480         break;
481     case 8:
482         return PITCH_LITERAL (G, SHARP, octave);
483         break;
484     case 9:
485         return PITCH_LITERAL (A, NATURAL, octave);
486         break;
487     case 10:
488         return PITCH_LITERAL (A, SHARP, octave);
489         break;
490     case 11:
491         return PITCH_LITERAL (B, NATURAL, octave);
492         break;
493     }
494 }
495
496 /* Return true if 'a' and 'b' sound identical, (even if spelled differently)
497  *
498  * This comparison considers octaves as significant. So Bb and A# in
499  * the same octave are considered enharmonic, but Bb and A# in
500  * different octaves are not. */
501 static int
502 _pitches_are_enharmonic (pitch_t a, pitch_t b)
503 {
504     return _pitch_to_midi (a) == _pitch_to_midi (b);
505 }
506
507 /* Determine a chord name (if any) from the current notes pressed */
508
509 typedef struct analyzed_pitch {
510     /* Original note being analzyed. */
511     pitch_t pitch;
512
513     /* Absolute pitch (expressed as midi number). */
514     int midi_pitch;
515
516     /* Pitch relative to bass note. */
517     int relative_pitch;
518 } analyzed_pitch_t;
519
520 static int
521 _compare_analyzed_pitch_by_midi_pitch (const void *va, const void *vb)
522 {
523     const analyzed_pitch_t *a = va, *b = vb;
524
525     return a->midi_pitch - b->midi_pitch;
526 }
527
528 static int
529 _compare_analyzed_pitch_by_relative_pitch (const void *va, const void *vb)
530 {
531     const analyzed_pitch_t *a = va, *b = vb;
532
533     return a->relative_pitch - b->relative_pitch;
534 }
535
536 typedef struct modified_degree
537 {
538     int degree;
539     int modification;
540 } modified_degree_t;
541
542 static int
543 _modified_degree_to_half_steps (const modified_degree_t *degree)
544 {
545     int half_steps;
546     int scale_degree = degree->degree;
547
548     /* Restrict to actual degrees within a scale. */
549     if (scale_degree > 7)
550         scale_degree = (scale_degree % 8) + 1;
551
552     /* Number of half steps from root to specified degree within a
553      * diatonic scale. */
554     switch (scale_degree) {
555     case 1:
556         half_steps = 0;
557         break;
558     case 2:
559         half_steps = 2;
560         break;
561     case 3:
562         half_steps = 4;
563         break;
564     case 4:
565         half_steps = 5;
566         break;
567     case 5:
568         half_steps = 7;
569         break;
570     case 6:
571         half_steps = 9;
572         break;
573     case 7:
574         half_steps = 11;
575         break;
576     default:
577         fprintf (stderr, "Internal: Invalid degree %d\n", degree->degree);
578         exit (1);
579         break;
580     }
581
582     return half_steps + degree->modification;
583 }
584
585 /* Number of half steps from 'root' up to 'pitch' (that is, counting
586  * the steps up a chromatic scale), within the same octave. */
587 static int
588 _pitch_from_root_in_half_steps (pitch_t pitch, pitch_t root)
589 {
590     int root_midi = _pitch_to_midi (root);
591     int pitch_midi = _pitch_to_midi (pitch);
592
593     while (pitch_midi < root_midi)
594         pitch_midi += 12;
595
596     return (pitch_midi - root_midi) % 12;
597 }
598
599 static int
600 _chord_signature_matches (analyzed_pitch_t *pitches,
601                           int num_pitches,
602                           modified_degree_t *degrees,
603                           int num_degrees,
604                           int inversion,
605                           pitch_t *root)
606 {
607 #define MAX_DEGREES 6
608     int relative_pitches[MAX_DEGREES];
609     int i, root_index;
610
611     assert (num_degrees <= MAX_DEGREES);
612
613     if (num_pitches != num_degrees)
614         return 0;
615
616     if (inversion >= num_degrees)
617         return 0;
618
619     /* We never spell simple intervals as inversions. */
620     if (num_degrees == 2 && inversion > 0)
621         return 0;
622
623     for (i = 0; i < num_degrees; i++) {
624         /* The num_degrees is in the addition just to ensure all
625          * inputs to the modulus operator remain positive. */
626         int index = (i + num_degrees - inversion) % num_degrees;
627
628         /* Again, adding a 12 to keep things positive. */
629         relative_pitches[index] =
630             (12 +
631              _modified_degree_to_half_steps (&degrees[i]) -
632              _modified_degree_to_half_steps (&degrees[inversion])) % 12;
633                 
634     }
635
636     for (i = 0; i < num_pitches; i++)
637         if (pitches[i].relative_pitch != relative_pitches[i])
638             return 0;
639
640     root_index = (num_pitches - inversion) % num_pitches;
641     *root = pitches[root_index].pitch;
642
643     return 1;
644 }
645
646 typedef struct chord_signature
647 {
648     int num_degrees;
649     modified_degree_t degrees[MAX_DEGREES];
650     const char *name;
651 } chord_signature_t;
652
653 /* XXX: The superscript rise value should be relative to the current
654  * font size. Best would be for pango to support this. See:
655  *
656  * https://bugzilla.gnome.org/show_bug.cgi?id=708780
657  *
658  * For now, these are emipirically-derived values that look reasonable
659  * at the default size that score.c is using to draw the staff. If the
660  * user scales the staff up or down then these will look wrong.
661  */
662
663 #define SUP "<span font='33' rise='30000'>"
664 #define PUS "</span>"
665
666 chord_signature_t signatures[] = {
667     /* Octave */
668     { 1, {{1, 0}}, "P8" },
669
670     /* Intervals */
671     { 2, {{1, 0}, {2, -1}}, "m2" },
672     { 2, {{1, 0}, {2,  0}}, "M2" },
673     { 2, {{1, 0}, {3, -1}}, "m3" },
674     { 2, {{1, 0}, {3,  0}}, "M3" },
675     { 2, {{1, 0}, {4,  0}}, "P4" },
676     { 2, {{1, 0}, {5, -1}}, "Tri-tone" },
677     { 2, {{1, 0}, {5,  0}}, "P5" },
678     { 2, {{1, 0}, {6, -1}}, "m6" },
679     { 2, {{1, 0}, {6,  0}}, "M6" },
680     { 2, {{1, 0}, {7, -1}}, "m7" },
681     { 2, {{1, 0}, {7,  0}}, "M7" },
682
683     /* Triads */
684     { 3, {{1, 0}, {4,  0}, {5,  0}}, "sus" },
685     { 3, {{1, 0}, {3,  0}, {5, +1}}, SUP "+" PUS },
686     { 3, {{1, 0}, {3,  0}, {5,  0}}, "" },
687     { 3, {{1, 0}, {3, -1}, {5,  0}}, "m" },
688     { 3, {{1, 0}, {3, -1}, {5, -1}}, "°" },
689     { 3, {{1, 0}, {2,  0}, {5,  0}}, "msus2" },
690
691     /* Seventh chords with no 3rd */
692     { 3, {{1, 0}, {5, +1}, {7,  0}}, SUP "+M7" PUS },
693     { 3, {{1, 0}, {5, +1}, {7, -1}}, SUP "+7" PUS },
694     { 3, {{1, 0}, {5,  0}, {7,  0}}, "M7" },
695     { 3, {{1, 0}, {5,  0}, {7, -1}}, "7" },
696     { 3, {{1, 0}, {5, -1}, {7, -1}}, "7♭5" },
697
698     /* Seventh chords with no 5th */
699     { 3, {{1, 0}, {4,  0}, {7,  0}}, "M7sus" },
700     { 3, {{1, 0}, {4,  0}, {7, -1}}, "7sus" },
701     { 3, {{1, 0}, {3,  0}, {7,  0}}, "M7" },
702     { 3, {{1, 0}, {3,  0}, {7, -1}}, "7" },
703     { 3, {{1, 0}, {3, -1}, {7,  0}}, "m" SUP "M7" PUS },
704     { 3, {{1, 0}, {3, -1}, {7, -1}}, "m7" },
705     { 3, {{1, 0}, {2,  0}, {7,  0}}, "m" SUP "M7" PUS "sus2" },
706     { 3, {{1, 0}, {2,  0}, {7, -1}}, "m7sus2" },
707
708     /* Sixth chords */
709     { 4, {{1, 0}, {4,  0}, {5,  0}, {6,  0}}, "6sus" },
710     { 4, {{1, 0}, {3,  0}, {5,  0}, {6,  0}}, "6" }, /* Ambiguous with m7 */
711     { 4, {{1, 0}, {3, -1}, {5,  0}, {6,  0}}, "m6" },
712     { 4, {{1, 0}, {2,  0}, {5,  0}, {6,  0}}, "m6sus2" },
713
714     /* Seventh chords */
715     { 4, {{1, 0}, {4,  0}, {5, +1}, {7,  0}}, SUP "+M7" PUS "sus" },
716     { 4, {{1, 0}, {4,  0}, {5, +1}, {7, -1}}, SUP "+7" PUS "sus" },
717     { 4, {{1, 0}, {4,  0}, {5,  0}, {7,  0}}, "M7sus" },
718     { 4, {{1, 0}, {4,  0}, {5,  0}, {7, -1}}, "7sus" },
719     { 4, {{1, 0}, {4,  0}, {5, -1}, {7, -1}}, "7♭5sus" },
720     { 4, {{1, 0}, {3,  0}, {5, +1}, {7,  0}}, SUP "+M7" PUS },
721     { 4, {{1, 0}, {3,  0}, {5, +1}, {7, -1}}, SUP "+7" PUS },
722     { 4, {{1, 0}, {3,  0}, {5,  0}, {7,  0}}, "M7" },
723     { 4, {{1, 0}, {3,  0}, {5,  0}, {7, -1}}, "7" },
724     { 4, {{1, 0}, {3,  0}, {5, -1}, {7, -1}}, "7♭5" },
725     { 4, {{1, 0}, {3, -1}, {5,  0}, {7,  0}}, "m" SUP "M7" PUS },
726     { 4, {{1, 0}, {3, -1}, {5,  0}, {7, -1}}, "m7" },
727     { 4, {{1, 0}, {3, -1}, {5, -1}, {7,  0}}, "°" SUP "M7" PUS },
728     { 4, {{1, 0}, {3, -1}, {5, -1}, {7, -1}}, "𝆩" SUP "7" PUS },
729     { 4, {{1, 0}, {3, -1}, {5, -1}, {7, -2}}, "°" SUP "7" PUS },
730     { 4, {{1, 0}, {2,  0}, {5,  0}, {7,  0}}, "m" SUP "M7" PUS "sus2" },
731     { 4, {{1, 0}, {2,  0}, {5,  0}, {7, -1}}, "m7sus2" },
732     { 4, {{1, 0}, {2,  0}, {5, -1}, {7,  0}}, "°" SUP "M7" PUS "sus2" },
733     { 4, {{1, 0}, {2,  0}, {5, -1}, {7, -1}}, "𝆩" SUP "7" PUS "sus2" },
734     { 4, {{1, 0}, {2,  0}, {5, -1}, {7, -2}}, "°" SUP "7" PUS "sus2" }, /* Ambiguous with 7 */
735
736     /* The sorting for chords with degree higher than 9 is funny
737      * to keep the array in degree order after reducing each
738      * degree to an actual scale degree, (9 -> 2, 11 -> 4, 13 ->
739      * 6) */
740
741     /* Ninth chords voiced with no 5th */
742     { 4, {{1, 0}, {9,  0}, {4,  0}, {7,  0}}, "M9sus" },
743     { 4, {{1, 0}, {9,  0}, {4,  0}, {7, -1}}, "9sus" },
744     { 4, {{1, 0}, {9,  0}, {3,  0}, {7,  0}}, "M9" },
745     { 4, {{1, 0}, {9,  0}, {3,  0}, {7, -1}}, "9" },
746     { 4, {{1, 0}, {9,  0}, {3, -1}, {7,  0}}, "m" SUP "M9" PUS },
747     { 4, {{1, 0}, {9,  0}, {3, -1}, {7, -1}}, "m9" },
748     { 4, {{1, 0}, {9, -1}, {3, -1}, {7, -1}}, "m♭9" },
749     { 4, {{1, 0}, {9,  0}, {3, -1}, {6,  0}}, "m6/9" },
750     { 4, {{1, 0}, {9, -1}, {3, -1}, {6,  0}}, "m6/♭9" },
751
752     /* Sixth plus 9 */
753     { 5, {{1, 0}, {9,  0}, {3,  0}, {5,  0}, {6,  0}}, "6/9" },
754     { 5, {{1, 0}, {9,  0}, {3, -1}, {5,  0}, {6,  0}}, "m6/9" },
755     { 5, {{1, 0}, {9, -1}, {3, -1}, {5,  0}, {6,  0}}, "m6/♭9" },
756
757     /* Seventh plus altered 9 */
758     { 5, {{1, 0}, {9, +1}, {3,  0}, {5,  0}, {7, -1}}, "7♯9" },
759     { 5, {{1, 0}, {9, -1}, {3,  0}, {5,  0}, {7, -1}}, "7♭9" },
760     { 5, {{1, 0}, {9, +1}, {3,  0}, {5, -1}, {7, -1}}, "7♭5♯9" },
761     { 5, {{1, 0}, {9, -1}, {3,  0}, {5, -1}, {7, -1}}, "7♭5♭9" },
762
763     /* Ninth chords */
764     { 5, {{1, 0}, {9,  0}, {4,  0}, {5, +1}, {7,  0}}, SUP "+M9" PUS "sus" },
765     { 5, {{1, 0}, {9,  0}, {4,  0}, {5, +1}, {7, -1}}, SUP "+9" PUS "sus" },
766     { 5, {{1, 0}, {9,  0}, {4,  0}, {5,  0}, {7,  0}}, "M9sus" },
767     { 5, {{1, 0}, {9,  0}, {4,  0}, {5,  0}, {7, -1}}, "9sus" },
768     { 5, {{1, 0}, {9,  0}, {3,  0}, {5, +1}, {7,  0}}, SUP "+M9" PUS },
769     { 5, {{1, 0}, {9,  0}, {3,  0}, {5, +1}, {7, -1}}, SUP "+9" PUS },
770     { 5, {{1, 0}, {9,  0}, {3,  0}, {5,  0}, {7,  0}}, "M9" },
771     { 5, {{1, 0}, {9,  0}, {3,  0}, {5,  0}, {7, -1}}, "9" },
772     { 5, {{1, 0}, {9,  0}, {3, -1}, {5,  0}, {7,  0}}, "m" SUP "M9" PUS },
773     { 5, {{1, 0}, {9,  0}, {3, -1}, {5,  0}, {7, -1}}, "m9" },
774     { 5, {{1, 0}, {9, -1}, {3, -1}, {5,  0}, {7, -1}}, "m♭9" },
775     { 5, {{1, 0}, {9,  0}, {3,  0}, {5, -1}, {7,  0}}, "M9" SUP "♭5" PUS },
776     { 5, {{1, 0}, {9,  0}, {3,  0}, {5, -1}, {7, -1}}, "9" SUP "♭5" PUS },
777     { 5, {{1, 0}, {9,  0}, {3, -1}, {5, -1}, {7,  0}}, "m" SUP "M9♭5" PUS },
778     { 5, {{1, 0}, {9,  0}, {3, -1}, {5, -1}, {7, -1}}, "𝆩" SUP "9" PUS },
779     { 5, {{1, 0}, {9, -1}, {3, -1}, {5, -1}, {7, -1}}, "𝆩" SUP "♭9" PUS },
780     { 5, {{1, 0}, {9,  0}, {3, -1}, {5, -1}, {7, -2}}, "°" SUP "9" PUS },
781     { 5, {{1, 0}, {9, -1}, {3, -1}, {5, -1}, {7, -2}}, "°" SUP "♭9" PUS },
782
783     /* Eleventh chords */
784     { 6, {{1, 0}, {9,  0}, {3,  0}, {11,  0}, {5, +1}, {7,  0}}, SUP "+M11" PUS },
785     { 6, {{1, 0}, {9,  0}, {3,  0}, {11,  0}, {5, +1}, {7, -1}}, SUP "+11" PUS },
786     { 6, {{1, 0}, {9,  0}, {3,  0}, {11,  0}, {5,  0}, {7,  0}}, "M11" },
787     { 6, {{1, 0}, {9,  0}, {3,  0}, {11,  0}, {5,  0}, {7, -1}}, "11" },
788     { 6, {{1, 0}, {9,  0}, {3, -1}, {11,  0}, {5,  0}, {7,  0}}, "m" SUP "M11" PUS },
789     { 6, {{1, 0}, {9,  0}, {3, -1}, {11,  0}, {5,  0}, {7, -1}}, "m11" },
790     { 6, {{1, 0}, {9, -1}, {3, -1}, {11,  0}, {5, -1}, {7, -1}}, "𝆩" SUP "11" PUS },
791     { 6, {{1, 0}, {9, -1}, {3, -1}, {11, -1}, {5, -1}, {7, -2}}, "°" SUP "11" PUS }
792 };
793
794 static void
795 scherzo_adjust_pitch_to_match_modified_degree (pitch_t *pitch,
796                                                pitch_t root,
797                                                modified_degree_t *degree)
798 {
799     pitch_name_t name = PITCH_NAME (*pitch);
800     pitch_accidental_t accidental = PITCH_ACCIDENTAL (*pitch);
801     int octave = PITCH_OCTAVE (*pitch);
802     int degree_zero_based = (degree->degree - 1) % 7;
803     int degree_delta;
804
805     int note_degree_zero_based = name - PITCH_NAME (root);
806     if (note_degree_zero_based < 0)
807         note_degree_zero_based += 7;
808
809     if (note_degree_zero_based == degree_zero_based)
810         return;
811
812     degree_delta = note_degree_zero_based - degree_zero_based;
813     if (degree_delta > 3)
814         degree_delta = - (7 - degree_delta);
815     if (degree_delta < -3)
816         degree_delta = - (-7 - degree_delta);
817
818     if (abs (degree_delta) != 1) {
819         fprintf (stderr, "Internal error: Cannot adjust a note more than one degree (%d vs. %d).\n", note_degree_zero_based + 1, degree->degree);
820         exit (1);
821     }
822
823     if (degree_delta == -1) {
824         if (name == PITCH_NAME_B) {
825             name = PITCH_NAME_C;
826             octave++;
827         } else {
828             name++;
829         }
830         switch (name) {
831         case PITCH_NAME_D:
832         case PITCH_NAME_E:
833         case PITCH_NAME_G:
834         case PITCH_NAME_A:
835         case PITCH_NAME_B:
836             accidental -= 2;
837             break;
838         case PITCH_NAME_C:
839         case PITCH_NAME_F:
840             accidental -= 1;
841             break;
842         }
843     }
844
845     if (degree_delta == +1) {
846         if (name == PITCH_NAME_C) {
847             name = PITCH_NAME_B;
848             octave--;
849         } else {
850             name--;
851         }
852         switch (name) {
853         case PITCH_NAME_C:
854         case PITCH_NAME_D:
855         case PITCH_NAME_F:
856         case PITCH_NAME_G:
857         case PITCH_NAME_A:
858             accidental += 2;
859             break;
860         case PITCH_NAME_E:
861         case PITCH_NAME_B:
862             accidental += 1;
863         }
864     }
865
866     if (accidental < 0 || accidental > PITCH_ACCIDENTAL_DOUBLE_SHARP) {
867         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);
868         exit (1);
869     }
870
871     *pitch = PITCH (name, accidental, octave);
872 }
873
874 static void
875 _spell_chord_by_signature (pitch_group_t *chord,
876                            chord_signature_t *signature,
877                            pitch_t root)
878 {
879     int i, degree, note_half_steps, degree_half_steps;
880     int root_midi;
881
882     /* Sanitize root to eliminate things like double-flats,
883      * double-sharps, Cb, E#, etc. */
884     root_midi = _pitch_to_midi (root);
885     root = _midi_to_pitch (root_midi);
886     
887     for (i = 0; i < chord->num_pitches; i++) {
888         note_half_steps = _pitch_from_root_in_half_steps (chord->pitches[i],
889                                                           root);
890         for (degree = 0; degree < signature->num_degrees; degree++) {
891             degree_half_steps = _modified_degree_to_half_steps (&signature->degrees[degree]);
892             if (note_half_steps == degree_half_steps) {
893                 scherzo_adjust_pitch_to_match_modified_degree (&chord->pitches[i],
894                                                                root,
895                                                                &signature->degrees[degree]);
896                 break;
897             }
898         }
899         if (note_half_steps != degree_half_steps) {
900             fprintf (stderr, "Internal error: Chord and degree mis-match\n");
901             exit (1);
902         }
903     }
904 }
905
906 static void
907 _analyze_chord (pitch_group_t *chord,
908                 chord_signature_t **signature_ret,
909                 pitch_t **root_ret)
910 {
911     void *local = talloc_new (NULL);
912     analyzed_pitch_t *pitches;
913     int i, j, num_pitches;
914     int bass_pitch, inversion;
915     pitch_t root;
916     chord_signature_t *match = NULL;
917
918     /* Default to no-match for any early return */
919     *signature_ret = NULL;
920     *root_ret = NULL;
921
922     num_pitches = chord->num_pitches;
923
924     if (chord->num_pitches <= 1)
925         goto DONE;
926
927     pitches = talloc_array (local, analyzed_pitch_t, num_pitches);
928     if (pitches == NULL)
929         goto DONE;
930
931     for (i = 0; i < num_pitches; i++) {
932         pitch_t pitch = chord->pitches[i];
933         pitches[i].pitch = pitch;
934         pitches[i].midi_pitch = _pitch_to_midi (pitch);
935         /* Relative pitch will be filled in after sorting. */
936         pitches[i].relative_pitch = 0;
937     }
938
939     /* First, sort by midi pitch to find the bass note. */
940     qsort (pitches, num_pitches, sizeof (analyzed_pitch_t),
941            _compare_analyzed_pitch_by_midi_pitch);
942     
943     bass_pitch = pitches[0].midi_pitch;
944
945     /* With the bass note identified, we can find all relative pitches. */
946     for (i = 0; i < num_pitches; i++) {
947         pitches[i].relative_pitch = pitches[i].midi_pitch - bass_pitch;
948         while (pitches[i].relative_pitch >= 12)
949             pitches[i].relative_pitch -= 12;
950     }
951
952     /* Now, sort again by relative pitch. */
953     qsort (pitches, num_pitches, sizeof (analyzed_pitch_t),
954            _compare_analyzed_pitch_by_relative_pitch);
955
956     /* Finally, eliminate all duplicate notes. */
957     for (i = 0; i < num_pitches - 1; i++) {
958             if (pitches[i+1].relative_pitch == pitches[i].relative_pitch) {
959                     j = i+1;
960                     while (j < num_pitches &&
961                            pitches[j].relative_pitch == pitches[i].relative_pitch)
962                     {
963                             j++;
964                     }
965                     /* The loop incremented j one past the last
966                      * duplicate. Decrement so that it points to the
967                      * last duplicate (and is guaranteed to not exceed
968                      * the array bounds).*/
969                     j--;
970
971                     if (j < num_pitches - 1) {
972                             memmove (&pitches[i+1], &pitches[j+1],
973                                      (num_pitches - j) * sizeof (analyzed_pitch_t));
974                     }
975
976                     num_pitches -= (j - i);
977             }
978     }
979
980     for (inversion = 0; inversion < 4; inversion++) {
981         for (i = 0; i < ARRAY_SIZE (signatures); i++) {
982             if (_chord_signature_matches (pitches, num_pitches,
983                                           signatures[i].degrees,
984                                           signatures[i].num_degrees,
985                                           inversion, &root))
986             {
987                 match = &signatures[i];
988                 goto HAVE_MATCH;
989             }
990         }
991     }
992 HAVE_MATCH:
993
994     if (match) {
995         *signature_ret = match;
996         for (i = 0; i < chord->num_pitches; i++) {
997             if (chord->pitches[i] == root) {
998                 *root_ret = &chord->pitches[i];
999                 break;
1000             }
1001         }
1002     }
1003
1004 DONE:
1005     talloc_free (local);
1006 }
1007
1008 static void
1009 pitch_group_init (void *ctx, pitch_group_t *group)
1010 {
1011     group->ctx = ctx;
1012     group->pitches = NULL;
1013     group->size = 0;
1014     group->num_pitches = 0;
1015 }
1016
1017 static void
1018 pitch_group_add_pitch (pitch_group_t *group, pitch_t pitch)
1019 {
1020     int i;
1021
1022     /* Do nothing if pitch is already in group. */
1023     for (i = 0; i < group->num_pitches; i++)
1024         if (group->pitches[i] == pitch)
1025             return;
1026
1027     group->num_pitches++;
1028
1029     if (group->num_pitches > group->size) {
1030         group->size++;
1031         group->pitches = talloc_realloc (group->ctx, group->pitches,
1032                                          pitch_t, group->size);
1033
1034         if (group->pitches == NULL) {
1035             fprintf (stderr, "Out of memory.\n");
1036             exit (1);
1037         }
1038     }
1039
1040     group->pitches[group->num_pitches - 1] = pitch;
1041 }
1042
1043 static void
1044 pitch_group_remove_pitch_at (pitch_group_t *group, int i)
1045 {
1046     if (i > group->num_pitches) {
1047         fprintf (stderr, "Internal error: Cannot remove pitch %d from group with only %d %s\n",
1048                  i, group->num_pitches,
1049                  group->num_pitches == 1 ? "pitch" : "pitches");
1050         exit (1);
1051     }
1052
1053     if (i < group->num_pitches - 1) {
1054         memmove (group->pitches + i, group->pitches + i + 1,
1055                  (group->num_pitches - 1 - i) * sizeof (pitch_t));
1056     }
1057
1058     group->num_pitches--;
1059 }
1060
1061 /* Remove a 'pitch' from 'group', (including any enharmonic pitch)
1062  * See also: pitch_group_remove_pitch
1063  */
1064 static void
1065 pitch_group_remove_pitch_enharmonic (pitch_group_t *group, pitch_t pitch)
1066 {
1067     int i;
1068
1069     for (i = 0; i < group->num_pitches; i++)
1070         if (_pitches_are_enharmonic (group->pitches[i], pitch))
1071             pitch_group_remove_pitch_at (group, i);
1072 }
1073
1074 /* Remove an exactly-matching pitch from 'group'
1075  * See also: pitch_group_remove_pitch_enharmonic
1076  *
1077 static void
1078 pitch_group_remove_pitch (pitch_group_t *group, pitch_t pitch)
1079 {
1080     int i;
1081
1082     for (i = 0; i < group->num_pitches; i++)
1083         if (group->pitches[i] == pitch)
1084             pitch_group_remove_pitch_at (group, i);
1085 }
1086 */
1087
1088 static void
1089 scherzo_update_notes_and_chord (scherzo_t *scherzo)
1090 {
1091     if (scherzo->notes_pressed.num_pitches == 0 &&
1092         scherzo->notes_pedaled.num_pitches == 0)
1093     {
1094         score_remove_notes (scherzo->score);
1095
1096         score_remove_chords (scherzo->score);
1097
1098         gtk_widget_queue_draw (scherzo->window);
1099     }
1100 }
1101
1102 static void
1103 scherzo_press_note (scherzo_t *scherzo, pitch_t pitch)
1104 {
1105     void *local = talloc_new (NULL);
1106     pitch_group_t *chord;
1107     chord_signature_t *signature;
1108     char *chord_name = NULL;
1109     pitch_t *root;
1110     int i;
1111
1112     /* Do nothing if this note is already pressed. */
1113     for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
1114         if (scherzo->notes_pressed.pitches[i] == pitch)
1115             return;
1116
1117     pitch_group_add_pitch (&scherzo->notes_pressed, pitch);
1118
1119     if (scherzo->pedal_pressed)
1120         pitch_group_add_pitch (&scherzo->notes_pedaled, pitch);
1121
1122     /* Remove all notes/chords from score, then add current notes. */
1123     score_remove_notes (scherzo->score);
1124     score_remove_chords (scherzo->score);
1125
1126     if (scherzo->pedal_pressed)
1127         chord = &scherzo->notes_pedaled;
1128     else
1129         chord = &scherzo->notes_pressed;
1130
1131     _analyze_chord (chord, &signature, &root);
1132
1133     if (signature) {
1134         /* Don't print root pitch for octaves and inversions,
1135          * (since a pitch name alone looks like a major triad) */
1136         if (signature->num_degrees < 3) {
1137             chord_name = talloc_strdup (local, signature->name);
1138         } else {
1139             _spell_chord_by_signature (&scherzo->notes_pressed,
1140                                        signature, *root);
1141             _spell_chord_by_signature (&scherzo->notes_pedaled,
1142                                        signature, *root);
1143
1144             chord_name = talloc_asprintf (local, "%s%s",
1145                                           pitch_string (*root),
1146                                           signature->name);
1147         }
1148     } else if (chord->num_pitches > 2) {
1149         chord_name = talloc_strdup (local, "?");
1150     }
1151
1152     if (chord_name)
1153         scherzo->chord = score_add_chord (scherzo->treble, chord_name);
1154
1155     for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
1156     {
1157         score_add_note (scherzo->score, scherzo->notes_pressed.pitches[i],
1158                         SCORE_DURATION_WHOLE);
1159     }
1160
1161     for (i = 0; i < scherzo->notes_pedaled.num_pitches; i++)
1162     {
1163         score_add_note (scherzo->score, scherzo->notes_pedaled.pitches[i],
1164                         SCORE_DURATION_WHOLE);
1165     }
1166
1167     talloc_free (local);
1168 }
1169
1170 static void
1171 scherzo_release_note (scherzo_t *scherzo, pitch_t pitch)
1172 {
1173     pitch_group_remove_pitch_enharmonic (&scherzo->notes_pressed, pitch);
1174
1175     if (scherzo->notes_pressed.num_pitches == 0)
1176         scherzo_update_notes_and_chord (scherzo);
1177 }
1178
1179 static pitch_t
1180 scherzo_press_note_midi (scherzo_t *scherzo, unsigned char midi_note)
1181 {
1182     pitch_t pitch = _midi_to_pitch (midi_note);
1183
1184     scherzo_press_note (scherzo, pitch);
1185
1186     return pitch;
1187 }
1188
1189 static void
1190 scherzo_release_note_midi (scherzo_t *scherzo, unsigned char midi_note)
1191 {
1192     scherzo_release_note (scherzo, _midi_to_pitch (midi_note));
1193 }
1194
1195 static void
1196 scherzo_press_pedal (scherzo_t *scherzo)
1197 {
1198     int i;
1199
1200     if (scherzo->pedal_pressed)
1201         return;
1202
1203     scherzo->pedal_pressed = 1;
1204
1205     /* Copy all pressed notes to pedaled notes */
1206     for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
1207         pitch_group_add_pitch (&scherzo->notes_pedaled, scherzo->notes_pressed.pitches[i]);
1208 }
1209
1210 static void
1211 scherzo_release_pedal (scherzo_t *scherzo)
1212 {
1213     int i;
1214
1215     if (! scherzo->pedal_pressed)
1216         return;
1217
1218     /* Remove all previously pedaled notes. */
1219     for (i = scherzo->notes_pedaled.num_pitches - 1; i >=0; i--)
1220         pitch_group_remove_pitch_at (&scherzo->notes_pedaled, i);
1221
1222     scherzo->pedal_pressed = 0;
1223
1224     scherzo_update_notes_and_chord (scherzo);
1225 }
1226
1227 static void
1228 _select_challenge (scherzo_t *scherzo)
1229 {
1230     category_t *category_unused;
1231     bool_t introduced_unused;
1232     item_t *item;
1233     challenge_t *challenge = &scherzo->challenge;
1234     pitch_name_t pitch_name;
1235     int octave;
1236     char *s;
1237
1238     mnemon_select_item (&scherzo->mnemon,
1239                         &challenge->bin,
1240                         &challenge->item_index,
1241                         &category_unused,
1242                         &introduced_unused);
1243
1244     item = challenge->bin->items[challenge->item_index];
1245
1246     s = item->challenge;
1247     if (strncmp (s, "treble:", 7) == 0) {
1248         s += 7;
1249         challenge->staff = scherzo->treble;
1250     } else if (strncmp (s, "bass:", 5) == 0) {
1251         s += 5;
1252         challenge->staff = scherzo->bass;
1253     } else {
1254         fprintf (stderr,
1255                  "Malformed staff name: %s (expected 'treble:' or 'bass:')\n",
1256                  s);
1257         exit (1);
1258     }
1259
1260     switch (*s) {
1261     case 'C':
1262         pitch_name = PITCH_NAME_C;
1263         break;
1264     case 'D':
1265         pitch_name = PITCH_NAME_D;
1266         break;
1267     case 'E':
1268         pitch_name = PITCH_NAME_E;
1269         break;
1270     case 'F':
1271         pitch_name = PITCH_NAME_F;
1272         break;
1273     case 'G':
1274         pitch_name = PITCH_NAME_G;
1275         break;
1276     case 'A':
1277         pitch_name = PITCH_NAME_A;
1278         break;
1279     case 'B':
1280         pitch_name = PITCH_NAME_B;
1281         break;
1282     default:
1283         fprintf (stderr, "Malformed pitch name: %s (expected 'A' - 'G')\n", s);
1284         exit (1);
1285     }
1286     s++;
1287
1288     if (*s < '0' || *s > '9') {
1289         fprintf (stderr, "Malformed octave number: %s (expected '0' - '9')\n", s);
1290         exit (1);
1291     }
1292
1293     octave = *s - '0';
1294
1295     challenge->pitch = PITCH (pitch_name, PITCH_ACCIDENTAL_NATURAL, octave);
1296
1297     challenge->active = 1;
1298     challenge->satisfied = 0;
1299     challenge->mistaken = 0;
1300 }
1301
1302 /* Determine whether the user hit the correct note. */
1303 static void
1304 _judge_pitch (scherzo_t *scherzo, pitch_t pitch)
1305 {
1306     challenge_t *challenge = &scherzo->challenge;
1307
1308     if (! challenge->active)
1309         return;
1310
1311     if (pitch == challenge->pitch)
1312         challenge->satisfied = 1;
1313     else
1314         challenge->mistaken = 1;
1315 }
1316
1317 /* If the user got the right note (eventually), then score it in
1318  * mnemon and show the next note. */
1319 static void
1320 _score_challenge (scherzo_t *scherzo)
1321 {
1322     challenge_t *challenge = &scherzo->challenge;
1323
1324     if (! challenge->active)
1325         return;
1326
1327     if (! challenge->satisfied)
1328         return;
1329
1330     mnemon_score_item (&scherzo->mnemon, challenge->bin, challenge->item_index,
1331                        ! challenge->mistaken);
1332
1333     _select_challenge (scherzo);
1334 }
1335
1336 static int
1337 on_midi_input (unused (GIOChannel *channel),
1338                unused (GIOCondition condition),
1339                void *user_data)
1340 {
1341     unsigned char buf[MIDI_BUF_SIZE], *next;
1342     scherzo_t *scherzo = user_data;
1343     ssize_t remaining;
1344     snd_seq_event_t event;
1345     pitch_t pitch;
1346     int need_redraw = FALSE;
1347
1348     remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
1349
1350     next = buf;
1351     while (remaining) {
1352         long consumed;
1353
1354         consumed = snd_midi_event_encode (scherzo->snd_midi_event,
1355                                           next, remaining, &event);
1356
1357         remaining -= consumed;
1358         next += consumed;
1359
1360         switch (event.type) {
1361         case SND_SEQ_EVENT_NONE:
1362             /* Incomplete event. Nothing to do. */
1363             break;
1364         case SND_SEQ_EVENT_NOTEON:
1365             pitch = scherzo_press_note_midi (scherzo, event.data.note.note);
1366             _judge_pitch (scherzo, pitch);
1367             need_redraw = TRUE;
1368             break;
1369         case SND_SEQ_EVENT_NOTEOFF:
1370             scherzo_release_note_midi (scherzo, event.data.note.note);
1371             _score_challenge (scherzo);
1372             need_redraw = TRUE;
1373             break;
1374         case SND_SEQ_EVENT_CLOCK:
1375             /* Ignore for now as my piano sends a constant stream of these. */
1376             break;
1377         case SND_SEQ_EVENT_SENSING:
1378             /* Ignore for now as my piano sends a constant stream of these. */
1379             break;
1380         case SND_SEQ_EVENT_CONTROLLER:
1381             /* XXX: My piano gives me 64 for the sustain pedal, is
1382              * that universal? */
1383             if (event.data.control.param == 64) {
1384                 if (event.data.control.value == 0)
1385                     scherzo_release_pedal (scherzo);
1386                 else
1387                     scherzo_press_pedal (scherzo);
1388             } else {
1389                 fprintf (stderr, "Fixme: Unhandled MIDI Control event (param=%d, value=%d)\n",
1390                          event.data.control.param, event.data.control.value);
1391             }
1392             break;
1393         default:
1394             fprintf (stderr, "Fixme: Do not yet know how to handle MIDI event %d\n",
1395                      event.type);
1396             break;
1397         }
1398     }
1399
1400     if (need_redraw)
1401         gtk_widget_queue_draw (scherzo->window);
1402
1403     /* Return TRUE to continue to get called in the future. */
1404     return TRUE;
1405 }
1406
1407 int
1408 main (int argc, char *argv[])
1409 {
1410     GtkWidget *drawing_area;
1411     scherzo_t scherzo;
1412     int err;
1413
1414     srand (time (NULL));
1415
1416     gtk_init (&argc, &argv);
1417
1418     scherzo.ctx = talloc_new (NULL);
1419
1420     scherzo.score = score_create (scherzo.ctx);
1421     scherzo.staff_height = 100;
1422     score_set_staff_height (scherzo.score, scherzo.staff_height);
1423
1424     score_add_brace (scherzo.score, 2);
1425     scherzo.treble = score_add_staff (scherzo.score, SCORE_CLEF_G);
1426     scherzo.bass = score_add_staff (scherzo.score, SCORE_CLEF_F);
1427
1428     scherzo.chord = NULL;
1429
1430     /* Default to octave 4 for computer keyboard keypresses. */
1431     scherzo.keyboard_octave = 4;
1432
1433     pitch_group_init (scherzo.ctx, &scherzo.notes_pressed);
1434     pitch_group_init (scherzo.ctx, &scherzo.notes_pedaled);
1435
1436     scherzo.pedal_pressed = 0;
1437
1438     scherzo.key = PITCH_CLASS_LITERAL (C, NATURAL);
1439     score_set_key (scherzo.score, scherzo.key);
1440
1441     mnemon_init (&scherzo.mnemon);
1442     /* XXX: Should create a default file if one cannot be loaded. */
1443     mnemon_load_category (&scherzo.mnemon, "scherzo-notes");
1444
1445     scherzo.challenge.active = 0;
1446 /*
1447     _select_challenge (&scherzo);
1448 */
1449
1450     err = snd_midi_event_new (MIDI_BUF_SIZE, &scherzo.snd_midi_event);
1451     if (err) {
1452         fprintf (stderr, "Out of memory.\n");
1453         return 1;
1454     }
1455
1456 #define MIDI_DEVICE "/dev/midi1"
1457     scherzo.midi_fd = open (MIDI_DEVICE, O_RDONLY);
1458     if (scherzo.midi_fd < 0) {
1459         printf ("failed to open " MIDI_DEVICE ". Midi input will not be available.\n");
1460     } else {
1461         GIOChannel *channel;
1462
1463         channel = g_io_channel_unix_new (scherzo.midi_fd);
1464         g_io_channel_set_encoding (channel, NULL, NULL);
1465         g_io_add_watch (channel, G_IO_IN, on_midi_input, &scherzo);
1466     }
1467
1468     scherzo.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1469
1470     gtk_window_set_default_size (GTK_WINDOW (scherzo.window), 1000, 600);
1471
1472     g_signal_connect (scherzo.window, "delete-event",
1473                       G_CALLBACK (on_delete_event_quit), NULL);
1474
1475     drawing_area = gtk_drawing_area_new ();
1476
1477     gtk_container_add (GTK_CONTAINER (scherzo.window), drawing_area);
1478
1479     g_signal_connect (drawing_area, "expose-event",  
1480                       G_CALLBACK (on_expose_event_draw),
1481                       &scherzo);
1482
1483     g_signal_connect (scherzo.window, "key-press-event",
1484                       G_CALLBACK (on_key_press_event),
1485                       &scherzo);
1486
1487     g_signal_connect (scherzo.window, "key-release-event",
1488                       G_CALLBACK (on_key_release_event),
1489                       &scherzo);
1490     
1491     gtk_widget_show_all (scherzo.window);
1492     
1493     gtk_main ();
1494
1495     mnemon_save (&scherzo.mnemon);
1496
1497     snd_midi_event_free (scherzo.snd_midi_event);
1498
1499     talloc_free (scherzo.ctx);
1500
1501     return 0;
1502 }