diff options
author | Vitaly Novichkov <admin@wohlnet.ru> | 2018-06-21 04:23:14 +0300 |
---|---|---|
committer | Vitaly Novichkov <admin@wohlnet.ru> | 2018-06-21 04:23:14 +0300 |
commit | 9f0f9e4e374798851da39335406ac4bafad81297 (patch) | |
tree | 28b744d0e52afc29c1d27f06b227e3101a8844a8 /src/adlmidi_xmi2mid.c | |
parent | a0fa0cded46bdc94293f02d4070a69bcae5478bb (diff) | |
download | libADLMIDI-9f0f9e4e374798851da39335406ac4bafad81297.tar.gz libADLMIDI-9f0f9e4e374798851da39335406ac4bafad81297.tar.bz2 libADLMIDI-9f0f9e4e374798851da39335406ac4bafad81297.zip |
Move MIDI sequencer into completely separated class
TODO:
- implement C bindings for most of class functions
- test it in work on any different synthesizer
Diffstat (limited to 'src/adlmidi_xmi2mid.c')
-rw-r--r-- | src/adlmidi_xmi2mid.c | 1106 |
1 files changed, 0 insertions, 1106 deletions
diff --git a/src/adlmidi_xmi2mid.c b/src/adlmidi_xmi2mid.c deleted file mode 100644 index 3389709..0000000 --- a/src/adlmidi_xmi2mid.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* - * XMIDI: Miles XMIDI to MID Library - * - * Copyright (C) 2001 Ryan Nunn - * Copyright (C) 2014 Bret Curtis - * Copyright (C) WildMIDI Developers 2015-2016 - * Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* XMIDI Converter */ - -#include <stddef.h> -#include <stdint.h> -#include <string.h> -#include <stdlib.h> - -#include "adlmidi_xmi2mid.h" - -/* Midi Status Bytes */ -#define MIDI_STATUS_NOTE_OFF 0x8 -#define MIDI_STATUS_NOTE_ON 0x9 -#define MIDI_STATUS_AFTERTOUCH 0xA -#define MIDI_STATUS_CONTROLLER 0xB -#define MIDI_STATUS_PROG_CHANGE 0xC -#define MIDI_STATUS_PRESSURE 0xD -#define MIDI_STATUS_PITCH_WHEEL 0xE -#define MIDI_STATUS_SYSEX 0xF - -typedef struct _midi_event { - int32_t time; - uint8_t status; - uint8_t data[2]; - uint32_t len; - uint8_t *buffer; - struct _midi_event *next; -} midi_event; - -typedef struct { - uint16_t type; - uint16_t tracks; -} midi_descriptor; - -struct xmi_ctx { - uint8_t *src, *src_ptr; - uint32_t srcsize; - uint32_t datastart; - uint8_t *dst, *dst_ptr; - uint32_t dstsize, dstrem; - uint32_t convert_type; - midi_descriptor info; - int bank127[16]; - midi_event **events; - signed short *timing; - midi_event *list; - midi_event *current; -}; - -/* forward declarations of private functions */ -static void DeleteEventList(midi_event *mlist); -static void CreateNewEvent(struct xmi_ctx *ctx, int32_t time); /* List manipulation */ -static int GetVLQ(struct xmi_ctx *ctx, uint32_t *quant); /* Variable length quantity */ -static int GetVLQ2(struct xmi_ctx *ctx, uint32_t *quant);/* Variable length quantity */ -static int PutVLQ(struct xmi_ctx *ctx, uint32_t value); /* Variable length quantity */ -static int ConvertEvent(struct xmi_ctx *ctx, - const int32_t time, const uint8_t status, const int size); -static int32_t ConvertSystemMessage(struct xmi_ctx *ctx, - const int32_t time, const uint8_t status); -static int32_t ConvertFiletoList(struct xmi_ctx *ctx); -static uint32_t ConvertListToMTrk(struct xmi_ctx *ctx, midi_event *mlist); -static int ParseXMI(struct xmi_ctx *ctx); -static int ExtractTracks(struct xmi_ctx *ctx); -static uint32_t ExtractTracksFromXmi(struct xmi_ctx *ctx); - -static uint32_t read1(struct xmi_ctx *ctx) -{ - uint8_t b0; - b0 = *ctx->src_ptr++; - return (b0); -} - -static uint32_t read2(struct xmi_ctx *ctx) -{ - uint8_t b0, b1; - b0 = *ctx->src_ptr++; - b1 = *ctx->src_ptr++; - return (b0 + ((uint32_t)b1 << 8)); -} - -static uint32_t read4(struct xmi_ctx *ctx) -{ - uint8_t b0, b1, b2, b3; - b3 = *ctx->src_ptr++; - b2 = *ctx->src_ptr++; - b1 = *ctx->src_ptr++; - b0 = *ctx->src_ptr++; - return (b0 + ((uint32_t)b1<<8) + ((uint32_t)b2<<16) + ((uint32_t)b3<<24)); -} - -static void copy(struct xmi_ctx *ctx, char *b, uint32_t len) -{ - memcpy(b, ctx->src_ptr, len); - ctx->src_ptr += len; -} - -#define DST_CHUNK 8192 -static void resize_dst(struct xmi_ctx *ctx) { - uint32_t pos = (uint32_t)(ctx->dst_ptr - ctx->dst); - ctx->dst = realloc(ctx->dst, ctx->dstsize + DST_CHUNK); - ctx->dstsize += DST_CHUNK; - ctx->dstrem += DST_CHUNK; - ctx->dst_ptr = ctx->dst + pos; -} - -static void write1(struct xmi_ctx *ctx, uint32_t val) -{ - if (ctx->dstrem < 1) - resize_dst(ctx); - *ctx->dst_ptr++ = val & 0xff; - ctx->dstrem--; -} - -static void write2(struct xmi_ctx *ctx, uint32_t val) -{ - if (ctx->dstrem < 2) - resize_dst(ctx); - *ctx->dst_ptr++ = (val>>8) & 0xff; - *ctx->dst_ptr++ = val & 0xff; - ctx->dstrem -= 2; -} - -static void write4(struct xmi_ctx *ctx, uint32_t val) -{ - if (ctx->dstrem < 4) - resize_dst(ctx); - *ctx->dst_ptr++ = (val>>24)&0xff; - *ctx->dst_ptr++ = (val>>16)&0xff; - *ctx->dst_ptr++ = (val>>8) & 0xff; - *ctx->dst_ptr++ = val & 0xff; - ctx->dstrem -= 4; -} - -static void seeksrc(struct xmi_ctx *ctx, uint32_t pos) { - ctx->src_ptr = ctx->src + pos; -} - -static void seekdst(struct xmi_ctx *ctx, uint32_t pos) { - ctx->dst_ptr = ctx->dst + pos; - while (ctx->dstsize < pos) - resize_dst(ctx); - ctx->dstrem = ctx->dstsize - pos; -} - -static void skipsrc(struct xmi_ctx *ctx, int32_t pos) { - ctx->src_ptr += pos; -} - -static void skipdst(struct xmi_ctx *ctx, int32_t pos) { - size_t newpos; - ctx->dst_ptr += pos; - newpos = ctx->dst_ptr - ctx->dst; - while (ctx->dstsize < newpos) - resize_dst(ctx); - ctx->dstrem = (uint32_t)(ctx->dstsize - newpos); -} - -static uint32_t getsrcsize(struct xmi_ctx *ctx) { - return (ctx->srcsize); -} - -static uint32_t getsrcpos(struct xmi_ctx *ctx) { - return (uint32_t)(ctx->src_ptr - ctx->src); -} - -static uint32_t getdstpos(struct xmi_ctx *ctx) { - return (uint32_t)(ctx->dst_ptr - ctx->dst); -} - -/* This is a default set of patches to convert from MT32 to GM - * The index is the MT32 Patch number and the value is the GM Patch - * This is only suitable for music that doesn't do timbre changes - * XMIDIs that contain Timbre changes will not convert properly. - */ -static const char mt32asgm[128] = { - 0, /* 0 Piano 1 */ - 1, /* 1 Piano 2 */ - 2, /* 2 Piano 3 (synth) */ - 4, /* 3 EPiano 1 */ - 4, /* 4 EPiano 2 */ - 5, /* 5 EPiano 3 */ - 5, /* 6 EPiano 4 */ - 3, /* 7 Honkytonk */ - 16, /* 8 Organ 1 */ - 17, /* 9 Organ 2 */ - 18, /* 10 Organ 3 */ - 16, /* 11 Organ 4 */ - 19, /* 12 Pipe Organ 1 */ - 19, /* 13 Pipe Organ 2 */ - 19, /* 14 Pipe Organ 3 */ - 21, /* 15 Accordion */ - 6, /* 16 Harpsichord 1 */ - 6, /* 17 Harpsichord 2 */ - 6, /* 18 Harpsichord 3 */ - 7, /* 19 Clavinet 1 */ - 7, /* 20 Clavinet 2 */ - 7, /* 21 Clavinet 3 */ - 8, /* 22 Celesta 1 */ - 8, /* 23 Celesta 2 */ - 62, /* 24 Synthbrass 1 (62) */ - 63, /* 25 Synthbrass 2 (63) */ - 62, /* 26 Synthbrass 3 Bank 8 */ - 63, /* 27 Synthbrass 4 Bank 8 */ - 38, /* 28 Synthbass 1 */ - 39, /* 29 Synthbass 2 */ - 38, /* 30 Synthbass 3 Bank 8 */ - 39, /* 31 Synthbass 4 Bank 8 */ - 88, /* 32 Fantasy */ - 90, /* 33 Harmonic Pan - No equiv closest is polysynth(90) :( */ - 52, /* 34 Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)??? */ - 92, /* 35 Glass */ - 97, /* 36 Soundtrack */ - 99, /* 37 Atmosphere */ - 14, /* 38 Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is! */ - 54, /* 39 FunnyVox, sounds alot like Bagpipe(109) and Shania(111) */ - 98, /* 40 EchoBell, no real equiv, sounds like Crystal(98) */ - 96, /* 41 IceRain */ - 68, /* 42 Oboe 2001, no equiv, just patching it to normal oboe(68) */ - 95, /* 43 EchoPans, no equiv, setting to SweepPad */ - 81, /* 44 DoctorSolo Bank 8 */ - 87, /* 45 SchoolDaze, no real equiv */ - 112,/* 46 Bell Singer */ - 80, /* 47 SquareWave */ - 48, /* 48 Strings 1 */ - 48, /* 49 Strings 2 - should be 49 */ - 44, /* 50 Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50 */ - 45, /* 51 Pizzicato Strings */ - 40, /* 52 Violin 1 */ - 40, /* 53 Violin 2 ? Viola */ - 42, /* 54 Cello 1 */ - 42, /* 55 Cello 2 */ - 43, /* 56 Contrabass */ - 46, /* 57 Harp 1 */ - 46, /* 58 Harp 2 */ - 24, /* 59 Guitar 1 (Nylon) */ - 25, /* 60 Guitar 2 (Steel) */ - 26, /* 61 Elec Guitar 1 */ - 27, /* 62 Elec Guitar 2 */ - 104,/* 63 Sitar */ - 32, /* 64 Acou Bass 1 */ - 32, /* 65 Acou Bass 2 */ - 33, /* 66 Elec Bass 1 */ - 34, /* 67 Elec Bass 2 */ - 36, /* 68 Slap Bass 1 */ - 37, /* 69 Slap Bass 2 */ - 35, /* 70 Fretless Bass 1 */ - 35, /* 71 Fretless Bass 2 */ - 73, /* 72 Flute 1 */ - 73, /* 73 Flute 2 */ - 72, /* 74 Piccolo 1 */ - 72, /* 75 Piccolo 2 */ - 74, /* 76 Recorder */ - 75, /* 77 Pan Pipes */ - 64, /* 78 Sax 1 */ - 65, /* 79 Sax 2 */ - 66, /* 80 Sax 3 */ - 67, /* 81 Sax 4 */ - 71, /* 82 Clarinet 1 */ - 71, /* 83 Clarinet 2 */ - 68, /* 84 Oboe */ - 69, /* 85 English Horn (Cor Anglais) */ - 70, /* 86 Bassoon */ - 22, /* 87 Harmonica */ - 56, /* 88 Trumpet 1 */ - 56, /* 89 Trumpet 2 */ - 57, /* 90 Trombone 1 */ - 57, /* 91 Trombone 2 */ - 60, /* 92 French Horn 1 */ - 60, /* 93 French Horn 2 */ - 58, /* 94 Tuba */ - 61, /* 95 Brass Section 1 */ - 61, /* 96 Brass Section 2 */ - 11, /* 97 Vibes 1 */ - 11, /* 98 Vibes 2 */ - 99, /* 99 Syn Mallet Bank 1 */ - 112,/* 100 WindBell no real equiv Set to TinkleBell(112) */ - 9, /* 101 Glockenspiel */ - 14, /* 102 Tubular Bells */ - 13, /* 103 Xylophone */ - 12, /* 104 Marimba */ - 107,/* 105 Koto */ - 111,/* 106 Sho?? set to Shanai(111) */ - 77, /* 107 Shakauhachi */ - 78, /* 108 Whistle 1 */ - 78, /* 109 Whistle 2 */ - 76, /* 110 Bottle Blow */ - 76, /* 111 Breathpipe no real equiv set to bottle blow(76) */ - 47, /* 112 Timpani */ - 117,/* 113 Melodic Tom */ - 116,/* 114 Deap Snare no equiv, set to Taiko(116) */ - 118,/* 115 Electric Perc 1 */ - 118,/* 116 Electric Perc 2 */ - 116,/* 117 Taiko */ - 115,/* 118 Taiko Rim, no real equiv, set to Woodblock(115) */ - 119,/* 119 Cymbal, no real equiv, set to reverse cymbal(119) */ - 115,/* 120 Castanets, no real equiv, in GM set to Woodblock(115) */ - 112,/* 121 Triangle, no real equiv, set to TinkleBell(112) */ - 55, /* 122 Orchestral Hit */ - 124,/* 123 Telephone */ - 123,/* 124 BirdTweet */ - 94, /* 125 Big Notes Pad no equiv, set to halo pad (94) */ - 98, /* 126 Water Bell set to Crystal Pad(98) */ - 121 /* 127 Jungle Tune set to Breath Noise */ -}; - -/* Same as above, except include patch changes - * so GS instruments can be used */ -static const char mt32asgs[256] = { - 0, 0, /* 0 Piano 1 */ - 1, 0, /* 1 Piano 2 */ - 2, 0, /* 2 Piano 3 (synth) */ - 4, 0, /* 3 EPiano 1 */ - 4, 0, /* 4 EPiano 2 */ - 5, 0, /* 5 EPiano 3 */ - 5, 0, /* 6 EPiano 4 */ - 3, 0, /* 7 Honkytonk */ - 16, 0, /* 8 Organ 1 */ - 17, 0, /* 9 Organ 2 */ - 18, 0, /* 10 Organ 3 */ - 16, 0, /* 11 Organ 4 */ - 19, 0, /* 12 Pipe Organ 1 */ - 19, 0, /* 13 Pipe Organ 2 */ - 19, 0, /* 14 Pipe Organ 3 */ - 21, 0, /* 15 Accordion */ - 6, 0, /* 16 Harpsichord 1 */ - 6, 0, /* 17 Harpsichord 2 */ - 6, 0, /* 18 Harpsichord 3 */ - 7, 0, /* 19 Clavinet 1 */ - 7, 0, /* 20 Clavinet 2 */ - 7, 0, /* 21 Clavinet 3 */ - 8, 0, /* 22 Celesta 1 */ - 8, 0, /* 23 Celesta 2 */ - 62, 0, /* 24 Synthbrass 1 (62) */ - 63, 0, /* 25 Synthbrass 2 (63) */ - 62, 0, /* 26 Synthbrass 3 Bank 8 */ - 63, 0, /* 27 Synthbrass 4 Bank 8 */ - 38, 0, /* 28 Synthbass 1 */ - 39, 0, /* 29 Synthbass 2 */ - 38, 0, /* 30 Synthbass 3 Bank 8 */ - 39, 0, /* 31 Synthbass 4 Bank 8 */ - 88, 0, /* 32 Fantasy */ - 90, 0, /* 33 Harmonic Pan - No equiv closest is polysynth(90) :( */ - 52, 0, /* 34 Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)??? */ - 92, 0, /* 35 Glass */ - 97, 0, /* 36 Soundtrack */ - 99, 0, /* 37 Atmosphere */ - 14, 0, /* 38 Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is! */ - 54, 0, /* 39 FunnyVox, sounds alot like Bagpipe(109) and Shania(111) */ - 98, 0, /* 40 EchoBell, no real equiv, sounds like Crystal(98) */ - 96, 0, /* 41 IceRain */ - 68, 0, /* 42 Oboe 2001, no equiv, just patching it to normal oboe(68) */ - 95, 0, /* 43 EchoPans, no equiv, setting to SweepPad */ - 81, 0, /* 44 DoctorSolo Bank 8 */ - 87, 0, /* 45 SchoolDaze, no real equiv */ - 112, 0, /* 46 Bell Singer */ - 80, 0, /* 47 SquareWave */ - 48, 0, /* 48 Strings 1 */ - 48, 0, /* 49 Strings 2 - should be 49 */ - 44, 0, /* 50 Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50 */ - 45, 0, /* 51 Pizzicato Strings */ - 40, 0, /* 52 Violin 1 */ - 40, 0, /* 53 Violin 2 ? Viola */ - 42, 0, /* 54 Cello 1 */ - 42, 0, /* 55 Cello 2 */ - 43, 0, /* 56 Contrabass */ - 46, 0, /* 57 Harp 1 */ - 46, 0, /* 58 Harp 2 */ - 24, 0, /* 59 Guitar 1 (Nylon) */ - 25, 0, /* 60 Guitar 2 (Steel) */ - 26, 0, /* 61 Elec Guitar 1 */ - 27, 0, /* 62 Elec Guitar 2 */ - 104, 0, /* 63 Sitar */ - 32, 0, /* 64 Acou Bass 1 */ - 32, 0, /* 65 Acou Bass 2 */ - 33, 0, /* 66 Elec Bass 1 */ - 34, 0, /* 67 Elec Bass 2 */ - 36, 0, /* 68 Slap Bass 1 */ - 37, 0, /* 69 Slap Bass 2 */ - 35, 0, /* 70 Fretless Bass 1 */ - 35, 0, /* 71 Fretless Bass 2 */ - 73, 0, /* 72 Flute 1 */ - 73, 0, /* 73 Flute 2 */ - 72, 0, /* 74 Piccolo 1 */ - 72, 0, /* 75 Piccolo 2 */ - 74, 0, /* 76 Recorder */ - 75, 0, /* 77 Pan Pipes */ - 64, 0, /* 78 Sax 1 */ - 65, 0, /* 79 Sax 2 */ - 66, 0, /* 80 Sax 3 */ - 67, 0, /* 81 Sax 4 */ - 71, 0, /* 82 Clarinet 1 */ - 71, 0, /* 83 Clarinet 2 */ - 68, 0, /* 84 Oboe */ - 69, 0, /* 85 English Horn (Cor Anglais) */ - 70, 0, /* 86 Bassoon */ - 22, 0, /* 87 Harmonica */ - 56, 0, /* 88 Trumpet 1 */ - 56, 0, /* 89 Trumpet 2 */ - 57, 0, /* 90 Trombone 1 */ - 57, 0, /* 91 Trombone 2 */ - 60, 0, /* 92 French Horn 1 */ - 60, 0, /* 93 French Horn 2 */ - 58, 0, /* 94 Tuba */ - 61, 0, /* 95 Brass Section 1 */ - 61, 0, /* 96 Brass Section 2 */ - 11, 0, /* 97 Vibes 1 */ - 11, 0, /* 98 Vibes 2 */ - 99, 0, /* 99 Syn Mallet Bank 1 */ - 112, 0, /* 100 WindBell no real equiv Set to TinkleBell(112) */ - 9, 0, /* 101 Glockenspiel */ - 14, 0, /* 102 Tubular Bells */ - 13, 0, /* 103 Xylophone */ - 12, 0, /* 104 Marimba */ - 107, 0, /* 105 Koto */ - 111, 0, /* 106 Sho?? set to Shanai(111) */ - 77, 0, /* 107 Shakauhachi */ - 78, 0, /* 108 Whistle 1 */ - 78, 0, /* 109 Whistle 2 */ - 76, 0, /* 110 Bottle Blow */ - 76, 0, /* 111 Breathpipe no real equiv set to bottle blow(76) */ - 47, 0, /* 112 Timpani */ - 117, 0, /* 113 Melodic Tom */ - 116, 0, /* 114 Deap Snare no equiv, set to Taiko(116) */ - 118, 0, /* 115 Electric Perc 1 */ - 118, 0, /* 116 Electric Perc 2 */ - 116, 0, /* 117 Taiko */ - 115, 0, /* 118 Taiko Rim, no real equiv, set to Woodblock(115) */ - 119, 0, /* 119 Cymbal, no real equiv, set to reverse cymbal(119) */ - 115, 0, /* 120 Castanets, no real equiv, in GM set to Woodblock(115) */ - 112, 0, /* 121 Triangle, no real equiv, set to TinkleBell(112) */ - 55, 0, /* 122 Orchestral Hit */ - 124, 0, /* 123 Telephone */ - 123, 0, /* 124 BirdTweet */ - 94, 0, /* 125 Big Notes Pad no equiv, set to halo pad (94) */ - 98, 0, /* 126 Water Bell set to Crystal Pad(98) */ - 121, 0 /* 127 Jungle Tune set to Breath Noise */ -}; - -int AdlMidi_xmi2midi(uint8_t *in, uint32_t insize, - uint8_t **out, uint32_t *outsize, - uint32_t convert_type) { - struct xmi_ctx ctx; - unsigned int i; - int ret = -1; - - if (convert_type > XMIDI_CONVERT_MT32_TO_GS) { - /*_WM_ERROR_NEW("%s:%i: %d is an invalid conversion type.", __FUNCTION__, __LINE__, convert_type);*/ - return (ret); - } - - memset(&ctx, 0, sizeof(struct xmi_ctx)); - ctx.src = ctx.src_ptr = in; - ctx.srcsize = insize; - ctx.convert_type = convert_type; - - if (ParseXMI(&ctx) < 0) { - /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0);*/ - goto _end; - } - - if (ExtractTracks(&ctx) < 0) { - /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MIDI, NULL, 0);*/ - goto _end; - } - - ctx.dst = malloc(DST_CHUNK); - ctx.dst_ptr = ctx.dst; - ctx.dstsize = DST_CHUNK; - ctx.dstrem = DST_CHUNK; - - /* Header is 14 bytes long and add the rest as well */ - write1(&ctx, 'M'); - write1(&ctx, 'T'); - write1(&ctx, 'h'); - write1(&ctx, 'd'); - - write4(&ctx, 6); - - write2(&ctx, ctx.info.type); - write2(&ctx, ctx.info.tracks); - write2(&ctx, ctx.timing[0]);/* write divisions from track0 */ - - for (i = 0; i < ctx.info.tracks; i++) - ConvertListToMTrk(&ctx, ctx.events[i]); - *out = ctx.dst; - *outsize = ctx.dstsize - ctx.dstrem; - ret = 0; - -_end: /* cleanup */ - if (ret < 0) { - free(ctx.dst); - *out = NULL; - *outsize = 0; - } - if (ctx.events) { - for (i = 0; i < ctx.info.tracks; i++) - DeleteEventList(ctx.events[i]); - free(ctx.events); - } - free(ctx.timing); - - return (ret); -} - -static void DeleteEventList(midi_event *mlist) { - midi_event *event; - midi_event *next; - - next = mlist; - - while ((event = next) != NULL) { - next = event->next; - free(event->buffer); - free(event); - } -} - -/* Sets current to the new event and updates list */ -static void CreateNewEvent(struct xmi_ctx *ctx, int32_t time) { - if (!ctx->list) { - ctx->list = ctx->current = calloc(1, sizeof(midi_event)); - ctx->current->time = (time < 0)? 0 : time; - return; - } - - if (time < 0) { - midi_event *event = calloc(1, sizeof(midi_event)); - event->next = ctx->list; - ctx->list = ctx->current = event; - return; - } - - if (ctx->current->time > time) - ctx->current = ctx->list; - - while (ctx->current->next) { - if (ctx->current->next->time > time) { - midi_event *event = calloc(1, sizeof(midi_event)); - event->next = ctx->current->next; - ctx->current->next = event; - ctx->current = event; - ctx->current->time = time; - return; - } - - ctx->current = ctx->current->next; - } - - ctx->current->next = calloc(1, sizeof(midi_event)); - ctx->current = ctx->current->next; - ctx->current->time = time; -} - -/* Conventional Variable Length Quantity */ -static int GetVLQ(struct xmi_ctx *ctx, uint32_t *quant) { - int i; - uint32_t data; - - *quant = 0; - for (i = 0; i < 4; i++) { - data = read1(ctx); - *quant <<= 7; - *quant |= data & 0x7F; - - if (!(data & 0x80)) { - i++; - break; - } - } - return (i); -} - -/* XMIDI Delta Variable Length Quantity */ -static int GetVLQ2(struct xmi_ctx *ctx, uint32_t *quant) { - int i; - int32_t data; - - *quant = 0; - for (i = 0; i < 4; i++) { - data = read1(ctx); - if (data & 0x80) { - skipsrc(ctx, -1); - break; - } - *quant += data; - } - return (i); -} - -static int PutVLQ(struct xmi_ctx *ctx, uint32_t value) { - int32_t buffer; - int i = 1, j; - buffer = value & 0x7F; - while (value >>= 7) { - buffer <<= 8; - buffer |= ((value & 0x7F) | 0x80); - i++; - } - for (j = 0; j < i; j++) { - write1(ctx, buffer & 0xFF); - buffer >>= 8; - } - - return (i); -} - -/* Converts Events - * - * Source is at the first data byte - * size 1 is single data byte - * size 2 is dual data byte - * size 3 is XMI Note on - * Returns bytes converted */ -static int ConvertEvent(struct xmi_ctx *ctx, const int32_t time, - const uint8_t status, const int size) { - uint32_t delta = 0; - int32_t data; - midi_event *prev; - int i; - - data = read1(ctx); - - /*HACK!*/ - if (((status >> 4) == 0xB) && (status & 0xF) != 9 && (data == 114)) { - data = 32; /*Change XMI 114 controller into XG bank*/ - } - - /* Bank changes are handled here */ - if ((status >> 4) == 0xB && data == 0) { - data = read1(ctx); - - ctx->bank127[status & 0xF] = 0; - - if ( ctx->convert_type == XMIDI_CONVERT_MT32_TO_GM || - ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS || - ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127 || - (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127DRUM - && (status & 0xF) == 9) ) - return (2); - - CreateNewEvent(ctx, time); - ctx->current->status = status; - ctx->current->data[0] = 0; - ctx->current->data[1] = data == 127 ? 0 : data;/*HACK:*/ - - if (ctx->convert_type == XMIDI_CONVERT_GS127_TO_GS && data == 127) - ctx->bank127[status & 0xF] = 1; - - return (2); - } - - /* Handling for patch change mt32 conversion, probably should go elsewhere */ - if ((status >> 4) == 0xC && (status&0xF) != 9 - && ctx->convert_type != XMIDI_CONVERT_NOCONVERSION) - { - if (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GM) - { - data = mt32asgm[data]; - } - else if ((ctx->convert_type == XMIDI_CONVERT_GS127_TO_GS && ctx->bank127[status&0xF]) || - ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS || - ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127DRUM) - { - CreateNewEvent (ctx, time); - ctx->current->status = 0xB0 | (status&0xF); - ctx->current->data[0] = 0; - ctx->current->data[1] = mt32asgs[data*2+1]; - - data = mt32asgs[data*2]; - } - else if (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127) - { - CreateNewEvent (ctx, time); - ctx->current->status = 0xB0 | (status&0xF); - ctx->current->data[0] = 0; - ctx->current->data[1] = 127; - } - } - /* Drum track handling */ - else if ((status >> 4) == 0xC && (status&0xF) == 9 && - (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127DRUM || ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127)) - { - CreateNewEvent (ctx, time); - ctx->current->status = 0xB9; - ctx->current->data[0] = 0; - ctx->current->data[1] = 127; - } - - CreateNewEvent(ctx, time); - ctx->current->status = status; - - ctx->current->data[0] = data; - - if (size == 1) - return (1); - - ctx->current->data[1] = read1(ctx); - - if (size == 2) - return (2); - - /* XMI Note On handling */ - prev = ctx->current; - i = GetVLQ(ctx, &delta); - CreateNewEvent(ctx, time + delta * 3); - - ctx->current->status = status; - ctx->current->data[0] = data; - ctx->current->data[1] = 0; - ctx->current = prev; - - return (i + 2); -} - -/* Simple routine to convert system messages */ -static int32_t ConvertSystemMessage(struct xmi_ctx *ctx, const int32_t time, - const uint8_t status) { - int32_t i = 0; - - CreateNewEvent(ctx, time); - ctx->current->status = status; - - /* Handling of Meta events */ - if (status == 0xFF) { - ctx->current->data[0] = read1(ctx); - i++; - } - - i += GetVLQ(ctx, &ctx->current->len); - - if (!ctx->current->len) - return (i); - - ctx->current->buffer = malloc(sizeof(uint8_t)*ctx->current->len); - copy(ctx, (char *) ctx->current->buffer, ctx->current->len); - - return (i + ctx->current->len); -} - -/* XMIDI and Midi to List - * Returns XMIDI PPQN */ -static int32_t ConvertFiletoList(struct xmi_ctx *ctx) { - int32_t time = 0; - uint32_t data; - int32_t end = 0; - int32_t tempo = 500000; - int32_t tempo_set = 0; - uint32_t status = 0; - uint32_t file_size = getsrcsize(ctx); - - /* Set Drum track to correct setting if required */ - if (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127) { - CreateNewEvent(ctx, 0); - ctx->current->status = 0xB9; - ctx->current->data[0] = 0; - ctx->current->data[1] = 127; - } - - while (!end && getsrcpos(ctx) < file_size) { - GetVLQ2(ctx, &data); - time += data * 3; - - status = read1(ctx); - - switch (status >> 4) { - case MIDI_STATUS_NOTE_ON: - ConvertEvent(ctx, time, status, 3); - break; - - /* 2 byte data */ - case MIDI_STATUS_NOTE_OFF: - case MIDI_STATUS_AFTERTOUCH: - case MIDI_STATUS_CONTROLLER: - case MIDI_STATUS_PITCH_WHEEL: - ConvertEvent(ctx, time, status, 2); - break; - - /* 1 byte data */ - case MIDI_STATUS_PROG_CHANGE: - case MIDI_STATUS_PRESSURE: - ConvertEvent(ctx, time, status, 1); - break; - - case MIDI_STATUS_SYSEX: - if (status == 0xFF) { - int32_t pos = getsrcpos(ctx); - uint32_t dat = read1(ctx); - - if (dat == 0x2F) /* End */ - end = 1; - else if (dat == 0x51 && !tempo_set) /* Tempo. Need it for PPQN */ - { - skipsrc(ctx, 1); - tempo = read1(ctx) << 16; - tempo += read1(ctx) << 8; - tempo += read1(ctx); - tempo *= 3; - tempo_set = 1; - } else if (dat == 0x51 && tempo_set) /* Skip any other tempo changes */ - { - GetVLQ(ctx, &dat); - skipsrc(ctx, dat); - break; - } - - seeksrc(ctx, pos); - } - ConvertSystemMessage(ctx, time, status); - break; - - default: - break; - } - } - return ((tempo * 3) / 25000); -} - -/* Converts and event list to a MTrk - * Returns bytes of the array - * buf can be NULL */ -static uint32_t ConvertListToMTrk(struct xmi_ctx *ctx, midi_event *mlist) { - int32_t time = 0; - midi_event *event; - uint32_t delta; - uint8_t last_status = 0; - uint32_t i = 8; - uint32_t j; - uint32_t size_pos, cur_pos; - int end = 0; - - write1(ctx, 'M'); - write1(ctx, 'T'); - write1(ctx, 'r'); - write1(ctx, 'k'); - - size_pos = getdstpos(ctx); - skipdst(ctx, 4); - - for (event = mlist; event && !end; event = event->next) { - delta = (event->time - time); - time = event->time; - - i += PutVLQ(ctx, delta); - - if ((event->status != last_status) || (event->status >= 0xF0)) { - write1(ctx, event->status); - i++; - } - - last_status = event->status; - - switch (event->status >> 4) { - /* 2 bytes data - * Note off, Note on, Aftertouch, Controller and Pitch Wheel */ - case 0x8: - case 0x9: - case 0xA: - case 0xB: - case 0xE: - write1(ctx, event->data[0]); - write1(ctx, event->data[1]); - i += 2; - break; - - /* 1 bytes data - * Program Change and Channel Pressure */ - case 0xC: - case 0xD: - write1(ctx, event->data[0]); - i++; - break; - - /* Variable length - * SysEx */ - case 0xF: - if (event->status == 0xFF) { - if (event->data[0] == 0x2f) - end = 1; - write1(ctx, event->data[0]); - i++; - } - i += PutVLQ(ctx, event->len); - if (event->len) { - for (j = 0; j < event->len; j++) { - write1(ctx, event->buffer[j]); - i++; - } - } - break; - - /* Never occur */ - default: - /*_WM_DEBUG_MSG("%s: unrecognized event", __FUNCTION__);*/ - break; - } - } - - cur_pos = getdstpos(ctx); - seekdst(ctx, size_pos); - write4(ctx, i - 8); - seekdst(ctx, cur_pos); - - return (i); -} - -/* Assumes correct xmidi */ -static uint32_t ExtractTracksFromXmi(struct xmi_ctx *ctx) { - uint32_t num = 0; - signed short ppqn; - uint32_t len = 0; - int32_t begin; - char buf[32]; - - while (getsrcpos(ctx) < getsrcsize(ctx) && num != ctx->info.tracks) { - /* Read first 4 bytes of name */ - copy(ctx, buf, 4); - len = read4(ctx); - - /* Skip the FORM entries */ - if (!memcmp(buf, "FORM", 4)) { - skipsrc(ctx, 4); - copy(ctx, buf, 4); - len = read4(ctx); - } - - if (memcmp(buf, "EVNT", 4)) { - skipsrc(ctx, (len + 1) & ~1); - continue; - } - - ctx->list = NULL; - begin = getsrcpos(ctx); - - /* Convert it */ - if (!(ppqn = ConvertFiletoList(ctx))) { - /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, NULL, 0);*/ - break; - } - ctx->timing[num] = ppqn; - ctx->events[num] = ctx->list; - - /* Increment Counter */ - num++; - - /* go to start of next track */ - seeksrc(ctx, begin + ((len + 1) & ~1)); - } - - /* Return how many were converted */ - return (num); -} - -static int ParseXMI(struct xmi_ctx *ctx) { - uint32_t i; - uint32_t start; - uint32_t len; - uint32_t chunk_len; - uint32_t file_size; - char buf[32]; - - file_size = getsrcsize(ctx); - if (getsrcpos(ctx) + 8 > file_size) { -badfile: /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);*/ - return (-1); - } - - /* Read first 4 bytes of header */ - copy(ctx, buf, 4); - - /* Could be XMIDI */ - if (!memcmp(buf, "FORM", 4)) { - /* Read length of */ - len = read4(ctx); - - start = getsrcpos(ctx); - if (start + 4 > file_size) - goto badfile; - - /* Read 4 bytes of type */ - copy(ctx, buf, 4); - - /* XDIRless XMIDI, we can handle them here. */ - if (!memcmp(buf, "XMID", 4)) { - /*_WM_DEBUG_MSG("Warning: XMIDI without XDIR");*/ - ctx->info.tracks = 1; - } - /* Not an XMIDI that we recognise */ - else if (memcmp(buf, "XDIR", 4)) { - goto badfile; - } - else { /* Seems Valid */ - ctx->info.tracks = 0; - - for (i = 4; i < len; i++) { - /* check too short files */ - if (getsrcpos(ctx) + 10 > file_size) - break; - - /* Read 4 bytes of type */ - copy(ctx, buf, 4); - - /* Read length of chunk */ - chunk_len = read4(ctx); - - /* Add eight bytes */ - i += 8; - - if (memcmp(buf, "INFO", 4)) { - /* Must align */ - skipsrc(ctx, (chunk_len + 1) & ~1); - i += (chunk_len + 1) & ~1; - continue; - } - - /* Must be at least 2 bytes long */ - if (chunk_len < 2) - break; - - ctx->info.tracks = read2(ctx); - break; - } - - /* Didn't get to fill the header */ - if (ctx->info.tracks == 0) { - goto badfile; - } - - /* Ok now to start part 2 - * Goto the right place */ - seeksrc(ctx, start + ((len + 1) & ~1)); - if (getsrcpos(ctx) + 12 > file_size) - goto badfile; - - /* Read 4 bytes of type */ - copy(ctx, buf, 4); - - if (memcmp(buf, "CAT ", 4)) { - /*_WM_ERROR_NEW("XMI error: expected \"CAT \", found \"%c%c%c%c\".", - buf[0], buf[1], buf[2], buf[3]);*/ - return (-1); - } - - /* Now read length of this track */ - read4(ctx); - - /* Read 4 bytes of type */ - copy(ctx, buf, 4); - - if (memcmp(buf, "XMID", 4)) { - /*_WM_ERROR_NEW("XMI error: expected \"XMID\", found \"%c%c%c%c\".", - buf[0], buf[1], buf[2], buf[3]);*/ - return (-1); - } - - /* Valid XMID */ - ctx->datastart = getsrcpos(ctx); - return (0); - } - } - - return (-1); -} - -static int ExtractTracks(struct xmi_ctx *ctx) { - uint32_t i; - - ctx->events = calloc(ctx->info.tracks, sizeof(midi_event*)); - ctx->timing = calloc(ctx->info.tracks, sizeof(int16_t)); - /* type-2 for multi-tracks, type-0 otherwise */ - ctx->info.type = (ctx->info.tracks > 1)? 2 : 0; - - seeksrc(ctx, ctx->datastart); - i = ExtractTracksFromXmi(ctx); - - if (i != ctx->info.tracks) { - /*_WM_ERROR_NEW("XMI error: extracted only %u out of %u tracks from XMIDI", - ctx->info.tracks, i);*/ - return (-1); - } - - return (0); -} - |