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