home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.72_stereo.zip / src / gt2stereo.c.bak < prev    next >
Text File  |  2010-10-21  |  35KB  |  1,370 lines

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