home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.73.zip / src / mod2sng.c < prev    next >
C/C++ Source or Header  |  2014-07-23  |  9KB  |  323 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 EXIT_FAILURE;
  79.   }
  80.  
  81.   in = fopen(argv[1], "rb");
  82.   if (!in)
  83.   {
  84.     printf("Source open error.\n");
  85.     return EXIT_FAILURE;
  86.   }
  87.   out = fopen(argv[2], "wb");
  88.   if (!out)
  89.   {
  90.     printf("Destination open error.\n");
  91.     fclose(in);
  92.     return EXIT_FAILURE;
  93.   }
  94.   if (argc > 3)
  95.   {
  96.     sscanf(argv[3], "%d", &leaveout);
  97.     leaveout--;
  98.     if ((leaveout < 0) || (leaveout > 3))
  99.     {
  100.       printf("Illegal channel number.\n");
  101.       fclose(in);
  102.       fclose(out);
  103.       return EXIT_FAILURE;
  104.     }
  105.   }
  106.  
  107.   if (argc > 4)
  108.   {
  109.     sscanf(argv[4], "%d", &transpose);
  110.   }
  111.  
  112.   for (c = 0; c < 1084; c++)
  113.   {
  114.     modheader[c] = fread8(in);
  115.   }
  116.   orderlen = modheader[950];
  117.   for (c = 0; c < 128; c++)
  118.   {
  119.     if (modheader[952+c] > maxpatt) maxpatt = modheader[952+c];
  120.   }
  121.   maxpatt++;
  122.   for (c = 0; c < maxpatt * 1024; c++)
  123.   {
  124.     modpatterns[c] = fread8(in);
  125.   }
  126.   fclose(in);
  127.  
  128.   // Convert patterns into easier-to-read format
  129.  
  130.   destptr = modnotes;
  131.   srcptr = modpatterns;
  132.   for (c = 0; c < maxpatt * 256; c++)
  133.   {
  134.     // Note: FT2 saves the 13th bit of period into 5th bit of
  135.     // samplenumber, and when loading it ofcourse cannot read
  136.     // the period back correctly! We don't use the 13th bit!
  137.  
  138.     unsigned short period = ((srcptr[0] & 0x0f) << 8) | srcptr[1];
  139.     unsigned char note = 0, instrument, command;
  140.     if (period)
  141.     {
  142.       int findnote;
  143.       int offset = 0x7fffffff;
  144.  
  145.       for (findnote = 0; findnote < 96; findnote++)
  146.       {
  147.         if (abs(period - (periodtable[0][findnote % 12] >> (findnote / 12))) < offset)
  148.         {
  149.           note = findnote + 1;
  150.           offset = abs(period - (periodtable[0][findnote % 12] >> (findnote / 12)));
  151.         }
  152.       }
  153.     }
  154.     instrument = (srcptr[0] & 0xf0) | ((srcptr[2] & 0xf0) >> 4);
  155.     command = srcptr[2] & 0x0f;
  156.     destptr->note = note;
  157.     destptr->instr = instrument;
  158.     destptr->command = command;
  159.     destptr->data = srcptr[3];
  160.     srcptr += 4;
  161.     destptr++;
  162.   }
  163.  
  164.   // Convert patterns into goatpatterns, and create orderlists
  165.   for (c = 0; c < 4; c++)
  166.   {
  167.     if (c != leaveout)
  168.     {
  169.       for (d = 0; d < orderlen; d++)
  170.       {
  171.         int patt = modheader[952+d];
  172.         int e = 0;
  173.         int o = patt*256+c;
  174.         int breakflag = 0;
  175.         unsigned char prevgoatdata = 0;
  176.  
  177.         memset(tempnotes, 0, sizeof tempnotes);
  178.         for (;;)
  179.         {
  180.           unsigned char goatcommand = 0;
  181.           unsigned char goatdata = 0;
  182.  
  183.           if (modnotes[o+e*4].note)
  184.           {
  185.             tempnotes[e].note = modnotes[o+e*4].note - 1 + transpose;
  186.             if (tempnotes[e].note > 0x5d) tempnotes[e].note = 0x5d;
  187.           }
  188.           else tempnotes[e].note = 0x5f;
  189.           switch(modnotes[o+e*4].command)
  190.           {
  191.             case 0:
  192.             goatcommand = modnotes[o+e*4].command;
  193.             goatdata = modnotes[o+e*4].data;
  194.             break;
  195.  
  196.             case 1:
  197.             case 2:
  198.             case 3:
  199.             case 4:
  200.             goatcommand = modnotes[o+e*4].command;
  201.             if (modnotes[o+e*4].data) goatdata = modnotes[o+e*4].data;
  202.             else goatdata = prevgoatdata;
  203.             prevgoatdata = goatdata;
  204.             break;
  205.  
  206.             case 0xf:
  207.             if (modnotes[o+e*4].data < 0x20) // Ticktempo
  208.             {
  209.               goatcommand = 7;
  210.               goatdata = modnotes[o+e*4].data;
  211.             }
  212.             break;
  213.  
  214.             case 0xc:
  215.             // Convert zero volume to keyoff
  216.             if ((!modnotes[o+e*4].data) && (tempnotes[e].note == 0x5f))
  217.               tempnotes[e].note = 0x5e;
  218.             break;
  219.  
  220.             case 0xb:
  221.             case 0xd:
  222.             breakflag = 1;
  223.             break;
  224.  
  225.             default:
  226.             break;
  227.           }
  228.           tempnotes[e].command = (modnotes[o+e*4].instr << 3) | goatcommand;
  229.           tempnotes[e].data = goatdata;
  230.  
  231.           e++;
  232.           if (e == 64) break;
  233.           if (breakflag) break;
  234.         }
  235.         tempnotes[e].note = 0xff;
  236.         for (e = 0; e < goatpatt; e++)
  237.         {
  238.           int f;
  239.           for (f = 0; f < 65; f++)
  240.           {
  241.             if ((goatnotes[e][f].note != tempnotes[f].note) ||
  242.                 (goatnotes[e][f].command != tempnotes[f].command) ||
  243.                 (goatnotes[e][f].data != tempnotes[f].data)) break;
  244.           }
  245.           // Same pattern
  246.           if (f == 65)
  247.           {
  248.             orderlist[goatchan][d] = e;
  249.             break;
  250.           }
  251.         }
  252.         // No same pattern pattern
  253.         if (e == goatpatt)
  254.         {
  255.           int f;
  256.           if (goatpatt >= 208)
  257.           {
  258.             printf("208 patterns exceeded!\n");
  259.             return EXIT_FAILURE;
  260.           }
  261.           for (f = 0; f < 65; f++)
  262.           {
  263.             goatnotes[goatpatt][f].note = tempnotes[f].note;
  264.             goatnotes[goatpatt][f].command = tempnotes[f].command;
  265.             goatnotes[goatpatt][f].data = tempnotes[f].data;
  266.           }
  267.           orderlist[goatchan][d] = goatpatt;
  268.           goatpatt++;
  269.         }
  270.       }
  271.       goatchan++;
  272.     }
  273.   }
  274.   fwrite(ident, 4, 1, out); // Ident
  275.   fwrite(&modheader[0], 20, 1, out); // Infotexts
  276.   fwrite(zeroarray, 12, 1, out);
  277.   fwrite(zeroarray, 32, 1, out);
  278.   fwrite(zeroarray, 32, 1, out);
  279.   fwrite8(out, 1); // Number of songs
  280.   // Orderlist
  281.   for (c = 0; c < 3; c++)
  282.   {
  283.     fwrite8(out, orderlen+1);
  284.     for (d = 0; d < orderlen; d++)
  285.     {
  286.       fwrite8(out, orderlist[c][d]);
  287.     }
  288.     fwrite8(out, 0xff); // Loop song
  289.     fwrite8(out, 0x0); // From beginning
  290.   }
  291.   // Instruments
  292.   for (c = 1; c < 32; c++)
  293.   {
  294.     fwrite8(out, 0);
  295.     fwrite8(out, 0);
  296.     fwrite8(out, 0);
  297.     fwrite8(out, 0);
  298.     fwrite8(out, 0);
  299.     fwrite8(out, 0);
  300.     fwrite8(out, 0);
  301.     fwrite8(out, 2);
  302.     fwrite(&modheader[20+30*(c-1)], 15, 1, out);
  303.     fwrite8(out, 0);
  304.     fwrite8(out, 0);
  305.     fwrite8(out, 0);
  306.   }
  307.   // Patterns
  308.   fwrite8(out, goatpatt);
  309.   for (c = 0; c < goatpatt; c++)
  310.   {
  311.     fwrite8(out, 65*3);
  312.     for (d = 0; d < 65; d++)
  313.     {
  314.       fwrite8(out, goatnotes[c][d].note);
  315.       fwrite8(out, goatnotes[c][d].command);
  316.       fwrite8(out, goatnotes[c][d].data);
  317.     }
  318.   }
  319.   fclose(out);
  320.   printf("Converted successfully.\n");
  321.   return EXIT_SUCCESS;
  322. }
  323.