home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.65_stereo.zip / src / gt2stereo.c < prev    next >
C/C++ Source or Header  |  2007-09-28  |  32KB  |  1,290 lines

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