shithub: choc

Download patch

ref: d8ada5c41da3eec5ef163d9efac9cb5dbdc2cb6b
parent: 3dd7e1db9bf26e1e50bc13f6b176e54d63f2da85
author: Simon Howard <[email protected]>
date: Wed Apr 15 15:00:25 EDT 2009

Parse MIDI events that reuse the event type from the previous event.

Subversion-branch: /branches/opl-branch
Subversion-revision: 1499

--- a/src/midifile.c
+++ b/src/midifile.c
@@ -198,8 +198,8 @@
 
     // Set basics:
 
-    event->event_type = event_type >> 4;
-    event->data.channel.channel = event_type & 0xf;
+    event->event_type = event_type & 0xf0;
+    event->data.channel.channel = event_type & 0x0f;
 
     // Read parameters:
 
@@ -296,7 +296,8 @@
     return true;
 }
 
-static boolean ReadEvent(midi_event_t *event, FILE *stream)
+static boolean ReadEvent(midi_event_t *event, unsigned int *last_event_type,
+                         FILE *stream)
 {
     byte event_type;
 
@@ -312,9 +313,29 @@
         return false;
     }
 
+    // All event types have their top bit set.  Therefore, if 
+    // the top bit is not set, it is because we are using the "same
+    // as previous event type" shortcut to save a byte.  Skip back
+    // a byte so that we read this byte again.
+
+    if ((event_type & 0x80) == 0)
+    {
+        event_type = *last_event_type;
+
+        if (fseek(stream, -1, SEEK_CUR) < 0)
+        {
+            fprintf(stderr, "ReadEvent: Unable to seek in stream\n");
+            return false;
+        }
+    }
+    else
+    {
+        *last_event_type = event_type;
+    }
+
     // Check event type:
 
-    switch (event_type >> 4)
+    switch (event_type & 0xf0)
     {
         // Two parameter channel events:
 
@@ -331,26 +352,27 @@
         case MIDI_EVENT_CHAN_AFTERTOUCH:
             return ReadChannelEvent(event, event_type, false, stream);
 
-        // Other event types:
+        default:
+            break;
+    }
 
-        case 0xf:
-            if (event_type == MIDI_EVENT_SYSEX
-             || event_type == MIDI_EVENT_SYSEX_SPLIT)
-            {
-                return ReadSysExEvent(event, event_type, stream);
-            }
-            else if (event_type == MIDI_EVENT_META)
-            {
-                return ReadMetaEvent(event, stream);
-            }
+    // Specific value?
 
-        // --- Fall-through deliberate ---
-        // Other 0xfx event types are unknown
+    switch (event_type)
+    {
+        case MIDI_EVENT_SYSEX:
+        case MIDI_EVENT_SYSEX_SPLIT:
+            return ReadSysExEvent(event, event_type, stream);
 
+        case MIDI_EVENT_META:
+            return ReadMetaEvent(event, stream);
+
         default:
-            fprintf(stderr, "Unknown MIDI event type: 0x%x\n", event_type);
-            return false;
+            break;
     }
+
+    fprintf(stderr, "ReadEvent: Unknown MIDI event type: 0x%x\n", event_type);
+    return false;
 }
 
 // Free an event:
@@ -405,6 +427,7 @@
 {
     midi_event_t *new_events;
     midi_event_t *event;
+    unsigned int last_event_type;
 
     track->num_events = 0;
     track->events = NULL;
@@ -418,6 +441,8 @@
 
     // Then the events:
 
+    last_event_type = 0;
+
     for (;;)
     {
         // Resize the track slightly larger to hold another event:
@@ -435,7 +460,7 @@
         // Read the next event:
 
         event = &track->events[track->num_events];
-        if (!ReadEvent(event, stream))
+        if (!ReadEvent(event, &last_event_type, stream))
         {
             return false;
         }
@@ -641,6 +666,11 @@
     for (i=0; i<track->num_events; ++i)
     {
         event = &track->events[i];
+
+        if (event->delta_time > 0)
+        {
+            printf("Delay: %i ticks\n", event->delta_time);
+        }
 
         printf("Event type: %s (%i)\n",
                MIDI_EventTypeToString(event->event_type),
--- a/src/midifile.h
+++ b/src/midifile.h
@@ -30,13 +30,13 @@
 
 typedef enum
 {
-    MIDI_EVENT_NOTE_OFF        = 0x8,
-    MIDI_EVENT_NOTE_ON         = 0x9,
-    MIDI_EVENT_AFTERTOUCH      = 0xa,
-    MIDI_EVENT_CONTROLLER      = 0xb,
-    MIDI_EVENT_PROGRAM_CHANGE  = 0xc,
-    MIDI_EVENT_CHAN_AFTERTOUCH = 0xd,
-    MIDI_EVENT_PITCH_BEND      = 0xe,
+    MIDI_EVENT_NOTE_OFF        = 0x80,
+    MIDI_EVENT_NOTE_ON         = 0x90,
+    MIDI_EVENT_AFTERTOUCH      = 0xa0,
+    MIDI_EVENT_CONTROLLER      = 0xb0,
+    MIDI_EVENT_PROGRAM_CHANGE  = 0xc0,
+    MIDI_EVENT_CHAN_AFTERTOUCH = 0xd0,
+    MIDI_EVENT_PITCH_BEND      = 0xe0,
 
     MIDI_EVENT_SYSEX           = 0xf0,
     MIDI_EVENT_SYSEX_SPLIT     = 0xf7,