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

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