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