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", ¢value);
1629 tuning[i] = pow(2.0, centvalue / 1200.0);
1630 }
1631 }
1632 fclose(scalatuningfile);
1633 }
1634 }
1635