home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.70.zip / src / mod2sng.c < prev    next >
C/C++ Source or Header  |  2008-04-01  |  9KB  |  321 lines

  1. /*
  2.  * MOD (4chn) -> GoatTracker SNG converter.
  3.  * Dedicated to T.M.R!
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include "bme_end.h"
  10.  
  11. typedef struct
  12. {
  13.   unsigned char note;
  14.   unsigned char instr;
  15.   unsigned char command;
  16.   unsigned char data;
  17. } NOTE;
  18.  
  19. typedef struct
  20. {
  21.   unsigned char note;
  22.   unsigned char command;
  23.   unsigned char data;
  24. } GOATNOTE;
  25.  
  26.  
  27. unsigned short periodtable[16][12] =
  28. {
  29.   {6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624},
  30.   {6800, 6416, 6056, 5720, 5392, 5096, 4808, 4536, 4280, 4040, 3816, 3600},
  31.   {6752, 6368, 6016, 5672, 5360, 5056, 4776, 4504, 4256, 4016, 3792, 3576},
  32.   {6704, 6328, 5968, 5632, 5320, 5024, 4736, 4472, 4224, 3984, 3760, 3552},
  33.   {6656, 6280, 5928, 5592, 5280, 4984, 4704, 4440, 4192, 3960, 3736, 3528},
  34.   {6608, 6232, 5888, 5552, 5240, 4952, 4672, 4408, 4160, 3928, 3704, 3496},
  35.   {6560, 6192, 5840, 5512, 5208, 4912, 4640, 4376, 4128, 3896, 3680, 3472},
  36.   {6512, 6144, 5800, 5472, 5168, 4880, 4600, 4344, 4104, 3872, 3656, 3448},
  37.   {7256, 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4032, 3840},
  38.   {7200, 6800, 6416, 6056, 5720, 5400, 5088, 4808, 4536, 4280, 4040, 3816},
  39.   {7152, 6752, 6368, 6016, 5672, 5360, 5056, 4776, 4504, 4256, 4016, 3792},
  40.   {7096, 6704, 6328, 5968, 5632, 5320, 5024, 4736, 4472, 4224, 3984, 3760},
  41.   {7048, 6656, 6280, 5928, 5592, 5280, 4984, 4704, 4440, 4192, 3952, 3736},
  42.   {7000, 6608, 6232, 5888, 5552, 5240, 4952, 4672, 4408, 4160, 3928, 3704},
  43.   {6944, 6560, 6192, 5840, 5512, 5208, 4912, 4640, 4376, 4128, 3896, 3680},
  44.   {6896, 6512, 6144, 5800, 5472, 5168, 4880, 4600, 4344, 4104, 3872, 3656}
  45. };
  46.  
  47. unsigned char modheader[1084];
  48. unsigned char modpatterns[64*64*4*4];
  49. NOTE modnotes[64*64*4];
  50. GOATNOTE goatnotes[208][65];
  51. unsigned char orderlist[3][256];
  52. GOATNOTE tempnotes[65];
  53.  
  54. char ident[] = {'G', 'T', 'S', '!'};
  55.  
  56. char zeroarray[32] = {0};
  57.  
  58. int maxpatt = 0;
  59. int orderlen;
  60. int leaveout = 3;
  61. int transpose = 0;
  62. int goatchan = 0;
  63. int goatpatt = 0;
  64.  
  65. int main(int argc, char **argv)
  66. {
  67.   FILE *in, *out;
  68.   int c, d;
  69.   unsigned char *srcptr;
  70.   NOTE *destptr;
  71.  
  72.   if (argc < 3)
  73.   {
  74.     printf("Usage: mod2sng <mod> <sng> [channel] [transpose]\n"
  75.            "[channel] is the channel to leave out (1-4), default 4\n"
  76.            "[transpose] is the halfstep transpose added to notes, default 0\n");
  77.  
  78.     return 1;
  79.   }
  80.  
  81.   in = fopen(argv[1], "rb");
  82.   if (!in)
  83.   {
  84.     printf("Source open error.\n");
  85.     return 1;
  86.   }
  87.   out = fopen(argv[2], "wb");
  88.   if (!out)
  89.   {
  90.     printf("Destination open error.\n");
  91.     return 1;
  92.   }
  93.   if (argc > 3)
  94.   {
  95.     sscanf(argv[3], "%d", &leaveout);
  96.     leaveout--;
  97.     if ((leaveout < 0) || (leaveout > 3))
  98.     {
  99.       printf("Illegal channel number.\n");
  100.       return 1;
  101.     }
  102.   }
  103.  
  104.   if (argc > 4)
  105.   {
  106.     sscanf(argv[4], "%d", &transpose);
  107.   }
  108.  
  109.   for (c = 0; c < 1084; c++)
  110.   {
  111.     modheader[c] = fread8(in);
  112.   }
  113.   orderlen = modheader[950];
  114.   for (c = 0; c < 128; c++)
  115.   {
  116.     if (modheader[952+c] > maxpatt) maxpatt = modheader[952+c];
  117.   }
  118.   maxpatt++;
  119.   for (c = 0; c < maxpatt * 1024; c++)
  120.   {
  121.     modpatterns[c] = fread8(in);
  122.   }
  123.   fclose(in);
  124.  
  125.   // Convert patterns into easier-to-read format
  126.  
  127.   destptr = modnotes;
  128.   srcptr = modpatterns;
  129.   for (c = 0; c < maxpatt * 256; c++)
  130.   {
  131.     // Note: FT2 saves the 13th bit of period into 5th bit of
  132.     // samplenumber, and when loading it ofcourse cannot read
  133.     // the period back correctly! We don't use the 13th bit!
  134.  
  135.     unsigned short period = ((srcptr[0] & 0x0f) << 8) | srcptr[1];
  136.     unsigned char note = 0, instrument, command;
  137.     if (period)
  138.     {
  139.       int findnote;
  140.       int offset = 0x7fffffff;
  141.  
  142.       for (findnote = 0; findnote < 96; findnote++)
  143.       {
  144.         if (abs(period - (periodtable[0][findnote % 12] >> (findnote / 12))) < offset)
  145.         {
  146.           note = findnote + 1;
  147.           offset = abs(period - (periodtable[0][findnote % 12] >> (findnote / 12)));
  148.         }
  149.       }
  150.     }
  151.     instrument = (srcptr[0] & 0xf0) | ((srcptr[2] & 0xf0) >> 4);
  152.     command = srcptr[2] & 0x0f;
  153.     destptr->note = note;
  154.     destptr->instr = instrument;
  155.     destptr->command = command;
  156.     destptr->data = srcptr[3];
  157.     srcptr += 4;
  158.     destptr++;
  159.   }
  160.  
  161.   // Convert patterns into goatpatterns, and create orderlists
  162.   for (c = 0; c < 4; c++)
  163.   {
  164.     if (c != leaveout)
  165.     {
  166.       for (d = 0; d < orderlen; d++)
  167.       {
  168.         int patt = modheader[952+d];
  169.         int e = 0;
  170.         int o = patt*256+c;
  171.         int breakflag = 0;
  172.         unsigned char prevgoatdata = 0;
  173.  
  174.         memset(tempnotes, 0, sizeof tempnotes);
  175.         for (;;)
  176.         {
  177.           unsigned char goatcommand = 0;
  178.           unsigned char goatdata = 0;
  179.  
  180.           if (modnotes[o+e*4].note)
  181.           {
  182.             tempnotes[e].note = modnotes[o+e*4].note - 1 + transpose;
  183.             if (tempnotes[e].note > 0x5d) tempnotes[e].note = 0x5d;
  184.           }
  185.           else tempnotes[e].note = 0x5f;
  186.           switch(modnotes[o+e*4].command)
  187.           {
  188.             case 0:
  189.             goatcommand = modnotes[o+e*4].command;
  190.             goatdata = modnotes[o+e*4].data;
  191.             break;
  192.  
  193.             case 1:
  194.             case 2:
  195.             case 3:
  196.             case 4:
  197.             goatcommand = modnotes[o+e*4].command;
  198.             if (modnotes[o+e*4].data) goatdata = modnotes[o+e*4].data;
  199.             else goatdata = prevgoatdata;
  200.             prevgoatdata = goatdata;
  201.             break;
  202.  
  203.             case 0xf:
  204.             if (modnotes[o+e*4].data < 0x20) // Ticktempo
  205.             {
  206.               goatcommand = 7;
  207.               goatdata = modnotes[o+e*4].data;
  208.             }
  209.             break;
  210.  
  211.             case 0xc:
  212.             // Convert zero volume to keyoff
  213.             if ((!modnotes[o+e*4].data) && (tempnotes[e].note == 0x5f))
  214.               tempnotes[e].note = 0x5e;
  215.             break;
  216.  
  217.             case 0xb:
  218.             case 0xd:
  219.             breakflag = 1;
  220.             break;
  221.  
  222.             default:
  223.             break;
  224.           }
  225.           tempnotes[e].command = (modnotes[o+e*4].instr << 3) | goatcommand;
  226.           tempnotes[e].data = goatdata;
  227.  
  228.           e++;
  229.           if (e == 64) break;
  230.           if (breakflag) break;
  231.         }
  232.         tempnotes[e].note = 0xff;
  233.         for (e = 0; e < goatpatt; e++)
  234.         {
  235.           int f;
  236.           for (f = 0; f < 65; f++)
  237.           {
  238.             if ((goatnotes[e][f].note != tempnotes[f].note) ||
  239.                 (goatnotes[e][f].command != tempnotes[f].command) ||
  240.                 (goatnotes[e][f].data != tempnotes[f].data)) break;
  241.           }
  242.           // Same pattern
  243.           if (f == 65)
  244.           {
  245.             orderlist[goatchan][d] = e;
  246.             break;
  247.           }
  248.         }
  249.         // No same pattern pattern
  250.         if (e == goatpatt)
  251.         {
  252.           int f;
  253.           if (goatpatt >= 208)
  254.           {
  255.             printf("208 patterns exceeded!\n");
  256.             return 1;
  257.           }
  258.           for (f = 0; f < 65; f++)
  259.           {
  260.             goatnotes[goatpatt][f].note = tempnotes[f].note;
  261.             goatnotes[goatpatt][f].command = tempnotes[f].command;
  262.             goatnotes[goatpatt][f].data = tempnotes[f].data;
  263.           }
  264.           orderlist[goatchan][d] = goatpatt;
  265.           goatpatt++;
  266.         }
  267.       }
  268.       goatchan++;
  269.     }
  270.   }
  271.   fwrite(ident, 4, 1, out); // Ident
  272.   fwrite(&modheader[0], 20, 1, out); // Infotexts
  273.   fwrite(zeroarray, 12, 1, out);
  274.   fwrite(zeroarray, 32, 1, out);
  275.   fwrite(zeroarray, 32, 1, out);
  276.   fwrite8(out, 1); // Number of songs
  277.   // Orderlist
  278.   for (c = 0; c < 3; c++)
  279.   {
  280.     fwrite8(out, orderlen+1);
  281.     for (d = 0; d < orderlen; d++)
  282.     {
  283.       fwrite8(out, orderlist[c][d]);
  284.     }
  285.     fwrite8(out, 0xff); // Loop song
  286.     fwrite8(out, 0x0); // From beginning
  287.   }
  288.   // Instruments
  289.   for (c = 1; c < 32; c++)
  290.   {
  291.     fwrite8(out, 0);
  292.     fwrite8(out, 0);
  293.     fwrite8(out, 0);
  294.     fwrite8(out, 0);
  295.     fwrite8(out, 0);
  296.     fwrite8(out, 0);
  297.     fwrite8(out, 0);
  298.     fwrite8(out, 2);
  299.     fwrite(&modheader[20+30*(c-1)], 15, 1, out);
  300.     fwrite8(out, 0);
  301.     fwrite8(out, 0);
  302.     fwrite8(out, 0);
  303.   }
  304.   // Patterns
  305.   fwrite8(out, goatpatt);
  306.   for (c = 0; c < goatpatt; c++)
  307.   {
  308.     fwrite8(out, 65*3);
  309.     for (d = 0; d < 65; d++)
  310.     {
  311.       fwrite8(out, goatnotes[c][d].note);
  312.       fwrite8(out, goatnotes[c][d].command);
  313.       fwrite8(out, goatnotes[c][d].data);
  314.     }
  315.   }
  316.   fclose(out);
  317.   printf("Converted successfully.\n");
  318.   return 0;
  319. }
  320.  
  321.