home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.73.zip / src / goattrk2.c < prev    next >
C/C++ Source or Header  |  2014-07-23  |  36KB  |  1,423 lines

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