home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.68_stereo.zip / src / gt2stereo.c < prev    next >
C/C++ Source or Header  |  2009-01-03  |  33KB  |  1,309 lines

  1. //
  2. // GOATTRACKER v2.68 Stereo
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17. //
  18.  
  19. #define GOATTRK2_C
  20.  
  21. #ifdef __WIN32__
  22. #include <windows.h>
  23. #endif
  24.  
  25. #include "goattrk2.h"
  26. #include "bme.h"
  27.  
  28. int menu = 0;
  29. int editmode = EDIT_PATTERN;
  30. int recordmode = 1;
  31. int followplay = 0;
  32. int hexnybble = -1;
  33. int stepsize = 4;
  34. int autoadvance = 0;
  35. int defaultpatternlength = 64;
  36. int cursorflash = 0;
  37. int cursorcolortable[] = {1,2,7,2};
  38. int exitprogram = 0;
  39. int eacolumn = 0;
  40. int eamode = 0;
  41.  
  42. unsigned keypreset = KEY_TRACKER;
  43. unsigned playerversion = 0;
  44. int fileformat = FORMAT_PRG;
  45. int zeropageadr = 0xfc;
  46. int playeradr = 0x1000;
  47. unsigned sidmodel = 0;
  48. unsigned multiplier = 1;
  49. unsigned adparam = 0x0f00;
  50. unsigned ntsc = 0;
  51. unsigned patternhex = 0;
  52. unsigned sidaddress = 0xd500d400;
  53. unsigned finevibrato = 1;
  54. unsigned optimizepulse = 1;
  55. unsigned optimizerealtime = 1;
  56. unsigned customclockrate = 0;
  57. unsigned usefinevib = 0;
  58. unsigned b = DEFAULTBUF;
  59. unsigned mr = DEFAULTMIXRATE;
  60. unsigned writer = 0;
  61. unsigned hardsid = 0;
  62. unsigned catweasel = 0;
  63. unsigned interpolate = 0;
  64. unsigned residdelay = 0;
  65. unsigned hardsidbufinteractive = 20;
  66. unsigned hardsidbufplayback = 400;
  67.  
  68. char *configptr;
  69. char configbuf[MAX_PATHNAME];
  70. char loadedsongfilename[MAX_FILENAME];
  71. char songfilename[MAX_FILENAME];
  72. char songfilter[MAX_FILENAME];
  73. char songpath[MAX_PATHNAME];
  74. char instrfilename[MAX_FILENAME];
  75. char instrfilter[MAX_FILENAME];
  76. char instrpath[MAX_PATHNAME];
  77. char packedpath[MAX_PATHNAME];
  78.  
  79. char *programname = "GoatTracker v2.68 Stereo";
  80.  
  81. char textbuffer[MAX_PATHNAME];
  82.  
  83. unsigned char hexkeytbl[] = {'0', '1', '2', '3', '4', '5', '6', '7',
  84.   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  85.  
  86. extern unsigned char datafile[];
  87.  
  88. int main(int argc, char **argv)
  89. {
  90.   char filename[MAX_PATHNAME];
  91.   FILE *configfile;
  92.   int c,d;
  93.  
  94.   // Open datafile
  95.   io_openlinkeddatafile(datafile);
  96.  
  97.   // Load configuration
  98.   #ifdef __WIN32__
  99.   GetModuleFileName(NULL, filename, MAX_PATHNAME);
  100.   filename[strlen(filename)-3] = 'c';
  101.   filename[strlen(filename)-2] = 'f';
  102.   filename[strlen(filename)-1] = 'g';
  103.   #else
  104.   strcpy(filename, getenv("HOME"));
  105.   strcat(filename, "/.goattrk/gt2stereo.cfg");
  106.   #endif
  107.   configfile = fopen(filename, "rt");
  108.   configptr = NULL;
  109.   if (configfile)
  110.   {
  111.     getparam(configfile, &b);
  112.     getparam(configfile, &mr);
  113.     getparam(configfile, &hardsid);
  114.     getparam(configfile, &sidmodel);
  115.     getparam(configfile, &ntsc);
  116.     getparam(configfile, (unsigned *)&fileformat);
  117.     getparam(configfile, (unsigned *)&playeradr);
  118.     getparam(configfile, (unsigned *)&zeropageadr);
  119.     getparam(configfile, &playerversion);
  120.     getparam(configfile, &keypreset);
  121.     getparam(configfile, (unsigned *)&stepsize);
  122.     getparam(configfile, &multiplier);
  123.     getparam(configfile, &catweasel);
  124.     getparam(configfile, &adparam);
  125.     getparam(configfile, &interpolate);
  126.     getparam(configfile, &patternhex);
  127.     getparam(configfile, &sidaddress);
  128.     getparam(configfile, &finevibrato);
  129.     getparam(configfile, &optimizepulse);
  130.     getparam(configfile, &optimizerealtime);
  131.     getparam(configfile, &residdelay);
  132.     getparam(configfile, &customclockrate);
  133.     getparam(configfile, &hardsidbufinteractive);
  134.     getparam(configfile, &hardsidbufplayback);
  135.     fclose(configfile);
  136.   }
  137.   zeropageadr &= 0xff;
  138.   playeradr &= 0xff00;
  139.   if (!stepsize) stepsize = 4;
  140.  
  141.   if (!initscreen())
  142.   {
  143.     return 1;
  144.   }
  145.  
  146.   // Init pathnames
  147.   initpaths();
  148.  
  149.   // Scan command line
  150.   for (c = 1; c < argc; c++)
  151.   {
  152.     if ((argv[c][0] == '-') || (argv[c][0] == '/'))
  153.     {
  154.       int y = 0;
  155.       switch(toupper(argv[c][1]))
  156.       {
  157.         case '?':
  158.         printtext(0,y++,15,"Usage: GT2STEREO [songname] [options]");
  159.         printtext(0,y++,15,"Options:");
  160.         printtext(0,y++,15,"/Axx Set ADSR parameter for hardrestart in hex. DEFAULT=0F00");
  161.         printtext(0,y++,15,"/Bxx Set sound buffer length in milliseconds DEFAULT=100");
  162.         printtext(0,y++,15,"/Cxx Use CatWeasel MK3 PCI SID (0 = off, 1 = on)");
  163.         printtext(0,y++,15,"/Dxx Pattern row display (0 = decimal, 1 = hexadecimal)");
  164.         printtext(0,y++,15,"/Exx Set emulated SID model (0 = 6581 1 = 8580) DEFAULT=6581");
  165.         printtext(0,y++,15,"/Fxx Set custom SID clock cycles per second (0 = use PAL/NTSC default)");
  166.         printtext(0,y++,15,"/Hxx Use HardSID (0 = off, 1 = HardSID ID0 2 = HardSID ID1 etc.)");
  167.         printtext(0,y++,15,"     Use high nybble (it's hexadecimal) to specify right HardSID ID");
  168.         printtext(0,y++,15,"/Ixx Set reSID interpolation (0 = off, 1 = on, 2 = distortion, 3 = distortion & on) DEFAULT=off");
  169.         printtext(0,y++,15,"/Kxx Note-entry mode (0 = PROTRACKER 1 = DMC) DEFAULT=PROTRK.");
  170.         printtext(0,y++,15,"/Lxx SID memory locations in hex. DEFAULT=D500D400");
  171.         printtext(0,y++,15,"/Mxx Set sound mixing rate DEFAULT=44100");
  172.         printtext(0,y++,15,"/Oxx Set pulseoptimization/skipping (0 = off, 1 = on) DEFAULT=on");
  173.         printtext(0,y++,15,"/Rxx Set realtime-effect optimization/skipping (0 = off, 1 = on) DEFAULT=on");
  174.         printtext(0,y++,15,"/Sxx Set speed multiplier (0 for 25Hz, 1 for 1x, 2 for 2x etc.)");
  175.         printtext(0,y++,15,"/Txx Set HardSID interactive mode sound buffer length in milliseconds DEFAULT=20, max.buffering=0");
  176.         printtext(0,y++,15,"/Uxx Set HardSID playback mode sound buffer length in milliseconds DEFAULT=400, max.buffering=0");
  177.         printtext(0,y++,15,"/Vxx Set finevibrato conversion (0 = off, 1 = on) DEFAULT=1");
  178.         printtext(0,y++,15,"/Zxx Set random reSID write delay in cycles (0 = off) DEFAULT=0");
  179.         printtext(0,y++,15,"/N   Use NTSC timing");
  180.         printtext(0,y++,15,"/P   Use PAL timing (DEFAULT)");
  181.         printtext(0,y++,15,"/W   Write sound output to a file SIDAUDIO.RAW");
  182.         printtext(0,y++,15,"/?   Show this info again");
  183.         waitkeynoupdate();
  184.         return 0;
  185.  
  186.         case 'Z':
  187.         sscanf(&argv[c][2], "%u", &residdelay);
  188.         break;
  189.  
  190.         case 'A':
  191.         sscanf(&argv[c][2], "%x", &adparam);
  192.         break;
  193.  
  194.         case 'S':
  195.         sscanf(&argv[c][2], "%u", &multiplier);
  196.         break;
  197.  
  198.         case 'B':
  199.         sscanf(&argv[c][2], "%u", &b);
  200.         break;
  201.  
  202.         case 'D':
  203.         sscanf(&argv[c][2], "%u", &patternhex);
  204.         break;
  205.  
  206.         case 'E':
  207.         sscanf(&argv[c][2], "%u", &sidmodel);
  208.         break;
  209.  
  210.         case 'I':
  211.         sscanf(&argv[c][2], "%u", &interpolate);
  212.         break;
  213.  
  214.         case 'K':
  215.         sscanf(&argv[c][2], "%u", &keypreset);
  216.         break;
  217.  
  218.         case 'L':
  219.         sscanf(&argv[c][2], "%x", &sidaddress);
  220.         break;
  221.  
  222.         case 'N':
  223.         ntsc = 1;
  224.         customclockrate = 0;
  225.         break;
  226.  
  227.         case 'P':
  228.         ntsc = 0;
  229.         customclockrate = 0;
  230.         break;
  231.  
  232.         case 'F':
  233.         sscanf(&argv[c][2], "%u", &customclockrate);
  234.         break;
  235.  
  236.         case 'M':
  237.         sscanf(&argv[c][2], "%u", &mr);
  238.         break;
  239.  
  240.         case 'O':
  241.         sscanf(&argv[c][2], "%u", &optimizepulse);
  242.         break;
  243.  
  244.         case 'R':
  245.         sscanf(&argv[c][2], "%u", &optimizerealtime);
  246.         break;
  247.  
  248.         case 'H':
  249.         sscanf(&argv[c][2], "%x", &hardsid);
  250.         break;
  251.  
  252.         case 'V':
  253.         sscanf(&argv[c][2], "%u", &finevibrato);
  254.         break;
  255.  
  256.         case 'T':
  257.         sscanf(&argv[c][2], "%u", &hardsidbufinteractive);
  258.         break;
  259.  
  260.         case 'U':
  261.         sscanf(&argv[c][2], "%u", &hardsidbufplayback);
  262.         break;
  263.  
  264.         case 'W':
  265.         writer = 1;
  266.         break;
  267.  
  268.         case 'C':
  269.         sscanf(&argv[c][2], "%u", &catweasel);
  270.         break;
  271.       }
  272.     }
  273.     else
  274.     {
  275.       char startpath[MAX_PATHNAME];
  276.  
  277.       strcpy(songfilename, argv[c]);
  278.       for (d = strlen(argv[c])-1; d >= 0; d--)
  279.       {
  280.         if ((argv[c][d] == '/') || (argv[c][d] == '\\'))
  281.         {
  282.           strcpy(startpath, argv[c]);
  283.           startpath[d+1] = 0;
  284.           chdir(startpath);
  285.           initpaths();
  286.           strcpy(songfilename, &argv[c][d+1]);
  287.           break;
  288.         }
  289.       }
  290.     }
  291.   }
  292.  
  293.   // Validate parameters
  294.   sidmodel &= 1;
  295.   adparam &= 0xffff;
  296.   if (multiplier > 16) multiplier = 16;
  297.   if (keypreset > 2) keypreset = 0;
  298.   if ((finevibrato == 1) && (multiplier < 2)) usefinevib = 1;
  299.   if (finevibrato > 1) usefinevib = 1;
  300.   if (optimizepulse > 1) optimizepulse = 1;
  301.   if (optimizerealtime > 1) optimizerealtime = 1;
  302.   if (residdelay > 63) residdelay = 63;
  303.   if (customclockrate < 100) customclockrate = 0;
  304.  
  305.   // Reset channels/song
  306.   initchannels();
  307.   clearsong(1,1,1,1,1);
  308.  
  309.   // Init sound
  310.   if (!sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate))
  311.   {
  312.     printtextc(MAX_ROWS/2-1,15,"Sound init failed. Press any key to run without sound (notice that song timer won't start)");
  313.     waitkeynoupdate();
  314.   }
  315.  
  316.   // Load song if applicable
  317.   if (strlen(songfilename)) loadsong();
  318.  
  319.   // Start editor mainloop
  320.   printmainscreen();
  321.   while (!exitprogram)
  322.   {
  323.     waitkeymouse();
  324.     docommand();
  325.   }
  326.  
  327.   // Shutdown sound output now
  328.   sound_uninit();
  329.  
  330.   // Save configuration
  331.   #ifndef __WIN32__
  332.   strcpy(filename, getenv("HOME"));
  333.   strcat(filename, "/.goattrk");
  334.   mkdir(filename, S_IRUSR | S_IWUSR | S_IXUSR);
  335.   strcat(filename, "/gt2stereo.cfg");
  336.   #endif
  337.   configfile = fopen(filename, "wt");
  338.   if (configfile)
  339.   {
  340.     fprintf(configfile, ";------------------------------------------------------------------------------\n"
  341.                         ";GT2 config file. Rows starting with ; are comments. Hexadecimal parameters are\n"
  342.                         ";to be preceded with $ and decimal parameters with nothing.                    \n"
  343.                         ";------------------------------------------------------------------------------\n"
  344.                         "\n"
  345.                         ";reSID buffer length (in milliseconds)\n%d\n\n"
  346.                         ";reSID mixing rate (in Hz)\n%d\n\n"
  347.                         ";Hardsid device number (0 = off)\n%d\n\n"
  348.                         ";reSID model (0 = 6581, 1 = 8580)\n%d\n\n"
  349.                         ";Timing mode (0 = PAL, 1 = NTSC)\n%d\n\n"
  350.                         ";Packer/relocator fileformat (0 = SID, 1 = PRG, 2 = BIN)\n%d\n\n"
  351.                         ";Packer/relocator player address\n$%04x\n\n"
  352.                         ";Packer/relocator zeropage baseaddress\n$%02x\n\n"
  353.                         ";Packer/relocator player type (0 = standard ... 3 = minimal)\n%d\n\n"
  354.                         ";Key entry mode (0 = Protracker, 1 = DMC)\n%d\n\n"
  355.                         ";Pattern highlight step size\n%d\n\n"
  356.                         ";Speed multiplier (0 = 25Hz, 1 = 1X, 2 = 2X etc.)\n%d\n\n"
  357.                         ";Use CatWeasel SID (0 = off, 1 = on)\n%d\n\n"
  358.                         ";Hardrestart ADSR parameter\n$%04x\n\n"
  359.                         ";reSID interpolation (0 = off, 1 = on, 2 = distortion, 3 = distortion & on)\n%d\n\n"
  360.                         ";Hexadecimal pattern display (0 = off, 1 = on)\n%d\n\n"
  361.                         ";SID baseaddresses\n$%08x\n\n"
  362.                         ";Finevibrato mode (0 = off, 1 = on)\n%d\n\n"
  363.                         ";Pulseskipping (0 = off, 1 = on)\n%d\n\n"
  364.                         ";Realtime effect skipping (0 = off, 1 = on)\n%d\n\n"
  365.                         ";Random reSID write delay in cycles (0 = off)\n%d\n\n"
  366.                         ";Custom SID clock cycles per second (0 = use PAL/NTSC default)\n%d\n\n"
  367.                         ";HardSID interactive mode buffer size (in milliseconds, 0 = maximum/no flush)\n%d\n\n"
  368.                         ";HardSID playback mode buffer size (in milliseconds, 0 = maximum/no flush)\n%d\n\n",
  369.     b,
  370.     mr,
  371.     hardsid,
  372.     sidmodel,
  373.     ntsc,
  374.     fileformat,
  375.     playeradr,
  376.     zeropageadr,
  377.     playerversion,
  378.     keypreset,
  379.     stepsize,
  380.     multiplier,
  381.     catweasel,
  382.     adparam,
  383.     interpolate,
  384.     patternhex,
  385.     sidaddress,
  386.     finevibrato,
  387.     optimizepulse,
  388.     optimizerealtime,
  389.     residdelay,
  390.     customclockrate,
  391.     hardsidbufinteractive,
  392.     hardsidbufplayback);
  393.  
  394.     fclose(configfile);
  395.   }
  396.  
  397.   // Exit
  398.   return 0;
  399. }
  400.  
  401. void waitkey(void)
  402. {
  403.   for (;;)
  404.   {
  405.     displayupdate();
  406.     getkey();
  407.     if ((rawkey) || (key)) break;
  408.     if (win_quitted) break;
  409.   }
  410.  
  411.   converthex();
  412. }
  413.  
  414. void waitkeymouse(void)
  415. {
  416.   for (;;)
  417.   {
  418.     displayupdate();
  419.     getkey();
  420.     if ((rawkey) || (key)) break;
  421.     if (win_quitted) break;
  422.     if (mouseb) break;
  423.   }
  424.  
  425.   converthex();
  426. }
  427.  
  428. void waitkeymousenoupdate(void)
  429. {
  430.   for (;;)
  431.   {
  432.       fliptoscreen();
  433.     getkey();
  434.     if ((rawkey) || (key)) break;
  435.     if (win_quitted) break;
  436.     if (mouseb) break;
  437.   }
  438.  
  439.   converthex();
  440. }
  441.  
  442. void waitkeynoupdate(void)
  443. {
  444.   for (;;)
  445.   {
  446.       fliptoscreen();
  447.     getkey();
  448.     if ((rawkey) || (key)) break;
  449.     if ((mouseb) && (!prevmouseb)) break;
  450.     if (win_quitted) break;
  451.   }
  452. }
  453.  
  454. void converthex()
  455. {
  456.   int c;
  457.  
  458.   hexnybble = -1;
  459.   for (c = 0; c < 16; c++)
  460.   {
  461.     if (tolower(key) == hexkeytbl[c])
  462.     {
  463.       if (c >= 10)
  464.       {
  465.         if (!shiftpressed) hexnybble = c;
  466.       }
  467.       else
  468.       {
  469.         hexnybble = c;
  470.       }
  471.     }
  472.   }
  473. }
  474.  
  475.  
  476. void docommand(void)
  477. {
  478.   // "GUI" operation :)
  479.   mousecommands();
  480.  
  481.   // Mode-specific commands
  482.   switch(editmode)
  483.   {
  484.     case EDIT_ORDERLIST:
  485.     orderlistcommands();
  486.     break;
  487.  
  488.     case EDIT_INSTRUMENT:
  489.     instrumentcommands();
  490.     break;
  491.  
  492.     case EDIT_TABLES:
  493.     tablecommands();
  494.     break;
  495.  
  496.     case EDIT_PATTERN:
  497.     patterncommands();
  498.     break;
  499.  
  500.     case EDIT_NAMES:
  501.     namecommands();
  502.     break;
  503.   }
  504.  
  505.   // General commands
  506.   generalcommands();
  507. }
  508.  
  509. void mousecommands(void)
  510. {
  511.   int c;
  512.  
  513.   if (!mouseb) return;
  514.  
  515.   // Pattern editpos & pattern number selection
  516.   for (c = 0; c < MAX_CHN; c++)
  517.   {
  518.     if ((mousey == 2) && (mousex >= 11 + c*9) && (mousex <= 12 + c*9))
  519.     {
  520.         if ((!prevmouseb) || (mouseheld > HOLDDELAY))
  521.         {
  522.         if (mouseb & MOUSEB_LEFT)
  523.         {
  524.           epchn = c;
  525.           nextpattern();
  526.         }
  527.         if (mouseb & MOUSEB_RIGHT)
  528.         {
  529.           epchn = c;
  530.           prevpattern();
  531.         }
  532.       }
  533.     }
  534.     else
  535.     {
  536.       if ((mousey >= 2) && (mousey <= 34) && (mousex >= 5 + c*9) && (mousex <= 12 + c*9))
  537.       {
  538.         int x = mousex - 5 - c*9;
  539.         int newpos = mousey - 3 + epview;
  540.         if (newpos < 0) newpos = 0;
  541.         if (newpos > pattlen[epnum[epchn]]) newpos = pattlen[epnum[epchn]];
  542.  
  543.         editmode = EDIT_PATTERN;
  544.  
  545.         if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (!prevmouseb))
  546.         {
  547.           if ((epmarkchn != c) || (newpos != epmarkend))
  548.           {
  549.             epmarkchn = c;
  550.             epmarkstart = epmarkend = newpos;
  551.           }
  552.         }
  553.  
  554.         if (mouseb & MOUSEB_LEFT)
  555.         {
  556.           epchn = c;
  557.           if (x < 3) epcolumn = 0;
  558.           if (x >= 3) epcolumn = x - 2;
  559.         }
  560.  
  561.         if (!prevmouseb)
  562.         {
  563.           if (mouseb & MOUSEB_LEFT)
  564.             eppos = newpos;
  565.         }
  566.         else
  567.         {
  568.             if (mouseb & MOUSEB_LEFT)
  569.             {
  570.             if (mousey == 2) eppos--;
  571.             if (mousey == 34) eppos++;
  572.           }
  573.         }
  574.         if (eppos < 0) eppos = 0;
  575.         if (eppos > pattlen[epnum[epchn]]) eppos = pattlen[epnum[epchn]];
  576.  
  577.         if (mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) epmarkend = newpos;
  578.       }
  579.     }
  580.   }
  581.  
  582.  
  583.   // Song editpos & songnumber selection
  584.   if ((mousey >= 3) && (mousey <= 8) && (mousex >= 40+20))
  585.   {
  586.     int newpos = esview + (mousex - 44 - 20) / 3;
  587.     int newcolumn = (mousex - 44 - 20) % 3;
  588.     int newchn = mousey - 3;
  589.     if (newcolumn < 0) newcolumn = 0;
  590.     if (newcolumn > 1) newcolumn = 1;
  591.     if (newpos < 0)
  592.     {
  593.       newpos = 0;
  594.       newcolumn = 0;
  595.     }
  596.     if (newpos == songlen[esnum][eschn])
  597.     {
  598.       newpos++;
  599.       newcolumn = 0;
  600.     }
  601.     if (newpos > songlen[esnum][eschn]+1)
  602.     {
  603.       newpos = songlen[esnum][eschn] + 1;
  604.       newcolumn = 1;
  605.     }
  606.  
  607.     editmode = EDIT_ORDERLIST;
  608.  
  609.     if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (!prevmouseb) && (newpos < songlen[esnum][eschn]))
  610.     {
  611.       if ((esmarkchn != newchn) || (newpos != esmarkend))
  612.       {
  613.         esmarkchn = newchn;
  614.         esmarkstart = esmarkend = newpos;
  615.       }
  616.     }
  617.  
  618.     if (mouseb & MOUSEB_LEFT)
  619.     {
  620.       eschn = newchn;
  621.       eseditpos = newpos;
  622.       escolumn = newcolumn;
  623.     }
  624.  
  625.     if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (newpos < songlen[esnum][eschn])) esmarkend = newpos;
  626.   }
  627.   if (((!prevmouseb) || (mouseheld > HOLDDELAY)) && (mousey == 2) && (mousex >= 63+20) && (mousex <= 64+20))
  628.   {
  629.     if (mouseb & MOUSEB_LEFT) nextsong();
  630.     if (mouseb & MOUSEB_RIGHT) prevsong();
  631.   }
  632.  
  633.   // Instrument editpos & instrument number selection
  634.   if ((mousey >= 8+3) && (mousey <= 12+3) && (mousex >= 56+20) && (mousex <= 57+20))
  635.   {
  636.     editmode = EDIT_INSTRUMENT;
  637.     eipos = mousey - 8 - 3;
  638.     eicolumn = mousex - 56 - 20;
  639.   }
  640.   if ((mousey >= 8+3) && (mousey <= 11+3) && (mousex >= 76+20) && (mousex <= 77+20))
  641.   {
  642.     editmode = EDIT_INSTRUMENT;
  643.     eipos = mousey - 8 - 3 + 5;
  644.     eicolumn = mousex - 76 - 20;
  645.   }
  646.   if ((mousey == 7+3) && (mousex >= 60+20))
  647.   {
  648.     editmode = EDIT_INSTRUMENT;
  649.     eipos = 9;
  650.   }
  651.   if (((!prevmouseb) || (mouseheld > HOLDDELAY)) && (mousey == 7+3) && (mousex >= 56+20) && (mousex <= 57+20))
  652.   {
  653.     if (mouseb & MOUSEB_LEFT) nextinstr();
  654.     if (mouseb & MOUSEB_RIGHT) previnstr();
  655.   }
  656.  
  657.   // Table editpos
  658.   for (c = 0; c < MAX_TABLES; c++)
  659.   {
  660.     if ((mousey >= 14+3) && (mousey <= 20+3+9) && (mousex >= 43 + 20 + c*10) && (mousex <= 47 + 20 + c*10))
  661.     {
  662.       int newpos = mousey - 15 - 3 + etview[etnum];
  663.       if (newpos < 0) newpos = 0;
  664.       if (newpos >= MAX_TABLELEN) newpos = MAX_TABLELEN-1;
  665.  
  666.       editmode = EDIT_TABLES;
  667.  
  668.       if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (!prevmouseb))
  669.       {
  670.         if ((etmarknum != etnum) || (newpos != etmarkend))
  671.         {
  672.           etmarknum = c;
  673.           etmarkstart = etmarkend = newpos;
  674.         }
  675.       }
  676.       if (mouseb & MOUSEB_LEFT)
  677.       {
  678.         etnum = c;
  679.         etpos = mousey - 15 - 3 + etview[etnum];
  680.         etcolumn = mousex - 43 - 20 - c*10;
  681.       }
  682.       if (etcolumn >= 2) etcolumn--;
  683.       if (etpos < 0) etpos = 0;
  684.       if (etpos > MAX_TABLELEN-1) etpos = MAX_TABLELEN-1;
  685.  
  686.       if (mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) etmarkend = newpos;
  687.     }
  688.   }
  689.  
  690.   // Name editpos
  691.   if ((mousey == 21+3+9) && (mousex >= 47+20))
  692.   {
  693.     editmode = EDIT_NAMES;
  694.     if ((!prevmouseb) && (mouseb & MOUSEB_RIGHT))
  695.     {
  696.       enpos++;
  697.       if (enpos > 2) enpos = 0;
  698.     }
  699.   }
  700.  
  701.   // Status panel
  702.   if ((!prevmouseb) && (mousex == 7) && (mousey == 23+3+9))
  703.   {
  704.     if (mouseb & (MOUSEB_LEFT))
  705.       if (epoctave < 7) epoctave++;
  706.     if (mouseb & (MOUSEB_RIGHT))
  707.       if (epoctave > 0) epoctave--;
  708.   }
  709.   if ((!prevmouseb) && (mousex <= 7) && (mousey == 24+3+9))
  710.   {
  711.     recordmode ^= 1;
  712.   }
  713.   for (c = 0; c < MAX_CHN; c++)
  714.   {
  715.     if ((!prevmouseb) && (mousey >= 23+3+9) && (mousex >= 59 + 7*c) && (mousex <= 64 + 7*c))
  716.       mutechannel(c);
  717.   }
  718.  
  719.   // Titlebar actions
  720.   if (!menu)
  721.   {
  722.     if ((mousey == 0) && (!prevmouseb) && (mouseb == MOUSEB_LEFT))
  723.     {
  724.       if ((mousex >= 40+20) && (mousex <= 41+20))
  725.       {
  726.         usefinevib ^= 1;
  727.       }
  728.       if ((mousex >= 43+20) && (mousex <= 44+20))
  729.       {
  730.         optimizepulse ^= 1;
  731.       }
  732.       if ((mousex >= 46+20) && (mousex <= 47+20))
  733.       {
  734.         optimizerealtime ^= 1;
  735.       }
  736.       if ((mousex >= 49+20) && (mousex <= 52+20))
  737.       {
  738.         ntsc ^= 1;
  739.         sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  740.       }
  741.       if ((mousex >= 54+20) && (mousex <= 57+20))
  742.       {
  743.         sidmodel ^= 1;
  744.         sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  745.       }
  746.       if ((mousex >= 62+20) && (mousex <= 65+20)) editadsr();
  747.       if ((mousex >= 67+20) && (mousex <= 68+20)) prevmultiplier();
  748.       if ((mousex >= 69+20) && (mousex <= 70+20)) nextmultiplier();
  749.     }
  750.   }
  751.   else
  752.   {
  753.     if ((!mousey) && (mouseb & MOUSEB_LEFT) && (!(prevmouseb & MOUSEB_LEFT)))
  754.     {
  755.       if ((mousex >= 0) && (mousex <= 5))
  756.       {
  757.         initsong(esnum, PLAY_BEGINNING);
  758.         followplay = shiftpressed;
  759.       }
  760.       if ((mousex >= 7) && (mousex <= 15))
  761.       {
  762.         initsong(esnum, PLAY_POS);
  763.         followplay = shiftpressed;
  764.       }
  765.       if ((mousex >= 17) && (mousex <= 26))
  766.       {
  767.         initsong(esnum, PLAY_PATTERN);
  768.         followplay = shiftpressed;
  769.       }
  770.       if ((mousex >= 28) && (mousex <= 33))
  771.         stopsong();
  772.       if ((mousex >= 35) && (mousex <= 40))
  773.         load();
  774.       if ((mousex >= 42) && (mousex <= 47))
  775.         save();
  776.       if ((mousex >= 49) && (mousex <= 57))
  777.         relocator();
  778.       if ((mousex >= 59) && (mousex <= 64))
  779.         onlinehelp();
  780.       if ((mousex >= 66) && (mousex <= 72))
  781.         clear();
  782.       if ((mousex >= 74) && (mousex <= 79))
  783.         quit();
  784.     }
  785.   }
  786. }
  787.  
  788. void generalcommands(void)
  789. {
  790.   int c;
  791.  
  792.   switch(key)
  793.   {
  794.     case '?':
  795.     case '-':
  796.     if ((editmode != EDIT_NAMES) && (editmode != EDIT_ORDERLIST))
  797.     {
  798.       if (!((editmode == EDIT_INSTRUMENT) && (eipos == 9))) previnstr();
  799.     }
  800.     break;
  801.  
  802.     case '+':
  803.     case '_':
  804.     if ((editmode != EDIT_NAMES) && (editmode != EDIT_ORDERLIST))
  805.     {
  806.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9))) nextinstr();
  807.  
  808.     }
  809.     break;
  810.  
  811.     case '*':
  812.     if (editmode != EDIT_NAMES)
  813.     {
  814.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  815.       {
  816.         if (epoctave < 7) epoctave++;
  817.       }
  818.     }
  819.     break;
  820.  
  821.     case '/':
  822.     case '\'':
  823.     if (editmode != EDIT_NAMES)
  824.     {
  825.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  826.       {
  827.         if (epoctave > 0) epoctave--;
  828.       }
  829.     }
  830.     break;
  831.  
  832.     case '<':
  833.     if (((editmode == EDIT_INSTRUMENT) && (eipos != 9)) || (editmode == EDIT_TABLES))
  834.       previnstr();
  835.     break;
  836.  
  837.     case '>':
  838.     if (((editmode == EDIT_INSTRUMENT) && (eipos != 9)) || (editmode == EDIT_TABLES))
  839.       nextinstr();
  840.     break;
  841.  
  842.     case ';':
  843.     for (c = 0; c < MAX_CHN; c++)
  844.     {
  845.       if (espos[c]) espos[c]--;
  846.       if (espos[c] < esview)
  847.       {
  848.         esview = espos[c];
  849.         eseditpos = espos[c];
  850.       }
  851.     }
  852.     updateviewtopos();
  853.     rewindsong();
  854.     break;
  855.  
  856.     case ':':
  857.     for (c = 0; c < MAX_CHN; c++)
  858.     {
  859.       if (espos[c] < songlen[esnum][c]-1)
  860.         espos[c]++;
  861.       if (espos[c] - esview >= VISIBLEORDERLIST)
  862.       {
  863.         esview = espos[c] - VISIBLEORDERLIST + 1;
  864.         eseditpos = espos[c];
  865.       }
  866.     }
  867.     updateviewtopos();
  868.     rewindsong();
  869.     break;
  870.  
  871.   }
  872.   if (win_quitted) exitprogram = 1;
  873.   switch(rawkey)
  874.   {
  875.     case KEY_ESC:
  876.     if (!shiftpressed)
  877.       quit();
  878.     else
  879.       clear();
  880.     break;
  881.  
  882.     case KEY_KPMULTIPLY:
  883.     if ((editmode != EDIT_NAMES) && (!key))
  884.     {
  885.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  886.       {
  887.         if (epoctave < 7) epoctave++;
  888.       }
  889.     }
  890.     break;
  891.  
  892.     case KEY_KPDIVIDE:
  893.     if ((editmode != EDIT_NAMES) && (!key))
  894.     {
  895.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  896.       {
  897.         if (epoctave > 0) epoctave--;
  898.       }
  899.     }
  900.     break;
  901.  
  902.     case KEY_F12:
  903.     onlinehelp();
  904.     break;
  905.  
  906.     case KEY_TAB:
  907.     if (!shiftpressed) editmode++;
  908.     else editmode--;
  909.     if (editmode > EDIT_NAMES) editmode = EDIT_PATTERN;
  910.     if (editmode < EDIT_PATTERN) editmode = EDIT_NAMES;
  911.     break;
  912.  
  913.     case KEY_F1:
  914.     initsong(esnum, PLAY_BEGINNING);
  915.     followplay = shiftpressed;
  916.     break;
  917.  
  918.     case KEY_F2:
  919.     initsong(esnum, PLAY_POS);
  920.     followplay = shiftpressed;
  921.     break;
  922.  
  923.     case KEY_F3:
  924.     initsong(esnum, PLAY_PATTERN);
  925.     followplay = shiftpressed;
  926.     break;
  927.  
  928.     case KEY_F4:
  929.     if (shiftpressed)
  930.       mutechannel(epchn);
  931.     else
  932.     stopsong();
  933.     break;
  934.  
  935.     case KEY_F5:
  936.     if (!shiftpressed)
  937.       editmode = EDIT_PATTERN;
  938.     else prevmultiplier();
  939.     break;
  940.  
  941.     case KEY_F6:
  942.     if (!shiftpressed)
  943.       editmode = EDIT_ORDERLIST;
  944.     else nextmultiplier();
  945.     break;
  946.  
  947.     case KEY_F7:
  948.     if (!shiftpressed)
  949.     {
  950.       if (editmode == EDIT_INSTRUMENT)
  951.         editmode = EDIT_TABLES;
  952.       else
  953.         editmode = EDIT_INSTRUMENT;
  954.     }
  955.     else editadsr();
  956.     break;
  957.  
  958.     case KEY_F8:
  959.     if (!shiftpressed)
  960.       editmode = EDIT_NAMES;
  961.     else
  962.     {
  963.       sidmodel ^= 1;
  964.       sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  965.     }
  966.     break;
  967.  
  968.     case KEY_F9:
  969.     relocator();
  970.     break;
  971.  
  972.     case KEY_F10:
  973.     load();
  974.     break;
  975.  
  976.     case KEY_F11:
  977.     save();
  978.     break;
  979.   }
  980. }
  981.  
  982. void load(void)
  983. {
  984.   if ((editmode != EDIT_INSTRUMENT) && (editmode != EDIT_TABLES))
  985.   {
  986.     if (fileselector(songfilename, songpath, songfilter, "LOAD SONG", 0))
  987.       loadsong();
  988.   }
  989.   else
  990.   {
  991.     if (einum)
  992.     {
  993.       if (fileselector(instrfilename, instrpath, instrfilter, "LOAD INSTRUMENT", 0))
  994.         loadinstrument();
  995.     }
  996.   }
  997.   key = 0;
  998.   rawkey = 0;
  999. }
  1000.  
  1001. void save(void)
  1002. {
  1003.   if ((editmode != EDIT_INSTRUMENT) && (editmode != EDIT_TABLES))
  1004.   {
  1005.     int done = 0;
  1006.  
  1007.     // Repeat until quit or save successful
  1008.     while (!done)
  1009.     {
  1010.       if (strlen(loadedsongfilename)) strcpy(songfilename, loadedsongfilename);
  1011.       if (fileselector(songfilename, songpath, songfilter, "SAVE SONG", 3))
  1012.         done = savesong();
  1013.       else done = 1;
  1014.     }
  1015.   }
  1016.   else
  1017.   {
  1018.     if (einum)
  1019.     {
  1020.       int done = 0;
  1021.       int useinstrname = 0;
  1022.       char tempfilename[MAX_FILENAME];
  1023.  
  1024.       // Repeat until quit or save successful
  1025.       while (!done)
  1026.       {
  1027.         if ((!strlen(instrfilename)) && (strlen(instr[einum].name)))
  1028.         {
  1029.           useinstrname = 1;
  1030.           strcpy(instrfilename, instr[einum].name);
  1031.           strcat(instrfilename, ".ins");
  1032.           strcpy(tempfilename, instrfilename);
  1033.         }
  1034.  
  1035.         if (fileselector(instrfilename, instrpath, instrfilter, "SAVE INSTRUMENT", 3))
  1036.           done = saveinstrument();
  1037.         else done = 1;
  1038.  
  1039.         if (useinstrname)
  1040.         {
  1041.           if (!strcmp(tempfilename, instrfilename))
  1042.             memset(instrfilename, 0, sizeof instrfilename);
  1043.         }
  1044.       }
  1045.     }
  1046.   }
  1047.   key = 0;
  1048.   rawkey = 0;
  1049. }
  1050.  
  1051. void quit(void)
  1052. {
  1053.   if ((!shiftpressed) || (mouseb))
  1054.   {
  1055.     printtextcp(38, 36, 15, "Really Quit (y/n)?");
  1056.     waitkey();
  1057.     printblank(20, 36, 39);
  1058.     if ((key == 'y') || (key == 'Y')) exitprogram = 1;
  1059.   }
  1060.   key = 0;
  1061.   rawkey = 0;
  1062. }
  1063.  
  1064. void clear(void)
  1065. {
  1066.   int cs = 0;
  1067.   int cp = 0;
  1068.   int ci = 0;
  1069.   int ct = 0;
  1070.   int cn = 0;
  1071.  
  1072.   printtextcp(38, 36, 15, "Optimize everything (y/n)?");
  1073.   waitkey();
  1074.   printblank(20, 36, 39);
  1075.   if ((key == 'y') || (key == 'Y'))
  1076.   {
  1077.     optimizeeverything(1, 1);
  1078.     key = 0;
  1079.     rawkey = 0;
  1080.     return;
  1081.   }
  1082.  
  1083.   printtextcp(38, 36, 15, "Clear orderlists (y/n)?");
  1084.   waitkey();
  1085.   printblank(20, 36, 39);
  1086.   if ((key == 'y') || (key == 'Y')) cs = 1;
  1087.  
  1088.   printtextcp(38, 36, 15, "Clear patterns (y/n)?");
  1089.   waitkey();
  1090.   printblank(20, 36, 39);
  1091.   if ((key == 'y') || (key == 'Y')) cp = 1;
  1092.  
  1093.   printtextcp(38, 36, 15, "Clear instruments (y/n)?");
  1094.   waitkey();
  1095.   printblank(20, 36, 39);
  1096.   if ((key == 'y') || (key == 'Y')) ci = 1;
  1097.  
  1098.   printtextcp(38, 36, 15, "Clear tables (y/n)?");
  1099.   waitkey();
  1100.   printblank(20, 36, 39);
  1101.   if ((key == 'y') || (key == 'Y')) ct = 1;
  1102.  
  1103.   printtextcp(38, 36, 15, "Clear songname (y/n)?");
  1104.   waitkey();
  1105.   printblank(20, 36, 39);
  1106.   if ((key == 'y') || (key == 'Y')) cn = 1;
  1107.  
  1108.   if (cp == 1)
  1109.   {
  1110.     int selectdone = 0;
  1111.     int olddpl = defaultpatternlength;
  1112.  
  1113.     printtext(29, 36, 15,"Pattern length:");
  1114.     while (!selectdone)
  1115.     {
  1116.       sprintf(textbuffer, "%02d ", defaultpatternlength);
  1117.       printtext(44, 36, 15, textbuffer);
  1118.       waitkey();
  1119.       switch(rawkey)
  1120.       {
  1121.         case KEY_LEFT:
  1122.         defaultpatternlength -= 7;
  1123.         case KEY_DOWN:
  1124.         defaultpatternlength--;
  1125.         if (defaultpatternlength < 1) defaultpatternlength = 1;
  1126.         break;
  1127.  
  1128.         case KEY_RIGHT:
  1129.         defaultpatternlength += 7;
  1130.         case KEY_UP:
  1131.         defaultpatternlength++;
  1132.         if (defaultpatternlength > MAX_PATTROWS) defaultpatternlength = MAX_PATTROWS;
  1133.         break;
  1134.  
  1135.         case KEY_ESC:
  1136.         defaultpatternlength = olddpl;
  1137.         selectdone = 1;
  1138.         break;
  1139.  
  1140.         case KEY_ENTER:
  1141.         selectdone = 1;
  1142.         break;
  1143.       }
  1144.     }
  1145.     printblank(20, 36, 39);
  1146.   }
  1147.  
  1148.   if (cs | cp | ci | ct | cn)
  1149.     memset(songfilename, 0, sizeof songfilename);
  1150.   clearsong(cs, cp, ci, ct, cn);
  1151.  
  1152.   key = 0;
  1153.   rawkey = 0;
  1154. }
  1155.  
  1156.  
  1157. void editadsr(void)
  1158. {
  1159.   eamode = 1;
  1160.   eacolumn = 0;
  1161.  
  1162.   for (;;)
  1163.   {
  1164.     waitkeymouse();
  1165.  
  1166.     if (win_quitted)
  1167.     {
  1168.       exitprogram = 1;
  1169.       key = 0;
  1170.       rawkey = 0;
  1171.       return;
  1172.     }
  1173.  
  1174.     if (hexnybble >= 0)
  1175.     {
  1176.       switch(eacolumn)
  1177.       {
  1178.         case 0:
  1179.         adparam &= 0x0fff;
  1180.         adparam |= hexnybble << 12;
  1181.         break;
  1182.  
  1183.         case 1:
  1184.         adparam &= 0xf0ff;
  1185.         adparam |= hexnybble << 8;
  1186.         break;
  1187.  
  1188.         case 2:
  1189.         adparam &= 0xff0f;
  1190.         adparam |= hexnybble << 4;
  1191.         break;
  1192.  
  1193.         case 3:
  1194.         adparam &= 0xfff0;
  1195.         adparam |= hexnybble;
  1196.         break;
  1197.       }
  1198.       eacolumn++;
  1199.     }
  1200.  
  1201.     switch(rawkey)
  1202.     {
  1203.       case KEY_F7:
  1204.       if (!shiftpressed) break;
  1205.  
  1206.       case KEY_ESC:
  1207.       case KEY_ENTER:
  1208.       case KEY_TAB:
  1209.       eamode = 0;
  1210.       key = 0;
  1211.       rawkey = 0;
  1212.       return;
  1213.  
  1214.       case KEY_BACKSPACE:
  1215.       if (!eacolumn) break;
  1216.       case KEY_LEFT:
  1217.       eacolumn--;
  1218.       break;
  1219.  
  1220.       case KEY_RIGHT:
  1221.       eacolumn++;
  1222.     }
  1223.     eacolumn &= 3;
  1224.  
  1225.     if ((mouseb) && (!prevmouseb))
  1226.     {
  1227.       eamode = 0;
  1228.       return;
  1229.     }
  1230.   }
  1231. }
  1232.  
  1233. void getparam(FILE *handle, unsigned *value)
  1234. {
  1235.   for (;;)
  1236.   {
  1237.     while (!configptr)
  1238.     {
  1239.       if (feof(handle)) return;
  1240.       fgets(configbuf, MAX_PATHNAME, handle);
  1241.       if ((configbuf[0]) && (configbuf[0] != ';')) configptr = configbuf;
  1242.     }
  1243.  
  1244.     if ((*configptr == '$') || ((*configptr >= '0') && (*configptr <= '9'))) break;
  1245.     if (!(*configptr)) configptr = NULL;
  1246.     else configptr++;
  1247.   }
  1248.  
  1249.   if (*configptr == '$')
  1250.   {
  1251.     *value = 0;
  1252.     configptr++;
  1253.     for (;;)
  1254.     {
  1255.       char c = tolower(*configptr++);
  1256.       int h = -1;
  1257.  
  1258.       if ((c >= 'a') && (c <= 'f')) h = c - 'a' + 10;
  1259.       if ((c >= '0') && (c <= '9')) h = c - '0';
  1260.  
  1261.       if (h >= 0)
  1262.       {
  1263.         *value *= 16;
  1264.         *value += h;
  1265.       }
  1266.       else break;
  1267.     }
  1268.   }
  1269.   else
  1270.   {
  1271.     *value = 0;
  1272.     for (;;)
  1273.     {
  1274.       char c = tolower(*configptr++);
  1275.       int d = -1;
  1276.  
  1277.       if ((c >= '0') && (c <= '9')) d = c - '0';
  1278.  
  1279.       if (d >= 0)
  1280.       {
  1281.         *value *= 10;
  1282.         *value += d;
  1283.       }
  1284.       else break;
  1285.     }
  1286.   }
  1287.  
  1288.   if (!(*configptr)) configptr = NULL;
  1289. }
  1290.  
  1291.  
  1292. void prevmultiplier(void)
  1293. {
  1294.   if (multiplier > 0)
  1295.   {
  1296.     multiplier--;
  1297.     sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  1298.   }
  1299. }
  1300.  
  1301. void nextmultiplier(void)
  1302. {
  1303.   if (multiplier < 16)
  1304.   {
  1305.     multiplier++;
  1306.     sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  1307.   }
  1308. }
  1309.