home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.67_stereo.zip / src / gt2stereo.c < prev    next >
C/C++ Source or Header  |  2008-07-21  |  33KB  |  1,306 lines

  1. //
  2. // GOATTRACKER v2.67 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.67 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) 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=off");
  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.   // Save configuration
  328.   #ifndef __WIN32__
  329.   strcpy(filename, getenv("HOME"));
  330.   strcat(filename, "/.goattrk");
  331.   mkdir(filename, S_IRUSR | S_IWUSR | S_IXUSR);
  332.   strcat(filename, "/gt2stereo.cfg");
  333.   #endif
  334.   configfile = fopen(filename, "wt");
  335.   if (configfile)
  336.   {
  337.     fprintf(configfile, ";------------------------------------------------------------------------------\n"
  338.                         ";GT2 config file. Rows starting with ; are comments. Hexadecimal parameters are\n"
  339.                         ";to be preceded with $ and decimal parameters with nothing.                    \n"
  340.                         ";------------------------------------------------------------------------------\n"
  341.                         "\n"
  342.                         ";reSID buffer length (in milliseconds)\n%d\n\n"
  343.                         ";reSID mixing rate (in Hz)\n%d\n\n"
  344.                         ";Hardsid device number (0 = off)\n%d\n\n"
  345.                         ";reSID model (0 = 6581, 1 = 8580)\n%d\n\n"
  346.                         ";Timing mode (0 = PAL, 1 = NTSC)\n%d\n\n"
  347.                         ";Packer/relocator fileformat (0 = SID, 1 = PRG, 2 = BIN)\n%d\n\n"
  348.                         ";Packer/relocator player address\n$%04x\n\n"
  349.                         ";Packer/relocator zeropage baseaddress\n$%02x\n\n"
  350.                         ";Packer/relocator player type (0 = standard ... 3 = minimal)\n%d\n\n"
  351.                         ";Key entry mode (0 = Protracker, 1 = DMC)\n%d\n\n"
  352.                         ";Pattern highlight step size\n%d\n\n"
  353.                         ";Speed multiplier (0 = 25Hz, 1 = 1X, 2 = 2X etc.)\n%d\n\n"
  354.                         ";Use CatWeasel SID (0 = off, 1 = on)\n%d\n\n"
  355.                         ";Hardrestart ADSR parameter\n$%04x\n\n"
  356.                         ";reSID interpolation (0 = off, 1 = on)\n%d\n\n"
  357.                         ";Hexadecimal pattern display (0 = off, 1 = on)\n%d\n\n"
  358.                         ";SID baseaddresses\n$%08x\n\n"
  359.                         ";Finevibrato mode (0 = off, 1 = on)\n%d\n\n"
  360.                         ";Pulseskipping (0 = off, 1 = on)\n%d\n\n"
  361.                         ";Realtime effect skipping (0 = off, 1 = on)\n%d\n\n"
  362.                         ";Random reSID write delay in cycles (0 = off)\n%d\n\n"
  363.                         ";Custom SID clock cycles per second (0 = use PAL/NTSC default)\n%d\n\n"
  364.                         ";HardSID interactive mode buffer size (in milliseconds, 0 = maximum/no flush)\n%d\n\n"
  365.                         ";HardSID playback mode buffer size (in milliseconds, 0 = maximum/no flush)\n%d\n\n",
  366.     b,
  367.     mr,
  368.     hardsid,
  369.     sidmodel,
  370.     ntsc,
  371.     fileformat,
  372.     playeradr,
  373.     zeropageadr,
  374.     playerversion,
  375.     keypreset,
  376.     stepsize,
  377.     multiplier,
  378.     catweasel,
  379.     adparam,
  380.     interpolate,
  381.     patternhex,
  382.     sidaddress,
  383.     finevibrato,
  384.     optimizepulse,
  385.     optimizerealtime,
  386.     residdelay,
  387.     customclockrate,
  388.     hardsidbufinteractive,
  389.     hardsidbufplayback);
  390.  
  391.     fclose(configfile);
  392.   }
  393.  
  394.   // Exit
  395.   return 0;
  396. }
  397.  
  398. void waitkey(void)
  399. {
  400.   for (;;)
  401.   {
  402.     displayupdate();
  403.     getkey();
  404.     if ((rawkey) || (key)) break;
  405.     if (win_quitted) break;
  406.   }
  407.  
  408.   converthex();
  409. }
  410.  
  411. void waitkeymouse(void)
  412. {
  413.   for (;;)
  414.   {
  415.     displayupdate();
  416.     getkey();
  417.     if ((rawkey) || (key)) break;
  418.     if (win_quitted) break;
  419.     if (mouseb) break;
  420.   }
  421.  
  422.   converthex();
  423. }
  424.  
  425. void waitkeymousenoupdate(void)
  426. {
  427.   for (;;)
  428.   {
  429.       fliptoscreen();
  430.     getkey();
  431.     if ((rawkey) || (key)) break;
  432.     if (win_quitted) break;
  433.     if (mouseb) break;
  434.   }
  435.  
  436.   converthex();
  437. }
  438.  
  439. void waitkeynoupdate(void)
  440. {
  441.   for (;;)
  442.   {
  443.       fliptoscreen();
  444.     getkey();
  445.     if ((rawkey) || (key)) break;
  446.     if ((mouseb) && (!prevmouseb)) break;
  447.     if (win_quitted) break;
  448.   }
  449. }
  450.  
  451. void converthex()
  452. {
  453.   int c;
  454.  
  455.   hexnybble = -1;
  456.   for (c = 0; c < 16; c++)
  457.   {
  458.     if (tolower(key) == hexkeytbl[c])
  459.     {
  460.       if (c >= 10)
  461.       {
  462.         if (!shiftpressed) hexnybble = c;
  463.       }
  464.       else
  465.       {
  466.         hexnybble = c;
  467.       }
  468.     }
  469.   }
  470. }
  471.  
  472.  
  473. void docommand(void)
  474. {
  475.   // "GUI" operation :)
  476.   mousecommands();
  477.  
  478.   // Mode-specific commands
  479.   switch(editmode)
  480.   {
  481.     case EDIT_ORDERLIST:
  482.     orderlistcommands();
  483.     break;
  484.  
  485.     case EDIT_INSTRUMENT:
  486.     instrumentcommands();
  487.     break;
  488.  
  489.     case EDIT_TABLES:
  490.     tablecommands();
  491.     break;
  492.  
  493.     case EDIT_PATTERN:
  494.     patterncommands();
  495.     break;
  496.  
  497.     case EDIT_NAMES:
  498.     namecommands();
  499.     break;
  500.   }
  501.  
  502.   // General commands
  503.   generalcommands();
  504. }
  505.  
  506. void mousecommands(void)
  507. {
  508.   int c;
  509.  
  510.   if (!mouseb) return;
  511.  
  512.   // Pattern editpos & pattern number selection
  513.   for (c = 0; c < MAX_CHN; c++)
  514.   {
  515.     if ((mousey == 2) && (mousex >= 11 + c*9) && (mousex <= 12 + c*9))
  516.     {
  517.         if ((!prevmouseb) || (mouseheld > HOLDDELAY))
  518.         {
  519.         if (mouseb & MOUSEB_LEFT)
  520.         {
  521.           epchn = c;
  522.           nextpattern();
  523.         }
  524.         if (mouseb & MOUSEB_RIGHT)
  525.         {
  526.           epchn = c;
  527.           prevpattern();
  528.         }
  529.       }
  530.     }
  531.     else
  532.     {
  533.       if ((mousey >= 2) && (mousey <= 34) && (mousex >= 5 + c*9) && (mousex <= 12 + c*9))
  534.       {
  535.         int x = mousex - 5 - c*9;
  536.         int newpos = mousey - 3 + epview;
  537.         if (newpos < 0) newpos = 0;
  538.         if (newpos > pattlen[epnum[epchn]]) newpos = pattlen[epnum[epchn]];
  539.  
  540.         editmode = EDIT_PATTERN;
  541.  
  542.         if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (!prevmouseb))
  543.         {
  544.           if ((epmarkchn != c) || (newpos != epmarkend))
  545.           {
  546.             epmarkchn = c;
  547.             epmarkstart = epmarkend = newpos;
  548.           }
  549.         }
  550.  
  551.         if (mouseb & MOUSEB_LEFT)
  552.         {
  553.           epchn = c;
  554.           if (x < 3) epcolumn = 0;
  555.           if (x >= 3) epcolumn = x - 2;
  556.         }
  557.  
  558.         if (!prevmouseb)
  559.         {
  560.           if (mouseb & MOUSEB_LEFT)
  561.             eppos = newpos;
  562.         }
  563.         else
  564.         {
  565.             if (mouseb & MOUSEB_LEFT)
  566.             {
  567.             if (mousey == 2) eppos--;
  568.             if (mousey == 34) eppos++;
  569.           }
  570.         }
  571.         if (eppos < 0) eppos = 0;
  572.         if (eppos > pattlen[epnum[epchn]]) eppos = pattlen[epnum[epchn]];
  573.  
  574.         if (mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) epmarkend = newpos;
  575.       }
  576.     }
  577.   }
  578.  
  579.  
  580.   // Song editpos & songnumber selection
  581.   if ((mousey >= 3) && (mousey <= 8) && (mousex >= 40+20))
  582.   {
  583.     int newpos = esview + (mousex - 44 - 20) / 3;
  584.     int newcolumn = (mousex - 44 - 20) % 3;
  585.     int newchn = mousey - 3;
  586.     if (newcolumn < 0) newcolumn = 0;
  587.     if (newcolumn > 1) newcolumn = 1;
  588.     if (newpos < 0)
  589.     {
  590.       newpos = 0;
  591.       newcolumn = 0;
  592.     }
  593.     if (newpos == songlen[esnum][eschn])
  594.     {
  595.       newpos++;
  596.       newcolumn = 0;
  597.     }
  598.     if (newpos > songlen[esnum][eschn]+1)
  599.     {
  600.       newpos = songlen[esnum][eschn] + 1;
  601.       newcolumn = 1;
  602.     }
  603.  
  604.     editmode = EDIT_ORDERLIST;
  605.  
  606.     if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (!prevmouseb) && (newpos < songlen[esnum][eschn]))
  607.     {
  608.       if ((esmarkchn != newchn) || (newpos != esmarkend))
  609.       {
  610.         esmarkchn = newchn;
  611.         esmarkstart = esmarkend = newpos;
  612.       }
  613.     }
  614.  
  615.     if (mouseb & MOUSEB_LEFT)
  616.     {
  617.       eschn = newchn;
  618.       eseditpos = newpos;
  619.       escolumn = newcolumn;
  620.     }
  621.  
  622.     if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (newpos < songlen[esnum][eschn])) esmarkend = newpos;
  623.   }
  624.   if (((!prevmouseb) || (mouseheld > HOLDDELAY)) && (mousey == 2) && (mousex >= 63+20) && (mousex <= 64+20))
  625.   {
  626.     if (mouseb & MOUSEB_LEFT) nextsong();
  627.     if (mouseb & MOUSEB_RIGHT) prevsong();
  628.   }
  629.  
  630.   // Instrument editpos & instrument number selection
  631.   if ((mousey >= 8+3) && (mousey <= 12+3) && (mousex >= 56+20) && (mousex <= 57+20))
  632.   {
  633.     editmode = EDIT_INSTRUMENT;
  634.     eipos = mousey - 8 - 3;
  635.     eicolumn = mousex - 56 - 20;
  636.   }
  637.   if ((mousey >= 8+3) && (mousey <= 11+3) && (mousex >= 76+20) && (mousex <= 77+20))
  638.   {
  639.     editmode = EDIT_INSTRUMENT;
  640.     eipos = mousey - 8 - 3 + 5;
  641.     eicolumn = mousex - 76 - 20;
  642.   }
  643.   if ((mousey == 7+3) && (mousex >= 60+20))
  644.   {
  645.     editmode = EDIT_INSTRUMENT;
  646.     eipos = 9;
  647.   }
  648.   if (((!prevmouseb) || (mouseheld > HOLDDELAY)) && (mousey == 7+3) && (mousex >= 56+20) && (mousex <= 57+20))
  649.   {
  650.     if (mouseb & MOUSEB_LEFT) nextinstr();
  651.     if (mouseb & MOUSEB_RIGHT) previnstr();
  652.   }
  653.  
  654.   // Table editpos
  655.   for (c = 0; c < MAX_TABLES; c++)
  656.   {
  657.     if ((mousey >= 14+3) && (mousey <= 20+3+9) && (mousex >= 43 + 20 + c*10) && (mousex <= 47 + 20 + c*10))
  658.     {
  659.       int newpos = mousey - 15 - 3 + etview[etnum];
  660.       if (newpos < 0) newpos = 0;
  661.       if (newpos >= MAX_TABLELEN) newpos = MAX_TABLELEN-1;
  662.  
  663.       editmode = EDIT_TABLES;
  664.  
  665.       if ((mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) && (!prevmouseb))
  666.       {
  667.         if ((etmarknum != etnum) || (newpos != etmarkend))
  668.         {
  669.           etmarknum = c;
  670.           etmarkstart = etmarkend = newpos;
  671.         }
  672.       }
  673.       if (mouseb & MOUSEB_LEFT)
  674.       {
  675.         etnum = c;
  676.         etpos = mousey - 15 - 3 + etview[etnum];
  677.         etcolumn = mousex - 43 - 20 - c*10;
  678.       }
  679.       if (etcolumn >= 2) etcolumn--;
  680.       if (etpos < 0) etpos = 0;
  681.       if (etpos > MAX_TABLELEN-1) etpos = MAX_TABLELEN-1;
  682.  
  683.       if (mouseb & (MOUSEB_RIGHT|MOUSEB_MIDDLE)) etmarkend = newpos;
  684.     }
  685.   }
  686.  
  687.   // Name editpos
  688.   if ((mousey == 21+3+9) && (mousex >= 47+20))
  689.   {
  690.     editmode = EDIT_NAMES;
  691.     if ((!prevmouseb) && (mouseb & MOUSEB_RIGHT))
  692.     {
  693.       enpos++;
  694.       if (enpos > 2) enpos = 0;
  695.     }
  696.   }
  697.  
  698.   // Status panel
  699.   if ((!prevmouseb) && (mousex == 7) && (mousey == 23+3+9))
  700.   {
  701.     if (mouseb & (MOUSEB_LEFT))
  702.       if (epoctave < 7) epoctave++;
  703.     if (mouseb & (MOUSEB_RIGHT))
  704.       if (epoctave > 0) epoctave--;
  705.   }
  706.   if ((!prevmouseb) && (mousex <= 7) && (mousey == 24+3+9))
  707.   {
  708.     recordmode ^= 1;
  709.   }
  710.   for (c = 0; c < MAX_CHN; c++)
  711.   {
  712.     if ((!prevmouseb) && (mousey >= 23+3+9) && (mousex >= 59 + 7*c) && (mousex <= 64 + 7*c))
  713.       mutechannel(c);
  714.   }
  715.  
  716.   // Titlebar actions
  717.   if (!menu)
  718.   {
  719.     if ((mousey == 0) && (!prevmouseb) && (mouseb == MOUSEB_LEFT))
  720.     {
  721.       if ((mousex >= 40+20) && (mousex <= 41+20))
  722.       {
  723.         usefinevib ^= 1;
  724.       }
  725.       if ((mousex >= 43+20) && (mousex <= 44+20))
  726.       {
  727.         optimizepulse ^= 1;
  728.       }
  729.       if ((mousex >= 46+20) && (mousex <= 47+20))
  730.       {
  731.         optimizerealtime ^= 1;
  732.       }
  733.       if ((mousex >= 49+20) && (mousex <= 52+20))
  734.       {
  735.         ntsc ^= 1;
  736.         sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  737.       }
  738.       if ((mousex >= 54+20) && (mousex <= 57+20))
  739.       {
  740.         sidmodel ^= 1;
  741.         sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  742.       }
  743.       if ((mousex >= 62+20) && (mousex <= 65+20)) editadsr();
  744.       if ((mousex >= 67+20) && (mousex <= 68+20)) prevmultiplier();
  745.       if ((mousex >= 69+20) && (mousex <= 70+20)) nextmultiplier();
  746.     }
  747.   }
  748.   else
  749.   {
  750.     if ((!mousey) && (mouseb & MOUSEB_LEFT) && (!(prevmouseb & MOUSEB_LEFT)))
  751.     {
  752.       if ((mousex >= 0) && (mousex <= 5))
  753.       {
  754.         initsong(esnum, PLAY_BEGINNING);
  755.         followplay = shiftpressed;
  756.       }
  757.       if ((mousex >= 7) && (mousex <= 15))
  758.       {
  759.         initsong(esnum, PLAY_POS);
  760.         followplay = shiftpressed;
  761.       }
  762.       if ((mousex >= 17) && (mousex <= 26))
  763.       {
  764.         initsong(esnum, PLAY_PATTERN);
  765.         followplay = shiftpressed;
  766.       }
  767.       if ((mousex >= 28) && (mousex <= 33))
  768.         stopsong();
  769.       if ((mousex >= 35) && (mousex <= 40))
  770.         load();
  771.       if ((mousex >= 42) && (mousex <= 47))
  772.         save();
  773.       if ((mousex >= 49) && (mousex <= 57))
  774.         relocator();
  775.       if ((mousex >= 59) && (mousex <= 64))
  776.         onlinehelp();
  777.       if ((mousex >= 66) && (mousex <= 72))
  778.         clear();
  779.       if ((mousex >= 74) && (mousex <= 79))
  780.         quit();
  781.     }
  782.   }
  783. }
  784.  
  785. void generalcommands(void)
  786. {
  787.   int c;
  788.  
  789.   switch(key)
  790.   {
  791.     case '?':
  792.     case '-':
  793.     if ((editmode != EDIT_NAMES) && (editmode != EDIT_ORDERLIST))
  794.     {
  795.       if (!((editmode == EDIT_INSTRUMENT) && (eipos == 9))) previnstr();
  796.     }
  797.     break;
  798.  
  799.     case '+':
  800.     case '_':
  801.     if ((editmode != EDIT_NAMES) && (editmode != EDIT_ORDERLIST))
  802.     {
  803.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9))) nextinstr();
  804.  
  805.     }
  806.     break;
  807.  
  808.     case '*':
  809.     if (editmode != EDIT_NAMES)
  810.     {
  811.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  812.       {
  813.         if (epoctave < 7) epoctave++;
  814.       }
  815.     }
  816.     break;
  817.  
  818.     case '/':
  819.     case '\'':
  820.     if (editmode != EDIT_NAMES)
  821.     {
  822.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  823.       {
  824.         if (epoctave > 0) epoctave--;
  825.       }
  826.     }
  827.     break;
  828.  
  829.     case '<':
  830.     if (((editmode == EDIT_INSTRUMENT) && (eipos != 9)) || (editmode == EDIT_TABLES))
  831.       previnstr();
  832.     break;
  833.  
  834.     case '>':
  835.     if (((editmode == EDIT_INSTRUMENT) && (eipos != 9)) || (editmode == EDIT_TABLES))
  836.       nextinstr();
  837.     break;
  838.  
  839.     case ';':
  840.     for (c = 0; c < MAX_CHN; c++)
  841.     {
  842.       if (espos[c]) espos[c]--;
  843.       if (espos[c] < esview)
  844.       {
  845.         esview = espos[c];
  846.         eseditpos = espos[c];
  847.       }
  848.     }
  849.     updateviewtopos();
  850.     rewindsong();
  851.     break;
  852.  
  853.     case ':':
  854.     for (c = 0; c < MAX_CHN; c++)
  855.     {
  856.       if (espos[c] < songlen[esnum][c]-1)
  857.         espos[c]++;
  858.       if (espos[c] - esview >= VISIBLEORDERLIST)
  859.       {
  860.         esview = espos[c] - VISIBLEORDERLIST + 1;
  861.         eseditpos = espos[c];
  862.       }
  863.     }
  864.     updateviewtopos();
  865.     rewindsong();
  866.     break;
  867.  
  868.   }
  869.   if (win_quitted) exitprogram = 1;
  870.   switch(rawkey)
  871.   {
  872.     case KEY_ESC:
  873.     if (!shiftpressed)
  874.       quit();
  875.     else
  876.       clear();
  877.     break;
  878.  
  879.     case KEY_KPMULTIPLY:
  880.     if ((editmode != EDIT_NAMES) && (!key))
  881.     {
  882.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  883.       {
  884.         if (epoctave < 7) epoctave++;
  885.       }
  886.     }
  887.     break;
  888.  
  889.     case KEY_KPDIVIDE:
  890.     if ((editmode != EDIT_NAMES) && (!key))
  891.     {
  892.       if (!((editmode == EDIT_INSTRUMENT) && (eipos >= 9)))
  893.       {
  894.         if (epoctave > 0) epoctave--;
  895.       }
  896.     }
  897.     break;
  898.  
  899.     case KEY_F12:
  900.     onlinehelp();
  901.     break;
  902.  
  903.     case KEY_TAB:
  904.     if (!shiftpressed) editmode++;
  905.     else editmode--;
  906.     if (editmode > EDIT_NAMES) editmode = EDIT_PATTERN;
  907.     if (editmode < EDIT_PATTERN) editmode = EDIT_NAMES;
  908.     break;
  909.  
  910.     case KEY_F1:
  911.     initsong(esnum, PLAY_BEGINNING);
  912.     followplay = shiftpressed;
  913.     break;
  914.  
  915.     case KEY_F2:
  916.     initsong(esnum, PLAY_POS);
  917.     followplay = shiftpressed;
  918.     break;
  919.  
  920.     case KEY_F3:
  921.     initsong(esnum, PLAY_PATTERN);
  922.     followplay = shiftpressed;
  923.     break;
  924.  
  925.     case KEY_F4:
  926.     if (shiftpressed)
  927.       mutechannel(epchn);
  928.     else
  929.     stopsong();
  930.     break;
  931.  
  932.     case KEY_F5:
  933.     if (!shiftpressed)
  934.       editmode = EDIT_PATTERN;
  935.     else prevmultiplier();
  936.     break;
  937.  
  938.     case KEY_F6:
  939.     if (!shiftpressed)
  940.       editmode = EDIT_ORDERLIST;
  941.     else nextmultiplier();
  942.     break;
  943.  
  944.     case KEY_F7:
  945.     if (!shiftpressed)
  946.     {
  947.       if (editmode == EDIT_INSTRUMENT)
  948.         editmode = EDIT_TABLES;
  949.       else
  950.         editmode = EDIT_INSTRUMENT;
  951.     }
  952.     else editadsr();
  953.     break;
  954.  
  955.     case KEY_F8:
  956.     if (!shiftpressed)
  957.       editmode = EDIT_NAMES;
  958.     else
  959.     {
  960.       sidmodel ^= 1;
  961.       sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  962.     }
  963.     break;
  964.  
  965.     case KEY_F9:
  966.     relocator();
  967.     break;
  968.  
  969.     case KEY_F10:
  970.     load();
  971.     break;
  972.  
  973.     case KEY_F11:
  974.     save();
  975.     break;
  976.   }
  977. }
  978.  
  979. void load(void)
  980. {
  981.   if ((editmode != EDIT_INSTRUMENT) && (editmode != EDIT_TABLES))
  982.   {
  983.     if (fileselector(songfilename, songpath, songfilter, "LOAD SONG", 0))
  984.       loadsong();
  985.   }
  986.   else
  987.   {
  988.     if (einum)
  989.     {
  990.       if (fileselector(instrfilename, instrpath, instrfilter, "LOAD INSTRUMENT", 0))
  991.         loadinstrument();
  992.     }
  993.   }
  994.   key = 0;
  995.   rawkey = 0;
  996. }
  997.  
  998. void save(void)
  999. {
  1000.   if ((editmode != EDIT_INSTRUMENT) && (editmode != EDIT_TABLES))
  1001.   {
  1002.     int done = 0;
  1003.  
  1004.     // Repeat until quit or save successful
  1005.     while (!done)
  1006.     {
  1007.       if (strlen(loadedsongfilename)) strcpy(songfilename, loadedsongfilename);
  1008.       if (fileselector(songfilename, songpath, songfilter, "SAVE SONG", 3))
  1009.         done = savesong();
  1010.       else done = 1;
  1011.     }
  1012.   }
  1013.   else
  1014.   {
  1015.     if (einum)
  1016.     {
  1017.       int done = 0;
  1018.       int useinstrname = 0;
  1019.       char tempfilename[MAX_FILENAME];
  1020.  
  1021.       // Repeat until quit or save successful
  1022.       while (!done)
  1023.       {
  1024.         if ((!strlen(instrfilename)) && (strlen(instr[einum].name)))
  1025.         {
  1026.           useinstrname = 1;
  1027.           strcpy(instrfilename, instr[einum].name);
  1028.           strcat(instrfilename, ".ins");
  1029.           strcpy(tempfilename, instrfilename);
  1030.         }
  1031.  
  1032.         if (fileselector(instrfilename, instrpath, instrfilter, "SAVE INSTRUMENT", 3))
  1033.           done = saveinstrument();
  1034.         else done = 1;
  1035.  
  1036.         if (useinstrname)
  1037.         {
  1038.           if (!strcmp(tempfilename, instrfilename))
  1039.             memset(instrfilename, 0, sizeof instrfilename);
  1040.         }
  1041.       }
  1042.     }
  1043.   }
  1044.   key = 0;
  1045.   rawkey = 0;
  1046. }
  1047.  
  1048. void quit(void)
  1049. {
  1050.   if ((!shiftpressed) || (mouseb))
  1051.   {
  1052.     printtextcp(38, 36, 15, "Really Quit (y/n)?");
  1053.     waitkey();
  1054.     printblank(20, 36, 39);
  1055.     if ((key == 'y') || (key == 'Y')) exitprogram = 1;
  1056.   }
  1057.   key = 0;
  1058.   rawkey = 0;
  1059. }
  1060.  
  1061. void clear(void)
  1062. {
  1063.   int cs = 0;
  1064.   int cp = 0;
  1065.   int ci = 0;
  1066.   int ct = 0;
  1067.   int cn = 0;
  1068.  
  1069.   printtextcp(38, 36, 15, "Optimize everything (y/n)?");
  1070.   waitkey();
  1071.   printblank(20, 36, 39);
  1072.   if ((key == 'y') || (key == 'Y'))
  1073.   {
  1074.     optimizeeverything(1, 1);
  1075.     key = 0;
  1076.     rawkey = 0;
  1077.     return;
  1078.   }
  1079.  
  1080.   printtextcp(38, 36, 15, "Clear orderlists (y/n)?");
  1081.   waitkey();
  1082.   printblank(20, 36, 39);
  1083.   if ((key == 'y') || (key == 'Y')) cs = 1;
  1084.  
  1085.   printtextcp(38, 36, 15, "Clear patterns (y/n)?");
  1086.   waitkey();
  1087.   printblank(20, 36, 39);
  1088.   if ((key == 'y') || (key == 'Y')) cp = 1;
  1089.  
  1090.   printtextcp(38, 36, 15, "Clear instruments (y/n)?");
  1091.   waitkey();
  1092.   printblank(20, 36, 39);
  1093.   if ((key == 'y') || (key == 'Y')) ci = 1;
  1094.  
  1095.   printtextcp(38, 36, 15, "Clear tables (y/n)?");
  1096.   waitkey();
  1097.   printblank(20, 36, 39);
  1098.   if ((key == 'y') || (key == 'Y')) ct = 1;
  1099.  
  1100.   printtextcp(38, 36, 15, "Clear songname (y/n)?");
  1101.   waitkey();
  1102.   printblank(20, 36, 39);
  1103.   if ((key == 'y') || (key == 'Y')) cn = 1;
  1104.  
  1105.   if (cp == 1)
  1106.   {
  1107.     int selectdone = 0;
  1108.     int olddpl = defaultpatternlength;
  1109.  
  1110.     printtext(29, 36, 15,"Pattern length:");
  1111.     while (!selectdone)
  1112.     {
  1113.       sprintf(textbuffer, "%02d ", defaultpatternlength);
  1114.       printtext(44, 36, 15, textbuffer);
  1115.       waitkey();
  1116.       switch(rawkey)
  1117.       {
  1118.         case KEY_LEFT:
  1119.         defaultpatternlength -= 7;
  1120.         case KEY_DOWN:
  1121.         defaultpatternlength--;
  1122.         if (defaultpatternlength < 1) defaultpatternlength = 1;
  1123.         break;
  1124.  
  1125.         case KEY_RIGHT:
  1126.         defaultpatternlength += 7;
  1127.         case KEY_UP:
  1128.         defaultpatternlength++;
  1129.         if (defaultpatternlength > MAX_PATTROWS) defaultpatternlength = MAX_PATTROWS;
  1130.         break;
  1131.  
  1132.         case KEY_ESC:
  1133.         defaultpatternlength = olddpl;
  1134.         selectdone = 1;
  1135.         break;
  1136.  
  1137.         case KEY_ENTER:
  1138.         selectdone = 1;
  1139.         break;
  1140.       }
  1141.     }
  1142.     printblank(20, 36, 39);
  1143.   }
  1144.  
  1145.   if (cs | cp | ci | ct | cn)
  1146.     memset(songfilename, 0, sizeof songfilename);
  1147.   clearsong(cs, cp, ci, ct, cn);
  1148.  
  1149.   key = 0;
  1150.   rawkey = 0;
  1151. }
  1152.  
  1153.  
  1154. void editadsr(void)
  1155. {
  1156.   eamode = 1;
  1157.   eacolumn = 0;
  1158.  
  1159.   for (;;)
  1160.   {
  1161.     waitkeymouse();
  1162.  
  1163.     if (win_quitted)
  1164.     {
  1165.       exitprogram = 1;
  1166.       key = 0;
  1167.       rawkey = 0;
  1168.       return;
  1169.     }
  1170.  
  1171.     if (hexnybble >= 0)
  1172.     {
  1173.       switch(eacolumn)
  1174.       {
  1175.         case 0:
  1176.         adparam &= 0x0fff;
  1177.         adparam |= hexnybble << 12;
  1178.         break;
  1179.  
  1180.         case 1:
  1181.         adparam &= 0xf0ff;
  1182.         adparam |= hexnybble << 8;
  1183.         break;
  1184.  
  1185.         case 2:
  1186.         adparam &= 0xff0f;
  1187.         adparam |= hexnybble << 4;
  1188.         break;
  1189.  
  1190.         case 3:
  1191.         adparam &= 0xfff0;
  1192.         adparam |= hexnybble;
  1193.         break;
  1194.       }
  1195.       eacolumn++;
  1196.     }
  1197.  
  1198.     switch(rawkey)
  1199.     {
  1200.       case KEY_F7:
  1201.       if (!shiftpressed) break;
  1202.  
  1203.       case KEY_ESC:
  1204.       case KEY_ENTER:
  1205.       case KEY_TAB:
  1206.       eamode = 0;
  1207.       key = 0;
  1208.       rawkey = 0;
  1209.       return;
  1210.  
  1211.       case KEY_BACKSPACE:
  1212.       if (!eacolumn) break;
  1213.       case KEY_LEFT:
  1214.       eacolumn--;
  1215.       break;
  1216.  
  1217.       case KEY_RIGHT:
  1218.       eacolumn++;
  1219.     }
  1220.     eacolumn &= 3;
  1221.  
  1222.     if ((mouseb) && (!prevmouseb))
  1223.     {
  1224.       eamode = 0;
  1225.       return;
  1226.     }
  1227.   }
  1228. }
  1229.  
  1230. void getparam(FILE *handle, unsigned *value)
  1231. {
  1232.   for (;;)
  1233.   {
  1234.     while (!configptr)
  1235.     {
  1236.       if (feof(handle)) return;
  1237.       fgets(configbuf, MAX_PATHNAME, handle);
  1238.       if ((configbuf[0]) && (configbuf[0] != ';')) configptr = configbuf;
  1239.     }
  1240.  
  1241.     if ((*configptr == '$') || ((*configptr >= '0') && (*configptr <= '9'))) break;
  1242.     if (!(*configptr)) configptr = NULL;
  1243.     else configptr++;
  1244.   }
  1245.  
  1246.   if (*configptr == '$')
  1247.   {
  1248.     *value = 0;
  1249.     configptr++;
  1250.     for (;;)
  1251.     {
  1252.       char c = tolower(*configptr++);
  1253.       int h = -1;
  1254.  
  1255.       if ((c >= 'a') && (c <= 'f')) h = c - 'a' + 10;
  1256.       if ((c >= '0') && (c <= '9')) h = c - '0';
  1257.  
  1258.       if (h >= 0)
  1259.       {
  1260.         *value *= 16;
  1261.         *value += h;
  1262.       }
  1263.       else break;
  1264.     }
  1265.   }
  1266.   else
  1267.   {
  1268.     *value = 0;
  1269.     for (;;)
  1270.     {
  1271.       char c = tolower(*configptr++);
  1272.       int d = -1;
  1273.  
  1274.       if ((c >= '0') && (c <= '9')) d = c - '0';
  1275.  
  1276.       if (d >= 0)
  1277.       {
  1278.         *value *= 10;
  1279.         *value += d;
  1280.       }
  1281.       else break;
  1282.     }
  1283.   }
  1284.  
  1285.   if (!(*configptr)) configptr = NULL;
  1286. }
  1287.  
  1288.  
  1289. void prevmultiplier(void)
  1290. {
  1291.   if (multiplier > 0)
  1292.   {
  1293.     multiplier--;
  1294.     sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  1295.   }
  1296. }
  1297.  
  1298. void nextmultiplier(void)
  1299. {
  1300.   if (multiplier < 16)
  1301.   {
  1302.     multiplier++;
  1303.     sound_init(b, mr, writer, hardsid, sidmodel, ntsc, multiplier, catweasel, interpolate, customclockrate);
  1304.   }
  1305. }
  1306.