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

  1. /*
  2.  * MOD (4chn or 6chn) -> GoatTracker stereo 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*6*4];
  49. NOTE modnotes[64*64*6];
  50. GOATNOTE goatnotes[208][65];
  51. unsigned char orderlist[6][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 transpose = 0;
  61. int goatchan = 0;
  62. int goatpatt = 1;
  63. int channels = 4;
  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: mod2sng2 <mod> <sng> [halfstep transpose, default 0]\n");
  75.     return 1;
  76.   }
  77.  
  78.   in = fopen(argv[1], "rb");
  79.   if (!in)
  80.   {
  81.     printf("Source open error.\n");
  82.     return 1;
  83.   }
  84.   out = fopen(argv[2], "wb");
  85.   if (!out)
  86.   {
  87.     printf("Destination open error.\n");
  88.     return 1;
  89.   }
  90.  
  91.   if (argc > 3)
  92.   {
  93.     sscanf(argv[3], "%d", &transpose);
  94.   }
  95.  
  96.   printf("Load mod header\n");
  97.   for (c = 0; c < 1084; c++)
  98.   {
  99.     modheader[c] = fread8(in);
  100.   }
  101.   if (modheader[1080] == '6') channels = 6;
  102.  
  103.   orderlen = modheader[950];
  104.   for (c = 0; c < 128; c++)
  105.   {
  106.     if (modheader[952+c] > maxpatt) maxpatt = modheader[952+c];
  107.   }
  108.   maxpatt++;
  109.   printf("Read in patterns\n");
  110.   for (c = 0; c < maxpatt * channels * 4 * 64; c++)
  111.   {
  112.     modpatterns[c] = fread8(in);
  113.   }
  114.   fclose(in);
  115.  
  116.   // Convert patterns into easier-to-read format
  117.  
  118.   printf("Convert patterns into easy to read format\n");
  119.   destptr = modnotes;
  120.   srcptr = modpatterns;
  121.   for (c = 0; c < maxpatt * channels * 64; c++)
  122.   {
  123.     // Note: FT2 saves the 13th bit of period into 5th bit of
  124.     // samplenumber, and when loading it ofcourse cannot read
  125.     // the period back correctly! We don't use the 13th bit!
  126.  
  127.     unsigned short period = ((srcptr[0] & 0x0f) << 8) | srcptr[1];
  128.     unsigned char note = 0, instrument, command;
  129.     if (period)
  130.     {
  131.             int findnote;
  132.             int offset = 0x7fffffff;
  133.  
  134.             for (findnote = 0; findnote < 96; findnote++)
  135.             {
  136.                     if (abs(period - (periodtable[0][findnote % 12] >> (findnote / 12))) < offset)
  137.                     {
  138.                             note = findnote + 1;
  139.                             offset = abs(period - (periodtable[0][findnote % 12] >> (findnote / 12)));
  140.                     }
  141.             }
  142.     }
  143.     instrument = (srcptr[0] & 0xf0) | ((srcptr[2] & 0xf0) >> 4);
  144.     command = srcptr[2] & 0x0f;
  145.     destptr->note = note;
  146.     destptr->instr = instrument;
  147.     destptr->command = command;
  148.     destptr->data = srcptr[3];
  149.     srcptr += 4;
  150.     destptr++;
  151.   }
  152.  
  153.   // Make empty pattern
  154.   for (c = 0; c < 65; c++)
  155.   {
  156.     goatnotes[0][c].note = 0x5f;
  157.     goatnotes[0][c].command = 0;
  158.     goatnotes[0][c].data = 0;
  159.   }
  160.   goatnotes[0][64].note = 0xff;
  161.  
  162.   printf("Convert patterns into goatpatterns\n");
  163.   // Convert patterns into goatpatterns, and create orderlists
  164.   for (c = 0; c < channels; c++)
  165.   {
  166.     for (d = 0; d < orderlen; d++)
  167.     {
  168.       int patt = modheader[952+d];
  169.       int e = 0;
  170.       int o = patt*(64*channels)+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
  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.   printf("Write song\n");
  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 < channels; 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.   for (c = channels; c < 6; c++)
  289.   {
  290.     fwrite8(out, 2);
  291.     fwrite8(out, 0);
  292.     fwrite8(out, 0xff); // Loop song
  293.     fwrite8(out, 0x0); // From beginning
  294.   }
  295.   // Instruments
  296.   for (c = 1; c < 32; c++)
  297.   {
  298.     fwrite8(out, 0);
  299.     fwrite8(out, 0);
  300.     fwrite8(out, 0);
  301.     fwrite8(out, 0);
  302.     fwrite8(out, 0);
  303.     fwrite8(out, 0);
  304.     fwrite8(out, 0);
  305.     fwrite8(out, 2);
  306.     fwrite(&modheader[20+30*(c-1)], 15, 1, out);
  307.     fwrite8(out, 0);
  308.     fwrite8(out, 0);
  309.     fwrite8(out, 0);
  310.   }
  311.   // Patterns
  312.   fwrite8(out, goatpatt);
  313.   for (c = 0; c < goatpatt; c++)
  314.   {
  315.     fwrite8(out, 65*3);
  316.     for (d = 0; d < 65; d++)
  317.     {
  318.       fwrite8(out, goatnotes[c][d].note);
  319.       fwrite8(out, goatnotes[c][d].command);
  320.       fwrite8(out, goatnotes[c][d].data);
  321.     }
  322.   }
  323.   fclose(out);
  324.   printf("Converted successfully.\n");
  325.   return 0;
  326. }
  327.  
  328.