home *** CD-ROM | disk | FTP | other *** search
/ Best Objectech Shareware Selections / UNTITLED.iso / boss / musi / misc / 013 / midimod.c < prev    next >
Text File  |  1993-04-13  |  36KB  |  1,385 lines

  1. /*
  2.  * MIDIMOD.C - Amiga Module to MIDI file converter
  3.  * Turbo C 2.0
  4.  *
  5.  * Description: Takes a .mod file and has a good go at converting it to
  6.  *              a .mid file. Equivalents to certain .mod samples can be
  7.  *              set to default to particular MIDI instruments. Multiple
  8.  *              MIDI instrument tables should be supported. Note that .mod
  9.  *              and .mid are at the end of the file.
  10.  *
  11.  * Author: Andrew Scott (Adrenalin Software)
  12.  *
  13.  * Date: 14/3/1993 ver 0.1
  14.  */
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include <dos.h>
  21.  
  22. #include "textwin.h" /* Simple text-windowing environment */
  23. #include "midimod.h" /* Dialog/Info box messages and definitions */
  24.  
  25. #define ANOTE(x) ((x < 0) ? (-x) : (NoteValue(x)))
  26. #define ENOTE(x,y) ((sam->m > 127) ? (sam->m - 128) : (ANOTE(x) + sam->t[y]))
  27.  
  28. bfile MidFile, ModFile;
  29. char SongName[21];
  30. samps Samples;
  31. unsigned long PosLog[64];
  32. int PosI = 0;
  33. string MidFN, ModFN;
  34.  
  35. void OutByte(bfile f, char b)
  36. /* Post: The byte b has been written to the buffer of the file f */
  37. {
  38.     if (f->o == BUFFSIZE) {
  39.         fwrite(f->b, 1, BUFFSIZE, f->f);
  40.         f->o = 0;
  41.   }
  42.     f->b[f->o++] = b;
  43. }
  44.  
  45. void FlushOut(bfile f)
  46. /* Pre: f was opened for writing */
  47. /* Post: The file f has has its buffer flushed */
  48. {
  49.     if (f->o > 0)
  50.         fwrite(f->b, 1, f->o, f->f);
  51.     f->o = 0;
  52. }
  53.  
  54. void CloseOut(bfile f)
  55. /* Pre: f was opened for writing */
  56. /* Post: The file f has been flushed and is now closed */
  57. {
  58.     FlushOut(f);
  59.     fclose(f->f);
  60.     f->f = NULL;
  61. }
  62.  
  63. int OpenOut(bfile f, string fn)
  64. /* Returns: NZ if the file f has been opened for writing with the name fn */
  65. {
  66.     if (f->f != NULL)
  67.         CloseOut(f);
  68.     f->f = fopen(fn, "wb");
  69.     f->o = 0;
  70.     return f->f != NULL;
  71. }
  72.  
  73. unsigned long Beatle(bfile f)
  74. /* Returns: bfile-tell (btell=beatle). The offset from the start */
  75. {
  76.     return ftell(f->f) + f->o;
  77. }
  78.  
  79. unsigned char InByte(bfile f)
  80. /* Pre: f was opened for reading */
  81. /* Returns: The next byte from the file f */
  82. {
  83.     if (f->o == BUFFSIZE && !feof(f->f)) {
  84.         f->r = fread(f->b, 1, BUFFSIZE, f->f);
  85.         if (f->r < BUFFSIZE)
  86.             f->b[f->r] = 0;
  87.         f->o = 0;
  88.     }
  89.     if (f->o < f->r)
  90.          return f->b[f->o++];
  91.     return f->b[f->o];
  92. }
  93.  
  94. void CloseIn(bfile f)
  95. /* Post: The file f is now closed */
  96. {
  97.     fclose(f->f);
  98.     f->f = NULL;
  99. }
  100.  
  101. int OpenIn(bfile f, string fn)
  102. /* Returns: NZ if the file f has been opened for reading with the name fn */
  103. {
  104.     if (f->f != NULL)
  105.         CloseIn(f);
  106.     f->f = fopen(fn, "rb");
  107.     f->o = f->r = BUFFSIZE;
  108.     return f->f != NULL;
  109. }
  110.  
  111. void Inskipp(bfile f, unsigned long n) /* Stainless-steel rat for Pres */
  112. /* Pre: f was opened for reading */
  113. /* Post: f's file pointer has skipped forward n bytes */
  114. {
  115.     n += f->o;
  116.     while (n >= BUFFSIZE && !feof(f->f)) {
  117.         f->r = fread(f->b, 1, BUFFSIZE, f->f);
  118.         if (f->r < BUFFSIZE)
  119.             f->b[f->r] = 0;
  120.         n -= BUFFSIZE;
  121.     }
  122.     f->o = n; /* hmmm.. may cause an error if was eof.. X-fingers */
  123. }
  124.  
  125. struct bpos FPos(bfile f)
  126. /* Returns: All necessary information regarding file f's status */
  127. {
  128.     struct bpos x;
  129.  
  130.     x.d = *f;
  131.     x.p = ftell(f->f);
  132.     return x;
  133. }
  134.  
  135. void FGoto(bfile f, struct bpos x)
  136. /* Pre: x was the status of f previously */
  137. /* Post: File f has had its status changed to x */
  138. {
  139.     fseek(f->f, x.p, SEEK_SET);
  140.     *f = x.d;
  141. }
  142.  
  143. int WriteVLQ(bfile f, unsigned long i)
  144. /*
  145.  * Returns: # of bytes written after a variable-length-quantity equivalent
  146.  *    of i has been written to the file f.
  147.  */
  148. {
  149.     int x = 0;
  150.     unsigned long buffer;
  151.  
  152.     buffer = i & 127;
  153.     while ((i >>= 7) > 0)
  154.         buffer = ((buffer << 8) | 128) + (i & 127);
  155.     while (1) {
  156.         OutByte(f, buffer & 255);
  157.         x++;
  158.         if (buffer & 128)
  159.             buffer >>= 8;
  160.         else
  161.             return x;
  162.     }
  163. }
  164.  
  165. string InitFile(bfile f, string deffn, string t, int inpm)
  166. /* Returns: NULL if file is unacceptable, the filename otherwise. The
  167.  *    filename corresponds to file f, type t, with default filename deffn.
  168.  *    Will open an input file if inpm is NZ. deffn will be freed.
  169.  */
  170. {
  171.     int r = 0;
  172.     string newfn;
  173.  
  174.     _IF[1] = t;
  175.     newfn = DialogBox(_IF, deffn);
  176.     free(deffn);
  177.     if (! *newfn) {
  178.         free(newfn);
  179.         return NULL;
  180.     }
  181.     if (inpm)
  182.         r = OpenIn(f, newfn);
  183.     else if (fclose(fopen(newfn, "r"))==EOF || tolower(InfoBox(_OUTE))=='y')
  184.         r = OpenOut(f, newfn);
  185.     if (!r) {
  186.         free(newfn);
  187.         return NULL;
  188.     }
  189.     return newfn;
  190. }
  191.  
  192. int MKTest(bfile f)
  193. /* Returns: The number of samples in the Module file f */
  194. {
  195.     unsigned long offset;
  196.     int i = 15;
  197.     char s[4];
  198.  
  199.     offset = ftell(f->f);
  200.     if (!fseek(f->f, 1080, SEEK_SET)) {
  201.         fread(s, 1, 4, f->f);
  202.         if (!memcmp(s, "M.K.", 4) || !memcmp(s, "FLT",3))
  203.             i = 31;
  204.     }
  205.     fseek(f->f, offset, SEEK_SET);
  206.     return i;
  207. }
  208.  
  209. string SimplifyName(string s)
  210. /*
  211.  * Returns: A string similar to s, but has had any nasty headers removed
  212.  *    any leading spaces or trailing spaces, and all made lower-case
  213.  */
  214. {
  215.     string t, r, x;
  216.  
  217.     x = strchr(s, ':');
  218.     if (x != NULL && x-s == 5 && tolower(s[0])=='s' && tolower(s[1])=='t' &&
  219.      s[2]=='-') {
  220.         r = x = (string) malloc(18);
  221.         t = s + 6;
  222.         while (*(x++) = *(t++)); /* remove soundtracker header */
  223.     } else
  224.         r = strdup(s);
  225.     for (t = r; *t == ' '; t++);
  226.     x = r;
  227.     while (*(x++) = *(t++)); /* remove leading spaces */
  228.     t = strchr(r, ' ');
  229.     if (t != NULL)
  230.         *t = 0; /* remove 'trailing' spaces */
  231.     return strlwr((string) realloc(r, strlen(r) + 1));
  232. }
  233.  
  234. string GetLine(FILE *f)
  235. /* Returns: Next line from file f, NULL on error/eof */
  236. {
  237.     string s, t;
  238.     int c;
  239.  
  240.     if ((t = s = (string) malloc(MAXSTRING))==NULL) {
  241.         InfoBox(_OOME);
  242.         return NULL;
  243.     }
  244.     while ((c = fgetc(f)) != EOF && c != '\n')
  245.         *(t++) = c;
  246.     if (s == t) {
  247.         free(s);
  248.         return NULL;
  249.     }
  250.     *t = 0;
  251.     return (string) realloc(s, t-s+1);
  252. }
  253.  
  254. int ReadModSpecs(bfile f, string n, samps s)
  255. /*
  256.  * Returns: Z if f is not a supported Amiga Module, else n is set to
  257.  * be the name of the Module and s is set to hold sample information
  258.  */
  259. {
  260.     unsigned char b, c;
  261.     int i;
  262.     string t1;
  263.     samp *t2;
  264.  
  265.     for (i = 20, t1 = n; i--; *(t1++) = InByte(f));
  266.     *t1 = 0;
  267.     c = s->n = MKTest(f);
  268.     for (t2 = s->s; c--; t2++) {
  269.         for (i = 22, t1 = t2->n; i--; *(t1++) = InByte(f));
  270.         *t1 = 0;
  271.         b = InByte(f);
  272.         t2->l = 256 * b + InByte(f);
  273.         if (t2->l < 4)
  274.             t2->l = 0;   /* 6 bytes is pretty much a non-sample */
  275.         b = InByte(f);
  276.         t2->v = InByte(f);
  277.         InByte(f);
  278.         InByte(f);
  279.         b = InByte(f);
  280.         if (256 * b + InByte(f) > 1 && t2->l)
  281.             t2->l = -1;    /* looping: plays 'forever' */
  282.         t2->m = 0;
  283.         t2->t[0] = 0; /* set transposition values to 0 */
  284.         t2->t[1] = 0;
  285.         t2->t[2] = 0;
  286.     }
  287.     return !feof(f->f);
  288. }
  289.  
  290. int SetDefaults(samps s, string fn)
  291. /*
  292.  * Returns: NZ if the samples in s have been sucessfully allocated default
  293.  *    values corresponding to definitions in the DEF_MAPFILE file, and from
  294.  *    a .mm file corresponding to the filename fn
  295.  */
  296. {
  297.     FILE *f;
  298.     char i, m[MAXSTRING];
  299.     int d, e[3], v;
  300.     samp *sam;
  301.     string n, t;
  302.     bfile mmf;
  303.  
  304.     t = strchr(strcpy(m, fn), '.');
  305.     if (t==NULL) {
  306.         i = strlen(m);
  307.         m[i] = '.';
  308.     } else
  309.         i = t-m;
  310.     m[++i] = 'm';
  311.     m[++i] = 'm';
  312.     m[++i] = 0;
  313.     if (OpenIn(mmf, m)) {
  314.         for (i = s->n, sam = s->s; i--; sam++) {
  315.             sam->m = InByte(mmf);
  316.             sam->t[0] = (signed char) InByte(mmf);
  317.             sam->t[1] = (signed char) InByte(mmf);
  318.             sam->t[2] = (signed char) InByte(mmf);
  319.             InByte(mmf); /* volume data - not used */
  320.             InByte(mmf);
  321.             InByte(mmf);
  322.         }
  323.         CloseIn(mmf);
  324.     }
  325.     if ((f = fopen(DEF_MAPFILE, "rt"))==NULL) {
  326.         _NOFIL[3] = DEF_MAPFILE;
  327.         InfoBox(_NOFIL);
  328.         return 0;
  329.     }
  330.     i = s->n;
  331.     for (sam = s->s; i--; sam++)
  332.         if (sam->l) {
  333.             n = SimplifyName(sam->n);
  334.             t = GetLine(f);
  335.             sscanf(t, "%s %d %d %d %d", m, &d, &e[0], &e[1], &e[2]);
  336.             if ((v = strcmp(m, n))>0) {
  337.                 rewind(f);
  338.                 free(t);
  339.                 t = GetLine(f);
  340.                 sscanf(t, "%s %d %d %d %d", m, &d, &e[0], &e[1], &e[2]);
  341.                 v = strcmp(m, n);
  342.             }
  343.             free(t);
  344.             while (v < 0 && (t = GetLine(f)) != NULL) {
  345.                 sscanf(t, "%s %d %d %d %d", m, &d, &e[0], &e[1], &e[2]);
  346.                 free(t);
  347.                 v = strcmp(m, n);
  348.             }
  349.             if (!v) {
  350.                 sam->m = d;
  351.                 sam->t[0] = e[0];
  352.                 sam->t[1] = e[1];