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

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