+static void
+_midi_to_score_pitch_and_octave (unsigned char midi_note,
+ score_pitch_t *pitch,
+ int *octave)
+{
+ *octave = midi_note / 12 - 1;
+
+ switch (midi_note % 12)
+ {
+ case 0:
+ *pitch = SCORE_PITCH_C;
+ break;
+ case 1:
+ *pitch = SCORE_PITCH_Cs;
+ break;
+ case 2:
+ *pitch = SCORE_PITCH_D;
+ break;
+ case 3:
+ *pitch = SCORE_PITCH_Ds;
+ break;
+ case 4:
+ *pitch = SCORE_PITCH_E;
+ break;
+ case 5:
+ *pitch = SCORE_PITCH_F;
+ break;
+ case 6:
+ *pitch = SCORE_PITCH_Fs;
+ break;
+ case 7:
+ *pitch = SCORE_PITCH_G;
+ break;
+ case 8:
+ *pitch = SCORE_PITCH_Gs;
+ break;
+ case 9:
+ *pitch = SCORE_PITCH_A;
+ break;
+ case 10:
+ *pitch = SCORE_PITCH_As;
+ break;
+ case 11:
+ *pitch = SCORE_PITCH_B;
+ break;
+ }
+}
+
+static void
+scherzo_add_note_midi (scherzo_t *scherzo, unsigned char midi_note)
+{
+ score_staff_t *staff;
+ score_pitch_t pitch;
+ int octave;
+
+ /* Anything at Middle C and above goes on the treble staff by default. */
+ if (midi_note >= 60)
+ staff = scherzo->treble;
+ else
+ staff = scherzo->bass;
+
+ _midi_to_score_pitch_and_octave (midi_note, &pitch, &octave);
+
+ score_staff_add_note (staff, pitch, octave, SCORE_DURATION_WHOLE);
+}
+
+static void
+scherzo_remove_note_midi (scherzo_t *scherzo, unsigned char midi_note)
+{
+ score_staff_t *staff;
+ score_pitch_t pitch;
+ int octave;
+ score_note_t *note;
+
+ /* Anything at Middle C and above goes on the treble staff by default. */
+ if (midi_note >= 60)
+ staff = scherzo->treble;
+ else
+ staff = scherzo->bass;
+
+ _midi_to_score_pitch_and_octave (midi_note, &pitch, &octave);
+
+ note = score_staff_find_note (staff, pitch, octave, SCORE_DURATION_WHOLE);
+ score_staff_remove_note (staff, note);
+}
+
+static int
+on_midi_input (unused (GIOChannel *channel),
+ unused (GIOCondition condition),
+ void *user_data)
+{
+ unsigned char buf[MIDI_BUF_SIZE], *next;
+ scherzo_t *scherzo = user_data;
+ ssize_t remaining;
+ snd_seq_event_t event;
+
+ remaining = read (scherzo->midi_fd, buf, MIDI_BUF_SIZE);
+
+ next = buf;
+ while (remaining) {
+ long consumed;
+
+ consumed = snd_midi_event_encode (scherzo->snd_midi_event,
+ next, remaining, &event);
+
+ remaining -= consumed;
+
+ switch (event.type) {
+ case SND_SEQ_EVENT_NONE:
+ /* Incomplete event. Nothing to do. */
+ break;
+ case SND_SEQ_EVENT_NOTEON:
+ scherzo_add_note_midi (scherzo, event.data.note.note);
+ gtk_widget_queue_draw (scherzo->window);
+ break;
+ case SND_SEQ_EVENT_NOTEOFF:
+ scherzo_remove_note_midi (scherzo, event.data.note.note);
+ gtk_widget_queue_draw (scherzo->window);
+ break;
+ case SND_SEQ_EVENT_CLOCK:
+ /* Ignore for now as my piano sends a constant stream of these. */
+ break;
+ case SND_SEQ_EVENT_SENSING:
+ /* Ignore for now as my piano sends a constant stream of these. */
+ break;
+ default:
+ fprintf (stderr, "Fixme: Do not yet know how to handle MIDI event %d\n",
+ event.type);
+ break;
+ }
+ }
+
+ /* Return TRUE to continue to get called in the future. */
+ return TRUE;
+}
+