123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- #include "native_midi_common.h"
- #include "SDL.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- typedef struct
- {
- Uint8 *data;
- int len;
- } MIDITrack;
- typedef struct
- {
- int division;
- int nTracks;
- MIDITrack *track;
- } MIDIFile;
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- #define BE_SHORT(x) (x)
- #define BE_LONG(x) (x)
- #else
- #define BE_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
- #define BE_LONG(x) ((((x)&0x0000FF)<<24) | \
- (((x)&0x00FF00)<<8) | \
- (((x)&0xFF0000)>>8) | \
- (((x)>>24)&0xFF))
- #endif
- static int GetVLQ(MIDITrack *track, int *currentPos)
- {
- int l = 0;
- Uint8 c;
- while(1)
- {
- c = track->data[*currentPos];
- (*currentPos)++;
- l += (c & 0x7f);
- if (!(c & 0x80))
- return l;
- l <<= 7;
- }
- }
- static MIDIEvent *CreateEvent(Uint32 time, Uint8 event, Uint8 a, Uint8 b)
- {
- MIDIEvent *newEvent;
- newEvent = calloc(1, sizeof(MIDIEvent));
- if (newEvent)
- {
- newEvent->time = time;
- newEvent->status = event;
- newEvent->data[0] = a;
- newEvent->data[1] = b;
- }
- else
- printf("Out of memory");
- return newEvent;
- }
- static MIDIEvent *MIDITracktoStream(MIDITrack *track)
- {
- Uint32 atime = 0;
- Uint32 len = 0;
- Uint8 event,type,a,b;
- Uint8 laststatus = 0;
- Uint8 lastchan = 0;
- int currentPos = 0;
- int end = 0;
- MIDIEvent *head = CreateEvent(0,0,0,0);
- MIDIEvent *currentEvent = head;
- while (!end)
- {
- if (currentPos >= track->len)
- break;
- atime += GetVLQ(track, ¤tPos);
- event = track->data[currentPos++];
-
-
- if (((event>>4) & 0x0F) == MIDI_STATUS_SYSEX)
- {
- if (event == 0xFF)
- {
- type = track->data[currentPos];
- currentPos++;
- switch(type)
- {
- case 0x2f:
- end = 1;
- case 0x51:
-
- break;
- }
- }
- else
- type = 0;
- len = GetVLQ(track, ¤tPos);
-
-
- currentEvent->next = CreateEvent(atime, event, type, 0);
- currentEvent = currentEvent->next;
- if (NULL == currentEvent)
- {
- FreeMIDIEventList(head);
- return NULL;
- }
- if (len)
- {
- currentEvent->extraLen = len;
- currentEvent->extraData = malloc(len);
- memcpy(currentEvent->extraData, &(track->data[currentPos]), len);
- currentPos += len;
- }
- }
- else
- {
- a = event;
- if (a & 0x80)
- {
-
- lastchan = a & 0x0F;
- laststatus = (a>>4) & 0x0F;
-
-
- a = track->data[currentPos++] & 0x7F;
- }
- switch(laststatus)
- {
- case MIDI_STATUS_NOTE_OFF:
- case MIDI_STATUS_NOTE_ON:
- case MIDI_STATUS_AFTERTOUCH:
- case MIDI_STATUS_CONTROLLER:
- case MIDI_STATUS_PITCH_WHEEL:
- b = track->data[currentPos++] & 0x7F;
- currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, b);
- currentEvent = currentEvent->next;
- if (NULL == currentEvent)
- {
- FreeMIDIEventList(head);
- return NULL;
- }
- break;
- case MIDI_STATUS_PROG_CHANGE:
- case MIDI_STATUS_PRESSURE:
- a &= 0x7f;
- currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, 0);
- currentEvent = currentEvent->next;
- if (NULL == currentEvent)
- {
- FreeMIDIEventList(head);
- return NULL;
- }
- break;
- default:
- break;
- }
- }
- }
-
- currentEvent = head->next;
- free(head);
- return currentEvent;
- }
- static MIDIEvent *MIDItoStream(MIDIFile *mididata)
- {
- MIDIEvent **track;
- MIDIEvent *head = CreateEvent(0,0,0,0);
- MIDIEvent *currentEvent = head;
- int trackID;
- if (NULL == head)
- return NULL;
-
- track = (MIDIEvent**) calloc(1, sizeof(MIDIEvent*) * mididata->nTracks);
- if (NULL == head)
- return NULL;
-
-
- for (trackID = 0; trackID < mididata->nTracks; trackID++)
- track[trackID] = MIDITracktoStream(&mididata->track[trackID]);
-
-
- while(1)
- {
- Uint32 lowestTime = INT_MAX;
- int currentTrackID = -1;
-
-
- for (trackID = 0; trackID < mididata->nTracks; trackID++)
- {
- if (track[trackID] && (track[trackID]->time < lowestTime))
- {
- currentTrackID = trackID;
- lowestTime = track[currentTrackID]->time;
- }
- }
-
-
- if (currentTrackID == -1)
- break;
-
- currentEvent->next = track[currentTrackID];
- track[currentTrackID] = track[currentTrackID]->next;
- currentEvent = currentEvent->next;
-
-
- lowestTime = 0;
- }
-
- currentEvent->next = 0;
- currentEvent = head->next;
- free(track);
- free(head);
- return currentEvent;
- }
- static int ReadMIDIFile(MIDIFile *mididata, SDL_RWops *rw)
- {
- int i = 0;
- Uint32 ID;
- Uint32 size;
- Uint16 format;
- Uint16 tracks;
- Uint16 division;
- if (!mididata)
- return 0;
- if (!rw)
- return 0;
-
- SDL_RWread(rw, &ID, 1, 4);
- if (BE_LONG(ID) != 'MThd')
- return 0;
-
-
- SDL_RWread(rw, &size, 1, 4);
- size = BE_LONG(size);
- if (size != 6)
- return 0;
-
-
- SDL_RWread(rw, &format, 1, 2);
- format = BE_SHORT(format);
- if (format != 0 && format != 1)
- return 0;
-
- SDL_RWread(rw, &tracks, 1, 2);
- tracks = BE_SHORT(tracks);
- mididata->nTracks = tracks;
-
-
- mididata->track = (MIDITrack*) calloc(1, sizeof(MIDITrack) * mididata->nTracks);
- if (NULL == mididata->track)
- {
- printf("Out of memory");
- goto bail;
- }
-
-
- SDL_RWread(rw, &division, 1, 2);
- mididata->division = BE_SHORT(division);
-
-
- for (i=0; i<tracks; i++)
- {
- SDL_RWread(rw, &ID, 1, 4);
- SDL_RWread(rw, &size, 1, 4);
- size = BE_LONG(size);
- mididata->track[i].len = size;
- mididata->track[i].data = malloc(size);
- if (NULL == mididata->track[i].data)
- {
- printf("Out of memory");
- goto bail;
- }
- SDL_RWread(rw, mididata->track[i].data, 1, size);
- }
- return 1;
- bail:
- for(;i >= 0; i--)
- {
- if (mididata->track[i].data)
- free(mididata->track[i].data);
- }
- return 0;
- }
- MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division)
- {
- MIDIFile *mididata = NULL;
- MIDIEvent *eventList;
- int trackID;
-
- mididata = calloc(1, sizeof(MIDIFile));
- if (!mididata)
- return NULL;
-
- if ( rw != NULL )
- {
-
- if ( ! ReadMIDIFile(mididata, rw))
- {
- free(mididata);
- return NULL;
- }
- }
- else
- {
- free(mididata);
- return NULL;
- }
-
- if (division)
- *division = mididata->division;
-
- eventList = MIDItoStream(mididata);
-
- for(trackID = 0; trackID < mididata->nTracks; trackID++)
- {
- if (mididata->track[trackID].data)
- free(mididata->track[trackID].data);
- }
- free(mididata->track);
- free(mididata);
-
- return eventList;
- }
- void FreeMIDIEventList(MIDIEvent *head)
- {
- MIDIEvent *cur, *next;
-
- cur = head;
- while (cur)
- {
- next = cur->next;
- if (cur->extraData)
- free (cur->extraData);
- free (cur);
- cur = next;
- }
- }
|