/src/vlc/contrib/contrib-build/libmodplug/src/load_mid.cpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | MikMod Sound System |
4 | | |
5 | | By Jake Stine of Divine Entertainment (1996-2000) |
6 | | |
7 | | Support: |
8 | | If you find problems with this code, send mail to: |
9 | | air@divent.org |
10 | | |
11 | | Distribution / Code rights: |
12 | | Use this source code in any fashion you see fit. Giving me credit where |
13 | | credit is due is optional, depending on your own levels of integrity and |
14 | | honesty. |
15 | | |
16 | | ----------------------------------------- |
17 | | Module: LOAD_MID |
18 | | |
19 | | MID module loader. |
20 | | by Peter Grootswagers (2006) |
21 | | <email:pgrootswagers@planet.nl> |
22 | | |
23 | | Portability: |
24 | | All systems - all compilers (hopefully) |
25 | | */ |
26 | | |
27 | | #include <stdlib.h> |
28 | | #include <time.h> |
29 | | #include <string.h> |
30 | | #include <math.h> |
31 | | #include <ctype.h> |
32 | | #ifndef _WIN32 |
33 | | #include <unistd.h> // for sleep |
34 | | #endif |
35 | | |
36 | | #include "stdafx.h" |
37 | | #include "sndfile.h" |
38 | 10 | #define PAN_LEFT 0x30 |
39 | 5 | #define PAN_RIGHT 0xD0 |
40 | 10 | #define MAX_POLYPHONY 16 // max notes in one midi channel |
41 | 8 | #define MAX_TRACKS (MAX_BASECHANNELS-6) // max mod tracks |
42 | 0 | #define WHEELSHIFT 10 // how many bits the 13bit midi wheel value must shift right |
43 | | |
44 | | #include "load_pat.h" |
45 | | |
46 | 223 | #define ROWSPERNOTE 16 |
47 | 2 | #define ENV_MMMID_SPEED "MMMID_SPEED" |
48 | 2 | #define ENV_MMMID_DEBUG "MMMID_DEBUG" |
49 | 2 | #define ENV_MMMID_VERBOSE "MMMID_VERBOSE" |
50 | | |
51 | | /**********************************************************************/ |
52 | | |
53 | | typedef enum { |
54 | | none, |
55 | | wheeldown, |
56 | | wheelup, |
57 | | fxbrk, |
58 | | tmpo, |
59 | | fxsync, |
60 | | modwheel, |
61 | | mainvol, |
62 | | prog |
63 | | } MIDEVENT_X_EFFECT; |
64 | | |
65 | | typedef struct _MIDEVENT |
66 | | { |
67 | | struct _MIDEVENT *next; |
68 | | ULONG tracktick; |
69 | | BYTE flg; // 1 = note present |
70 | | BYTE note; |
71 | | BYTE volume; |
72 | | BYTE smpno; |
73 | | BYTE fx; |
74 | | BYTE fxparam; |
75 | | } MIDEVENT; |
76 | | |
77 | | typedef struct _MIDTRACK |
78 | | { |
79 | | struct _MIDTRACK *next; |
80 | | MIDEVENT *head; |
81 | | MIDEVENT *tail; |
82 | | MIDEVENT *workevent; // keeps track of events in track |
83 | | int balance; // last balance on this track |
84 | | ULONG vtracktick; // tracktick of last note event (on or off) |
85 | | BYTE chan; |
86 | | BYTE vpos; // 0xff is track is free for use, otherwise it's the note playing on this track |
87 | | BYTE volume; // last note volume on this track |
88 | | BYTE instr; // current instrument for this track |
89 | | } MIDTRACK; |
90 | | |
91 | | #if defined(WIN32) && defined(_mm_free) |
92 | | #undef _mm_free |
93 | | #endif |
94 | | |
95 | | #define MMSTREAM FILE |
96 | | #define _mm_fseek(f,pos,whence) fseek(f,pos,whence) |
97 | | #define _mm_read_UBYTES(buf,sz,f) fread(buf,sz,1,f) |
98 | | #define _mm_read_SBYTES(buf,sz,f) fread(buf,sz,1,f) |
99 | | #define DupStr(h,buf,sz) strdup(buf) |
100 | 43 | #define _mm_calloc(h,n,sz) calloc(n,sz) |
101 | | #define _mm_recalloc(h,buf,sz,elsz) realloc(buf,sz) |
102 | | #define _mm_free(h,p) free(p) |
103 | | |
104 | | typedef struct { |
105 | | char *mm; |
106 | | unsigned int sz; |
107 | | int pos; |
108 | | } MMFILE; |
109 | | |
110 | | static void mmfseek(MMFILE *mmfile, long p, int whence) |
111 | 2.18k | { |
112 | 2.18k | switch(whence) { |
113 | 2.18k | case SEEK_SET: |
114 | 2.18k | mmfile->pos = p; |
115 | 2.18k | break; |
116 | 0 | case SEEK_CUR: |
117 | 0 | mmfile->pos += p; |
118 | 0 | break; |
119 | 0 | case SEEK_END: |
120 | 0 | mmfile->pos = mmfile->sz + p; |
121 | 0 | break; |
122 | 2.18k | } |
123 | 2.18k | } |
124 | | |
125 | | static long mmftell(MMFILE *mmfile) |
126 | 0 | { |
127 | 0 | return mmfile->pos; |
128 | 0 | } |
129 | | |
130 | | static BYTE mmreadUBYTE(MMFILE *mmfile) |
131 | 199 | { |
132 | 199 | BYTE b; |
133 | 199 | b = (BYTE)mmfile->mm[mmfile->pos]; |
134 | 199 | mmfile->pos++; |
135 | 199 | return b; |
136 | 199 | } |
137 | | |
138 | | static void mmreadUBYTES(BYTE *buf, long sz, MMFILE *mmfile) |
139 | 57 | { |
140 | 57 | memcpy(buf, &mmfile->mm[mmfile->pos], sz); |
141 | 57 | mmfile->pos += sz; |
142 | 57 | } |
143 | | |
144 | | static void mmreadSBYTES(char *buf, long sz, MMFILE *mmfile) |
145 | 2.19k | { |
146 | 2.19k | memcpy(buf, &mmfile->mm[mmfile->pos], sz); |
147 | 2.19k | mmfile->pos += sz; |
148 | 2.19k | } |
149 | | |
150 | | /**********************************************************************/ |
151 | | |
152 | | typedef struct _MIDHANDLE |
153 | | { |
154 | | MMFILE *mmf; |
155 | | MIDTRACK *track; |
156 | | MIDTRACK *tp; |
157 | | ULONG tracktime; |
158 | | const char *debug; |
159 | | const char *verbose; |
160 | | int speed; |
161 | | int midispeed; |
162 | | int midiformat; |
163 | | int resolution; |
164 | | int miditracks; |
165 | | int divider; |
166 | | int tempo; |
167 | | int percussion; |
168 | | long deltatime; |
169 | | } MIDHANDLE; |
170 | | |
171 | | static void mid_dump_tracks(MIDHANDLE *h) |
172 | 0 | { |
173 | 0 | MIDTRACK *tr; |
174 | 0 | MIDEVENT *e; |
175 | 0 | int t; |
176 | 0 | printf("tracktime = %ld\n", (long)(h->tracktime)); |
177 | 0 | printf("speed = %d\n", h->speed); |
178 | 0 | printf("midispeed = %d\n", h->midispeed); |
179 | 0 | printf("midiformat = %d\n", h->midiformat); |
180 | 0 | printf("resolution = %d\n", h->resolution); |
181 | 0 | printf("miditracks = %d\n", h->miditracks); |
182 | 0 | printf("divider = %d\n", h->divider); |
183 | 0 | printf("tempo = %d\n", h->tempo); |
184 | 0 | printf("percussion = %d\n", h->percussion); |
185 | 0 | printf("deltatime = %ld\n", h->deltatime); |
186 | 0 | t = 0; |
187 | 0 | for( tr=h->track; tr; tr = tr->next ) { |
188 | 0 | t++; |
189 | 0 | printf("TRACK %2d chan=%d note=0x%02x vol=%d pan=0x%02x instr=%d\n", t, tr->chan + 1, tr->vpos, tr->balance, tr->volume, tr->instr); |
190 | 0 | for( e=tr->head; e; e=e->next ) { |
191 | 0 | printf("%2d %6ld %s %3d %3d %3d ", |
192 | 0 | t, (long)(e->tracktick), |
193 | 0 | e->flg? "NOTE": "CTRL", e->note, e->volume, e->smpno); |
194 | 0 | switch( e->fx ) { |
195 | 0 | case fxbrk: printf("fxbrk\n");break; |
196 | 0 | case fxsync: printf("fxsync\n");break; |
197 | 0 | case prog: printf("prog %d\n", e->fxparam);break; |
198 | 0 | case mainvol: printf("mainvol %d\n", e->fxparam);break; |
199 | 0 | case modwheel: printf("modwheel %d\n", e->fxparam);break; |
200 | 0 | case wheeldown: printf("wheeldown %d\n", e->fxparam);break; |
201 | 0 | case wheelup: printf("wheelup %d\n", e->fxparam);break; |
202 | 0 | case tmpo: printf("tmpo %d\n", e->fxparam);break; |
203 | 0 | default: printf("\n");break; |
204 | 0 | } |
205 | 0 | } |
206 | 0 | } |
207 | 0 | } |
208 | | |
209 | | static void mid_message(const char *s1, const char *s2) |
210 | 0 | { |
211 | 0 | char txt[256]; |
212 | 0 | if( strlen(s1) + strlen(s2) > 255 ) return; |
213 | 0 | sprintf(txt, s1, s2); |
214 | 0 | fprintf(stderr, "load_mid > %s\n", txt); |
215 | 0 | } |
216 | | |
217 | | static ULONG miditicks(MIDHANDLE *h, ULONG modtick) |
218 | 205 | { |
219 | 205 | return modtick * h->divider / ROWSPERNOTE / h->speed; |
220 | 205 | } |
221 | | |
222 | | static ULONG modticks(MIDHANDLE *h, ULONG miditick) |
223 | 18 | { |
224 | 18 | return miditick * ROWSPERNOTE * h->speed / h->divider; |
225 | 18 | } |
226 | | |
227 | | static void mid_adjust_for_optimal_tempo(MIDHANDLE *h, int maxtempo) |
228 | 2 | { |
229 | | // the tempo is adjusted so that the maximum tempo is 255 |
230 | | // this way we have the biggest change that very short notes get played |
231 | | // and we make sure the tempo doesn't become too large or too small |
232 | | // if the piece in hand isn't so weird it changes tempo from 20 to 255, that is. |
233 | | // tempo is only registered in first track (h->track) because it is a global event |
234 | 2 | MIDEVENT *e; |
235 | 2 | int d, t; |
236 | 2 | if( maxtempo < 1 ) return; |
237 | 2 | d = h->divider; |
238 | 2 | t = maxtempo; |
239 | 2 | h->divider = (t * d) / 255; |
240 | 2 | while( (h->midispeed = miditicks(h, h->speed)) < h->speed ) { |
241 | 0 | ++t; |
242 | 0 | h->divider = (t * d) / 255; |
243 | 0 | } |
244 | 2 | if( h->verbose && t > maxtempo ) |
245 | 0 | printf("Adjusted maximum tempo from %d to %d to get %d miditicks per patternrow\n", |
246 | 0 | maxtempo, 2 * maxtempo - t, h->midispeed); |
247 | 2 | if( h->track ) { |
248 | 20 | for( e=h->track->head; e; e=e->next ) { |
249 | 18 | if( e->fx == tmpo ) |
250 | 0 | e->fxparam = (255 * e->fxparam ) / t; |
251 | 18 | } |
252 | 2 | } |
253 | 2 | } |
254 | | |
255 | | // ===================================================================================== |
256 | | static MIDEVENT *mid_new_event(MIDHANDLE *h) |
257 | | // ===================================================================================== |
258 | 38 | { |
259 | 38 | MIDEVENT *retval; |
260 | | |
261 | 38 | retval = (MIDEVENT *)_mm_calloc(h->trackhandle, 1,sizeof(MIDEVENT)); |
262 | 38 | retval->next = NULL; |
263 | 38 | retval->tracktick = h->tracktime; |
264 | 38 | retval->flg = 0; |
265 | 38 | retval->note = 0; |
266 | 38 | retval->volume = 0; |
267 | 38 | retval->smpno = 0; |
268 | 38 | retval->fx = none; |
269 | 38 | retval->fxparam = 0; |
270 | 38 | return retval; |
271 | 38 | } |
272 | | |
273 | | // ===================================================================================== |
274 | | static MIDTRACK *mid_new_track(MIDHANDLE *h, int mch, int pos) |
275 | | // ===================================================================================== |
276 | 5 | { |
277 | 5 | MIDTRACK *retval; |
278 | 5 | retval = (MIDTRACK *)_mm_calloc(h->trackhandle, 1,sizeof(MIDTRACK)); |
279 | 5 | retval->next = NULL; |
280 | 5 | retval->vpos = pos; |
281 | 5 | retval->instr = 1; |
282 | 5 | retval->chan = mch; |
283 | 5 | retval->head = NULL; |
284 | 5 | retval->tail = NULL; |
285 | 5 | retval->workevent = NULL; |
286 | 5 | retval->vtracktick = 0; |
287 | 5 | retval->volume = h->track? h->track->volume: 120; |
288 | 5 | retval->balance = 64; |
289 | 5 | return retval; |
290 | 5 | } |
291 | | |
292 | | static int mid_numtracks(MIDHANDLE *h) |
293 | 2 | { |
294 | 2 | int n; |
295 | 2 | MIDTRACK *t; |
296 | 2 | n=0; |
297 | 7 | for( t = h->track; t; t=t->next ) |
298 | 5 | n++; |
299 | 2 | return n; |
300 | 2 | } |
301 | | |
302 | | // find out how many midichannel we have |
303 | | static int mid_numchans(MIDHANDLE *h) |
304 | 2 | { |
305 | 2 | int i,c,n; |
306 | 2 | MIDTRACK *t; |
307 | 2 | c = 0; |
308 | 7 | for( t = h->track; t; t=t->next ) |
309 | 5 | c |= (1<<t->chan); |
310 | 2 | n = 0; |
311 | 34 | for( i=0; i<16; i++ ) |
312 | 32 | if( c & (1<<i) ) n++; |
313 | 2 | return n; |
314 | 2 | } |
315 | | |
316 | | // find out which ordinal a midichannel has |
317 | | static int mid_ordchan(MIDHANDLE *h, int mch) |
318 | 5 | { |
319 | 5 | int i,c,n; |
320 | 5 | MIDTRACK *t; |
321 | 5 | c = 0; |
322 | 18 | for( t = h->track; t; t=t->next ) |
323 | 13 | c |= (1<<t->chan); |
324 | 5 | n = 0; |
325 | 8 | for( i=0; i<mch; i++ ) |
326 | 3 | if( c & (1<<i) ) n++; |
327 | 5 | return n; |
328 | 5 | } |
329 | | |
330 | | static void mid_rewind_tracks(MIDHANDLE *h) |
331 | 1 | { |
332 | 1 | MIDTRACK *tr; |
333 | 1 | h->tracktime = 0; |
334 | 1 | for( tr = h->track; tr; tr = tr->next ) { |
335 | 0 | tr->vpos = 0xff; |
336 | 0 | tr->workevent = tr->head; |
337 | 0 | tr->vtracktick = 0; |
338 | 0 | } |
339 | 1 | } |
340 | | |
341 | | static void mid_update_track(MIDTRACK *tr) |
342 | 141 | { |
343 | 141 | MIDEVENT *e; |
344 | 141 | e = tr->workevent; |
345 | 141 | if( e->flg ) { |
346 | 123 | if( e->volume ) tr->vpos = e->note; |
347 | 75 | else tr->vpos = 0xff; |
348 | 123 | tr->volume = e->volume; |
349 | 123 | tr->vtracktick = e->tracktick; |
350 | 123 | } |
351 | 141 | if( e->fx == prog ) tr->instr = e->fxparam; |
352 | 141 | } |
353 | | |
354 | | static void mid_sync_track(MIDTRACK *tr, ULONG tracktime) |
355 | 70 | { |
356 | 70 | MIDEVENT *e; |
357 | 70 | e = tr->workevent; |
358 | 70 | if( e && e->tracktick > tracktime ) e = tr->head; // start again.... |
359 | 140 | for( ; e && e->tracktick <= tracktime; e=e->next ) { |
360 | 70 | tr->workevent = e; |
361 | 70 | mid_update_track(tr); |
362 | 70 | } |
363 | 70 | } |
364 | | |
365 | | // ===================================================================================== |
366 | | static MIDTRACK *mid_find_track(MIDHANDLE *h, int mch, int pos) |
367 | | // ===================================================================================== |
368 | 16 | { |
369 | 16 | MIDTRACK *tr; |
370 | 29 | for( tr=h->track; tr; tr=tr->next ) { |
371 | 29 | mid_sync_track(tr, h->tracktime); |
372 | 29 | if( tr->chan == mch && tr->vpos == pos ) |
373 | 16 | return tr; |
374 | 29 | } |
375 | 0 | return NULL; |
376 | 16 | } |
377 | | |
378 | | // ===================================================================================== |
379 | | static MIDTRACK *mid_locate_track(MIDHANDLE *h, int mch, int pos) |
380 | | // ===================================================================================== |
381 | 18 | { |
382 | 18 | MIDTRACK *tr, *prev, *trunused; |
383 | 18 | MIDEVENT *e; |
384 | 18 | int instrno = 1; |
385 | 18 | int polyphony; |
386 | 18 | int vol = 0, bal = 0; |
387 | 18 | int numtracks; |
388 | 18 | ULONG tmin; |
389 | 18 | prev = NULL; |
390 | 18 | trunused = NULL; |
391 | 18 | polyphony = 0; |
392 | 18 | numtracks = 0; |
393 | 18 | tmin = h->midispeed; // minimal distance between note events in track |
394 | | // look up track with desired channel and pos (note) |
395 | 54 | for( tr=h->track; tr; tr=tr->next ) { |
396 | 36 | mid_sync_track(tr, h->tracktime); |
397 | 36 | if( tr->chan == mch ) { |
398 | 36 | if( tr->vpos == pos ) |
399 | 0 | return tr; |
400 | 36 | if( tr->vpos == 0xff ) { |
401 | | // check if track with silence is quiet long enough |
402 | 36 | if( h->tracktime > tr->vtracktick + tmin ) trunused = tr; |
403 | 36 | } |
404 | 0 | else vol = tr->volume; |
405 | 36 | instrno = tr->instr; |
406 | 36 | bal = tr->balance; |
407 | 36 | polyphony++; |
408 | 36 | } |
409 | 36 | numtracks++; |
410 | 36 | prev = tr; |
411 | 36 | } |
412 | 18 | if( trunused ) { |
413 | 13 | trunused->vpos = pos; |
414 | 13 | return trunused; |
415 | 13 | } |
416 | 5 | if( polyphony > MAX_POLYPHONY || (polyphony > 0 && numtracks > MAX_TRACKS) ) { // do not use up too much channels |
417 | 0 | for( tr=h->track; tr; tr=tr->next ) { |
418 | 0 | if( tr->chan == mch ) { |
419 | 0 | e = tr->workevent; |
420 | 0 | if( h->tracktime > e->tracktick + tmin ) { |
421 | 0 | tmin = h->tracktime - e->tracktick; |
422 | 0 | trunused = tr; |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | 0 | if( trunused ) { |
427 | 0 | trunused->vpos = pos; |
428 | 0 | return trunused; |
429 | 0 | } |
430 | 0 | } |
431 | 5 | if( numtracks > MAX_TRACKS ) { // we can not allocate new tracks |
432 | 0 | tmin = 0; |
433 | 0 | for( tr=h->track; tr; tr=tr->next ) { |
434 | 0 | if( tr->chan == mch ) { |
435 | 0 | e = tr->workevent; |
436 | 0 | if( h->tracktime >= e->tracktick + tmin ) { |
437 | 0 | tmin = h->tracktime - e->tracktick; |
438 | 0 | trunused = tr; |
439 | 0 | } |
440 | 0 | } |
441 | 0 | } |
442 | 0 | if( trunused ) { |
443 | 0 | trunused->vpos = pos; |
444 | 0 | return trunused; |
445 | 0 | } |
446 | 0 | tmin = 0; |
447 | 0 | for( tr=h->track; tr; tr=tr->next ) { |
448 | 0 | e = tr->workevent; |
449 | 0 | if( h->tracktime >= e->tracktick + tmin ) { |
450 | 0 | tmin = h->tracktime - e->tracktick; |
451 | 0 | trunused = tr; |
452 | 0 | } |
453 | 0 | } |
454 | 0 | if( trunused ) { |
455 | 0 | trunused->vpos = pos; |
456 | 0 | trunused->chan = mch; |
457 | 0 | return trunused; |
458 | 0 | } |
459 | 0 | } |
460 | 5 | tr = mid_new_track(h, mch, pos); |
461 | 5 | tr->instr = instrno; |
462 | 5 | tr->volume = vol; |
463 | 5 | tr->balance = bal; |
464 | 5 | if( prev ) prev->next = tr; |
465 | 2 | else h->track = tr; |
466 | 5 | return tr; |
467 | 5 | } |
468 | | |
469 | | static void mid_add_event(MIDHANDLE *h, MIDTRACK *tp, MIDEVENT *e) |
470 | 38 | { |
471 | 38 | MIDEVENT *ew, *ep; |
472 | 38 | ep = NULL; |
473 | 38 | ew = tp->workevent; |
474 | 38 | if( ew && ew->tracktick > e->tracktick ) ew = tp->head; // start again from the beginning... |
475 | 71 | for( ; ew && ew->tracktick <= e->tracktick; ew = ew->next ) { |
476 | 33 | ep = ew; |
477 | 33 | tp->workevent = ew; |
478 | 33 | mid_update_track(tp); |
479 | 33 | } |
480 | 38 | if( ep ) { |
481 | 33 | ep->next = e; |
482 | 33 | e->next = ew; |
483 | 33 | } |
484 | 5 | else { |
485 | 5 | e->next = tp->head; |
486 | 5 | tp->head = e; |
487 | 5 | } |
488 | 38 | if( !e->next ) |
489 | 38 | tp->tail = e; |
490 | 38 | tp->workevent = e; |
491 | 38 | mid_update_track(tp); |
492 | 38 | } |
493 | | |
494 | | static void mid_add_tempo_event(MIDHANDLE *h, int tempo) |
495 | 0 | { |
496 | 0 | MIDEVENT *e; |
497 | 0 | e = mid_new_event(h); |
498 | 0 | e->flg = 0; |
499 | 0 | e->fx = tmpo; |
500 | 0 | e->fxparam = tempo; |
501 | 0 | mid_add_event(h, h->track, e); |
502 | 0 | } |
503 | | |
504 | | static void mid_add_partbreak(MIDHANDLE *h) |
505 | 2 | { |
506 | 2 | MIDEVENT *e; |
507 | 2 | e = mid_new_event(h); |
508 | 2 | e->flg = 0; |
509 | 2 | e->fx = fxbrk; |
510 | 2 | mid_add_event(h, h->track, e); |
511 | 2 | } |
512 | | |
513 | | static void mid_add_noteoff(MIDHANDLE *h, MIDTRACK *tp) |
514 | 16 | { |
515 | 16 | MIDEVENT *e; |
516 | 16 | e = mid_new_event(h); |
517 | 16 | e->flg = 1; |
518 | 16 | e->note = tp->vpos; |
519 | 16 | e->smpno = tp->instr; |
520 | 16 | mid_add_event(h, tp, e); |
521 | 16 | } |
522 | | |
523 | | static void mid_add_noteon(MIDHANDLE *h, MIDTRACK *tp, int n, int vol) |
524 | 16 | { |
525 | 16 | MIDEVENT *e; |
526 | 16 | e = mid_new_event(h); |
527 | 16 | e->flg = 1; |
528 | 16 | e->note = n; |
529 | 16 | e->smpno = tp->instr; |
530 | 16 | e->volume = vol; |
531 | 16 | mid_add_event(h, tp, e); |
532 | 16 | } |
533 | | |
534 | | static BYTE modtremolo(int midimod) |
535 | 0 | { |
536 | 0 | int m; |
537 | 0 | if( midimod == 0 ) return 0; |
538 | 0 | if( midimod > 63 ) { |
539 | 0 | m = (128 - midimod) / 4; |
540 | 0 | if( m==0 ) m = 1; |
541 | 0 | return m|0xf0; // find slide down |
542 | 0 | } |
543 | 0 | m = midimod / 4; |
544 | 0 | if( m==0 ) m = 1; |
545 | 0 | return (m<<4)|0x0f; // find slide up |
546 | 0 | } |
547 | | |
548 | | // ===================================================================================== |
549 | | static void mid_mod_wheel(MIDHANDLE *h, int mch, int mod) |
550 | | // ===================================================================================== |
551 | 0 | { |
552 | 0 | MIDTRACK *tr; |
553 | 0 | MIDEVENT *e; |
554 | 0 | for( tr=h->track; tr; tr=tr->next ) { |
555 | 0 | if( tr->chan == mch ) { |
556 | 0 | mid_sync_track(tr, h->tracktime); |
557 | 0 | if( tr->vpos != 0xff ) { // only on tracks with notes on... |
558 | 0 | e = mid_new_event(h); |
559 | 0 | e->flg = 0; |
560 | 0 | e->fx = modwheel; |
561 | 0 | e->fxparam = modtremolo(mod); |
562 | 0 | mid_add_event(h, tr, e); |
563 | 0 | } |
564 | 0 | } |
565 | 0 | } |
566 | 0 | } |
567 | | |
568 | | // ===================================================================================== |
569 | | static void mid_main_volume(MIDHANDLE *h, int mch, int vol) |
570 | | // ===================================================================================== |
571 | 2 | { |
572 | 2 | MIDTRACK *tr; |
573 | 2 | MIDEVENT *e; |
574 | 4 | for( tr=h->track; tr; tr=tr->next ) { |
575 | 2 | if( tr->chan == mch ) { |
576 | 2 | e = mid_new_event(h); |
577 | 2 | e->flg = 0; |
578 | 2 | e->fx = mainvol; |
579 | 2 | e->fxparam = vol; |
580 | 2 | mid_add_event(h, tr, e); |
581 | 2 | } |
582 | 2 | } |
583 | 2 | } |
584 | | |
585 | | // transform 0..63..127 to left..center..right in 2n+1 areas |
586 | | static int modpan(int midipan, int n) |
587 | 5 | { |
588 | 5 | int npan, area, x; |
589 | 5 | x = 2 * n + 1; |
590 | 5 | area = (midipan * x * (PAN_RIGHT - PAN_LEFT))>>7; |
591 | 5 | npan = (PAN_LEFT * x + area) / x; |
592 | 5 | return npan; |
593 | 5 | } |
594 | | |
595 | | // ===================================================================================== |
596 | | static void mid_pan(MIDHANDLE *h, int mch, int pan) |
597 | | // ===================================================================================== |
598 | 1 | { |
599 | 1 | MIDTRACK *tr; |
600 | 1 | int hits; |
601 | 1 | hits = 0; |
602 | 2 | for( tr=h->track; tr; tr=tr->next ) { |
603 | 1 | if( tr->chan == mch ) { |
604 | 1 | hits++; |
605 | 1 | tr->balance = pan; |
606 | 1 | } |
607 | 1 | } |
608 | 1 | if( !hits ) { |
609 | 0 | tr = mid_locate_track(h, mch, 0xff); |
610 | 0 | tr->balance = pan; |
611 | 0 | } |
612 | 1 | } |
613 | | |
614 | | // ===================================================================================== |
615 | | static void mid_add_program(MIDHANDLE *h, int mch, int pr) |
616 | | // ===================================================================================== |
617 | 2 | { |
618 | 2 | MIDTRACK *tr; |
619 | 2 | MIDEVENT *e; |
620 | 2 | int hits; |
621 | 2 | hits = 0; |
622 | 2 | for( tr=h->track; tr; tr=tr->next ) { |
623 | 0 | if( tr->chan == mch ) { |
624 | 0 | hits++; |
625 | 0 | e = mid_new_event(h); |
626 | 0 | e->flg = 0; |
627 | 0 | e->fx = prog; |
628 | 0 | e->fxparam = pat_gmtosmp(pr + 1); |
629 | 0 | mid_add_event(h, tr, e); |
630 | 0 | } |
631 | 0 | } |
632 | 2 | if( !hits ) { |
633 | 2 | tr = mid_locate_track(h, mch, 0xff); |
634 | 2 | e = mid_new_event(h); |
635 | 2 | e->flg = 0; |
636 | 2 | e->fx = prog; |
637 | 2 | e->fxparam = pat_gmtosmp(pr + 1); |
638 | 2 | mid_add_event(h, tr, e); |
639 | 2 | } |
640 | 2 | } |
641 | | |
642 | | // ===================================================================================== |
643 | | static void mid_all_notes_off(MIDHANDLE *h, int mch) |
644 | | // ===================================================================================== |
645 | 0 | { |
646 | 0 | MIDTRACK *tr; |
647 | 0 | if( h->debug ) printf("%ld %d all notes off\n",(long)(h->tracktime), mch+1); |
648 | 0 | for( tr=h->track; tr; tr=tr->next ) { |
649 | 0 | if( tr->chan == mch || mch == -1 ) { |
650 | 0 | mid_sync_track(tr, h->tracktime); |
651 | 0 | if( tr->vpos != 0xff ) |
652 | 0 | mid_add_noteoff(h, tr); |
653 | 0 | } |
654 | 0 | } |
655 | 0 | } |
656 | | |
657 | | static void mid_add_sync(MIDHANDLE *h, MIDTRACK *tp) |
658 | 0 | { |
659 | 0 | MIDEVENT *e; |
660 | 0 | e = mid_new_event(h); |
661 | 0 | e->flg = 0; |
662 | 0 | e->fx = fxsync; |
663 | 0 | mid_add_event(h, tp, e); |
664 | 0 | } |
665 | | |
666 | | static BYTE mid_to_mod_wheel(unsigned int midwheel) |
667 | 0 | { |
668 | 0 | unsigned int i; |
669 | 0 | if( midwheel == 0 ) return 0; |
670 | 0 | i = midwheel >> WHEELSHIFT; |
671 | 0 | return i+1; |
672 | 0 | } |
673 | | |
674 | | static void mid_add_wheel(MIDHANDLE *h, MIDTRACK *tp, int wheel) |
675 | 0 | { |
676 | 0 | MIDEVENT *e; |
677 | 0 | e = mid_new_event(h); |
678 | 0 | e->flg = 0; |
679 | 0 | if( wheel < 0 ) { |
680 | 0 | e->fx = wheeldown; |
681 | 0 | e->fxparam = mid_to_mod_wheel(-wheel); |
682 | 0 | } |
683 | 0 | else { |
684 | 0 | e->fx = wheelup; |
685 | 0 | e->fxparam = mid_to_mod_wheel(wheel); |
686 | 0 | } |
687 | 0 | mid_add_event(h, tp, e); |
688 | 0 | } |
689 | | |
690 | | static void mid_add_pitchwheel(MIDHANDLE *h, int mch, int wheel) |
691 | 2 | { |
692 | 2 | MIDTRACK *tr; |
693 | 2 | int hits; |
694 | 2 | hits = 0; |
695 | 7 | for( tr=h->track; tr; tr=tr->next ) { |
696 | 5 | if( tr->chan == mch ) { |
697 | 5 | hits++; |
698 | 5 | mid_sync_track(tr, h->tracktime); |
699 | 5 | if( tr->vpos != 0xff ) // only on tracks with notes on... |
700 | 0 | mid_add_wheel(h, tr, wheel); |
701 | 5 | } |
702 | 5 | } |
703 | 2 | if( !hits ) { // special case in midiformat 1 events in first track... |
704 | 0 | tr = mid_locate_track(h, mch, 0xff); |
705 | 0 | mid_add_wheel(h, tr, wheel); |
706 | 0 | } |
707 | 2 | } |
708 | | |
709 | | static uint32_t mid_read_long(MIDHANDLE *h) |
710 | 51 | { |
711 | 51 | BYTE buf[4]; |
712 | 51 | mmreadUBYTES(buf, 4, h->mmf); |
713 | 51 | return (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]; |
714 | 51 | } |
715 | | |
716 | | static short int mid_read_short(MIDHANDLE *h) |
717 | 6 | { |
718 | 6 | BYTE buf[2]; |
719 | 6 | mmreadUBYTES(buf, 2, h->mmf); |
720 | 6 | return (buf[0]<<8)|buf[1]; |
721 | 6 | } |
722 | | |
723 | | static BYTE mid_read_byte(MIDHANDLE *h) |
724 | 199 | { |
725 | 199 | return mmreadUBYTE(h->mmf); |
726 | 199 | } |
727 | | |
728 | | static int mid_read_delta(MIDHANDLE *h) |
729 | 58 | { |
730 | 58 | BYTE bits; |
731 | 58 | int i, d; |
732 | 58 | d = 0; |
733 | 58 | for( i=0; i<4; ) { |
734 | 58 | bits = mid_read_byte(h); |
735 | 58 | i++; |
736 | 58 | d = (d<<7)|(bits&0x7f); |
737 | 58 | if( !(bits & 0x80) ) |
738 | 58 | break; |
739 | 58 | } |
740 | 58 | h->deltatime = d; |
741 | 58 | return i; |
742 | 58 | } |
743 | | |
744 | | // ===================================================================================== |
745 | | BOOL CSoundFile::TestMID(const BYTE *lpStream, DWORD dwMemLength) |
746 | | // ===================================================================================== |
747 | 2.18k | { |
748 | 2.18k | char id[5]; |
749 | 2.18k | MIDHANDLE h; |
750 | 2.18k | MMFILE mm; |
751 | 2.18k | mm.mm = (char *)lpStream; |
752 | 2.18k | mm.sz = dwMemLength; |
753 | 2.18k | h.mmf = &mm; |
754 | 2.18k | if (h.mmf->sz < 4) return FALSE; |
755 | 2.18k | mmfseek(h.mmf,0,SEEK_SET); |
756 | 2.18k | mmreadSBYTES(id, 4, h.mmf); |
757 | 2.18k | id[4] = '\0'; |
758 | 2.18k | return !strcmp(id,"MThd") && mid_read_long(&h) == 6; |
759 | 2.18k | } |
760 | | |
761 | | // ===================================================================================== |
762 | | static MIDHANDLE *MID_Init(void) |
763 | 2 | { |
764 | 2 | MIDHANDLE *retval; |
765 | 2 | retval = (MIDHANDLE *)calloc(1,sizeof(MIDHANDLE)); |
766 | 2 | if( !retval ) return NULL; |
767 | 2 | retval->track = NULL; |
768 | 2 | retval->percussion = 0; |
769 | 2 | retval->debug = NULL; |
770 | 2 | return retval; |
771 | 2 | } |
772 | | |
773 | | static void MID_CleanupTrack(MIDTRACK *tp) |
774 | 5 | { |
775 | 5 | MIDEVENT *ep, *en; |
776 | 5 | if( tp ) { |
777 | 43 | for( ep=tp->head; ep; ep = en ) { |
778 | 38 | en=ep->next; |
779 | 38 | free(ep); |
780 | 38 | } |
781 | 5 | tp->head = NULL; |
782 | 5 | } |
783 | 5 | } |
784 | | |
785 | | // ===================================================================================== |
786 | | static void MID_CleanupTracks(MIDHANDLE *handle) |
787 | | // ===================================================================================== |
788 | 2 | { |
789 | 2 | MIDTRACK *tp, *tn; |
790 | 2 | if(handle) { |
791 | 7 | for( tp=handle->track; tp; tp = tn ) { |
792 | 5 | tn=tp->next; |
793 | 5 | MID_CleanupTrack(tp); |
794 | 5 | } |
795 | 2 | handle->track = NULL; |
796 | 2 | } |
797 | 2 | } |
798 | | |
799 | | // ===================================================================================== |
800 | | static void MID_Cleanup(MIDHANDLE *handle) |
801 | | // ===================================================================================== |
802 | 2 | { |
803 | 2 | if(handle) { |
804 | 2 | MID_CleanupTracks(handle); |
805 | 2 | free(handle); |
806 | 2 | handle = 0; |
807 | 2 | } |
808 | 2 | } |
809 | | |
810 | | static int mid_is_global_event(MIDEVENT *e) |
811 | 884 | { |
812 | 884 | return (e->fx == tmpo || e->fx == fxbrk); |
813 | 884 | } |
814 | | |
815 | | static MIDEVENT *mid_next_global(MIDEVENT *e) |
816 | 283 | { |
817 | 975 | for( ; e && !mid_is_global_event(e); e=e->next ) ; |
818 | 283 | return e; |
819 | 283 | } |
820 | | |
821 | | static MIDEVENT *mid_next_fx(MIDEVENT *e) |
822 | 567 | { |
823 | 2.04k | for( ; e && e->fx == none; e=e->next ) ; |
824 | 567 | return e; |
825 | 567 | } |
826 | | |
827 | | static int mid_is_note_event(MIDEVENT *e) |
828 | 1.18k | { |
829 | | #ifdef LOOPED_NOTES_OFF |
830 | | return (e->flg == 0); |
831 | | #else |
832 | 1.18k | if( e->flg == 0 ) return 0; |
833 | 1.03k | if( e->volume ) return 1; |
834 | 445 | return pat_smplooped(e->smpno); // let non looping samples die out... |
835 | 1.03k | #endif |
836 | 1.03k | } |
837 | | |
838 | | static MIDEVENT *mid_next_note(MIDEVENT *e) |
839 | 893 | { |
840 | 1.48k | for( ; e && !mid_is_note_event(e); e=e->next ) ; |
841 | 893 | return e; |
842 | 893 | } |
843 | | |
844 | | // ===================================================================================== |
845 | | static int MID_ReadPatterns(MODCOMMAND *pattern[], WORD psize[], MIDHANDLE *h, int numpat, int channels) |
846 | | // ===================================================================================== |
847 | 2 | { |
848 | 2 | int pat,row,i,ch; |
849 | 2 | BYTE n,ins,vol; |
850 | 2 | MIDTRACK *t; |
851 | 2 | MIDEVENT *e, *en, *ef, *el; |
852 | 2 | ULONG tt1, tt2; |
853 | 2 | MODCOMMAND *m; |
854 | 2 | int patbrk, tempo; |
855 | 2 | if( numpat > MAX_PATTERNS ) numpat = MAX_PATTERNS; |
856 | | |
857 | | // initialize start points of event list in tracks |
858 | 7 | for( t = h->track; t; t = t->next ) t->workevent = t->head; |
859 | 5 | for( pat = 0; pat < numpat; pat++ ) { |
860 | 3 | pattern[pat] = CSoundFile::AllocatePattern(64, channels); |
861 | 3 | if( !pattern[pat] ) return 0; |
862 | 3 | psize[pat] = 64; |
863 | 195 | for( row = 0; row < 64; row++ ) { |
864 | 192 | tt1 = miditicks(h, (pat * 64 + row ) * h->speed); |
865 | 192 | tt2 = tt1 + h->midispeed; |
866 | 192 | ch = 0; |
867 | 192 | tempo = 0; |
868 | 192 | patbrk = 0; |
869 | 192 | if ( h->track ) |
870 | 283 | for( e=mid_next_global(h->track->workevent); e && e->tracktick < tt2; e=mid_next_global(e->next) ) { |
871 | 91 | if( e && e->tracktick >= tt1 ) { // we have a controller event in this row |
872 | 2 | switch( e->fx ) { |
873 | 0 | case tmpo: |
874 | 0 | tempo = e->fxparam; |
875 | 0 | break; |
876 | 2 | case fxbrk: |
877 | 2 | patbrk = 1; |
878 | 2 | break; |
879 | 2 | } |
880 | 2 | } |
881 | 91 | } |
882 | 640 | for( t = h->track; t; t = t->next ) { |
883 | 448 | m = &pattern[pat][row * channels + ch]; |
884 | 448 | m->param = 0; |
885 | 448 | m->command = CMD_NONE; |
886 | 567 | for( e=mid_next_fx(t->workevent); e && e->tracktick < tt2; e=mid_next_fx(e->next) ) { |
887 | 119 | if( e && e->tracktick >= tt1 ) { // we have a controller event in this row |
888 | 6 | switch( e->fx ) { |
889 | 0 | case modwheel: |
890 | 0 | m->param = e->fxparam; |
891 | 0 | m->command = CMD_VOLUMESLIDE; |
892 | 0 | break; |
893 | 0 | case wheelup: |
894 | 0 | m->param = e->fxparam|0x10; |
895 | 0 | m->command = CMD_XFINEPORTAUPDOWN; |
896 | 0 | break; |
897 | 0 | case wheeldown: |
898 | 0 | m->param = e->fxparam|0x20; |
899 | 0 | m->command = CMD_XFINEPORTAUPDOWN; |
900 | 0 | break; |
901 | 6 | } |
902 | 6 | } |
903 | 119 | } |
904 | 877 | for( e=mid_next_note(t->workevent); e && e->tracktick < tt1; e=mid_next_note(e->next) ) |
905 | 429 | t->workevent = e; |
906 | 448 | i = 0; |
907 | 448 | ef = NULL; |
908 | 448 | en = e; |
909 | 448 | el = e; |
910 | 464 | for( ; e && e->tracktick < tt2; e=mid_next_note(e->next) ) { // we have a note event in this row |
911 | 16 | t->workevent = e; |
912 | 16 | i++; |
913 | 16 | if( e->volume ) { |
914 | 16 | if( !ef ) ef = e; |
915 | 16 | el = e; |
916 | 16 | } |
917 | 16 | } |
918 | 448 | if( i ) { |
919 | 16 | if( i == 1 || ef == el || !ef ) { // only one event in this row or a note on with some note off |
920 | 16 | if( ef ) e = ef; |
921 | 0 | else e = en; |
922 | 16 | el = t->workevent; |
923 | 16 | n = pat_modnote(e->note); |
924 | 16 | ins = e->smpno; |
925 | 16 | if( e->volume == 0 ) { |
926 | 0 | m->param = (BYTE)modticks(h, e->tracktick - tt1); |
927 | 0 | if( m->param ) { // note cut |
928 | 0 | m->command = CMD_S3MCMDEX; |
929 | 0 | m->param |= 0xC0; |
930 | 0 | } |
931 | 0 | else { |
932 | 0 | m->param = 0; |
933 | 0 | m->command = CMD_KEYOFF; |
934 | 0 | } |
935 | 0 | vol = 0; |
936 | 0 | } |
937 | 16 | else { |
938 | 16 | vol = e->volume/2; |
939 | 16 | if( el->volume == 0 ) { |
940 | 0 | m->param = (BYTE)modticks(h, el->tracktick - tt1); |
941 | 0 | if( m->param ) { // note cut |
942 | 0 | m->command = CMD_S3MCMDEX; |
943 | 0 | m->param |= 0xC0; |
944 | 0 | } |
945 | 0 | } |
946 | 16 | else { |
947 | 16 | m->param = (BYTE)modticks(h, e->tracktick - tt1); |
948 | 16 | if( m->param ) { // note delay |
949 | 10 | m->command = CMD_S3MCMDEX; |
950 | 10 | m->param |= 0xD0; |
951 | 10 | } |
952 | 16 | } |
953 | 16 | } |
954 | 16 | m->instr = ins; |
955 | 16 | m->note = n; // <- normal note |
956 | 16 | m->volcmd = VOLCMD_VOLUME; |
957 | 16 | m->vol = vol; |
958 | 16 | } |
959 | 0 | else { |
960 | | // two notes in one row, use FINEPITCHSLIDE runonce effect |
961 | | // start first note on first tick and framedly runonce on seconds note tick |
962 | | // use volume and instrument of last note |
963 | 0 | n = pat_modnote(ef->note); |
964 | 0 | i = pat_modnote(el->note); |
965 | 0 | ins = el->smpno; |
966 | 0 | vol = el->volume/2; |
967 | 0 | if( vol > 64 ) vol = 64; |
968 | 0 | m->instr = ins; |
969 | 0 | m->note = n; // <- normal note |
970 | 0 | m->volcmd = VOLCMD_VOLUME; |
971 | 0 | m->vol = vol; |
972 | 0 | m->param = ((i > n)?i-n:n-i); |
973 | 0 | if( m->param < 16 ) { |
974 | 0 | if( m->param ) { |
975 | 0 | m->command = CMD_XFINEPORTAUPDOWN; |
976 | 0 | m->param |= (i > n)? 0x10: 0x20; |
977 | 0 | } |
978 | 0 | else { // retrigger same note... |
979 | 0 | m->command = CMD_RETRIG; |
980 | 0 | m->param = (BYTE)modticks(h, el->tracktick - tt1); |
981 | 0 | } |
982 | 0 | } |
983 | 0 | else |
984 | 0 | m->command = (i > n)? CMD_PORTAMENTOUP: CMD_PORTAMENTODOWN; |
985 | 0 | } |
986 | 16 | } |
987 | 448 | if( m->param == 0 && m->command == CMD_NONE ) { |
988 | 438 | if( tempo ) { |
989 | 0 | m->command = CMD_TEMPO; |
990 | 0 | m->param = tempo; |
991 | 0 | tempo = 0; |
992 | 0 | } |
993 | 438 | else { |
994 | 438 | if( patbrk ) { |
995 | 2 | m->command = CMD_PATTERNBREAK; |
996 | 2 | patbrk = 0; |
997 | 2 | } |
998 | 438 | } |
999 | 438 | } |
1000 | 448 | ch++; |
1001 | 448 | } |
1002 | 192 | if( tempo || patbrk ) return 1; |
1003 | 192 | } |
1004 | 3 | } |
1005 | 2 | return 0; |
1006 | 2 | } |
1007 | | |
1008 | | static ULONG mid_next_tracktick(MIDEVENT *e) |
1009 | 0 | { |
1010 | 0 | MIDEVENT *en; |
1011 | 0 | en = e->next; |
1012 | 0 | if( en ) return en->tracktick; |
1013 | 0 | return 0x7fffffff; // practically indefinite |
1014 | 0 | } |
1015 | | |
1016 | | // cut off alle events that follow the given event |
1017 | | static void mid_stripoff(MIDTRACK *tp, MIDEVENT *e) |
1018 | 0 | { |
1019 | 0 | MIDEVENT *ep, *en; |
1020 | 0 | for( ep=e->next; ep; ep = en ) { |
1021 | 0 | en=ep->next; |
1022 | 0 | free(ep); |
1023 | 0 | } |
1024 | 0 | e->next = NULL; |
1025 | 0 | tp->tail = e; |
1026 | 0 | tp->workevent = tp->head; |
1027 | 0 | mid_sync_track(tp, e->tracktick); |
1028 | 0 | } |
1029 | | |
1030 | | static void mid_notes_to_percussion(MIDTRACK *tp, ULONG adjust, ULONG tmin) |
1031 | 0 | { |
1032 | 0 | MIDEVENT *e, *lno = 0; |
1033 | 0 | int n = 0,v; |
1034 | 0 | ULONG ton, toff = 0, tnext; |
1035 | 0 | v = 0x7f; // as loud as it gets |
1036 | 0 | ton = 0; |
1037 | 0 | for( e=tp->head; e; e=e->next ) { |
1038 | 0 | if( e->tracktick < adjust ) e->tracktick = 0; |
1039 | 0 | else e->tracktick -= adjust; |
1040 | 0 | if( e->flg == 1 ) { |
1041 | 0 | if( e->volume > 0 ) { |
1042 | 0 | n = e->note; |
1043 | 0 | e->smpno = pat_gmtosmp(pat_gm_drumnr(n)); |
1044 | 0 | e->note = pat_gm_drumnote(n); |
1045 | 0 | e->volume = (v * e->volume) / 128; |
1046 | 0 | if( v && !e->volume ) e->volume = 1; |
1047 | 0 | ton = e->tracktick; |
1048 | 0 | } |
1049 | 0 | else { |
1050 | 0 | toff = ton + tmin; |
1051 | 0 | if( toff > e->tracktick ) { |
1052 | 0 | tnext = mid_next_tracktick(e); |
1053 | 0 | if( toff + tmin < tnext ) e->tracktick = toff; |
1054 | 0 | else { |
1055 | 0 | if( toff < tnext ) e->tracktick = toff - 1; |
1056 | 0 | else e->tracktick = tnext - 1; |
1057 | 0 | } |
1058 | 0 | } |
1059 | 0 | toff = e->tracktick; |
1060 | 0 | lno = e; |
1061 | 0 | } |
1062 | 0 | } |
1063 | 0 | else { |
1064 | 0 | if( e->fx == mainvol ) { |
1065 | 0 | v = e->fxparam; |
1066 | 0 | if( !v && ton > toff ) { |
1067 | 0 | e->flg = 1; |
1068 | 0 | e->volume = 0; |
1069 | 0 | e->note = pat_gm_drumnote(n); |
1070 | 0 | toff = e->tracktick; |
1071 | 0 | lno = e; |
1072 | 0 | } |
1073 | 0 | } |
1074 | 0 | } |
1075 | 0 | } |
1076 | 0 | if( ton > toff ) { |
1077 | 0 | char info[32]; |
1078 | 0 | sprintf(info,"%ld > %ld note %d", (long)ton, (long)toff, n); |
1079 | 0 | mid_message("drum track ends with note on (%s)", info); |
1080 | 0 | } |
1081 | 0 | if( lno && lno->next ) mid_stripoff(tp, lno); |
1082 | 0 | } |
1083 | | |
1084 | | static void mid_prog_to_notes(MIDTRACK *tp, ULONG adjust, ULONG tmin) |
1085 | 5 | { |
1086 | 5 | MIDEVENT *e, *lno = 0; |
1087 | 5 | int i = 0, n = 0, v = 0x7f; |
1088 | 5 | ULONG ton, toff = 0, tnext; |
1089 | 5 | ton = 0; |
1090 | 41 | for( e=tp->head; e; e=e->next ) { |
1091 | 36 | if( e->tracktick < adjust ) e->tracktick = 0; |
1092 | 36 | else e->tracktick -= adjust; |
1093 | 36 | if( e->flg == 1 ) { |
1094 | 32 | if( !i ) i = pat_gmtosmp(1); // happens in eternal2.mid |
1095 | 32 | e->smpno = i; |
1096 | 32 | n = e->note; |
1097 | 32 | if( e->volume > 0 ) { |
1098 | 16 | e->volume = (v * e->volume) / 128; |
1099 | 16 | if( v && !e->volume ) e->volume = 1; |
1100 | 16 | ton = e->tracktick; |
1101 | 16 | } |
1102 | 16 | else { |
1103 | 16 | toff = ton + tmin; |
1104 | 16 | if( toff > e->tracktick ) { |
1105 | 0 | tnext = mid_next_tracktick(e); |
1106 | 0 | if( toff + tmin < tnext ) e->tracktick = toff; |
1107 | 0 | else { |
1108 | 0 | if( toff < tnext ) e->tracktick = toff - 1; |
1109 | 0 | else e->tracktick = tnext - 1; |
1110 | 0 | } |
1111 | 0 | } |
1112 | 16 | toff = e->tracktick; |
1113 | 16 | lno = e; |
1114 | 16 | } |
1115 | 32 | } |
1116 | 4 | else { |
1117 | 4 | if( e->fx == prog ) i = e->fxparam; |
1118 | 4 | if( e->fx == mainvol ) { |
1119 | 2 | v = e->fxparam; |
1120 | 2 | if( !v && ton > toff ) { |
1121 | 0 | e->flg = 1; |
1122 | 0 | e->volume = 0; |
1123 | 0 | e->note = n; |
1124 | 0 | toff = e->tracktick; |
1125 | 0 | lno = e; |
1126 | 0 | } |
1127 | 2 | } |
1128 | 4 | } |
1129 | 36 | } |
1130 | 5 | if( ton > toff ) { |
1131 | 0 | char info[40]; |
1132 | 0 | sprintf(info,"channel %d, %ld > %ld note %d", tp->chan + 1, (long)ton, (long)toff, n); |
1133 | 0 | mid_message("melody track ends with note on (%s)", info); |
1134 | 0 | } |
1135 | 5 | if( lno && lno->next ) mid_stripoff(tp, lno); |
1136 | 5 | } |
1137 | | |
1138 | | static int midiword(BYTE *b) |
1139 | 2 | { |
1140 | 2 | int i; |
1141 | 2 | i = (b[0]&0x7f)|((b[1]&0x7f)<<7); |
1142 | 2 | return i; |
1143 | 2 | } |
1144 | | |
1145 | | static int midishort(BYTE *b) |
1146 | 2 | { |
1147 | 2 | return midiword(b) - 0x2000; |
1148 | 2 | } |
1149 | | |
1150 | | ULONG mid_first_noteonevent_tick(MIDEVENT *e) |
1151 | 5 | { |
1152 | 9 | while( e && (e->flg == 0 || e->volume == 0) ) e=e->next; |
1153 | 5 | if( !e ) return 0x7fffffff; |
1154 | 5 | return e->tracktick; |
1155 | 5 | } |
1156 | | |
1157 | | // ===================================================================================== |
1158 | | BOOL CSoundFile::ReadMID(const BYTE *lpStream, DWORD dwMemLength) |
1159 | 2.18k | { |
1160 | 2.18k | static int avoid_reentry = 0; |
1161 | 2.18k | MIDHANDLE *h; |
1162 | 2.18k | MMFILE mm; |
1163 | 2.18k | int ch, dmulti, maxtempo, panlow, panhigh, numchans, numtracks; |
1164 | 2.18k | MIDTRACK *ttp; |
1165 | 2.18k | uint32_t t, numpats; |
1166 | 2.18k | char buf[256]; |
1167 | 2.18k | uint32_t miditracklen; |
1168 | 2.18k | BYTE runningstatus; |
1169 | 2.18k | BYTE cmd; |
1170 | 2.18k | BYTE midibyte[2]; |
1171 | 2.18k | long metalen, delta; |
1172 | 2.18k | BYTE *p; |
1173 | 2.18k | while( avoid_reentry ) sleep(1); |
1174 | 2.18k | avoid_reentry = 1; |
1175 | 2.18k | if( !TestMID(lpStream, dwMemLength) ) { |
1176 | 2.18k | avoid_reentry = 0; |
1177 | 2.18k | return FALSE; |
1178 | 2.18k | } |
1179 | 2 | h = MID_Init(); |
1180 | 2 | if( !h ) { |
1181 | 0 | avoid_reentry = 0; |
1182 | 0 | return FALSE; |
1183 | 0 | } |
1184 | 2 | h->mmf = &mm; |
1185 | 2 | mm.mm = (char *)lpStream; |
1186 | 2 | mm.sz = dwMemLength; |
1187 | 2 | mm.pos = 0; |
1188 | 2 | h->debug = getenv(ENV_MMMID_DEBUG); |
1189 | 2 | h->verbose = getenv(ENV_MMMID_VERBOSE); |
1190 | 2 | pat_resetsmp(); |
1191 | 2 | pat_init_patnames(); |
1192 | 2 | mmfseek(h->mmf,8,SEEK_SET); |
1193 | 2 | h->midiformat = mid_read_short(h); |
1194 | 2 | h->miditracks = mid_read_short(h); |
1195 | 2 | h->resolution = mid_read_short(h); |
1196 | | // at this point the h->mmf is positioned at first miditrack |
1197 | 2 | if( h->midiformat == 0 ) h->miditracks = 1; |
1198 | 2 | if( h->resolution & 0x8000 ) |
1199 | 0 | h->divider = ((h->resolution & 0x7f00)>>8)*(h->resolution & 0xff); |
1200 | 2 | else |
1201 | 2 | h->divider = h->resolution; |
1202 | 2 | h->divider <<= 2; // ticks per quartnote ==> ticks per note |
1203 | 2 | if (!h->divider) h->divider = 1; |
1204 | 2 | h->tempo = 122; |
1205 | 2 | m_nDefaultTempo = 0; |
1206 | 2 | h->tracktime = 0; |
1207 | 2 | h->speed = 6; |
1208 | 2 | if (h->miditracks == 0) { |
1209 | 0 | MID_Cleanup(h); |
1210 | 0 | avoid_reentry = 0; |
1211 | 0 | return FALSE; |
1212 | 0 | } |
1213 | 2 | p = (BYTE *)getenv(ENV_MMMID_SPEED); |
1214 | 2 | if( p && isdigit(*p) && p[0] != '0' && p[1] == '\0' ) { |
1215 | | // transform speed |
1216 | 0 | t = *p - '0'; |
1217 | 0 | h->speed *= t; |
1218 | 0 | h->divider *= t; |
1219 | 0 | h->speed /= 6; |
1220 | 0 | h->divider /= 6; |
1221 | 0 | } |
1222 | | // calculate optimal delta multiplier dmulti keeping tempo adjustments |
1223 | | // from 10 to 255 in mind (hoping there will be no midi's with tempo's |
1224 | | // lower than 10, that is sooo sick...) |
1225 | | // this is necessary for the tracks to patterns routine |
1226 | 2 | dmulti = 1; |
1227 | 2 | maxtempo = h->divider; |
1228 | 11 | while( (h->midispeed = miditicks(h, h->speed)) * 10 < 255 * h->speed ) { |
1229 | 9 | ++dmulti; |
1230 | 9 | h->divider = maxtempo * dmulti; |
1231 | 9 | } |
1232 | 2 | h->tp = NULL; |
1233 | 2 | memset(buf,0,sizeof(buf)); |
1234 | 2 | strcpy(m_szNames[0], ""); |
1235 | 2 | maxtempo = 0; |
1236 | 2 | panlow = 64; |
1237 | 2 | panhigh = 64; |
1238 | 2 | if( h->verbose ) { |
1239 | 0 | printf("Scanning MIDI with format: %d resolution: %d tracks: %d\n", |
1240 | 0 | h->midiformat, |
1241 | 0 | h->resolution, |
1242 | 0 | h->miditracks); |
1243 | 0 | } |
1244 | 2 | if( h->verbose && dmulti > 1 ) { |
1245 | 0 | printf("Multiplying resolution and deltatimes by %d to get %d miditicks per patternrow\n", |
1246 | 0 | dmulti, h->midispeed); |
1247 | 0 | } |
1248 | 5 | for( t=0; t<(uint32_t)h->miditracks; t++ ) { |
1249 | 3 | if( h->verbose ) printf("Parsing track %d\n", t+1); |
1250 | 3 | mmreadSBYTES(buf,4,h->mmf); |
1251 | 3 | buf[4] = '\0'; |
1252 | 3 | if( strcmp(buf,"MTrk") ) { |
1253 | 0 | mid_message("invalid track-chunk '%s' is not 'MTrk'",buf); |
1254 | 0 | MID_Cleanup(h); |
1255 | 0 | avoid_reentry = 0; |
1256 | 0 | return FALSE; |
1257 | 0 | } |
1258 | 3 | miditracklen = mid_read_long(h); |
1259 | 3 | if (mm.sz < miditracklen) continue; |
1260 | 3 | runningstatus = 0; |
1261 | 3 | if( t && h->midiformat == 1 ) mid_rewind_tracks(h); // tracks sound simultaneously |
1262 | 53 | while( miditracklen > 0 ) { |
1263 | 50 | miditracklen -= mid_read_delta(h); |
1264 | 50 | midibyte[0] = mid_read_byte(h); |
1265 | 50 | miditracklen--; |
1266 | 50 | if( midibyte[0] & 0x80 ) { |
1267 | 49 | runningstatus = midibyte[0]; |
1268 | 49 | switch( runningstatus ) { |
1269 | 0 | case 0xf1: |
1270 | 0 | case 0xf4: |
1271 | 0 | case 0xf5: |
1272 | 0 | case 0xf6: |
1273 | 0 | case 0xf7: |
1274 | 0 | case 0xf8: |
1275 | 0 | case 0xf9: |
1276 | 0 | case 0xfa: |
1277 | 0 | case 0xfb: |
1278 | 0 | case 0xfc: |
1279 | 0 | case 0xfd: |
1280 | 0 | case 0xfe: |
1281 | 0 | break; |
1282 | 49 | default: |
1283 | 49 | midibyte[0] = mid_read_byte(h); |
1284 | 49 | miditracklen--; |
1285 | 49 | break; |
1286 | 49 | } |
1287 | 49 | } |
1288 | 50 | h->tracktime += dmulti * h->deltatime; |
1289 | 50 | ch = runningstatus & 0x0f; |
1290 | 50 | cmd = runningstatus & 0xf0; |
1291 | 50 | switch( cmd ) { |
1292 | 16 | case 0x80: // note off |
1293 | 16 | midibyte[1] = mid_read_byte(h); |
1294 | 16 | miditracklen--; |
1295 | 16 | ttp = mid_find_track(h, ch, midibyte[0]); |
1296 | 16 | if( ttp ) mid_add_noteoff(h, ttp); |
1297 | 16 | if( h->debug ) |
1298 | 0 | printf("%2d %08ld Note off: ch %d 0x%02x 0x%02x\n", |
1299 | 0 | t, (long)(h->tracktime), |
1300 | 0 | ch + 1, midibyte[0], midibyte[1]); |
1301 | 16 | break; |
1302 | 16 | case 0x90: // note on |
1303 | 16 | midibyte[1] = mid_read_byte(h); |
1304 | 16 | miditracklen--; |
1305 | 16 | if( midibyte[1] ) { |
1306 | 16 | ttp = mid_locate_track(h, ch, midibyte[0]); |
1307 | 16 | mid_add_noteon(h, ttp, midibyte[0], midibyte[1]); |
1308 | 16 | if( h->debug ) |
1309 | 0 | printf("%2d %08ld Note on: ch %d 0x%02x 0x%02x\n", |
1310 | 0 | t, (long)(h->tracktime), |
1311 | 0 | ch + 1, midibyte[0], midibyte[1]); |
1312 | 16 | } |
1313 | 0 | else { |
1314 | 0 | ttp = mid_find_track(h, ch, midibyte[0]); |
1315 | 0 | if( ttp ) mid_add_noteoff(h, ttp); |
1316 | 0 | if( h->debug ) |
1317 | 0 | printf("%2d %08ld note off: ch %d 0x%02x\n", |
1318 | 0 | t, (long)(h->tracktime), |
1319 | 0 | ch + 1, midibyte[0]); |
1320 | 0 | } |
1321 | 16 | break; |
1322 | 1 | case 0xa0: // polyphonic key pressure |
1323 | 1 | midibyte[1] = mid_read_byte(h); |
1324 | 1 | miditracklen--; |
1325 | 1 | if( h->debug ) |
1326 | 0 | printf("%2d %08ld polyphonic key pressure: ch %d 0x%02x 0x%02x\n", t, (long)(h->tracktime), ch + 1, midibyte[0], midibyte[1]); |
1327 | 1 | break; |
1328 | 3 | case 0xb0: // control change |
1329 | 3 | midibyte[1] = mid_read_byte(h); |
1330 | 3 | miditracklen--; |
1331 | 3 | switch(midibyte[0]) { |
1332 | 0 | case 0x01: // mod wheel |
1333 | 0 | mid_mod_wheel(h, ch, midibyte[1]); |
1334 | 0 | break; |
1335 | 2 | case 0x07: // main volume |
1336 | 2 | mid_main_volume(h, ch, midibyte[1]); |
1337 | 2 | break; |
1338 | 1 | case 0x0a: // pan |
1339 | 1 | if( midibyte[1] < panlow ) panlow = midibyte[1]; |
1340 | 1 | if( midibyte[1] > panhigh ) panhigh = midibyte[1]; |
1341 | 1 | mid_pan(h, ch, midibyte[1]); |
1342 | 1 | break; |
1343 | 0 | case 0x0b: // expression |
1344 | 0 | break; |
1345 | 0 | case 0x7b: |
1346 | 0 | if( midibyte[1] == 0x00 ) // all notes off |
1347 | 0 | mid_all_notes_off(h, ch); |
1348 | 0 | break; |
1349 | 0 | default: |
1350 | 0 | break; |
1351 | 3 | } |
1352 | 3 | if( h->debug ) |
1353 | 0 | printf("%2d %08ld control change: ch %d 0x%02x 0x%02x\n", |
1354 | 0 | t, (long)(h->tracktime), ch + 1, midibyte[0], midibyte[1]); |
1355 | 3 | break; |
1356 | 2 | case 0xc0: // program change |
1357 | 2 | mid_add_program(h, ch, midibyte[0]); |
1358 | 2 | if( h->debug ) |
1359 | 0 | printf("%2d %08ld program change: ch %d %d\n", |
1360 | 0 | t, (long)(h->tracktime), ch + 1, midibyte[0]); |
1361 | 2 | break; |
1362 | 1 | case 0xd0: // channel pressure |
1363 | 1 | if( h->debug ) |
1364 | 0 | printf("%2d %08ld channel pressure: ch %d 0x%02x\n", t, (long)(h->tracktime), ch + 1, midibyte[0]); |
1365 | 1 | break; |
1366 | 2 | case 0xe0: // pitch wheel change |
1367 | 2 | midibyte[1] = mid_read_byte(h); |
1368 | 2 | miditracklen--; |
1369 | 2 | if( h->debug ) |
1370 | 0 | printf("%2d %08ld pitch wheel change: ch %d %d\n", |
1371 | 0 | t, (long)(h->tracktime), ch + 1, midishort(midibyte)); |
1372 | 2 | mid_add_pitchwheel(h, ch, midishort(midibyte)); |
1373 | 2 | break; |
1374 | 9 | case 0xf0: // system & realtime |
1375 | 9 | switch( runningstatus ) { |
1376 | 1 | case 0xf0: // sysex |
1377 | 1 | if( h->debug ) printf("%2d %08ld sysex: 0x%02x", |
1378 | 0 | t, (long)(h->tracktime), midibyte[0]); |
1379 | 5 | while( midibyte[0] != 0xf7 ) { |
1380 | 4 | midibyte[0] = mid_read_byte(h); |
1381 | 4 | miditracklen--; |
1382 | 4 | if( h->debug ) printf(" %02X", midibyte[0]); |
1383 | 4 | } |
1384 | 1 | if( h->debug ) printf("\n"); |
1385 | 1 | break; |
1386 | 0 | case 0xf2: // song position pointer |
1387 | 0 | midibyte[1] = mid_read_byte(h); |
1388 | 0 | miditracklen--; |
1389 | 0 | if( h->debug ) |
1390 | 0 | printf("%2d %08ld song position pointer: %d", |
1391 | 0 | t, (long)(h->tracktime), midishort(midibyte)); |
1392 | 0 | break; |
1393 | 0 | case 0xf7: |
1394 | 0 | delta = h->deltatime; |
1395 | 0 | miditracklen -= mid_read_delta(h); |
1396 | 0 | metalen = h->deltatime; |
1397 | 0 | if( h->debug ) |
1398 | 0 | printf("%2d %08ld sysex continued: %ld", |
1399 | 0 | t, (long)(h->tracktime), metalen); |
1400 | 0 | while( metalen > 0 ) { |
1401 | 0 | midibyte[1] = mid_read_byte(h); |
1402 | 0 | metalen--; |
1403 | 0 | miditracklen--; |
1404 | 0 | if( h->debug ) printf(" %02X", midibyte[1]); |
1405 | 0 | } |
1406 | 0 | h->deltatime = delta; |
1407 | 0 | break; |
1408 | 8 | case 0xff: // meta event |
1409 | 8 | delta = h->deltatime; |
1410 | 8 | miditracklen -= mid_read_delta(h); |
1411 | 8 | metalen = h->deltatime; |
1412 | 8 | if( metalen > 31 ) metalen = 31; |
1413 | 8 | if( metalen ) { |
1414 | 5 | mmreadSBYTES(buf, metalen, h->mmf); |
1415 | 5 | miditracklen -= metalen; |
1416 | 5 | } |
1417 | 8 | buf[metalen] = '\0'; |
1418 | 8 | metalen = h->deltatime - metalen; |
1419 | 8 | while( metalen > 0 ) { |
1420 | 0 | midibyte[1] = mid_read_byte(h); |
1421 | 0 | metalen--; |
1422 | 0 | miditracklen--; |
1423 | 0 | } |
1424 | 8 | h->deltatime = delta; |
1425 | 8 | switch( midibyte[0] ) { |
1426 | 1 | case 0x03: // type: track name |
1427 | 1 | if( h->debug ) |
1428 | 0 | printf("%2d %08ld META trackname:%s\n", t, (long)(h->tracktime), buf); |
1429 | 1 | if( m_szNames[0][0] == '\0' ) |
1430 | 1 | strcpy(m_szNames[0], buf); |
1431 | 1 | break; |
1432 | 2 | case 0x51: // type: tempo |
1433 | 2 | p=(BYTE *)buf; |
1434 | 2 | delta = (p[0]<<16)|(p[1]<<8)|p[2]; |
1435 | 2 | if( delta ) |
1436 | 2 | h->tempo = 60000000 / delta; |
1437 | 2 | if( h->debug ) printf("%2d %08ld META tempo:%d\n", t, (long)(h->tracktime), h->tempo); |
1438 | 2 | if( m_nDefaultTempo == 0 ) m_nDefaultTempo = h->tempo; |
1439 | 0 | else { |
1440 | 0 | ttp = h->track; |
1441 | 0 | if( !ttp ) mid_locate_track(h, 0, 0xff); |
1442 | 0 | mid_add_tempo_event(h,h->tempo); |
1443 | 0 | } |
1444 | 2 | if( h->tempo > maxtempo ) maxtempo = h->tempo; |
1445 | 2 | break; |
1446 | 3 | case 0x2f: // type: end of track |
1447 | 3 | if( h->debug ) printf("%2d %08ld META end of track\n", t, (long)(h->tracktime)); |
1448 | 3 | if( miditracklen > 0 ) { |
1449 | 0 | sprintf(buf, "%u", miditracklen); |
1450 | 0 | mid_message("Meta event not at end of track, %s bytes left in track", buf); |
1451 | 0 | miditracklen = 0; |
1452 | 0 | } |
1453 | 3 | break; |
1454 | 2 | default: |
1455 | 2 | if( h->debug ) printf("%2d %08ld META type 0x%02x\n", t, (long)(h->tracktime), midibyte[0]); |
1456 | 2 | break; |
1457 | 8 | } |
1458 | 8 | break; |
1459 | 8 | default: |
1460 | 0 | if( h->debug ) printf("%2d %08ld System type 0x%02x\n", t, (long)(h->tracktime), midibyte[0]); |
1461 | 0 | break; |
1462 | 9 | } |
1463 | 9 | break; |
1464 | 9 | default: // no running status, just skip it... |
1465 | 0 | if( h->debug ) printf("%2d %08ld unknown runningstatus: 0x%02x skipped:0x%02x\n", t, (long)(h->tracktime), runningstatus, midibyte[0]); |
1466 | 0 | break; |
1467 | 50 | } |
1468 | 50 | if( miditracklen < 1 && (runningstatus != 0xff || midibyte[0] != 0x2f) ) { |
1469 | 0 | delta = mmftell(h->mmf); |
1470 | 0 | mmreadSBYTES(buf,4,h->mmf); |
1471 | 0 | buf[4] = '\0'; |
1472 | 0 | if( strcmp(buf,"MTrk") ) { |
1473 | 0 | miditracklen = 0x7fffffff; |
1474 | 0 | mid_message("Meta event not at end of track, %s bytes left in track", "superfluous"); |
1475 | 0 | } |
1476 | 0 | else |
1477 | 0 | mid_message("Meta event not at end of track, %s bytes left in track", "no"); |
1478 | 0 | mmfseek(h->mmf,delta,SEEK_SET); |
1479 | 0 | } |
1480 | 50 | } |
1481 | 3 | } |
1482 | 2 | if( h->verbose ) printf("Determining percussion channel\n"); |
1483 | | // get the lowest event time and the used channels |
1484 | 2 | delta = 0x7fffffff; |
1485 | 2 | metalen = 0; // use as bit bucket for used channels |
1486 | 7 | for( ttp=h->track; ttp; ttp=ttp->next ) { |
1487 | 5 | metalen |= (1<<ttp->chan); |
1488 | 5 | if( ttp->head ) { |
1489 | 5 | ULONG tt; |
1490 | 5 | tt = mid_first_noteonevent_tick(ttp->head); |
1491 | 5 | if( tt < (ULONG)delta ) |
1492 | 4 | delta = tt; |
1493 | 5 | } |
1494 | 5 | } |
1495 | 2 | if( metalen & 0x03ff ) { |
1496 | 2 | if( (metalen & 0x0f00) == 0x0400 ) |
1497 | 0 | h->percussion = 10; // buggy sng2mid uses channel 10 |
1498 | 2 | else |
1499 | 2 | h->percussion = 9; |
1500 | 2 | } |
1501 | 0 | else h->percussion = 15; |
1502 | 2 | if( h->verbose ) |
1503 | 0 | printf("Percussion channel is %d\nStripping off silences and other optimalisations\n", h->percussion + 1); |
1504 | | // last but not least shut off all pending events, transform drumnotes when appropriate |
1505 | | // strip off silences at begin and end and get the greatest tracktime |
1506 | 2 | h->tracktime = 0; |
1507 | 2 | metalen = h->midispeed; |
1508 | 7 | for( ttp=h->track; ttp; ttp=ttp->next ) { |
1509 | 5 | if( ttp->chan == h->percussion ) |
1510 | 0 | mid_notes_to_percussion(ttp, delta, metalen); |
1511 | 5 | else |
1512 | 5 | mid_prog_to_notes(ttp, delta, metalen); |
1513 | 5 | if( ttp->tail && ttp->tail->tracktick > h->tracktime ) |
1514 | 4 | h->tracktime = ttp->tail->tracktick; |
1515 | 5 | } |
1516 | | |
1517 | 2 | h->tracktime += h->divider >> 2; // add one quartnote to the song for silence |
1518 | 2 | if ( h->track ) |
1519 | 2 | mid_add_partbreak(h); |
1520 | 2 | if( h->debug ) |
1521 | 0 | mid_dump_tracks(h); |
1522 | 2 | numchans = mid_numchans(h); |
1523 | 2 | if( panlow > 48 || panhigh < 80 ) { |
1524 | 7 | for( ttp=h->track; ttp; ttp=ttp->next ) { |
1525 | 5 | ttp->balance = ((0x40*numchans+0x80*mid_ordchan(h, ttp->chan))/numchans)&0x7f; |
1526 | 5 | } |
1527 | 2 | } |
1528 | | // set module variables |
1529 | 2 | numtracks = mid_numtracks(h); |
1530 | 2 | if( m_nDefaultTempo == 0 ) m_nDefaultTempo = h->tempo; |
1531 | 2 | if( maxtempo == 0 ) maxtempo = h->tempo; |
1532 | 2 | if( maxtempo != 255 ) { |
1533 | 2 | if( h->verbose ) printf("Adjusting tempo %d to 255\n", maxtempo); |
1534 | 2 | mid_adjust_for_optimal_tempo(h, maxtempo); |
1535 | 2 | } |
1536 | 2 | if( maxtempo > 0 ) m_nDefaultTempo = (255 * m_nDefaultTempo) / maxtempo; |
1537 | | |
1538 | 2 | numpats = 1 + (modticks(h, h->tracktime) / h->speed / 64 ); |
1539 | 2 | if (numpats > MAX_PATTERNS) numpats = MAX_PATTERNS; |
1540 | | |
1541 | 2 | if( h->verbose ) printf("Generating %d patterns with speed %d\n", numpats, h->speed); |
1542 | 2 | m_nType = MOD_TYPE_MID; |
1543 | 2 | m_nDefaultSpeed = h->speed; |
1544 | 2 | m_nChannels = numtracks; |
1545 | 2 | m_dwSongFlags = SONG_LINEARSLIDES; |
1546 | 2 | m_nMinPeriod = 28 << 2; |
1547 | 2 | m_nMaxPeriod = 1712 << 3; |
1548 | 2 | if (m_nChannels == 0) |
1549 | 0 | return FALSE; |
1550 | | // orderlist |
1551 | 5 | for(t=0; t < numpats; t++) |
1552 | 3 | Order[t] = t; |
1553 | 2 | if( !PAT_Load_Instruments(this) ) { |
1554 | 0 | avoid_reentry = 0; |
1555 | 0 | return FALSE; |
1556 | 0 | } |
1557 | | // ============================== |
1558 | | // Load the pattern info now! |
1559 | 2 | if( MID_ReadPatterns(Patterns, PatternSize, h, numpats, m_nChannels) ) { |
1560 | | // :^( need one more channel to handle the global events ;^b |
1561 | 0 | m_nChannels++; |
1562 | 0 | h->tp = mid_new_track(h, h->track->chan, 0xff); |
1563 | 0 | for( ttp=h->track; ttp->next; ttp=ttp->next ) ; |
1564 | 0 | ttp->next = h->tp; |
1565 | 0 | mid_add_sync(h, h->tp); |
1566 | 0 | for( t=0; t<numpats; t++ ) { |
1567 | 0 | FreePattern(Patterns[t]); |
1568 | 0 | Patterns[t] = NULL; |
1569 | 0 | } |
1570 | 0 | MID_ReadPatterns(Patterns, PatternSize, h, numpats, m_nChannels); |
1571 | 0 | } |
1572 | | // ============================================================ |
1573 | | // set panning positions |
1574 | 2 | t = 0; |
1575 | 7 | for( ttp=h->track; ttp; ttp=ttp->next ) { |
1576 | 5 | ChnSettings[t].nPan = modpan(ttp->balance, numchans / 2); |
1577 | 5 | ChnSettings[t].nVolume = 64; |
1578 | 5 | t++; |
1579 | 5 | } |
1580 | 2 | if( h->verbose ) printf("Cleanup.\n"); |
1581 | 2 | MID_Cleanup(h); // we dont need it anymore |
1582 | 2 | avoid_reentry = 0; // it is safe now, I'm finished |
1583 | 2 | return TRUE; |
1584 | 2 | } |