foxygit / doom Log in
commit 9b192c44f932542ccd835936d593c43ce3e9e9e3
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Apr 3 19:58:08 2009 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Apr 3 19:58:08 2009 +0000

    Fix up MIDI reading code; add test code.

    Subversion-branch: /branches/opl-branch
    Subversion-revision: 1494
---
 src/Makefile.am |   3 ++
 src/midifile.c  | 104 +++++++++++++++++++++++++++++++++++++++++++++++---------
 src/midifile.h  |  15 ++++----
 3 files changed, 98 insertions(+), 24 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 92095b5c..3874c35f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -195,3 +195,6 @@ icon.c : ../data/doom.ico

 endif

+midiread : midifile.c
+	$(CC) -DTEST $(CFLAGS) @LDFLAGS@ $^ -o $@
+
diff --git a/src/midifile.c b/src/midifile.c
index ed60958d..e4273c12 100644
--- a/src/midifile.c
+++ b/src/midifile.c
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <string.h>

+#include "doomdef.h"
 #include "doomtype.h"
 #include "i_swap.h"
 #include "midifile.h"
@@ -39,15 +40,15 @@ typedef struct
 {
     byte chunk_id[4];
     unsigned int chunk_size;
-} chunk_header_t;
+} PACKEDATTR chunk_header_t;

 typedef struct
 {
     chunk_header_t chunk_header;
     unsigned short format_type;
     unsigned short num_tracks;
-    unsigned int time_division;
-} midi_header_t;
+    unsigned short time_division;
+} PACKEDATTR midi_header_t;

 struct midi_file_s
 {
@@ -65,12 +66,15 @@ static boolean CheckChunkHeader(chunk_header_t *chunk,
 {
     boolean result;

-    result = (strcmp((char *) chunk->chunk_id, expected_id) == 0);
+    result = (memcmp((char *) chunk->chunk_id, expected_id, 4) == 0);

     if (!result)
     {
-        fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header\n",
-                        expected_id);
+        fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header, "
+                        "got '%c%c%c%c'\n",
+                        expected_id,
+                        chunk->chunk_id[0], chunk->chunk_id[1],
+                        chunk->chunk_id[2], chunk->chunk_id[3]);
     }

     return result;
@@ -80,24 +84,26 @@ static boolean CheckChunkHeader(chunk_header_t *chunk,

 static boolean ReadHeaderChunk(midi_file_t *file)
 {
-    size_t bytes_read;
+    size_t records_read;

-    bytes_read = fread(&file->header, sizeof(midi_header_t), 1, file->stream);
+    records_read = fread(&file->header, sizeof(midi_header_t), 1, file->stream);

-    if (bytes_read < sizeof(midi_header_t))
+    if (records_read < 1)
     {
         return false;
     }

     if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID)
-     || LONG(file->header.chunk_header.chunk_size) != 6)
+     || SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6)
     {
-        fprintf(stderr, "ReadHeaderChunk: Invalid MIDI chunk header!\n");
+        fprintf(stderr, "ReadHeaderChunk: Invalid MIDI chunk header! "
+                        "chunk_size=%i\n",
+                        SDL_SwapBE32(file->header.chunk_header.chunk_size));
         return false;
     }

-    if (SHORT(file->header.format_type) != 0
-     || SHORT(file->header.num_tracks) != 1)
+    if (SDL_SwapBE16(file->header.format_type) != 0
+     || SDL_SwapBE16(file->header.num_tracks) != 1)
     {
         fprintf(stderr, "ReadHeaderChunk: Only single track, "
                                         "type 0 MIDI files supported!\n");
@@ -111,12 +117,12 @@ static boolean ReadHeaderChunk(midi_file_t *file)

 static boolean ReadTrackChunk(midi_file_t *file)
 {
-    size_t bytes_read;
+    size_t records_read;
     chunk_header_t chunk_header;

-    bytes_read = fread(&chunk_header, sizeof(chunk_header_t), 1, file->stream);
+    records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, file->stream);

-    if (bytes_read < sizeof(chunk_header))
+    if (records_read < 1)
     {
         return false;
     }
@@ -126,7 +132,7 @@ static boolean ReadTrackChunk(midi_file_t *file)
         return false;
     }

-    file->data_len = LONG(chunk_header.chunk_size);
+    file->data_len = SDL_SwapBE32(chunk_header.chunk_size);

     return true;
 }
@@ -375,6 +381,8 @@ static boolean ReadMetaEvent(midi_file_t *file, midi_event_t *event)
 {
     byte b;

+    event->event_type = MIDI_EVENT_META;
+
     // Read meta event type:

     if (!ReadByte(file, &b))
@@ -464,3 +472,65 @@ boolean MIDI_ReadEvent(midi_file_t *file, midi_event_t *event)
     }
 }

+#ifdef TEST
+
+int main(int argc, char *argv[])
+{
+    midi_file_t *file;
+    midi_event_t event;
+
+    if (argc < 2)
+    {
+        printf("Usage: %s <filename>\n", argv[0]);
+        exit(1);
+    }
+
+    file = MIDI_OpenFile(argv[1]);
+
+    if (file == NULL)
+    {
+        fprintf(stderr, "Failed to open %s\n", argv[1]);
+        exit(1);
+    }
+
+    while (MIDI_ReadEvent(file, &event))
+    {
+        printf("Event type: %i\n", event.event_type);
+
+        switch(event.event_type)
+        {
+            case MIDI_EVENT_NOTE_OFF:
+            case MIDI_EVENT_NOTE_ON:
+            case MIDI_EVENT_AFTERTOUCH:
+            case MIDI_EVENT_CONTROLLER:
+            case MIDI_EVENT_PROGRAM_CHANGE:
+            case MIDI_EVENT_CHAN_AFTERTOUCH:
+            case MIDI_EVENT_PITCH_BEND:
+                printf("\tChannel: %i\n", event.data.channel.channel);
+                printf("\tParameter 1: %i\n", event.data.channel.param1);
+                printf("\tParameter 2: %i\n", event.data.channel.param2);
+                break;
+
+            case MIDI_EVENT_SYSEX:
+            case MIDI_EVENT_SYSEX_SPLIT:
+                printf("\tLength: %i\n", event.data.sysex.length);
+                break;
+
+            case MIDI_EVENT_META:
+                printf("\tMeta type: %i\n", event.data.meta.type);
+                printf("\tLength: %i\n", event.data.meta.length);
+                break;
+        }
+
+        if (event.event_type == MIDI_EVENT_META
+         && event.data.meta.type == MIDI_META_END_OF_TRACK)
+        {
+            break;
+        }
+    }
+
+    return 0;
+}
+
+#endif
+
diff --git a/src/midifile.h b/src/midifile.h
index d7df8b86..7928fdda 100644
--- a/src/midifile.h
+++ b/src/midifile.h
@@ -65,13 +65,14 @@ typedef enum
     MIDI_META_MARKER                = 0x6,
     MIDI_META_CUE_POINT             = 0x7,

-    MIDI_META_CHANNEL_PREFIX        = 0x8,
-    MIDI_META_END_OF_TRACK          = 0x9,
-    MIDI_META_SET_TEMPO             = 0xa,
-    MIDI_META_SMPTE_OFFSET          = 0xb,
-    MIDI_META_TIME_SIGNATURE        = 0xc,
-    MIDI_META_KEY_SIGNATURE         = 0xd,
-    MIDI_META_SEQUENCER_SPECIFIC    = 0xe,
+    MIDI_META_CHANNEL_PREFIX        = 0x20,
+    MIDI_META_END_OF_TRACK          = 0x2f,
+
+    MIDI_META_SET_TEMPO             = 0x51,
+    MIDI_META_SMPTE_OFFSET          = 0x54,
+    MIDI_META_TIME_SIGNATURE        = 0x58,
+    MIDI_META_KEY_SIGNATURE         = 0x59,
+    MIDI_META_SEQUENCER_SPECIFIC    = 0x7f,
 } midi_meta_event_type_t;

 typedef struct