]> git.cworth.org Git - scherzo/blob - scherzo.c
Use a pitch_t rather than a score_note_t for challenge
[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     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 } scherzo_t;
82
83 /* Forward declarations. */
84 static void
85 scherzo_press_note (scherzo_t *scherzo, pitch_t pitch);
86
87 static void
88 scherzo_release_note (scherzo_t *scherzo, pitch_t pitch);
89
90 static void
91 scherzo_press_pedal (scherzo_t *scherzo);
92
93 static void
94 scherzo_release_pedal (scherzo_t *scherzo);
95
96 static void
97 _judge_pitch (scherzo_t *scherzo, pitch_t pitch);
98
99 static void
100 _score_challenge (scherzo_t *scherzo);
101
102 static int
103 on_delete_event_quit (unused (GtkWidget *widget),
104                       unused (GdkEvent *event),
105                       unused (gpointer user_data))
106 {
107     gtk_main_quit ();
108
109     /* Returning FALSE allows the default handler for delete-event
110      * to proceed to cleanup the widget. */
111     return FALSE;
112 }
113
114 static int
115 on_expose_event_draw (GtkWidget *widget,
116                       unused (GdkEventExpose *expose),
117                       void * user_data)
118 {
119     scherzo_t *scherzo = user_data;
120     score_t *score = scherzo->score;
121     cairo_t *cr;
122     GtkAllocation allocation;
123     static const int pad = 10;
124     int widget_width;
125
126     gtk_widget_get_allocation (widget, &allocation);
127     widget_width = allocation.width;
128
129     cr = gdk_cairo_create (widget->window);
130
131     /* White background */
132     cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
133     cairo_paint (cr);
134
135     /* Add some padding on the sides and top */
136     cairo_translate (cr, pad, scherzo->staff_height);
137     score_set_staff_height (score, scherzo->staff_height);
138     score_set_width (score, widget_width - 2 * pad);
139
140     score_draw (score, cr);
141  
142     return TRUE;
143 }
144
145 static int
146 on_key_press_event (GtkWidget *widget,
147                     GdkEventKey *key,
148                     void *user_data)
149 {
150     scherzo_t *scherzo = user_data;
151     int octave;
152     /* Initialize to keep the compiler quiet. */
153     pitch_name_t pitch_name = PITCH_NATURAL (C, 0);
154     pitch_t pitch;
155
156     if (scherzo->challenge.active)
157         octave = PITCH_OCTAVE (scherzo->challenge.pitch);
158     else
159         octave = scherzo->keyboard_octave;
160
161     switch (key->keyval) {
162     case GDK_KEY_plus:
163     case GDK_KEY_KP_Add:
164     case GDK_KEY_equal:
165     case GDK_KEY_KP_Equal:
166         scherzo->staff_height += 4;
167         gtk_widget_queue_draw (widget);
168         return TRUE;
169         break;
170     case GDK_KEY_minus:
171     case GDK_KEY_KP_Subtract:
172         scherzo->staff_height -= 4;
173         gtk_widget_queue_draw (widget);
174         return TRUE;
175         break;
176     case GDK_KEY_q:
177     case GDK_KEY_Q:
178     case GDK_KEY_Escape:
179         gtk_main_quit ();
180         return FALSE;
181     case GDK_KEY_c:
182     case GDK_KEY_C:
183         pitch_name = PITCH_NAME_C;
184         break;
185     case GDK_KEY_d:
186     case GDK_KEY_D:
187         pitch_name = PITCH_NAME_D;
188         break;
189     case GDK_KEY_e:
190     case GDK_KEY_E:
191         pitch_name = PITCH_NAME_E;
192         break;
193     case GDK_KEY_f:
194     case GDK_KEY_F:
195         pitch_name = PITCH_NAME_F;
196         break;
197     case GDK_KEY_g:
198     case GDK_KEY_G:
199         pitch_name = PITCH_NAME_G;
200         break;
201     case GDK_KEY_a:
202     case GDK_KEY_A:
203         pitch_name = PITCH_NAME_A;
204         break;
205     case GDK_KEY_b:
206     case GDK_KEY_B:
207         pitch_name = PITCH_NAME_B;
208         break;
209     case GDK_KEY_0:
210     case GDK_KEY_1:
211     case GDK_KEY_2:
212     case GDK_KEY_3:
213     case GDK_KEY_4:
214     case GDK_KEY_5:
215     case GDK_KEY_6:
216     case GDK_KEY_7:
217     case GDK_KEY_8:
218         scherzo->keyboard_octave = key->keyval - GDK_KEY_0;
219         break;
220     case GDK_KEY_space:
221         scherzo_press_pedal (scherzo);
222         break;
223     case GDK_KEY_Up:
224         if (scherzo->keyboard_accidental < PITCH_ACCIDENTAL_DOUBLE_SHARP)
225             scherzo->keyboard_accidental++;
226         break;
227     case GDK_KEY_Down:
228         if (scherzo->keyboard_accidental > PITCH_ACCIDENTAL_DOUBLE_FLAT)
229             scherzo->keyboard_accidental--;
230         break;
231     }
232
233     pitch = PITCH (pitch_name, scherzo->keyboard_accidental, octave);
234
235     if ((key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_G) ||
236         (key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_g))
237     {
238         scherzo_press_note (scherzo, pitch);
239         _judge_pitch (scherzo, pitch);
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.active)
262         octave = PITCH_OCTAVE (scherzo->challenge.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_pitch {
417     /* Original note being analzyed. */
418     pitch_t pitch;
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_pitch_t;
426
427 static int
428 _compare_analyzed_pitch_by_midi_pitch (const void *va, const void *vb)
429 {
430     const analyzed_pitch_t *a = va, *b = vb;
431
432     return a->midi_pitch - b->midi_pitch;
433 }
434
435 static int
436 _compare_analyzed_pitch_by_relative_pitch (const void *va, const void *vb)
437 {
438     const analyzed_pitch_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_pitch_t *pitches,
508                           int num_pitches,
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_pitches != 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_pitches; i++)
544         if (pitches[i].relative_pitch != relative_pitches[i])
545             return 0;
546
547     root_index = (num_pitches - inversion) % num_pitches;
548     *root = pitches[root_index].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_pitch_to_match_modified_degree (pitch_t *pitch,
758                                                pitch_t root,
759                                                modified_degree_t *degree)
760 {
761     pitch_name_t name = PITCH_NAME (*pitch);
762     pitch_accidental_t accidental = PITCH_ACCIDENTAL (*pitch);
763     int octave = PITCH_OCTAVE (*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     *pitch = PITCH (name, accidental, octave);
834 }
835
836 static void
837 _spell_chord_by_signature (pitch_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->pitches[i],
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_pitch_to_match_modified_degree (&chord->pitches[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_pitch_t *pitches;
874     pitch_group_t *pitch_group;
875     unsigned i, j, num_pitches;
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         pitch_group = &scherzo->notes_pedaled;
883     else
884         pitch_group = &scherzo->notes_pressed;
885
886     num_pitches = pitch_group->num_pitches;
887
888     if (scherzo->chord) {
889         score_remove_chord (scherzo->chord);
890         scherzo->chord = NULL;
891     }
892
893     if (num_pitches <= 1)
894         goto DONE;
895
896     pitches = talloc_array (local, analyzed_pitch_t, num_pitches);
897     if (pitches == NULL)
898         goto DONE;
899
900     for (i = 0; i < num_pitches; i++) {
901         pitch_t pitch = pitch_group->pitches[i];
902         pitches[i].pitch = pitch;
903         pitches[i].midi_pitch = _pitch_to_midi (pitch);
904         /* Relative pitch will be filled in after sorting. */
905         pitches[i].relative_pitch = 0;
906     }
907
908     /* First, sort by midi pitch to find the bass note. */
909     qsort (pitches, num_pitches, sizeof (analyzed_pitch_t),
910            _compare_analyzed_pitch_by_midi_pitch);
911     
912     bass_pitch = pitches[0].midi_pitch;
913
914     /* With the bass note identified, we can find all relative pitches. */
915     for (i = 0; i < num_pitches; i++) {
916         pitches[i].relative_pitch = pitches[i].midi_pitch - bass_pitch;
917         while (pitches[i].relative_pitch >= 12)
918             pitches[i].relative_pitch -= 12;
919     }
920
921     /* Now, sort again by relative pitch. */
922     qsort (pitches, num_pitches, sizeof (analyzed_pitch_t),
923            _compare_analyzed_pitch_by_relative_pitch);
924
925     /* Finally, eliminate all duplicate notes. */
926     for (i = 0; i < num_pitches - 1; i++) {
927             if (pitches[i+1].relative_pitch == pitches[i].relative_pitch) {
928                     j = i+1;
929                     while (j < num_pitches &&
930                            pitches[j].relative_pitch == pitches[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_pitches - 1) {
941                             memmove (&pitches[i+1], &pitches[j+1],
942                                      (num_pitches - j) * sizeof (analyzed_pitch_t));
943                     }
944
945                     num_pitches -= (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 (pitches, num_pitches,
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_pitches < 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 (pitch_group, num_pitches,
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 pitch_group_init (void *ctx, pitch_group_t *group)
990 {
991     group->ctx = ctx;
992     group->pitches = NULL;
993     group->size = 0;
994     group->num_pitches = 0;
995 }
996
997 static void
998 pitch_group_add_pitch (pitch_group_t *group, pitch_t pitch)
999 {
1000     int i;
1001
1002     /* Do nothing if pitch is already in group. */
1003     for (i = 0; i < group->num_pitches; i++)
1004         if (group->pitches[i] == pitch)
1005             return;
1006
1007     group->num_pitches++;
1008
1009     if (group->num_pitches > group->size) {
1010         group->size++;
1011         group->pitches = talloc_realloc (group->ctx, group->pitches,
1012                                          pitch_t, group->size);
1013
1014         if (group->pitches == NULL) {
1015             fprintf (stderr, "Out of memory.\n");
1016             exit (1);
1017         }
1018     }
1019
1020     group->pitches[group->num_pitches - 1] = pitch;
1021 }
1022
1023 static void
1024 pitch_group_remove_pitch_at (pitch_group_t *group, int i)
1025 {
1026     if (i > group->num_pitches) {
1027         fprintf (stderr, "Internal error: Cannot remove pitch %d from group with only %d %s\n",
1028                  i, group->num_pitches,
1029                  group->num_pitches == 1 ? "pitch" : "pitches");
1030         exit (1);
1031     }
1032
1033     if (i < group->num_pitches - 1) {
1034         memmove (group->pitches + i, group->pitches + i + 1,
1035                  (group->num_pitches - 1 - i) * sizeof (pitch_t));
1036     }
1037
1038     group->num_pitches--;
1039 }
1040
1041 static void
1042 pitch_group_remove_pitch (pitch_group_t *group, pitch_t pitch)
1043 {
1044     int i;
1045
1046     for (i = 0; i < group->num_pitches; i++)
1047         if (group->pitches[i] == pitch)
1048             pitch_group_remove_pitch_at (group, i);
1049 }
1050
1051 static void
1052 scherzo_update_notes_and_chord (scherzo_t *scherzo)
1053 {
1054     if (scherzo->notes_pressed.num_pitches == 0 &&
1055         scherzo->notes_pedaled.num_pitches == 0)
1056     {
1057         score_remove_notes (scherzo->score);
1058
1059         if (scherzo->chord)
1060             score_remove_chord (scherzo->chord);
1061
1062         gtk_widget_queue_draw (scherzo->window);
1063     }
1064 }
1065
1066 static void
1067 scherzo_press_note (scherzo_t *scherzo, pitch_t pitch)
1068 {
1069     int i;
1070
1071     /* Do nothing if this note is already pressed. */
1072     for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
1073         if (scherzo->notes_pressed.pitches[i] == pitch)
1074             return;
1075
1076     pitch_group_add_pitch (&scherzo->notes_pressed, pitch);
1077
1078     if (scherzo->pedal_pressed)
1079         pitch_group_add_pitch (&scherzo->notes_pedaled, pitch);
1080
1081     /* Remove all notes from score, then add current notes. */
1082     score_remove_notes (scherzo->score);
1083
1084     for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
1085     {
1086         score_add_note (scherzo->score, scherzo->notes_pressed.pitches[i],
1087                         SCORE_DURATION_WHOLE);
1088     }
1089
1090     for (i = 0; i < scherzo->notes_pedaled.num_pitches; i++)
1091     {
1092         score_add_note (scherzo->score, scherzo->notes_pedaled.pitches[i],
1093                         SCORE_DURATION_WHOLE);
1094     }
1095
1096     scherzo_analyze_chord (scherzo);
1097 }
1098
1099 static void
1100 scherzo_release_note (scherzo_t *scherzo, pitch_t pitch)
1101 {
1102     pitch_group_remove_pitch (&scherzo->notes_pressed, pitch);
1103
1104     if (scherzo->notes_pressed.num_pitches == 0)
1105         scherzo_update_notes_and_chord (scherzo);
1106 }
1107
1108 static pitch_t
1109 scherzo_press_note_midi (scherzo_t *scherzo, unsigned char midi_note)
1110 {
1111     pitch_t pitch = _midi_to_pitch (midi_note);
1112
1113     scherzo_press_note (scherzo, pitch);
1114
1115     return pitch;
1116 }
1117
1118 static void
1119 scherzo_release_note_midi (scherzo_t *scherzo, unsigned char midi_note)
1120 {
1121     scherzo_release_note (scherzo, _midi_to_pitch (midi_note));
1122 }
1123
1124 static void
1125 scherzo_press_pedal (scherzo_t *scherzo)
1126 {
1127     int i;
1128
1129     scherzo->pedal_pressed = 1;
1130
1131     /* Copy all pressed notes to pedaled notes */
1132     for (i = 0; i < scherzo->notes_pressed.num_pitches; i++)
1133         pitch_group_add_pitch (&scherzo->notes_pedaled, scherzo->notes_pressed.pitches[i]);
1134 }
1135
1136 static void
1137 scherzo_release_pedal (scherzo_t *scherzo)
1138 {
1139     int i;
1140
1141     /* Remove all previously pedaled notes. */
1142     for (i = scherzo->notes_pedaled.num_pitches - 1; i >=0; i--)
1143         pitch_group_remove_pitch_at (&scherzo->notes_pedaled, i);
1144
1145     scherzo->pedal_pressed = 0;
1146
1147     scherzo_update_notes_and_chord (scherzo);
1148 }
1149
1150 void
1151 _select_challenge (scherzo_t *scherzo)
1152 {
1153     category_t *category_unused;
1154     bool_t introduced_unused;
1155     item_t *item;
1156     challenge_t *challenge = &scherzo->challenge;
1157     pitch_name_t pitch_name;
1158     int octave;
1159     char *s;
1160
1161     mnemon_select_item (&scherzo->mnemon,
1162                         &challenge->bin,
1163                         &challenge->item_index,
1164                         &category_unused,
1165                         &introduced_unused);
1166
1167     item = challenge->bin->items[challenge->item_index];
1168
1169     s = item->challenge;
1170     if (strncmp (s, "treble:", 7) == 0) {
1171         s += 7;
1172         challenge->staff = scherzo->treble;
1173     } else if (strncmp (s, "bass:", 5) == 0) {
1174         s += 5;
1175         challenge->staff = scherzo->bass;
1176     } else {
1177         fprintf (stderr,
1178                  "Malformed staff name: %s (expected 'treble:' or 'bass:')\n",
1179                  s);
1180         exit (1);
1181     }
1182
1183     switch (*s) {
1184     case 'C':
1185         pitch_name = PITCH_NAME_C;
1186         break;
1187     case 'D':
1188         pitch_name = PITCH_NAME_D;
1189         break;
1190     case 'E':
1191         pitch_name = PITCH_NAME_E;
1192         break;
1193     case 'F':
1194         pitch_name = PITCH_NAME_F;
1195         break;
1196     case 'G':
1197         pitch_name = PITCH_NAME_G;
1198         break;
1199     case 'A':
1200         pitch_name = PITCH_NAME_A;
1201         break;
1202     case 'B':
1203         pitch_name = PITCH_NAME_B;
1204         break;
1205     default:
1206         fprintf (stderr, "Malformed pitch name: %s (expected 'A' - 'G')\n", s);
1207         exit (1);
1208     }
1209     s++;
1210
1211     if (*s < '0' || *s > '9') {
1212         fprintf (stderr, "Malformed octave number: %s (expected '0' - '9')\n", s);
1213         exit (1);
1214     }
1215
1216     octave = *s - '0';
1217
1218     challenge->pitch = PITCH (pitch_name, PITCH_ACCIDENTAL_NATURAL, octave);
1219
1220     challenge->active = 1;
1221     challenge->satisfied = 0;
1222     challenge->mistaken = 0;
1223 }
1224
1225 /* Determine whether the user hit the correct note. */
1226 static void
1227 _judge_pitch (scherzo_t *scherzo, pitch_t pitch)
1228 {
1229     challenge_t *challenge = &scherzo->challenge;
1230
1231     if (! challenge->active)
1232         return;
1233
1234     if (pitch == challenge->pitch)
1235         challenge->satisfied = 1;
1236     else
1237         challenge->mistaken = 1;
1238 }
1239
1240 /* If the user got the right note (eventually), then score it in
1241  * mnemon and show the next note. */
1242 static void
1243 _score_challenge (scherzo_t *scherzo)
1244 {
1245     challenge_t *challenge = &scherzo->challenge;
1246
1247     if (! challenge->active)
1248         return;
1249
1250     if (! challenge->satisfied)
1251         return;
1252
1253     mnemon_score_item (&scherzo->mnemon, challenge->bin, challenge->item_index,
1254                        ! challenge->mistaken);
1255
1256     _select_challenge (scherzo);
1257 }
1258
1259 static int
1260 on_midi_input (unused (GIOChannel *channel),
1261                unused (GIOCondition condition),
1262                void *user_data)
1263 {
1264     unsigned char buf[MIDI_BUF_SIZE], *next;
1265     scherzo_t *scherzo = user_data;
1266     ssize_t remaining;
1267     snd_seq_event_t event;
1268     pitch_t pitch;
1269     int need_redraw = FALSE;
1270
1271     remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
1272
1273     next = buf;
1274     while (remaining) {
1275         long consumed;
1276
1277         consumed = snd_midi_event_encode (scherzo->snd_midi_event,
1278                                           next, remaining, &event);
1279
1280         remaining -= consumed;
1281         next += consumed;
1282
1283         switch (event.type) {
1284         case SND_SEQ_EVENT_NONE:
1285             /* Incomplete event. Nothing to do. */
1286             break;
1287         case SND_SEQ_EVENT_NOTEON:
1288             pitch = scherzo_press_note_midi (scherzo, event.data.note.note);
1289             _judge_pitch (scherzo, pitch);
1290             need_redraw = TRUE;
1291             break;
1292         case SND_SEQ_EVENT_NOTEOFF:
1293             scherzo_release_note_midi (scherzo, event.data.note.note);
1294             _score_challenge (scherzo);
1295             need_redraw = TRUE;
1296             break;
1297         case SND_SEQ_EVENT_CLOCK:
1298             /* Ignore for now as my piano sends a constant stream of these. */
1299             break;
1300         case SND_SEQ_EVENT_SENSING:
1301             /* Ignore for now as my piano sends a constant stream of these. */
1302             break;
1303         case SND_SEQ_EVENT_CONTROLLER:
1304             /* XXX: My piano gives me 64 for the sustain pedal, is
1305              * that universal? */
1306             if (event.data.control.param == 64) {
1307                 if (event.data.control.value == 0)
1308                     scherzo_release_pedal (scherzo);
1309                 else
1310                     scherzo_press_pedal (scherzo);
1311             } else {
1312                 fprintf (stderr, "Fixme: Unhandled MIDI Control event (param=%d, value=%d)\n",
1313                          event.data.control.param, event.data.control.value);
1314             }
1315             break;
1316         default:
1317             fprintf (stderr, "Fixme: Do not yet know how to handle MIDI event %d\n",
1318                      event.type);
1319             break;
1320         }
1321     }
1322
1323     if (need_redraw)
1324         gtk_widget_queue_draw (scherzo->window);
1325
1326     /* Return TRUE to continue to get called in the future. */
1327     return TRUE;
1328 }
1329
1330 int
1331 main (int argc, char *argv[])
1332 {
1333     GtkWidget *drawing_area;
1334     scherzo_t scherzo;
1335     int err;
1336
1337     srand (time (NULL));
1338
1339     gtk_init (&argc, &argv);
1340
1341     scherzo.ctx = talloc_new (NULL);
1342
1343     scherzo.score = score_create (scherzo.ctx);
1344     scherzo.staff_height = 100;
1345     score_set_staff_height (scherzo.score, scherzo.staff_height);
1346
1347     score_add_brace (scherzo.score, 2);
1348     scherzo.treble = score_add_staff (scherzo.score, SCORE_CLEF_G);
1349     scherzo.bass = score_add_staff (scherzo.score, SCORE_CLEF_F);
1350
1351     scherzo.chord = NULL;
1352
1353     /* Default to octave 4 and natural for computer keyboard keypresses. */
1354     scherzo.keyboard_octave = 4;
1355     scherzo.keyboard_accidental = PITCH_ACCIDENTAL_NATURAL;
1356
1357     pitch_group_init (scherzo.ctx, &scherzo.notes_pressed);
1358     pitch_group_init (scherzo.ctx, &scherzo.notes_pedaled);
1359
1360     scherzo.pedal_pressed = 0;
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 }