Coverage Report

Created: 2026-07-12 08:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}