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,