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 ;-)
15 #include <fstream> // Needed for tracelog
16 #include "SDL.h" // Needed for screen.h
19 #include "resource.h" // Thunder graphics & sounds
21 using namespace std; // Yes!
25 extern SDL_Surface * screen;
27 extern BYTE my_scr[0x14000]; // Screen buffer...
28 extern BYTE * gram1; // Game RAM (do here??)
29 extern BYTE hScrollOffset; // Horizontal scroll offset
30 extern BYTE vScrollOffset; // Vertical scroll offset
31 extern DWORD voffsets[8];
32 extern BYTE * voice_rom; // PCM data pointer
33 extern fstream tr; // Tracelog
37 WORD text_life; // How long text is visible
38 bool show_text; // Whether or not to show text
39 WORD show_which_msg; // Which message to show
40 bool show_gui; // Whether or not to show GUI
41 WORD selection; // Which GUI item currently selected
43 WORD gui_debounce; // GUI key debounce value
44 WORD num_coins; // Number of coins dropped
45 WORD blink = 0; // Used to blink player 1 & 2 start buttons
46 WORD flash = 23; // Used to flash GUI lights
47 WORD iline = 0; // Used to roll line
48 WORD dcurcol = 179; // dipswitch cursor color
49 int dcurdir = 1; // Initially going up...
50 bool blink_on = false;
51 bool game_refresh; // Refresh rate user set
52 bool do_decrement; // Flag to handle decrement...
53 bool user_selected_something; // Flag for well, you know...
54 WORD dswitch; // Which dipswitch is selected...
56 // The following are global for the sound routines...
58 const float sampleBase = 22050.0/6000.0; // Btwn 5512.5 and 6000
60 bool chan1_go = false, chan2_go = false, chan3_go = false;
61 bool chan4_go = false, chan5_go = false, chan6_go = false;
62 BYTE * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6;
63 uint32 rom_pos, end_pos;
64 uint32 spos1, end_pos1;
65 uint32 spos2, end_pos2;
66 uint32 spos3, end_pos3;
67 uint32 spos4, end_pos4;
68 uint32 spos5, end_pos5;
69 uint32 spos6, end_pos6;
77 BYTE * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
78 DWORD snd_lens[3] = { sunknownlen, scyalen, scameralen };
83 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
85 0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
86 0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
87 0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
88 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
89 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
92 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
93 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
94 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
95 0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
96 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
97 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
98 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
101 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
102 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103 0,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
104 0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,
105 0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,
106 0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,
107 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0
109 BYTE boptions[] = { // 35x9
110 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,
111 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,
112 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,
113 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,
114 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,
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,0,1,1,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,0,0,1,0,
117 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,
118 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
272 user_selected_something = false;
276 // Handle key debounce
278 void HandleGUIDebounce(void)
280 if (gui_debounce) gui_debounce--; // Debounce GUI keys...
281 do_decrement = !do_decrement; // Called at 60Hz, so skip decrementing blink
284 if (blink) blink--; // Handle blinking stuff (Should prb go in DrawGUI)
286 flash-=2; // Handle flashing stuff (Should prb go in DrawGUI)
287 if (flash == 0xFFFF) flash = 23;
290 if (iline > 30) iline = 0; // 30 pixels high, going past by 1
293 if (dcurcol == 186) dcurdir = -1;
294 if (dcurcol == 179) dcurdir = 1;
299 // Set the refresh rate (30/60 Hz)
301 void SetRefreshRate(bool refresh)
303 game_refresh = refresh;
307 // Whether or not GUI is showing
309 bool ShowGUI(void) { return show_gui; }
314 void ActivateGUI(void) { show_gui = true; }
319 void DeactivateGUI(void) { show_gui = false; }
322 // Draw the small icons...
324 void DrawSmallIcons(WORD icon_not_to_draw)
328 BYTE * sIcons[12] = { inoguis, icoinus, ipl1sts, ipl2sts, ii30hzs, ii60hzs,
329 idipsws, ichecks, ikeycns, isnapss, iresets, ibyebys };
330 BYTE xlens[12] = { 31, 18, 32, 35, 37, 37, 29, 23, 28, 32, 19, 19 };
331 BYTE ylens[12] = { 31, 18, 19, 19, 21, 21, 23, 20, 16, 17, 20, 23 };
332 BYTE xpos[11] = { 33, 48, 63, 78, 104, 0, 184, 210, 225, 240, 255 };
333 BYTE iconidx[11] = { 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 6 };
335 if (game_refresh) iconidx[9] = 5; // 60 Hz...
337 // Draw small icons 1 to 5 on left, then 11 to 7 on right.
339 for(int i=0; i<5; i++)
341 WORD idx = i + icon_not_to_draw; // Get correct start pos.
342 if (idx > 10) idx -= 11;
344 iconmem = sIcons[iconidx[idx]];
345 xl = xlens[iconidx[idx]]; yl = ylens[iconidx[idx]];
347 DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
348 scadr += 320*((224-yl)/2); // Center vertically
349 scadr += xpos[i] - (xl/2); // Center around horiz. pos.
352 for(int yy=0; yy<yl; yy++)
354 for(int xx=0; xx<xl; xx++)
356 BYTE b = iconmem[bmpptr++];
357 if (b) my_scr[scadr+xx+yy*320] = b;
361 for(int i=10; i>5; i--)
363 WORD idx = i + icon_not_to_draw; // Get correct start pos.
364 if (idx > 10) idx -= 11;
366 iconmem = sIcons[iconidx[idx]];
367 xl = xlens[iconidx[idx]]; yl = ylens[iconidx[idx]];
369 DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
370 scadr += 320*((224-yl)/2); // Center vertically
371 scadr += xpos[i] - (xl/2); // Center around horiz. pos.
374 for(int yy=0; yy<yl; yy++)
376 for(int xx=0; xx<xl; xx++)
378 BYTE b = iconmem[bmpptr++];
379 if (b) my_scr[scadr+xx+yy*320] = b;
386 // Draw the large (selected) icon
388 void DrawLargeIcon(WORD icon)
392 BYTE * lIcons[11] = { inoguib, icoinub, ipl1stb, ipl2stb, ii30hzb, ii60hzb,
393 idipswb, ikeycnb, isnapsb, iresetb, ibyebyb };
394 BYTE xlens[11] = { 44, 45, 50, 52, 59, 59, 42, 45, 48, 58, 42 };
395 BYTE ylens[11] = { 44, 40, 33, 29, 52, 52, 34, 45, 37, 40, 50 };
397 BYTE gsubs1[24] = { 21, 21, 20, 19, 168, 168, 31, 155, 68, 68, 67, 66,
398 36, 36, 35, 34, 188, 188, 183, 181, 81, 81, 85, 80 },
399 gsubs2[24] = { 20, 20, 19, 19, 31, 31, 155, 155, 67, 67, 66, 66,
400 35, 35, 34, 34, 183, 183, 181, 181, 85, 85, 80, 80 },
401 gsubs3[24] = { 35, 34, 188, 188, 183, 181, 81, 81, 85, 80, 21, 21,
402 20, 19, 168, 168, 31, 155, 68, 68, 67, 66, 36, 36 },
403 gsubs4[24] = { 34, 34, 183, 183, 181, 181, 85, 85, 80, 80, 20, 20,
404 19, 19, 31, 31, 155, 155, 67, 67, 66, 66, 35, 35 },
405 gsubs5[24] = { 20, 20, 183, 183, 31, 31, 85, 85, 67, 67, 20, 20,
406 35, 35, 31, 31, 183, 183, 67, 67, 85, 85, 35, 35 };
408 iconmem = lIcons[icon];
409 xl = xlens[icon]; yl = ylens[icon];
415 if ((icon == REFRESH) && game_refresh)
418 xl = xlens[5]; yl = ylens[5];
420 if (icon == DIPSWITCH)
423 xl = xlens[6]; yl = ylens[6];
426 DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
427 scadr += 320*((224-yl)/2); // Center vertically
428 scadr += (288-xl)/2; // Center horizontally
431 for(int yy=0; yy<yl; yy++)
433 for(int xx=0; xx<xl; xx++)
435 BYTE b = iconmem[bmpptr++];
438 if ((icon == PL1START) && (b == 235) && (num_coins) && !blink_on)
439 b = 125; // Light ON color
440 /*noguib: 44x44 [Green (hi/lo): 36/235 Orange: 168/31 Neutral:12]
441 Rainbow (ROYGBP, hi/med/lo): 21,20,19; 168, 31,155; 68,67,66;
442 36,35,34; 188,183,181; 81,85,80 */
445 BYTE fln = (23 - flash) + 1; // Want to go forward (maybe fix it?)
448 case 36: { b = gsubs1[fln]; break; }
449 case 235: { b = gsubs2[fln]; break; }
450 case 168: { b = gsubs3[fln]; break; }
451 case 31: { b = gsubs4[fln]; break; }
452 case 12: { b = gsubs5[fln]; break; }
455 if ((icon == REFRESH) && (iline == yy) && (b == 50)) b = 188;
456 my_scr[scadr+xx+yy*320] = b;
460 if (!blink) // Should go here???
462 blink_on = !blink_on; // Switch blink state
463 if (blink_on) blink = 12;
466 //if (flash == 1) flash = 23; // Reset flash value
470 // Draw the dipswitch portion of the GUI
472 void DrawDipswitch(void)
474 BYTE dseloff[16] = { 0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11, 12 };
475 BYTE * dtxt[13] = { idstext1, idstext2, idstext3, idstext4, idstext5,
476 idstext2, idstext6, idstext7, idstext8, idstext9,
477 idstext10, idstext11, idstext12 };
479 BYTE dtx[13] = { 48, 80, 96, 82, 60, 80, 76, 57, 33, 50, 62, 65, 63 },
480 dty[13] = { 7, 9, 7, 9, 7, 9, 7, 7, 7, 9, 7, 9, 7 };
481 DWORD dtxtoff[13] = { 4*320+24, 14*320-78, 25*320+24, 32*320-80,
482 39*320+24, 49*320-78,
483 4*320+24, 11*320-55, 18*320+24, 25*320-48,
484 32*320+24, 42*320-63, 53*320+24 };
488 DWORD dbase = hScrollOffset + voffsets[vScrollOffset];
489 dbase += (288-26)/2; // Center horizontally
490 dbase += 320*((224-((65*2)+8))/2); // Center vertically
492 scadr = dbase; // Reset screen address
494 for(int yy=0; yy<65; yy++)
496 for(int xx=0; xx<26; xx++)
498 BYTE b = idswitch[bmpptr++];
499 if (b) my_scr[scadr+xx+yy*320] = b;
502 scadr = dbase + (320*73); // Reset screen address
504 for(int yy=0; yy<65; yy++)
506 for(int xx=0; xx<26; xx++)
508 BYTE b = idswitch[bmpptr++];
509 if (b) my_scr[scadr+xx+yy*320] = b;
512 for(int i=0; i<16; i++)
514 scadr = dbase + (5*320+5) + i*7*320;
515 if (i>7) scadr += 17*320; // Adjust for DSW #2
517 if (gram1[0x423D+(i<<1)]) scadr += 12; // Adjust position if ON
518 for(int yy=0; yy<5; yy++)
520 for(int xx=0; xx<5; xx++)
522 my_scr[scadr++] = idsbutton[bmpptr++];
524 scadr += 315; // Adjust position...
527 BYTE dselected_text = dseloff[dswitch];
528 for(int i=0; i<13; i++)
530 if (dselected_text != i)
532 scadr = dbase + dtxtoff[i];
533 if (i>5) scadr += (73*320);
535 for(int yy=0; yy<dty[i]; yy++)
537 for(int xx=0; xx<dtx[i]; xx++)
539 BYTE b = dtxt[i][bmpptr++];
540 if (b) my_scr[scadr] = b;
543 scadr += (320-dtx[i]); // Adjust position...
547 scadr = dbase + dtxtoff[dselected_text];
548 if (dselected_text>5) scadr += (73*320);
550 for(int yy=0; yy<dty[dselected_text]; yy++)
552 for(int xx=0; xx<dtx[dselected_text]; xx++)
554 BYTE b = dtxt[dselected_text][bmpptr++];
555 if (b) my_scr[scadr] = 125;
558 scadr += (320-dtx[dselected_text]); // Adjust position...
560 if (dswitch != 16) // Draw cursor
562 scadr = dbase + (4*320+4) + dswitch*7*320;
563 if (dswitch>7) scadr += 17*320; // Adjust for DSW #2
564 for(int xx=0; xx<19; xx++) my_scr[scadr++] = dcurcol;
566 for(int xx=0; xx<5; xx++)
568 my_scr[scadr] = dcurcol; scadr += 18;
569 my_scr[scadr] = dcurcol; scadr += 302;
571 for(int xx=0; xx<19; xx++) my_scr[scadr++] = dcurcol;
576 // The actual GUI display routine
580 if (!user_selected_something) // i.e. we're not inside a selection...
582 DrawSmallIcons(selection); // 'selection' is icon *not* to draw
583 DrawLargeIcon(selection);
587 if (selection == DIPSWITCH) DrawDipswitch();
592 // User pressed left arrow handler
594 void SelectLeft(void)
599 if (!user_selected_something)
602 if (selection > 10) selection = 0;
606 if (gram1[0x423D+(dswitch<<1)]) // It's switchable...
607 {} //SpawnSound(USERSOUND, SCLICK);
609 {} //SpawnSound(USERSOUND, SUNGH);
610 gram1[0x423D+(dswitch<<1)] = 0; // & turn it off
616 // User pressed right arrow handler
618 void SelectRight(void)
623 if (!user_selected_something)
626 if (selection > 10) selection = 10; // Unsigned compare
630 if (!gram1[0x423D+(dswitch<<1)]) // It's switchable...
631 {} //SpawnSound(USERSOUND, SCLICK);
633 {} //SpawnSound(USERSOUND, SUNGH);
634 gram1[0x423D+(dswitch<<1)] = 1; // & turn it on
640 // User pressed Up arrow handler
647 if (user_selected_something)
649 if (selection == DIPSWITCH)
652 if (dswitch > 16) dswitch = 16; // Wrap non-int
653 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
660 // User pressed down arrow handler
662 void SelectDown(void)
667 if (user_selected_something)
669 if (selection == DIPSWITCH)
672 if (dswitch > 16) dswitch = 0;
673 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
680 // User selected something! Handle it!
682 BYTE UserSelectedSomething(void)
684 //extern BYTE * gram1;
689 if (!user_selected_something) // Inside a selection? no...
691 if (selection == NOGUI) // Turn off GUI
695 if (selection == COINUP) // Coin up machine
697 gram1[0x41A5]++; // Add one coin... (prob. need sep. counter)
699 gram1[0x4189] = num_coins/10; // Should be in THUNDER.CPP?
700 gram1[0x418A] = num_coins - (gram1[0x4189]*10);
702 if (selection == PL1START) // 1 Player start
707 show_gui = false; // Shut off GUI only if coined up
709 gram1[0x418C] = 1; // Strobe start location
711 if (selection == PL2START) // 2 Player start
719 if (selection == REFRESH) // Toggle refresh rate
721 //SpawnSound(USERSOUND, SCLICK);
723 if (selection == DIPSWITCH) // Edit game settings
725 //SpawnSound(USERSOUND, SBLAH);
726 user_selected_something = true;
727 dswitch = 0; // Set at first dipswitch
729 if (selection == OPTIONS) // Edit emulator settings
732 if (selection == KEYCONFIG) // Edit game keys
735 if (selection == SNAPSHOT) // Snapshot
737 SpawnSound(USERSOUND, SCAMERA);
740 if (selection == RESET) // Reset machine
742 //SpawnSound(USERSOUND, SRESET);
744 if (selection == EXIT)
746 SpawnSound(USERSOUND, SCYA);
750 else // Selected something inside selection...
752 if (selection == DIPSWITCH)
754 if (dswitch == 16) // Selected 'back to GUI'
756 //SpawnSound(USERSOUND, SBLAH2);
757 user_selected_something = false;
761 //SpawnSound(USERSOUND, SCLICK);
762 gram1[0x423D + (dswitch<<1)] = !gram1[0x423D + (dswitch<<1)];
765 return 0xFF; // Nothing for main to do...
768 else return 0xFF; // Wasn't debounced, so return invalid
772 // Show byte passed to it
774 void ShowNumbers(int number)
776 BYTE * bnarray[16] = { bn0, bn1, bn2, bn3, bn4, bn5, bn6, bn7, bn8, bn9,
777 bnA, bnB, bnC, bnD, bnE, bnF };
778 DWORD scadr = hScrollOffset + voffsets[vScrollOffset] + 642 + 2560;
781 BYTE first_dig = number>>4, second_dig = number&0x0F;
782 for(int y=0; y<7; y++)
784 for(int x=0; x<6; x++)
786 if (bnarray[first_dig][bmpptr++] == 1) my_scr[scadr+x+y*320] = 7;
787 else my_scr[scadr+x+y*320] = 0;
790 bmpptr = 0; scadr += 6;
791 for(int y=0; y<7; y++)
793 for(int x=0; x<6; x++)
795 if (bnarray[second_dig][bmpptr++] == 1) my_scr[scadr+x+y*320] = 7;
796 else my_scr[scadr+x+y*320] = 0;
804 void SpawnMsg(BYTE msg)
806 text_life = 60; // 1 second...
807 show_text = true; // Show the damn thing...
808 show_which_msg = msg; // And tell it which message to show...
816 if (!text_life) // Kill text if it's time
822 text_life--; // Your life force is running out...
824 // Draw the message here...
825 DWORD scadr = hScrollOffset + voffsets[vScrollOffset] + 642;
828 for(int y=0; y<7; y++)
830 for(int x=0; x<21; x++)
832 if (show_which_msg == M60FPS)
834 if (bmp1[bmpptr++] == 1)
835 my_scr[scadr + x + y * 320] = 7;
837 my_scr[scadr + x + y * 320] = 0;
839 else if (show_which_msg == M30FPS)
841 if (bmp2[bmpptr++] == 1)
842 my_scr[scadr + x + y * 320] = 7;
844 my_scr[scadr + x + y * 320] = 0;
846 else if (show_which_msg == MSNAPSHOT)
848 if (bmp3[bmpptr++] == 1)
849 my_scr[scadr + x + y * 320] = 7;
851 my_scr[scadr + x + y * 320] = 0;
856 if (show_which_msg == MSHOWNUMS)
857 ShowNumbers(snd_num);
861 // Sound stuff (Will go elsewhere??? Perhaps in sound.cpp?)
863 void SpawnSound(int type, int snd, int channel/* = 0*/)
865 extern DWORD psg_lens[16];
866 extern BYTE * psg_adrs[16];
867 extern DWORD voc_lens[32];
868 extern BYTE * voc_adrs[32];
869 extern DWORD fm_lens[14];
870 extern BYTE * fm_adrs[14];
875 if (type == GAMESOUND)
877 snd--; // Will that do it??? Yes!!!
881 // 00 nn ss (nn # of repeats of sample ss)
890 spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
891 spos1 += st; // Need to add start somewhere...
906 spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
907 spos2 += st; // Need to add start somewhere...
913 else if (type == PSGSOUND)
915 if (snd_num & 0x10) // Second channel?
918 end_pos3 = psg_lens[snd_num & 0x0F];
919 sndp3 = psg_adrs[snd_num & 0x0F];
922 if (spos3 == end_pos3)
923 chan3_go = false; // No sound loaded, so don't do it!
925 else // First channel
928 end_pos4 = psg_lens[snd_num & 0x0F];
929 sndp4 = psg_adrs[snd_num & 0x0F];
932 if (spos4 == end_pos4)
933 chan4_go = false; // No sound loaded, so don't do it!
936 else if (type == FMSOUND)
939 end_pos5 = fm_lens[snd_num];
940 sndp5 = fm_adrs[snd_num];
943 if (spos5 == end_pos5)
944 chan5_go = false; // No sound loaded, so don't do it!
946 else if (type == USERSOUND)
949 end_pos6 = snd_lens[snd_num]; // User sound
950 sndp6 = snd_array[snd_num]; // Load pointer
956 // Sound card IRQ handler
958 void SoundFunc(void * userdata, Uint8 * buff, int num)
960 uint16 cnt = 0, sample; // 0-22 different sounds...
961 uint8 start_samp1, end_samp1, start_samp2, end_samp2;
962 uint8 samp1 = 128, samp2 = 128, samp3 = 128,
963 samp4 = 128, samp5 = 128, samp6 = 128; // Zero samples...
965 memset(buff, 128, num); // Kill sound...
967 if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go)
975 samp1 = voice_rom[spos1++];
980 samp1 = 128; // Kill channel 1 if done...
982 else if (samp1 == 0x00) // RLE compression...
984 sample1 += (float)voice_rom[spos1++] * sampleBase; // # of repeats
985 samp1 = prevSamp1; // Get last good sample
988 sample1 += sampleBase; // Keep fractional part intact
991 prevSamp1 = samp1; // Save last sample value
992 sample1 -= 1.0; // Decrement repeat counter
995 // Stretching 5KHz samples to 22KHz:
997 // 6KHz -> 22KHz: 22/6 repeats...
1002 samp2 = voice_rom[spos2++];
1007 samp2 = 128; // Kill channel 2 if done...
1009 else if (samp2 == 0x00) // RLE compression...
1011 sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats
1015 sample2 += sampleBase;
1018 // Delta-X values were making the samples sound like crap...
1019 // start_samp2 += delta_x2;
1026 samp3 = sndp3[spos3++];
1027 if (spos3 == end_pos3)
1029 chan3_go = false; samp3 = 128; // Kill channel 3 if done...
1035 samp4 = sndp4[spos4++];
1036 if (spos4 == end_pos4)
1038 chan4_go = false; samp4 = 128; // Kill channel 4 if done...
1044 samp5 = sndp5[spos5++];
1045 if (spos5 == end_pos5)
1047 chan5_go = false; samp5 = 128; // Kill channel 5 if done...
1053 samp6 = sndp6[spos6++];
1055 if (spos6 == end_pos6)
1056 chan6_go = false, samp6 = 128; // Kill channel 6...
1059 sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640; // Mix 'em...
1061 if (sample & 0xFF00) // i.e., it overflowed
1062 sample = (sample&0x8000 ? 0x00 : 0xFF); // Clip it
1064 buff[cnt++] = sample; // & store it...