Initial commit.
[amiga/xmodule.git] / Hooks / SaveMIDI.c
1 /*
2 **      SaveMIDI.c
3 **
4 **      Copyright (C) 1994 Bernardo Innocenti
5 **
6 **      Original MOD2MIDI PC code (C) 1993 Andrew Scott
7 **      Amiga Mod2Midi port (C) 1994 Raul Sobon
8 **
9 **      Save internal data to a MIDI type 1 file.
10 */
11
12 #include <exec/types.h>
13
14 #include <clib/dos_protos.h>
15
16 #include <pragmas/dos_pragmas.h>
17
18 #include "XModule.h"
19 #include "Gui.h"
20
21
22 #define ID_MThd         0x4D546864      /* "MThd", Midi Track HeaDer    */
23 #define ID_MTrk         0x4D54726B      /* "MTrk", Midi TRacK                   */
24
25
26
27 #define DRUMCHANNEL 9
28
29 /* Returns a volume in the range 0..127 */
30 #define RESTRICTVOL(v) (((v) < 0) ? 0 : (((v) > 127) ? 127 : (v)))
31
32 /* Convert XModule note -> MIDI note */
33 #define NOTEVALUE(n) ((n)+36)
34
35 #define EVOL(ie,x) (((x) + (ie)->VolShift[0]) * (ie)->VolShift[1] / (ie)->VolShift[2])
36
37 #define ANOTE(x) (((x) < 0) ? (-x) : NOTEVALUE(x))
38
39 #define ENOTE(ie,x,y) (((ie)->MidiCh > 127) ? ((ie)->MidiCh - 128) : (ANOTE(x) + (ie)->Transpose[y]))
40
41
42
43 struct MThd
44 {
45         UWORD unknown1;         /* Set to 1             */
46         UWORD Tracks;
47         UWORD unknown2;         /* Set to 192   */
48 };
49
50 struct TRKInfo
51 {
52         UBYTE unknown1[63];
53         UBYTE NameLen;
54         /* SongName follows */
55 };
56
57 struct InstrExtra
58 {
59         UBYTE MidiCh;
60         UBYTE MidiPr;
61         UBYTE VolShift[3];
62         UBYTE Transpose[3];
63 };
64
65
66 /* Local functions prototypes */
67
68 static UWORD ChooseChannels             (struct Instrument *instr, struct InstrExtra *ie, UBYTE DrumChann);
69 static ULONG WriteTrack0Info    (BPTR fp, struct SongInfo *si);
70 static UWORD WriteMIDIHeader    (BPTR fp, UWORD numofchannels);
71 static LONG WriteVLQ                    (BPTR fp, ULONG i);
72 static ULONG StopNote                   (BPTR fp, struct InstrExtra *ie, UWORD channel, UWORD note, UWORD vol, ULONG timer);
73 static ULONG NoteLength (UBYTE note, ULONG lenght, UWORD beats);
74
75
76
77 UWORD SaveMIDI (struct SongInfo *si, BPTR fp)
78 {
79         UWORD numofchannels, err,
80                 i, j, k;
81         struct Instrument *instr = &si->Inst[0], *inst1;
82         ULONG l;
83         BOOL tempodone = FALSE;
84
85         struct InstrExtra iext[MAXINSTRUMENTS], *ie1;
86
87         DisplayAction (MSG_CHOOSING_CHANNELS);
88
89         /* Setup InstrExtra structures */
90         for (i = 0; i < MAXINSTRUMENTS; i++)
91         {
92                 iext[i].VolShift[0] = 0;
93                 iext[i].VolShift[1] = 1;
94                 iext[i].VolShift[2] = 1;
95                 iext[i].Transpose[0] = 0;
96                 iext[i].Transpose[1] = 0;
97                 iext[i].Transpose[2] = 0;
98         }
99
100
101         /* Get required number of channels */
102         if ((numofchannels = ChooseChannels (instr, iext, DRUMCHANNEL)) > 16)
103         {
104                 ShowMessage (MSG_TOO_MANY_CHANNELS);
105                 return RETURN_FAIL;
106         }
107
108         /* Write Header */
109         if (err = WriteMIDIHeader (fp, numofchannels))
110                 return err;
111
112         DisplayAction (MSG_WRITING_MIDI_TRACKS);
113
114         for (i = 0, inst1 = instr, ie1 = iext ; i < MAXINSTRUMENTS; inst1++, ie1++, i++)
115         {
116                 ULONG count, mktrlenpos, timer, delay[MAXTRACKS];
117                 UBYTE c;
118
119                 if (!i || inst1->Length)
120                 {
121                         if (DisplayProgress (i, MAXINSTRUMENTS))
122                                 return ERROR_BREAK;
123
124                         /* Write MIDI Track */
125                         l = ID_MTrk;
126                         if (!FWrite (fp, &l, 4, 1)) return ERR_READWRITE;
127
128                         /* Write chunk length   (set to 0 now...) */
129
130                         mktrlenpos = Seek (fp, 0, OFFSET_CURRENT);      /* Write it later */
131                         l = 0;
132                         if (!FWrite (fp, &l, 4, 1)) return ERR_READWRITE;
133
134                         if (!i)
135                         {
136                                 if (!(count = WriteTrack0Info (fp, si)))
137                                         return ERR_READWRITE;
138                         }
139                         else
140                         {
141                                 static UBYTE unknown[4] = {0, 255, 3, 0};
142                                 static struct
143                                 {
144                                         UBYTE unknown_zero;
145                                         UBYTE channel;
146                                         UBYTE preset;
147                                 } instrinfo;
148
149                                 /* Write some unknown header */
150                                 unknown[3] = strlen (inst1->Name);
151                                 if (!FWrite (fp, unknown, 4, 1)) return ERR_READWRITE;
152
153                                 /* Write instrument name */
154                                 if (!FWrite (fp, inst1->Name, unknown[3], 1)) return ERR_READWRITE;
155
156                                 instrinfo.unknown_zero = 0;
157                                 instrinfo.channel = c = 0xC0 + ie1->MidiCh;
158                                 instrinfo.unknown_zero = (ie1->MidiPr > 127) ? 126 : ie1->MidiPr;
159                                 if (!FWrite (fp, &instrinfo, sizeof (instrinfo), 1))
160                                         return ERR_READWRITE;
161
162                                 count = sizeof (unknown) + sizeof (instrinfo) + unknown[3];
163                         }
164                 }
165
166                 timer = 0;
167                 if (!i || inst1->Length)
168                 {
169                         UWORD bpm, ticks, l, h;
170                         UBYTE sampnum, effnum, effval, lastsam[MAXTRACKS] = {0}, vol[MAXTRACKS];
171                         BYTE patbreak;
172                         ULONG x, pause;
173                         UWORD note, lastslide, slideto;
174                         UWORD n[MAXTRACKS][48][2];              /* Note data for a song position                */
175                         UWORD lastn[MAXTRACKS];                 /* Last note on a particular channel    */
176
177                         memset (lastn, 0, MAXTRACKS * sizeof (UWORD));
178                         memset (vol, 0, MAXTRACKS);
179                         memset (delay, 0, MAXTRACKS * sizeof (ULONG));
180
181                         bpm = si->GlobalTempo;
182                         ticks = si->GlobalSpeed;
183                         lastslide = slideto = 0;
184                         patbreak = 0;
185
186                         for (h = 48; h--; )
187                                 for (k = MAXTRACKS; k--; )
188                                         n[k][h][0] = 0;
189
190                         for (l = 0; l < si->Length; l++)
191                         {
192                                 struct Pattern *patt = &si->PattData[si->Sequence[l]];
193
194                                 /* ??? */
195                                 if (patbreak > 0)
196                                         patbreak = 1 - patbreak;
197
198                                 for (j = 0; j < patt->Lines; j++)
199                                 {
200                                         pause = 0;
201                                         if (!patbreak)
202                                         {
203                                                 for (k = 0; k < patt->Tracks; k++)
204                                                 {
205                                                         n[k][0][1] = inst1->Volume;
206
207                                                         sampnum = patt->Notes[k]->Inst;
208                                                         note    = patt->Notes[k]->Note;
209                                                         effnum  = patt->Notes[k]->EffNum;
210                                                         effval  = patt->Notes[k]->EffVal;
211
212                                                         if (!i) note = 0;
213
214                                                         if ((note || sampnum) && delay[k])
215                                                         {
216                                                                 count += StopNote (fp, ie1, c, lastn[k], vol[k], timer);
217                                                                 timer = 0;
218                                                                 delay[k] = 0;
219                                                         }
220
221                                                         if (!note && sampnum == i) /* check "defaults" */
222                                                                 note = lastn[k];
223                                                         else
224                                                         {
225                                                                 if (!sampnum)
226                                                                 {
227                                                                         if (lastsam[k] == i)
228                                                                                 sampnum = i;
229                                                                         else
230                                                                                 note = 0;
231                                                                 }
232                                                                 else
233                                                                 {
234                                                                         if (sampnum != i)
235                                                                                 note = 0;
236                                                                         lastsam[k] = sampnum;
237                                                                 }
238                                                                 n[k][0][0] = note;
239                                                         }
240
241                                                         /* Do Effects */
242                                                         switch (effnum)
243                                                         {
244                                                                 case 0x0:                               /* Arpeggio */
245                                                                 {
246                                                                         UWORD nv;
247
248                                                                         if (!i || !effval || ie1->MidiCh > 127)
249                                                                                 break;
250                                                                         if (!note)
251                                                                         {
252                                                                                 if (!delay[k])
253                                                                                         break;
254                                                                                 else
255                                                                                 {
256                                                                                         nv = NOTEVALUE(lastn[k]);
257                                                                                         n[k][47][0] = lastn[k];
258                                                                                         n[k][47][1] = vol[k];
259                                                                                         if (effval & 0xF0)
260                                                                                                 n[k][16][0] = -(nv + ((effval & 0xF0) >> 4));
261                                                                                         n[k][16][1] = vol[k];
262                                                                                         if (effval & 0x0F)
263                                                                                                 n[k][32][0] = -(nv + (effval & 0x0F));
264                                                                                         n[k][32][1] = vol[k];
265                                                                                 }
266                                                                         }
267                                                                         else
268                                                                         {
269                                                                                 nv = NOTEVALUE(note);
270                                                                                 n[k][47][0] = note;
271                                                                                 n[k][47][1] = inst1->Volume;
272                                                                                 if (effval & 0xF0)
273                                                                                         n[k][16][0] = -(nv + ((effval & 0xF0) >> 4));
274                                                                                 n[k][16][1] = inst1->Volume;
275                                                                                 if (effval & 0x0F)
276                                                                                         n[k][32][0] = -(nv + (effval & 0x0F));
277                                                                                 n[k][32][1] = inst1->Volume;
278                                                                         }
279                                                                         break;
280                                                                 }
281
282                                                                 case 0x1:                               /* Slide Up */
283                                                                 case 0x2:                               /* Slide Down */
284                                                                         if (!(effval & 0xFF) || ie1->MidiCh > 127)
285                                                                                 break;
286                                                                         if (effnum == 0x2)
287                                                                                 lastslide = effval;
288                                                                         else
289                                                                                 lastslide = -effval;
290                                                                         if (!note)
291                                                                                 if (!delay[k])
292                                                                                         break;
293                                                                                 else
294                                                                                 {
295                                                                                         n[k][0][0] = lastn[k] + lastslide;
296                                                                                         n[k][0][1] = vol[k];
297                                                                                 }
298                                                                         else
299                                                                                 n[k][0][0] += lastslide;
300                                                                         if (n[k][0][0] < 13)
301                                                                                 n[k][0][0] = 13;        /* C-1 */
302                                                                         else if (n[k][0][0] > 48)
303                                                                                 n[k][0][0] = 48;        /* B#3 */
304                                                                         break;
305
306                                                                 case 0x3:                               /* Slide To */
307                                                                         if (!note && !slideto || note == lastn[k] || ie1->MidiCh > 127)
308                                                                                 break;
309                                                                         if (effval & 0xFF)
310                                                                                 lastslide = effval;
311                                                                         else
312                                                                                 lastslide = abs (lastslide);
313                                                                         if (note)
314                                                                                 slideto = note;
315                                                                         if (slideto > lastn[k])
316                                                                         {
317                                                                                 n[k][0][0] = lastn[k] + lastslide * (ticks-1);
318                                                                                 if (n[k][0][0] < 13)
319                                                                                         n[k][0][0] = 13;        /* C-1 */
320                                                                                 if (n[k][0][0] > slideto)
321                                                                                         n[k][0][0] = slideto;
322                                                                         }
323                                                                         else
324                                                                         {
325                                                                                 n[k][0][0] = lastn[k] - lastslide*(ticks-1);
326                                                                                 if (n[k][0][0] > 48)
327                                                                                         n[k][0][0] = 48;        /* B#3 */
328                                                                                 if (n[k][0][0] < slideto)
329                                                                                         n[k][0][0] = slideto;
330                                                                         }
331                                                                         n[k][0][1] = vol[k];
332                                                                         break;
333
334                                                                 case 0x4:                       /* Vibrato */
335                                                                 case 0x7:                       /* Tremolo */
336                                                                         /* ignore these effects.. not convertable */
337                                                                         break;
338
339                                                                 case 0x5:                       /* Slide To + Volume Slide */
340                                                                         if ((note || slideto) && note!=lastn[k] && ie1->MidiCh < 128)
341                                                                         {
342                                                                                 if (note)
343                                                                                         slideto = note;
344                                                                                 if (slideto > lastn[k])
345                                                                                 {
346                                                                                         n[k][0][0] = lastn[k] + lastslide*(ticks-1);
347                                                                                         if (n[k][0][0] < 13)
348                                                                                                 n[k][0][0] = 13;        /* C-1 */
349                                                                                         if (n[k][0][0] > slideto)
350                                                                                                 n[k][0][0] = slideto;
351                                                                                 }
352                                                                                 else
353                                                                                 {
354                                                                                         n[k][0][0] = lastn[k] - lastslide*(ticks-1);
355                                                                                         if (n[k][0][0] > 48)
356                                                                                                 n[k][0][0] = 48;        /* B#3 */
357                                                                                         if (n[k][0][0] < slideto)
358                                                                                                 n[k][0][0] = slideto;
359                                                                                 }
360                                                                         }
361                                                                         else
362                                                                                 n[k][0][0] = 0;
363                                                                         note = 0;
364
365                                                                         /* We do not break here: the next case block (0xA)
366                                                                          * will slide volume for us
367                                                                          */
368
369                                                                 case 0x6:                       /* Vibrato & Volume Slide */
370                                                                         /* Ignore Vibrato; do Volume Slide only */
371
372                                                                 case 0xA:                       /* Volume Slide */
373                                                                 {
374                                                                         UWORD v;
375
376                                                                         if (!note)
377                                                                                 v = vol[k];
378                                                                         else
379                                                                                 v = inst1->Volume;
380                                                                         v += (ticks-1)*(effval & 0xF0); /* Can't really slide */
381                                                                         v -= (ticks-1)*(effval & 0x0F);
382                                                                         if (v > 127)
383                                                                                 v = 127;
384                                                                         else if (v < 0)
385                                                                                 v = 0;
386                                                                         n[k][0][1] = v;
387                                                                         break;
388                                                                 }
389
390                                                                 case 0x9:               /* Set offset: pretend it's retrigger */
391                                                                         if ((!n[k][0][0] || !sampnum) && delay[k])
392                                                                         {
393                                                                                 n[k][0][0] = lastn[k];
394                                                                                 n[k][0][1] = vol[k];
395                                                                         }
396                                                                         break;
397
398                                                                 case 0xB:                       /* Position Jump */
399                                                                         patbreak = 1;   /* Ignore, but break anyway */
400                                                                         break;
401
402                                                                 case 0xD:                       /* Pattern Break */
403                                                                         patbreak = 1 + 10 * (effval & 0xF0) + (effval & 0x0F);
404                                                                         break;
405
406                                                                 case 0xC:                       /* Set Volume */
407                                                                         {
408                                                                                 UWORD vol = effval;
409
410                                                                                 if (vol == 0x40) vol=0x3F;
411                                                                                 vol = vol & 0x3F;
412                                                                                 n[k][0][1] = vol << 1;
413                                                                         }
414                                                                         break;
415
416                                                                 case 0xF:                       /* Set Speed/Tempo */
417                                                                 {
418                                                                         UWORD temp;
419
420                                                                         temp = effval;
421
422                                                                         if (!temp)
423                                                                                 temp = 1;
424                                                                         if (temp < 32)
425                                                                         {
426                                                                                 ticks = temp;
427                                                                         //      if (TempoType)  /* Tempos act strangely so .. */
428                                                                                 {
429                                                                                         bpm = 750 / temp;
430                                                                                         x = 80000 * temp;
431                                                                                 }
432                                                                         }
433                                                                         else
434                                                                         {
435                                                                                 bpm = temp;
436                                                                                 x = 60000000 / temp;
437                                                                         }
438
439                                                                         if (i)          /* Only write tempo on track 0 */
440                                                                                 break;
441
442                                                                         count += 6 + WriteVLQ (fp, timer);
443                                                                         timer = 0;
444                                                                         FPutC (fp, 255);        /* Meta-Event   */
445                                                                         FPutC (fp, 81);         /* Set Tempo    */
446                                                                         FPutC (fp, 3);
447                                                                         FPutC (fp, x >> 16);
448                                                                         FPutC (fp, (x >> 8) & 0xFF);
449                                                                         FPutC (fp, x & 0xFF);
450                                                                         tempodone = TRUE;
451
452                                                                         break;
453                                                                 }
454
455                                                                 case 0xE:               /* Extended Effects */
456                                                                         switch (effval & 0xF0)
457                                                                         {
458                                                                                 case 0x10:              /* Fine Slide Up */
459                                                                                         if (!(effval & 0x0F) || ie1->MidiCh > 127)
460                                                                                                 break;
461                                                                                         if (!note)
462                                                                                         {
463                                                                                                 if (!delay[k])
464                                                                                                         break;
465                                                                                                 else
466                                                                                                 {
467                                                                                                         n[k][h][0] = lastn[k] + (effval & 0x0F);
468                                                                                                         n[k][h][1] = vol[k];
469                                                                                                 }
470                                                                                         }
471                                                                                         else
472                                                                                                 n[k][h][0] += effval & 0x0F;
473                                                                                         break;
474
475                                                                                 case 0x020:             /* Fine Slide Down */
476                                                                                         if (!(effval & 0x0F) || ie1->MidiCh > 127)
477                                                                                                 break;
478                                                                                         if (!note)
479                                                                                                 if (!delay[k])
480                                                                                                         break;
481                                                                                                 else {
482                                                                                                         n[k][h][0] = lastn[k] - (effval & 0x0F);
483                                                                                                         n[k][h][1] = vol[k];
484                                                                                                 }
485                                                                                         else
486                                                                                                 n[k][h][0] -= effval & 0x0F;
487                                                                                         break;
488                                                                                 case 0x00: /* set filter on/off */
489                                                                                 case 0x30: /* glissando on/off */
490                                                                                 case 0x40: /* set vibrato wave */
491                                                                                 case 0x50: /* set finetune */
492                                                                                 case 0x60: /* pattern loop */
493                                                                                 case 0x70: /* set tremolo wave */
494                                                                                 case 0x80: /* un-used */
495                                                                                 case 0xF0: /* invert loop */
496                                                                                         /* Can't do these in MIDI.. ignore */
497                                                                                         break;
498
499                                                                                 case 0x0A0:             /* Fine volume slide up         */
500                                                                                 case 0x0B0:             /* Fine volume slide down       */
501                                                                                 {
502                                                                                         UWORD v;
503
504                                                                                         v = inst1->Volume;
505                                                                                         if (effval & 0xA0)
506                                                                                                 v += effval & 0x0F;
507                                                                                         else
508                                                                                                 v -= effval & 0x0F;
509                                                                                         if (v < 0)
510                                                                                                 v = 0;
511                                                                                         else if (v>127)
512                                                                                                 v = 127;
513                                                                                         n[k][0][1] = v;
514                                                                                         break;
515                                                                                 }
516
517                                                                                 case 0x90:              /* Retrigger sample */
518                                                                                 {
519                                                                                         UWORD a, b, c;
520
521                                                                                         if (!note && !delay[k] || !(effval & 0x0F))
522                                                                                                 break;
523                                                                                         a = effval & 0x0F;
524                                                                                         if (!(ticks / a))
525                                                                                                 break;
526                                                                                         if (!note)
527                                                                                         {
528                                                                                                 n[k][0][0] = lastn[k];
529                                                                                                 n[k][0][1] = vol[k];
530                                                                                         }
531                                                                                         c = 0;
532                                                                                         b = 1;
533                                                                                         a *= 48;
534                                                                                         while (c < 48)
535                                                                                         {
536                                                                                                 n[k][c][0] = note;
537                                                                                                 n[k][c][1] = n[k][0][1];
538                                                                                                 c = b * a / ticks;
539                                                                                                 b++;
540                                                                                         }
541
542                                                                                         break;
543                                                                                 }
544
545                                                                                 case 0xC0:              /* Cut sample */
546                                                                                 {
547                                                                                         UWORD a;
548
549                                                                                         if (!note && !delay[k])
550                                                                                                 break;
551                                                                                         a = 48 * (effval & 0x0F) / ticks;
552                                                                                         if (a > 47)
553                                                                                                 break;
554                                                                                         if (note)
555                                                                                                 n[k][a][0] = note;
556                                                                                         else
557                                                                                                 n[k][a][0] = lastn[k];
558                                                                                         n[k][a][1] = 0;
559                                                                                         break;
560                                                                                 }
561
562                                                                                 case 0xD0:              /* Delay Sample */
563                                                                                 {
564                                                                                         UWORD a;
565
566                                                                                         if (!note || !(effval & 0x0F))
567                                                                                                 break;
568                                                                                         a = 48 * (effval & 0x0F) / ticks;
569                                                                                         n[k][0][0] = 0;
570                                                                                         if (a > 47)
571                                                                                                 break;
572                                                                                         n[k][a][0] = note;
573                                                                                         n[k][a][1] = n[k][a][0];
574                                                                                         break;
575                                                                                 }
576
577                                                                                 case 0xE0:              /* Pattern Pause */
578                                                                                         pause = 48 * (effval & 0x0F);
579                                                                                         break;
580
581                                                                         }       /* End Switch (E effects) */
582
583                                                                         break;
584                                                                         /* else dunno what it does.. disbelieve it ;) */
585
586                                                         }       /* End switch (effnum) */
587
588                                                 }       /* End for (Tracks) */
589                                         }       /* End if (!pattnreak) */
590
591                                         for (h = 0; h<48; h++)
592                                         {
593                                                 for (k = 0; k < patt->Tracks; k++)
594                                                 {
595                                                         if (n[k][h][0])
596                                                         {
597                                                                 if (delay[k])  /* Turn off old note on same channel */
598                                                                 {
599                                                                         count += StopNote (fp, ie1, c, lastn[k], vol[k], timer);
600                                                                         timer = 0;
601                                                                         delay[k] = 0;
602                                                                 }
603                                                                 lastn[k] = n[k][h][0];
604                                                                 n[k][h][0] = 0;
605                                                                 vol[k] = n[k][h][1];
606                                                                 count += 3 + WriteVLQ(fp, timer);
607                                                                 timer = 0;
608                                                                 FPutC (fp, 0x90 + c);   /* Note On */
609                                                                 FPutC (fp, ENOTE(ie1, lastn[k], 0));
610                                                                 FPutC (fp, RESTRICTVOL(EVOL(ie1,vol[k])));
611                                                                 if (ie1->Transpose[1])
612                                                                 {
613                                                                         count += 4;
614                                                                         FPutC (fp, 0);
615                                                                         FPutC (fp, 0x90 + c);
616                                                                         FPutC (fp, ENOTE(ie1, lastn[k], 1));
617                                                                         FPutC (fp, RESTRICTVOL(EVOL(ie1, vol[k])));
618                                                                         if (ie1->Transpose[2])
619                                                                         {
620                                                                                 count += 4;
621                                                                                 FPutC (fp, 0);
622                                                                                 FPutC (fp, 0x90 + c);
623                                                                                 FPutC (fp, ENOTE(ie1, lastn[k], 2));
624                                                                                 FPutC (fp, RESTRICTVOL(EVOL(ie1, vol[k])));
625                                                                         }
626                                                                 }
627                                                                 delay[k] = NoteLength (ANOTE(lastn[k]), inst1->Length, bpm);
628                                                         }
629                                                         else if (delay[k]==1)
630                                                         {
631                                                                 delay[k] = 0;
632                                                                 count += StopNote (fp, ie1, c, lastn[k], vol[k], timer);
633                                                                 timer = 0;
634                                                         }
635                                                         else if (delay[k]>0)
636                                                                 delay[k]--;
637                                                 }
638                                                 timer++;
639                                         }
640                                         timer += pause;
641                                         if (patbreak<0)
642                                                 patbreak++;
643                                         else if (patbreak>0)
644                                         {
645                                                 patbreak = 1 - patbreak;
646                                                 j = 0;
647                                         }
648                                 }       /* End for (Lines) */
649                         }       /* End for (si->Length) */
650
651                         for (k = 0; k < si->MaxTracks; k++)
652                                 if (delay[k])
653                                 {
654                                         count += StopNote (fp, ie1, c, lastn[k], vol[k], timer);
655                                         timer = 0;
656                                 }
657                 }
658
659                 if(!i && !tempodone)
660                 {
661                         count += 7;
662                         FPutC (fp, 0);          /* Give the default 128 bpm if none done yet */
663                         FPutC (fp, 255);
664                         FPutC (fp, 81);
665                         FPutC (fp, 3);
666                         FPutC (fp, 7);
667                         FPutC (fp, 39);
668                         FPutC (fp, 14);
669                 }
670
671                 if(inst1->Length || !i)         // RAUL addition
672                 {
673                         count += 3 + WriteVLQ (fp, timer);
674                         FPutC (fp, 255);
675                         FPutC (fp, 47);
676                         FPutC (fp, 0);
677
678                         /* Write total chunk length */
679
680                         if (Seek (fp, mktrlenpos, OFFSET_BEGINNING) == -1)
681                                 return ERR_READWRITE;
682
683                         if (!(FWrite (fp, &count, 4, 1)))
684                                 return ERR_READWRITE;
685
686                         if (Seek (fp, 0, OFFSET_END) == -1)
687                                 return ERR_READWRITE;
688                 }
689
690         }       /* End for (instruments) */
691
692         return RETURN_OK;
693 }
694
695
696
697 static UWORD ChooseChannels (struct Instrument *instr, struct InstrExtra *ie, UBYTE DrumChann)
698
699 /*      Returns: The number of different channels needed to play instruments.
700  *      If that number is not greater than 16, upto 16 channels will
701  *      be allocated to the samples.
702  */
703 {
704         UBYTE c, Presets[128], m, n, numchan;
705         UBYTE DrumUsed = 0;
706         struct Instrument *instr1, *instr2;
707         struct InstrExtra *ie1, *ie2;
708
709         /* Preset all presets !!! */
710         for (n = 0; n < MAXINSTRUMENTS; n++)
711                 ie[n].MidiPr = n;
712
713         memset (Presets, 0, 128);
714
715         for (n = MAXINSTRUMENTS, instr1 = &instr[1], ie1 = &ie[1]; n--; instr1++, ie1++)
716         {
717                 ie->MidiCh = 255;
718                 if (instr1->Length)
719                 {
720                         if (ie1->MidiPr > 127)
721                         {
722                                 DrumUsed = 1;
723                                 ie1->MidiCh = DrumChann;
724                         }
725                         else
726                                 Presets[ie1->MidiPr] = 1;
727                 }
728                 else
729                         ie1->MidiPr = 0;
730         }
731
732         for (numchan = DrumUsed, n = 128; n--; numchan += Presets[n]);
733
734         if (numchan > 16)
735                 return numchan;
736
737         /* Go through and set channels appropriately */
738         m = MAXINSTRUMENTS;
739         instr1 = &instr[1];
740         ie1 = &ie[1];
741         c = 0;
742         while (--m)
743         {
744                 if (ie1->MidiCh < 0)
745                 {
746                         ie1->MidiCh = c;
747                         n = m;
748                         ie2 = ie1 + 1;
749                         instr2 = instr1 + 1;
750
751                         /* Search for other instruments with the same preset and set
752                          * all them to the same MIDI channel.
753                          */
754                         while (n--)
755                         {
756                                 if (ie2->MidiCh < 0)
757                                         if (ie2->MidiPr == ie1->MidiPr || !instr2->Length)
758                                                 ie2->MidiCh = c;
759                                 instr2++;
760                                 ie2++;
761                         }
762                         if (++c == DrumChann && DrumUsed)
763                                 c++;
764                 }
765                 ie1++;
766                 instr1++;
767         }
768         return numchan;
769 }
770
771
772
773 static UWORD WriteMIDIHeader (BPTR fp, UWORD numofchannels)
774 {
775         ULONG l;
776
777         /* Write MIDI header    */
778         l = ID_MThd;
779         if (!FWrite (fp, &l, 4, 1)) return ERR_READWRITE;
780
781         /* Write chunk length   */
782         l = sizeof (struct MThd);
783         if (!FWrite (fp, &l, 4, 1)) return ERR_READWRITE;
784
785         /* Write header chunk   */
786         {
787                 struct MThd mthd;
788
789                 mthd.unknown1 = 1;
790                 mthd.Tracks = numofchannels;
791                 mthd.unknown2 = 192;
792
793                 if (!FWrite (fp, &mthd, sizeof (mthd), 1)) return ERR_READWRITE;
794         }
795
796         return RETURN_OK;
797 }
798
799
800
801 static ULONG WriteTrack0Info (BPTR fp, struct SongInfo *si)
802
803 /* Write info for track 0.
804  * Return actual number of bytes written, or 0 for failure.
805  */
806 {
807         static UBYTE TRK0I[63] =
808         {
809                 0, 255, 2, 42, 70, 105, 108, 101, 32, 67, 111, 112, 121, 114, 105, 103,
810                 104, 116, 32, 40, 99, 41, 32, 49 ,57, 57, 51, 32, 65, 100, 114, 101, 110,
811                 97, 108, 105, 110, 32, 83, 111, 102, 116, 119, 97, 114, 101,
812                 0, 255, 88, 4, 3, 2, 24, 8,
813                 0, 255, 89, 2, 0, 0,
814                 0, 255, 3
815         }; /* standard header + copyright message */
816
817         struct TRKInfo trkinfo;
818
819         memcpy (trkinfo.unknown1, TRK0I, 63);
820         trkinfo.NameLen = strlen (si->SongName);
821
822         if (!FWrite (fp, &trkinfo, sizeof (trkinfo), 1))
823                 return 0;
824
825         if (!FWrite (fp, si->SongName, trkinfo.NameLen, 1))
826                 return 0;
827
828         return (sizeof (trkinfo) + trkinfo.NameLen);
829 }
830
831
832
833 static LONG WriteVLQ (BPTR fp, ULONG i)
834
835 /*      Writes a stream of bytes, each with the msb (bit 7) set to 1 to mean
836  *      continuation and 0 to end the byte sequnce.  Note that the data is
837  *      put in reverse order.
838  *
839  *      Returns: # of bytes written after a variable-length-quantity equivalent
840  *      of i has been written to the file f, or 0 for failure.
841  */
842 {
843         LONG x = 0;
844         ULONG buffer;
845
846         buffer = i & 0x7F;
847         while ((i >>= 7) > 0)
848                 buffer = ((buffer << 8) | 0x80) + (i & 0x7F);
849         while (1)
850         {
851                 FPutC (fp, buffer & 0xFF);
852
853                 x++;
854
855                 if (buffer & 0x80)
856                         buffer >>= 8;
857                 else
858                         return x;
859         }
860 }
861
862
863
864 static ULONG StopNote (BPTR fp, struct InstrExtra *ie, UWORD channel, UWORD note, UWORD vol, ULONG timer)
865
866 /* stop old note */
867 {
868         UWORD count = 3 + WriteVLQ (fp, timer);
869
870         FPutC (fp, 0x80 + channel);     /* note off */
871         FPutC (fp, ENOTE(ie, note, 0));
872         FPutC (fp, RESTRICTVOL(EVOL(ie, vol)));
873         if (ie->Transpose[1])
874         {
875                 count += 4;
876                 FPutC (fp, 0);
877                 FPutC (fp, 0x80 + channel);
878                 FPutC (fp, ENOTE(ie, note, 1));
879                 FPutC (fp, RESTRICTVOL(EVOL(ie, vol)));
880                 if (ie->Transpose[2])
881                 {
882                         count += 4;
883                         FPutC (fp, 0);
884                         FPutC (fp, 0x80 + channel);
885                         FPutC (fp, ENOTE(ie, note, 2));
886                         FPutC (fp, RESTRICTVOL(EVOL(ie, vol)));
887                 }
888         }
889
890         return count;
891 }
892
893
894
895 static ULONG NoteLength (UBYTE note, ULONG lenght, UWORD beats)
896
897 {
898         ULONG idx;
899
900         /* Note conversion table for Sound/Noise/ProTracker */
901         static const UWORD TrackerNotes[] =
902         {
903                 0x000,                                                                          /* Null note */
904
905                 0x6B0, 0x650, 0x5F5, 0x5A0, 0x54D, 0x501,       /* Octave 0 */
906                 0x4B9, 0x475, 0x435, 0x3F9, 0x3C1, 0x38B,
907
908                 0x358, 0x328, 0x2FA, 0x2D0, 0x2A6, 0x280,       /* Octave 1 */
909                 0x25C, 0x23A, 0x21A, 0x1FC, 0x1E0, 0x1C5,
910
911                 0x1AC, 0x194, 0x17D, 0x168, 0x153, 0x140,       /* Octave 2 */
912                 0x12E, 0x11d, 0x10D, 0x0FE, 0x0F0, 0x0E2,
913
914                 0x0D6, 0x0CA, 0x0BE, 0x0B4, 0x0AA, 0x0A0,       /* Octave 3 */
915                 0x097, 0x08F, 0x087, 0x07F, 0x078, 0x071,
916
917                 0x06B, 0x065, 0x05F, 0x05A, 0x055, 0x050,       /* Octave 4 */
918                 0x04C, 0x047, 0x043, 0x040, 0x03C, 0x039,
919
920                 0x035, 0x032, 0x030, 0x02D, 0x02A, 0x028,       /* Octave 5 */
921                 0x026, 0x024, 0x022, 0x020, 0x01E, 0x01C
922         };
923
924 /*      static float t[84] =
925         {
926                 3.200e-3, 3.020e-3, 2.851e-3, 2.691e-3, 2.540e-3, 2.397e-3,
927                 2.263e-3, 2.136e-3, 2.016e-3, 1.903e-3, 1.796e-3, 1.695e-3,
928                 1.600e-3, 1.510e-3, 1.425e-3, 1.345e-3, 1.270e-3, 1.197e-3,
929                 1.131e-3, 1.068e-3, 1.008e-3, 9.514e-4, 8.980e-4, 8.476e-4,
930                 8.000e-4, 7.551e-4, 7.127e-4, 6.727e-4, 6.350e-4, 5.993e-4,
931                 5.657e-4, 5.339e-4, 5.040e-4, 4.757e-4, 4.490e-4, 4.238e-4,
932                 4.000e-4, 3.775e-4, 3.564e-4, 3.364e-4, 3.175e-4, 2.997e-4,
933                 2.828e-4, 2.670e-4, 2.520e-4, 2.378e-4, 2.245e-4, 2.119e-4,
934                 2.000e-4, 1.888e-4, 1.782e-4, 1.682e-4, 1.587e-4, 1.498e-4,
935                 1.414e-4, 1.335e-4, 1.260e-4, 1.189e-4, 1.122e-4, 1.059e-4,
936                 1.000e-4, 9.439e-5, 8.909e-5, 8.409e-5, 7.937e-5, 7.492e-5,
937                 7.071e-5, 6.674e-5, 6.300e-5, 5.946e-5, 5.612e-5, 5.297e-5,
938                 5.000e-5, 4.719e-5, 4.454e-5, 4.204e-5, 3.969e-5, 3.746e-5,
939                 3.536e-5, 3.337e-5, 3.150e-5, 2.973e-5, 2.806e-5, 2.649e-5
940         }; */ /* multipliers for each pitch: 12th roots of 2 apart */
941
942         idx = note - 36;
943         if (idx < 0) idx = 0;
944         if (idx > 84) idx = 84;
945
946         return (TrackerNotes[idx] * beats * lenght); /* better not slide out of this range :( */
947 }