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