home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.70_stereo.zip / src / gt2stereo.c < prev    next >
C/C++ Source or Header  |  2010-01-31  |  35KB  |  1,346 lines

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