2 // Thunder Graphic User Interface
5 // (c) 2004, 2009 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 07/23/2009 Added changelog ;-)
17 #include <fstream> // Needed for tracelog
18 //#include "SDL.h" // Needed for screen.h
20 #include "resource.h" // Thunder graphics & sounds
22 using namespace std; // Yes!
26 extern SDL_Surface * screen;
28 extern uint8 my_scr[0x14000]; // Screen buffer...
29 extern uint8 gram1[]; // Game RAM (do here??)
30 extern uint8 hScrollOffset; // Horizontal scroll offset
31 extern uint8 vScrollOffset; // Vertical scroll offset
32 extern uint32 voffsets[8];
33 extern uint8 voice_rom[]; // PCM data pointer
34 extern fstream tr; // Tracelog
38 uint16 text_life; // How long text is visible
39 bool show_text; // Whether or not to show text
40 uint16 show_which_msg; // Which message to show
41 bool show_gui; // Whether or not to show GUI
42 uint16 selection; // Which GUI item currently selected
44 uint16 gui_debounce; // GUI key debounce value
45 uint16 num_coins; // Number of coins dropped
46 uint16 blink = 0; // Used to blink player 1 & 2 start buttons
47 uint16 flash = 23; // Used to flash GUI lights
48 uint16 iline = 0; // Used to roll line
49 uint16 dcurcol = 179; // dipswitch cursor color
50 int dcurdir = 1; // Initially going up...
51 bool blink_on = false;
52 bool game_refresh; // Refresh rate user set
53 bool do_decrement; // Flag to handle decrement...
54 bool user_selected_something; // Flag for well, you know...
55 uint16 dswitch; // Which dipswitch is selected...
57 // The following are global for the sound routines...
59 const float sampleBase = 22050.0/6000.0; // Btwn 5512.5 and 6000
61 bool chan1_go = false, chan2_go = false, chan3_go = false;
62 bool chan4_go = false, chan5_go = false, chan6_go = false;
63 uint8 * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6;
64 uint32 rom_pos, end_pos;
65 uint32 spos1, end_pos1;
66 uint32 spos2, end_pos2;
67 uint32 spos3, end_pos3;
68 uint32 spos4, end_pos4;
69 uint32 spos5, end_pos5;
70 uint32 spos6, end_pos6;
78 uint8 * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
79 uint32 snd_lens[3] = { sunknownlen, scyalen, scameralen };
84 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
85 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
86 0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
87 0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
88 0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
89 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
90 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
93 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
94 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
95 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
96 0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
97 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
98 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
102 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
104 0,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
105 0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,
106 0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,
107 0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,
108 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0
110 uint8 boptions[] = { // 35x9
111 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
112 0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
113 0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
114 0,1,0,0,1,0,1,1,1,0,0,1,1,1,1,0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,
115 0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,
116 0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,0,
117 0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,
118 0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,
119 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
273 user_selected_something = false;
277 // Handle key debounce
279 void HandleGUIDebounce(void)
281 if (gui_debounce) gui_debounce--; // Debounce GUI keys...
282 do_decrement = !do_decrement; // Called at 60Hz, so skip decrementing blink
285 if (blink) blink--; // Handle blinking stuff (Should prb go in DrawGUI)
287 flash-=2; // Handle flashing stuff (Should prb go in DrawGUI)
288 if (flash == 0xFFFF) flash = 23;
291 if (iline > 30) iline = 0; // 30 pixels high, going past by 1
294 if (dcurcol == 186) dcurdir = -1;
295 if (dcurcol == 179) dcurdir = 1;
300 // Set the refresh rate (30/60 Hz)
302 void SetRefreshRate(bool refresh)
304 game_refresh = refresh;
308 // Whether or not GUI is showing
310 bool ShowGUI(void) { return show_gui; }
315 void ActivateGUI(void) { show_gui = true; }
320 void DeactivateGUI(void) { show_gui = false; }
323 // Draw the small icons...
325 void DrawSmallIcons(uint16 icon_not_to_draw)
329 uint8 * sIcons[12] = { inoguis, icoinus, ipl1sts, ipl2sts, ii30hzs, ii60hzs,
330 idipsws, ichecks, ikeycns, isnapss, iresets, ibyebys };
331 uint8 xlens[12] = { 31, 18, 32, 35, 37, 37, 29, 23, 28, 32, 19, 19 };
332 uint8 ylens[12] = { 31, 18, 19, 19, 21, 21, 23, 20, 16, 17, 20, 23 };
333 uint8 xpos[11] = { 33, 48, 63, 78, 104, 0, 184, 210, 225, 240, 255 };
334 uint8 iconidx[11] = { 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 6 };
336 if (game_refresh) iconidx[9] = 5; // 60 Hz...
338 // Draw small icons 1 to 5 on left, then 11 to 7 on right.
340 for(int i=0; i<5; i++)
342 uint16 idx = i + icon_not_to_draw; // Get correct start pos.
343 if (idx > 10) idx -= 11;
345 iconmem = sIcons[iconidx[idx]];
346 xl = xlens[iconidx[idx]]; yl = ylens[iconidx[idx]];
348 uint32 scadr = hScrollOffset + voffsets[vScrollOffset];
349 scadr += 320*((224-yl)/2); // Center vertically
350 scadr += xpos[i] - (xl/2); // Center around horiz. pos.
353 for(int yy=0; yy<yl; yy++)
355 for(int xx=0; xx<xl; xx++)
357 uint8 b = iconmem[bmpptr++];
358 if (b) my_scr[scadr+xx+yy*320] = b;
362 for(int i=10; i>5; i--)
364 uint16 idx = i + icon_not_to_draw; // Get correct start pos.
365 if (idx > 10) idx -= 11;
367 iconmem = sIcons[iconidx[idx]];
368 xl = xlens[iconidx[idx]]; yl = ylens[iconidx[idx]];
370 uint32 scadr = hScrollOffset + voffsets[vScrollOffset];
371 scadr += 320*((224-yl)/2); // Center vertically
372 scadr += xpos[i] - (xl/2); // Center around horiz. pos.
375 for(int yy=0; yy<yl; yy++)
377 for(int xx=0; xx<xl; xx++)
379 uint8 b = iconmem[bmpptr++];
380 if (b) my_scr[scadr+xx+yy*320] = b;
387 // Draw the large (selected) icon
389 void DrawLargeIcon(uint16 icon)
393 uint8 * lIcons[11] = { inoguib, icoinub, ipl1stb, ipl2stb, ii30hzb, ii60hzb,
394 idipswb, ikeycnb, isnapsb, iresetb, ibyebyb };
395 uint8 xlens[11] = { 44, 45, 50, 52, 59, 59, 42, 45, 48, 58, 42 };
396 uint8 ylens[11] = { 44, 40, 33, 29, 52, 52, 34, 45, 37, 40, 50 };
398 uint8 gsubs1[24] = { 21, 21, 20, 19, 168, 168, 31, 155, 68, 68, 67, 66,
399 36, 36, 35, 34, 188, 188, 183, 181, 81, 81, 85, 80 },
400 gsubs2[24] = { 20, 20, 19, 19, 31, 31, 155, 155, 67, 67, 66, 66,
401 35, 35, 34, 34, 183, 183, 181, 181, 85, 85, 80, 80 },
402 gsubs3[24] = { 35, 34, 188, 188, 183, 181, 81, 81, 85, 80, 21, 21,
403 20, 19, 168, 168, 31, 155, 68, 68, 67, 66, 36, 36 },
404 gsubs4[24] = { 34, 34, 183, 183, 181, 181, 85, 85, 80, 80, 20, 20,
405 19, 19, 31, 31, 155, 155, 67, 67, 66, 66, 35, 35 },
406 gsubs5[24] = { 20, 20, 183, 183, 31, 31, 85, 85, 67, 67, 20, 20,
407 35, 35, 31, 31, 183, 183, 67, 67, 85, 85, 35, 35 };
409 iconmem = lIcons[icon];
410 xl = xlens[icon]; yl = ylens[icon];
416 if ((icon == REFRESH) && game_refresh)
419 xl = xlens[5]; yl = ylens[5];
421 if (icon == DIPSWITCH)
424 xl = xlens[6]; yl = ylens[6];
427 uint32 scadr = hScrollOffset + voffsets[vScrollOffset];
428 scadr += 320*((224-yl)/2); // Center vertically
429 scadr += (288-xl)/2; // Center horizontally
432 for(int yy=0; yy<yl; yy++)
434 for(int xx=0; xx<xl; xx++)
436 uint8 b = iconmem[bmpptr++];
439 if ((icon == PL1START) && (b == 235) && (num_coins) && !blink_on)
440 b = 125; // Light ON color
441 /*noguib: 44x44 [Green (hi/lo): 36/235 Orange: 168/31 Neutral:12]
442 Rainbow (ROYGBP, hi/med/lo): 21,20,19; 168, 31,155; 68,67,66;
443 36,35,34; 188,183,181; 81,85,80 */
446 uint8 fln = (23 - flash) + 1; // Want to go forward (maybe fix it?)
449 case 36: { b = gsubs1[fln]; break; }
450 case 235: { b = gsubs2[fln]; break; }
451 case 168: { b = gsubs3[fln]; break; }
452 case 31: { b = gsubs4[fln]; break; }
453 case 12: { b = gsubs5[fln]; break; }
456 if ((icon == REFRESH) && (iline == yy) && (b == 50)) b = 188;
457 my_scr[scadr+xx+yy*320] = b;
461 if (!blink) // Should go here???
463 blink_on = !blink_on; // Switch blink state
464 if (blink_on) blink = 12;
467 //if (flash == 1) flash = 23; // Reset flash value
471 // Draw the dipswitch portion of the GUI
473 void DrawDipswitch(void)
475 uint8 dseloff[16] = { 0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11, 12 };
476 uint8 * dtxt[13] = { idstext1, idstext2, idstext3, idstext4, idstext5,
477 idstext2, idstext6, idstext7, idstext8, idstext9,
478 idstext10, idstext11, idstext12 };
480 uint8 dtx[13] = { 48, 80, 96, 82, 60, 80, 76, 57, 33, 50, 62, 65, 63 },
481 dty[13] = { 7, 9, 7, 9, 7, 9, 7, 7, 7, 9, 7, 9, 7 };
482 uint32 dtxtoff[13] = { 4*320+24, 14*320-78, 25*320+24, 32*320-80,
483 39*320+24, 49*320-78,
484 4*320+24, 11*320-55, 18*320+24, 25*320-48,
485 32*320+24, 42*320-63, 53*320+24 };
486 uint32 scadr, bmpptr;
489 uint32 dbase = hScrollOffset + voffsets[vScrollOffset];
490 dbase += (288-26)/2; // Center horizontally
491 dbase += 320*((224-((65*2)+8))/2); // Center vertically
493 scadr = dbase; // Reset screen address
495 for(int yy=0; yy<65; yy++)
497 for(int xx=0; xx<26; xx++)
499 uint8 b = idswitch[bmpptr++];
500 if (b) my_scr[scadr+xx+yy*320] = b;
503 scadr = dbase + (320*73); // Reset screen address
505 for(int yy=0; yy<65; yy++)
507 for(int xx=0; xx<26; xx++)
509 uint8 b = idswitch[bmpptr++];
510 if (b) my_scr[scadr+xx+yy*320] = b;
513 for(int i=0; i<16; i++)
515 scadr = dbase + (5*320+5) + i*7*320;
516 if (i>7) scadr += 17*320; // Adjust for DSW #2
518 if (gram1[0x423D+(i<<1)]) scadr += 12; // Adjust position if ON
519 for(int yy=0; yy<5; yy++)
521 for(int xx=0; xx<5; xx++)
523 my_scr[scadr++] = idsbutton[bmpptr++];
525 scadr += 315; // Adjust position...
528 uint8 dselected_text = dseloff[dswitch];
529 for(int i=0; i<13; i++)
531 if (dselected_text != i)
533 scadr = dbase + dtxtoff[i];
534 if (i>5) scadr += (73*320);
536 for(int yy=0; yy<dty[i]; yy++)
538 for(int xx=0; xx<dtx[i]; xx++)
540 uint8 b = dtxt[i][bmpptr++];
541 if (b) my_scr[scadr] = b;
544 scadr += (320-dtx[i]); // Adjust position...
548 scadr = dbase + dtxtoff[dselected_text];
549 if (dselected_text>5) scadr += (73*320);
551 for(int yy=0; yy<dty[dselected_text]; yy++)
553 for(int xx=0; xx<dtx[dselected_text]; xx++)
555 uint8 b = dtxt[dselected_text][bmpptr++];
556 if (b) my_scr[scadr] = 125;
559 scadr += (320-dtx[dselected_text]); // Adjust position...
561 if (dswitch != 16) // Draw cursor
563 scadr = dbase + (4*320+4) + dswitch*7*320;
564 if (dswitch>7) scadr += 17*320; // Adjust for DSW #2
565 for(int xx=0; xx<19; xx++) my_scr[scadr++] = dcurcol;
567 for(int xx=0; xx<5; xx++)
569 my_scr[scadr] = dcurcol; scadr += 18;
570 my_scr[scadr] = dcurcol; scadr += 302;
572 for(int xx=0; xx<19; xx++) my_scr[scadr++] = dcurcol;
577 // The actual GUI display routine
581 if (!user_selected_something) // i.e. we're not inside a selection...
583 DrawSmallIcons(selection); // 'selection' is icon *not* to draw
584 DrawLargeIcon(selection);
588 if (selection == DIPSWITCH) DrawDipswitch();
593 // User pressed left arrow handler
595 void SelectLeft(void)
600 if (!user_selected_something)
603 if (selection > 10) selection = 0;
607 if (gram1[0x423D+(dswitch<<1)]) // It's switchable...
608 {} //SpawnSound(USERSOUND, SCLICK);
610 {} //SpawnSound(USERSOUND, SUNGH);
611 gram1[0x423D+(dswitch<<1)] = 0; // & turn it off
617 // User pressed right arrow handler
619 void SelectRight(void)
624 if (!user_selected_something)
627 if (selection > 10) selection = 10; // Unsigned compare
631 if (!gram1[0x423D+(dswitch<<1)]) // It's switchable...
632 {} //SpawnSound(USERSOUND, SCLICK);
634 {} //SpawnSound(USERSOUND, SUNGH);
635 gram1[0x423D+(dswitch<<1)] = 1; // & turn it on
641 // User pressed Up arrow handler
648 if (user_selected_something)
650 if (selection == DIPSWITCH)
653 if (dswitch > 16) dswitch = 16; // Wrap non-int
654 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
661 // User pressed down arrow handler
663 void SelectDown(void)
668 if (user_selected_something)
670 if (selection == DIPSWITCH)
673 if (dswitch > 16) dswitch = 0;
674 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
681 // User selected something! Handle it!
683 uint8 UserSelectedSomething(void)
685 //extern uint8 * gram1;
690 if (!user_selected_something) // Inside a selection? no...
692 if (selection == NOGUI) // Turn off GUI
696 if (selection == COINUP) // Coin up machine
698 gram1[0x41A5]++; // Add one coin... (prob. need sep. counter)
700 gram1[0x4189] = num_coins/10; // Should be in THUNDER.CPP?
701 gram1[0x418A] = num_coins - (gram1[0x4189]*10);
703 if (selection == PL1START) // 1 Player start
708 show_gui = false; // Shut off GUI only if coined up
710 gram1[0x418C] = 1; // Strobe start location
712 if (selection == PL2START) // 2 Player start
720 if (selection == REFRESH) // Toggle refresh rate
722 //SpawnSound(USERSOUND, SCLICK);
724 if (selection == DIPSWITCH) // Edit game settings
726 //SpawnSound(USERSOUND, SBLAH);
727 user_selected_something = true;
728 dswitch = 0; // Set at first dipswitch
730 if (selection == OPTIONS) // Edit emulator settings
733 if (selection == KEYCONFIG) // Edit game keys
736 if (selection == SNAPSHOT) // Snapshot
738 SpawnSound(USERSOUND, SCAMERA);
741 if (selection == RESET) // Reset machine
743 //SpawnSound(USERSOUND, SRESET);
745 if (selection == EXIT)
747 SpawnSound(USERSOUND, SCYA);
751 else // Selected something inside selection...
753 if (selection == DIPSWITCH)
755 if (dswitch == 16) // Selected 'back to GUI'
757 //SpawnSound(USERSOUND, SBLAH2);
758 user_selected_something = false;
762 //SpawnSound(USERSOUND, SCLICK);
763 gram1[0x423D + (dswitch<<1)] = !gram1[0x423D + (dswitch<<1)];
766 return 0xFF; // Nothing for main to do...
769 else return 0xFF; // Wasn't debounced, so return invalid
773 // Show byte passed to it
775 void ShowNumbers(int number)
777 uint8 * bnarray[16] = { bn0, bn1, bn2, bn3, bn4, bn5, bn6, bn7, bn8, bn9,
778 bnA, bnB, bnC, bnD, bnE, bnF };
779 uint32 scadr = hScrollOffset + voffsets[vScrollOffset] + 642 + 2560;
782 uint8 first_dig = number>>4, second_dig = number&0x0F;
783 for(int y=0; y<7; y++)
785 for(int x=0; x<6; x++)
787 if (bnarray[first_dig][bmpptr++] == 1) my_scr[scadr+x+y*320] = 7;
788 else my_scr[scadr+x+y*320] = 0;
791 bmpptr = 0; scadr += 6;
792 for(int y=0; y<7; y++)
794 for(int x=0; x<6; x++)
796 if (bnarray[second_dig][bmpptr++] == 1) my_scr[scadr+x+y*320] = 7;
797 else my_scr[scadr+x+y*320] = 0;
805 void SpawnMsg(uint8 msg)
807 text_life = 60; // 1 second...
808 show_text = true; // Show the damn thing...
809 show_which_msg = msg; // And tell it which message to show...
817 if (!text_life) // Kill text if it's time
823 text_life--; // Your life force is running out...
825 // Draw the message here...
826 uint32 scadr = hScrollOffset + voffsets[vScrollOffset] + 642;
829 for(int y=0; y<7; y++)
831 for(int x=0; x<21; x++)
833 if (show_which_msg == M60FPS)
835 if (bmp1[bmpptr++] == 1)
836 my_scr[scadr + x + y * 320] = 7;
838 my_scr[scadr + x + y * 320] = 0;
840 else if (show_which_msg == M30FPS)
842 if (bmp2[bmpptr++] == 1)
843 my_scr[scadr + x + y * 320] = 7;
845 my_scr[scadr + x + y * 320] = 0;
847 else if (show_which_msg == MSNAPSHOT)
849 if (bmp3[bmpptr++] == 1)
850 my_scr[scadr + x + y * 320] = 7;
852 my_scr[scadr + x + y * 320] = 0;
857 if (show_which_msg == MSHOWNUMS)
858 ShowNumbers(snd_num);
862 // Sound stuff (Will go elsewhere??? Perhaps in sound.cpp?)
864 void SpawnSound(int type, int snd, int channel/* = 0*/)
866 extern uint32 psg_lens[16];
867 extern uint8 * psg_adrs[16];
868 extern uint32 voc_lens[32];
869 extern uint8 * voc_adrs[32];
870 extern uint32 fm_lens[14];
871 extern uint8 * fm_adrs[14];
876 if (type == GAMESOUND)
878 snd--; // Will that do it??? Yes!!!
882 // 00 nn ss (nn # of repeats of sample ss)
891 spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
892 spos1 += st; // Need to add start somewhere...
907 spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
908 spos2 += st; // Need to add start somewhere...
914 else if (type == PSGSOUND)
916 if (snd_num & 0x10) // Second channel?
919 end_pos3 = psg_lens[snd_num & 0x0F];
920 sndp3 = psg_adrs[snd_num & 0x0F];
923 if (spos3 == end_pos3)
924 chan3_go = false; // No sound loaded, so don't do it!
926 else // First channel
929 end_pos4 = psg_lens[snd_num & 0x0F];
930 sndp4 = psg_adrs[snd_num & 0x0F];
933 if (spos4 == end_pos4)
934 chan4_go = false; // No sound loaded, so don't do it!
937 else if (type == FMSOUND)
940 end_pos5 = fm_lens[snd_num];
941 sndp5 = fm_adrs[snd_num];
944 if (spos5 == end_pos5)
945 chan5_go = false; // No sound loaded, so don't do it!
947 else if (type == USERSOUND)
950 end_pos6 = snd_lens[snd_num]; // User sound
951 sndp6 = snd_array[snd_num]; // Load pointer
957 // Sound card IRQ handler
959 void SoundFunc(void * userdata, Uint8 * buff, int num)
961 uint16 cnt = 0, sample; // 0-22 different sounds...
962 uint8 start_samp1, end_samp1, start_samp2, end_samp2;
963 uint8 samp1 = 128, samp2 = 128, samp3 = 128,
964 samp4 = 128, samp5 = 128, samp6 = 128; // Zero samples...
966 memset(buff, 128, num); // Kill sound...
968 if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go)
976 samp1 = voice_rom[spos1++];
981 samp1 = 128; // Kill channel 1 if done...
983 else if (samp1 == 0x00) // RLE compression...
985 sample1 += (float)voice_rom[spos1++] * sampleBase; // # of repeats
986 samp1 = prevSamp1; // Get last good sample
989 sample1 += sampleBase; // Keep fractional part intact
992 prevSamp1 = samp1; // Save last sample value
993 sample1 -= 1.0; // Decrement repeat counter
996 // Stretching 5KHz samples to 22KHz:
998 // 6KHz -> 22KHz: 22/6 repeats...
1003 samp2 = voice_rom[spos2++];
1008 samp2 = 128; // Kill channel 2 if done...
1010 else if (samp2 == 0x00) // RLE compression...
1012 sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats
1016 sample2 += sampleBase;
1019 // Delta-X values were making the samples sound like crap...
1020 // start_samp2 += delta_x2;
1027 samp3 = sndp3[spos3++];
1028 if (spos3 == end_pos3)
1030 chan3_go = false; samp3 = 128; // Kill channel 3 if done...
1036 samp4 = sndp4[spos4++];
1037 if (spos4 == end_pos4)
1039 chan4_go = false; samp4 = 128; // Kill channel 4 if done...
1045 samp5 = sndp5[spos5++];
1046 if (spos5 == end_pos5)
1048 chan5_go = false; samp5 = 128; // Kill channel 5 if done...
1054 samp6 = sndp6[spos6++];
1056 if (spos6 == end_pos6)
1057 chan6_go = false, samp6 = 128; // Kill channel 6...
1060 sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640; // Mix 'em...
1062 if (sample & 0xFF00) // i.e., it overflowed
1063 sample = (sample&0x8000 ? 0x00 : 0xFF); // Clip it
1065 buff[cnt++] = sample; // & store it...