1 /*
2  * MUS2MIDI: MUS to MIDI Library
3  *
4  * Copyright (C) 2014  Bret Curtis
5  * Copyright (C) WildMIDI Developers  2015-2016
6  * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA  02110-1301, USA.
22  */
23 
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdint.h>
28 
29 #ifdef __DJGPP__
30 typedef signed char     int8_t;
31 typedef unsigned char   uint8_t;
32 typedef signed short    int16_t;
33 typedef unsigned short  uint16_t;
34 typedef signed long     int32_t;
35 typedef unsigned long   uint32_t;
36 #endif
37 
38 #define MUS_FREQUENCY   140 /* default Hz or BPM */
39 
40 #if 0 /* older units: */
41 #define MUS_TEMPO       0x001aa309 /* MPQN: 60000000 / 34.37Hz = 1745673 */
42 #define MUS_DIVISION    0x0059 /* 89 -- used by many mus2midi converters */
43 #endif
44 
45 #define MUS_TEMPO       0x00068A1B /* MPQN: 60000000 / 140BPM (140Hz) = 428571 */
46                 /*  0x000D1436 -> MPQN: 60000000 /  70BPM  (70Hz) = 857142 */
47 
48 #define MUS_DIVISION    0x0101 /* 257 for 140Hz files with a 140MPQN */
49                 /*  0x0088 -> 136 for  70Hz files with a 140MPQN */
50                 /*  0x010B -> 267 for  70hz files with a 70MPQN  */
51                 /*  0x01F9 -> 505 for 140hz files with a 70MPQN  */
52 
53 /* New
54  * QLS: MPQN/1000000 = 0.428571
55  * TDPS: QLS/PPQN = 0.428571/136 = 0.003151257
56  * PPQN: 136
57  *
58  * QLS: MPQN/1000000 = 0.428571
59  * TDPS: QLS/PPQN = 0.428571/257 = 0.001667591
60  * PPQN: 257
61  *
62  * QLS: MPQN/1000000 = 0.857142
63  * TDPS: QLS/PPQN = 0.857142/267 = 0.00321027
64  * PPQN: 267
65  *
66  * QLS: MPQN/1000000 = 0.857142
67  * TDPS: QLS/PPQN = 0.857142/505 = 0.001697311
68  * PPQN: 505
69  *
70  * Old
71  * QLS: MPQN/1000000 = 1.745673
72  * TDPS: QLS/PPQN = 1.745673 / 89 = 0.019614303 (seconds per tick)
73  * PPQN: (TDPS = QLS/PPQN) (0.019614303 = 1.745673/PPQN) (0.019614303*PPQN = 1.745673) (PPQN = 89.000001682)
74  *
75  */
76 
77 #define MUSEVENT_KEYOFF             0
78 #define MUSEVENT_KEYON              1
79 #define MUSEVENT_PITCHWHEEL         2
80 #define MUSEVENT_CHANNELMODE        3
81 #define MUSEVENT_CONTROLLERCHANGE   4
82 #define MUSEVENT_END                6
83 
84 #define MUS_MIDI_MAXCHANNELS        16
85 
86 static char MUS_ID[] = { 'M', 'U', 'S', 0x1A };
87 
88 static uint8_t mus_midimap[] =
89 {/* MIDI  Number  Description */
90     0,    /* 0    program change */
91     0,    /* 1    bank selection */
92     0x01, /* 2    Modulation pot (frequency vibrato depth) */
93     0x07, /* 3    Volume: 0-silent, ~100-normal, 127-loud */
94     0x0A, /* 4    Pan (balance) pot: 0-left, 64-center (default), 127-right */
95     0x0B, /* 5    Expression pot */
96     0x5B, /* 6    Reverb depth */
97     0x5D, /* 7    Chorus depth */
98     0x40, /* 8    Sustain pedal */
99     0x43, /* 9    Soft pedal */
100     0x78, /* 10   All sounds off */
101     0x7B, /* 11   All notes off */
102     0x7E, /* 12   Mono (use numchannels + 1) */
103     0x7F, /* 13   Poly */
104     0x79, /* 14   reset all controllers */
105 };
106 
107 typedef struct MUSHeader {
108     char ID[4];             /* identifier: "MUS" 0x1A */
109     uint16_t scoreLen;
110     uint16_t scoreStart;
111     uint16_t channels;      /* count of primary channels */
112     uint16_t sec_channels;  /* count of secondary channels */
113     uint16_t instrCnt;
114 } MUSHeader ;
115 #define MUS_HEADERSIZE 14
116 
117 typedef struct MidiHeaderChunk {
118     char name[4];
119     int32_t length;
120     int16_t format; /* make 0 */
121     int16_t ntracks;/* make 1 */
122     int16_t division; /* 0xe250 ?? */
123 } MidiHeaderChunk;
124 #define MIDI_HEADERSIZE 14
125 
126 typedef struct MidiTrackChunk {
127     char name[4];
128     int32_t length;
129 } MidiTrackChunk;
130 #define TRK_CHUNKSIZE 8
131 
132 struct mus_ctx {
133     uint8_t *src, *src_ptr;
134     uint32_t srcsize;
135     uint32_t datastart;
136     uint8_t *dst, *dst_ptr;
137     uint32_t dstsize, dstrem;
138 };
139 
140 #define DST_CHUNK 8192
mus2mid_resize_dst(struct mus_ctx * ctx)141 static void mus2mid_resize_dst(struct mus_ctx *ctx) {
142     uint32_t pos = (uint32_t)(ctx->dst_ptr - ctx->dst);
143     ctx->dst = (uint8_t *)realloc(ctx->dst, ctx->dstsize + DST_CHUNK);
144     ctx->dstsize += DST_CHUNK;
145     ctx->dstrem += DST_CHUNK;
146     ctx->dst_ptr = ctx->dst + pos;
147 }
148 
mus2mid_write1(struct mus_ctx * ctx,uint32_t val)149 static void mus2mid_write1(struct mus_ctx *ctx, uint32_t val)
150 {
151     if (ctx->dstrem < 1)
152         mus2mid_resize_dst(ctx);
153     *ctx->dst_ptr++ = val & 0xff;
154     ctx->dstrem--;
155 }
156 
mus2mid_write2(struct mus_ctx * ctx,uint32_t val)157 static void mus2mid_write2(struct mus_ctx *ctx, uint32_t val)
158 {
159     if (ctx->dstrem < 2)
160         mus2mid_resize_dst(ctx);
161     *ctx->dst_ptr++ = (val>>8) & 0xff;
162     *ctx->dst_ptr++ = val & 0xff;
163     ctx->dstrem -= 2;
164 }
165 
mus2mid_write4(struct mus_ctx * ctx,uint32_t val)166 static void mus2mid_write4(struct mus_ctx *ctx, uint32_t val)
167 {
168     if (ctx->dstrem < 4)
169         mus2mid_resize_dst(ctx);
170     *ctx->dst_ptr++ = (uint8_t)((val>>24)&0xff);
171     *ctx->dst_ptr++ = (uint8_t)((val>>16)&0xff);
172     *ctx->dst_ptr++ = (uint8_t)((val>>8) & 0xff);
173     *ctx->dst_ptr++ = (uint8_t)((val & 0xff));
174     ctx->dstrem -= 4;
175 }
176 
mus2mid_seekdst(struct mus_ctx * ctx,uint32_t pos)177 static void mus2mid_seekdst(struct mus_ctx *ctx, uint32_t pos) {
178     ctx->dst_ptr = ctx->dst + pos;
179     while (ctx->dstsize < pos)
180         mus2mid_resize_dst(ctx);
181     ctx->dstrem = ctx->dstsize - pos;
182 }
183 
mus2mid_skipdst(struct mus_ctx * ctx,int32_t pos)184 static void mus2mid_skipdst(struct mus_ctx *ctx, int32_t pos) {
185     size_t newpos;
186     ctx->dst_ptr += pos;
187     newpos = ctx->dst_ptr - ctx->dst;
188     while (ctx->dstsize < newpos)
189         mus2mid_resize_dst(ctx);
190     ctx->dstrem = (uint32_t)(ctx->dstsize - newpos);
191 }
192 
mus2mid_getdstpos(struct mus_ctx * ctx)193 static uint32_t mus2mid_getdstpos(struct mus_ctx *ctx) {
194     return (uint32_t)(ctx->dst_ptr - ctx->dst);
195 }
196 
197 /* writes a variable length integer to a buffer, and returns bytes written */
mus2mid_writevarlen(int32_t value,uint8_t * out)198 static int32_t mus2mid_writevarlen(int32_t value, uint8_t *out)
199 {
200     int32_t buffer, count = 0;
201 
202     buffer = value & 0x7f;
203     while ((value >>= 7) > 0) {
204         buffer <<= 8;
205         buffer += 0x80;
206         buffer += (value & 0x7f);
207     }
208 
209     while (1) {
210         ++count;
211         *out = (uint8_t)buffer;
212         ++out;
213         if (buffer & 0x80)
214             buffer >>= 8;
215         else
216             break;
217     }
218     return (count);
219 }
220 
221 #define MUS_READ_INT16(b) ((b)[0] | ((b)[1] << 8))
222 #define MUS_READ_INT32(b) ((b)[0] | ((b)[1] << 8) | ((b)[2] << 16) | ((b)[3] << 24))
223 
Convert_mus2midi(uint8_t * in,uint32_t insize,uint8_t ** out,uint32_t * outsize,uint16_t frequency)224 static int Convert_mus2midi(uint8_t *in, uint32_t insize,
225                             uint8_t **out, uint32_t *outsize,
226                             uint16_t frequency)
227 {
228     struct mus_ctx ctx;
229     MUSHeader header;
230     uint8_t *cur, *end;
231     uint32_t track_size_pos, begin_track_pos, current_pos;
232     int32_t delta_time;/* Delta time for midi event */
233     int temp, ret = -1;
234     int channel_volume[MUS_MIDI_MAXCHANNELS];
235     int channelMap[MUS_MIDI_MAXCHANNELS], currentChannel;
236 
237     if (insize < MUS_HEADERSIZE) {
238         /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);*/
239         return (-1);
240     }
241 
242     if (!frequency)
243         frequency = MUS_FREQUENCY;
244 
245     /* read the MUS header and set our location */
246     memcpy(header.ID, in, 4);
247     header.scoreLen = MUS_READ_INT16(&in[4]);
248     header.scoreStart = MUS_READ_INT16(&in[6]);
249     header.channels = MUS_READ_INT16(&in[8]);
250     header.sec_channels = MUS_READ_INT16(&in[10]);
251     header.instrCnt = MUS_READ_INT16(&in[12]);
252 
253     if (memcmp(header.ID, MUS_ID, 4)) {
254         /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, NULL, 0);*/
255         return (-1);
256     }
257     if (insize < (uint32_t)header.scoreLen + (uint32_t)header.scoreStart) {
258         /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);*/
259         return (-1);
260     }
261     /* channel #15 should be excluded in the numchannels field: */
262     if (header.channels > MUS_MIDI_MAXCHANNELS - 1) {
263         /*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0);*/
264         return (-1);
265     }
266 
267     memset(&ctx, 0, sizeof(struct mus_ctx));
268     ctx.src = ctx.src_ptr = in;
269     ctx.srcsize = insize;
270 
271     ctx.dst = (uint8_t*)calloc(DST_CHUNK, sizeof(uint8_t));
272     ctx.dst_ptr = ctx.dst;
273     ctx.dstsize = DST_CHUNK;
274     ctx.dstrem = DST_CHUNK;
275 
276     /* Map channel 15 to 9 (percussions) */
277     for (temp = 0; temp < MUS_MIDI_MAXCHANNELS; ++temp) {
278         channelMap[temp] = -1;
279         channel_volume[temp] = 0x40;
280     }
281     channelMap[15] = 9;
282 
283     /* Header is 14 bytes long and add the rest as well */
284     mus2mid_write1(&ctx, 'M');
285     mus2mid_write1(&ctx, 'T');
286     mus2mid_write1(&ctx, 'h');
287     mus2mid_write1(&ctx, 'd');
288     mus2mid_write4(&ctx, 6);    /* length of header */
289     mus2mid_write2(&ctx, 0);    /* MIDI type (always 0) */
290     mus2mid_write2(&ctx, 1);    /* MUS files only have 1 track */
291     mus2mid_write2(&ctx, MUS_DIVISION); /* division */
292 
293     /* Write out track header and track length position for later */
294     begin_track_pos = mus2mid_getdstpos(&ctx);
295     mus2mid_write1(&ctx, 'M');
296     mus2mid_write1(&ctx, 'T');
297     mus2mid_write1(&ctx, 'r');
298     mus2mid_write1(&ctx, 'k');
299     track_size_pos = mus2mid_getdstpos(&ctx);
300     mus2mid_skipdst(&ctx, 4);
301 
302     /* write tempo: microseconds per quarter note */
303     mus2mid_write1(&ctx, 0x00); /* delta time */
304     mus2mid_write1(&ctx, 0xff); /* sys command */
305     mus2mid_write2(&ctx, 0x5103);   /* command - set tempo */
306     mus2mid_write1(&ctx, MUS_TEMPO & 0x000000ff);
307     mus2mid_write1(&ctx, (MUS_TEMPO & 0x0000ff00) >> 8);
308     mus2mid_write1(&ctx, (MUS_TEMPO & 0x00ff0000) >> 16);
309 
310     /* Percussions channel starts out at full volume */
311     mus2mid_write1(&ctx, 0x00);
312     mus2mid_write1(&ctx, 0xB9);
313     mus2mid_write1(&ctx, 0x07);
314     mus2mid_write1(&ctx, 127);
315 
316     /* get current position in source, and end of position */
317     cur = in + header.scoreStart;
318     end = cur + header.scoreLen;
319 
320     currentChannel = 0;
321     delta_time = 0;
322 
323     /* main loop */
324     while(cur < end){
325         /*printf("LOOP DEBUG: %d\r\n",iterator++);*/
326         uint8_t channel;
327         uint8_t event;
328         uint8_t temp_buffer[32];    /* temp buffer for current iterator */
329         uint8_t *out_local = temp_buffer;
330         uint8_t status, bit1, bit2, bitc = 2;
331 
332         /* read in current bit */
333         event = *cur++;
334         channel = (event & 15);     /* current channel */
335 
336         /* write variable length delta time */
337         out_local += mus2mid_writevarlen(delta_time, out_local);
338 
339         /* set all channels to 127 (max) volume */
340         if (channelMap[channel] < 0) {
341             *out_local++ = 0xB0 + currentChannel;
342             *out_local++ = 0x07;
343             *out_local++ = 127;
344             *out_local++ = 0x00;
345             channelMap[channel] = currentChannel++;
346             if (currentChannel == 9)
347                 ++currentChannel;
348         }
349         status = channelMap[channel];
350 
351         /* handle events */
352         switch ((event & 122) >> 4){
353             case MUSEVENT_KEYOFF:
354                 status |=  0x80;
355                 bit1 = *cur++;
356                 bit2 = 0x40;
357                 break;
358             case MUSEVENT_KEYON:
359                 status |= 0x90;
360                 bit1 = *cur & 127;
361                 if (*cur++ & 128)   /* volume bit? */
362                     channel_volume[channelMap[channel]] = *cur++;
363                 bit2 = channel_volume[channelMap[channel]];
364                 break;
365             case MUSEVENT_PITCHWHEEL:
366                 status |= 0xE0;
367                 bit1 = (*cur & 1) >> 6;
368                 bit2 = (*cur++ >> 1) & 127;
369                 break;
370             case MUSEVENT_CHANNELMODE:
371                 status |= 0xB0;
372                 if (*cur >= sizeof(mus_midimap) / sizeof(mus_midimap[0])) {
373                     /*_WM_ERROR_NEW("%s:%i: can't map %u to midi",
374                                   __FUNCTION__, __LINE__, *cur);*/
375                     goto _end;
376                 }
377                 bit1 = mus_midimap[*cur++];
378                 bit2 = (*cur++ == 12) ? header.channels + 1 : 0x00;
379                 break;
380             case MUSEVENT_CONTROLLERCHANGE:
381                 if (*cur == 0) {
382                     cur++;
383                     status |= 0xC0;
384                     bit1 = *cur++;
385                     bit2 = 0;/* silence bogus warnings */
386                     bitc = 1;
387                 } else {
388                     status |= 0xB0;
389                     if (*cur >= sizeof(mus_midimap) / sizeof(mus_midimap[0])) {
390                         /*_WM_ERROR_NEW("%s:%i: can't map %u to midi",
391                                       __FUNCTION__, __LINE__, *cur);*/
392                         goto _end;
393                     }
394                     bit1 = mus_midimap[*cur++];
395                     bit2 = *cur++;
396                 }
397                 break;
398             case MUSEVENT_END:  /* End */
399                 status = 0xff;
400                 bit1 = 0x2f;
401                 bit2 = 0x00;
402                 if (cur != end) { /* should we error here or report-only? */
403                     /*_WM_DEBUG_MSG("%s:%i: MUS buffer off by %ld bytes",
404                                   __FUNCTION__, __LINE__, (long)(cur - end));*/
405                 }
406                 break;
407             case 5:/* Unknown */
408             case 7:/* Unknown */
409             default:/* shouldn't happen */
410                 /*_WM_ERROR_NEW("%s:%i: unrecognized event (%u)",
411                               __FUNCTION__, __LINE__, event);*/
412                 goto _end;
413         }
414 
415         /* write it out */
416         *out_local++ = status;
417         *out_local++ = bit1;
418         if (bitc == 2)
419             *out_local++ = bit2;
420 
421         /* write out our temp buffer */
422         if (out_local != temp_buffer)
423         {
424             if (ctx.dstrem < sizeof(temp_buffer))
425                 mus2mid_resize_dst(&ctx);
426 
427             memcpy(ctx.dst_ptr, temp_buffer, out_local - temp_buffer);
428             ctx.dst_ptr += out_local - temp_buffer;
429             ctx.dstrem -= (uint32_t)(out_local - temp_buffer);
430         }
431 
432         if (event & 128) {
433             delta_time = 0;
434             do {
435                 delta_time = (int32_t)((delta_time * 128 + (*cur & 127)) * (140.0 / (double)frequency));
436             } while ((*cur++ & 128));
437         } else {
438             delta_time = 0;
439         }
440     }
441 
442     /* write out track length */
443     current_pos = mus2mid_getdstpos(&ctx);
444     mus2mid_seekdst(&ctx, track_size_pos);
445     mus2mid_write4(&ctx, current_pos - begin_track_pos - TRK_CHUNKSIZE);
446     mus2mid_seekdst(&ctx, current_pos); /* reseek to end position */
447 
448     *out = ctx.dst;
449     *outsize = ctx.dstsize - ctx.dstrem;
450     ret = 0;
451 
452 _end:   /* cleanup */
453     if (ret < 0) {
454         free(ctx.dst);
455         *out = NULL;
456         *outsize = 0;
457     }
458 
459     return (ret);
460 }
461 
462