2 // Thunder Graphic User Interface
3 // v1.0 (Last build: 8/1/1998)
6 // (C) 1998 Underground Software
10 #include <fstream> // Needed for tracelog
11 #include "SDL.h" // Needed for screen.h
14 #include "resource.h" // Thunder graphics & sounds
16 using namespace std; // Yes!
20 extern SDL_Surface * screen;
22 extern BYTE my_scr[0x14000]; // Screen buffer...
23 extern BYTE * gram1; // Game RAM (do here??)
24 extern BYTE hScrollOffset; // Horizontal scroll offset
25 extern BYTE vScrollOffset; // Vertical scroll offset
26 extern DWORD voffsets[8];
27 extern BYTE * voice_rom; // PCM data pointer
28 extern fstream tr; // Tracelog
32 WORD text_life; // How long text is visible
33 bool show_text; // Whether or not to show text
34 WORD show_which_msg; // Which message to show
35 bool show_gui; // Whether or not to show GUI
36 WORD selection; // Which GUI item currently selected
38 WORD gui_debounce; // GUI key debounce value
39 WORD num_coins; // Number of coins dropped
40 WORD blink = 0; // Used to blink player 1 & 2 start buttons
41 WORD flash = 23; // Used to flash GUI lights
42 WORD iline = 0; // Used to roll line
43 WORD dcurcol = 179; // dipswitch cursor color
44 int dcurdir = 1; // Initially going up...
45 bool blink_on = false;
46 bool game_refresh; // Refresh rate user set
47 bool do_decrement; // Flag to handle decrement...
48 bool user_selected_something; // Flag for well, you know...
49 WORD dswitch; // Which dipswitch is selected...
51 // The following are global for the sound routines...
53 const float sampleBase = 22050.0/6000.0; // Btwn 5512.5 and 6000
55 bool chan1_go = false, chan2_go = false, chan3_go = false;
56 bool chan4_go = false, chan5_go = false, chan6_go = false;
57 BYTE * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6;
58 uint32 rom_pos, end_pos;
59 uint32 spos1, end_pos1;
60 uint32 spos2, end_pos2;
61 uint32 spos3, end_pos3;
62 uint32 spos4, end_pos4;
63 uint32 spos5, end_pos5;
64 uint32 spos6, end_pos6;
72 BYTE * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
73 DWORD snd_lens[3] = { sunknownlen, scyalen, scameralen };
78 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
79 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
80 0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
81 0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
82 0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
83 0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
84 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
87 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
88 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,
89 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,
90 0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
91 0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,
92 0,1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,
93 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
96 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
97 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98 0,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
99 0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,
100 0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,
101 0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,
102 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0
104 BYTE boptions[] = { // 35x9
105 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,
106 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,
107 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,
108 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,
109 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,
110 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,
111 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,
112 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,
113 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
267 user_selected_something = false;
271 // Handle key debounce
273 void HandleGUIDebounce(void)
275 if (gui_debounce) gui_debounce--; // Debounce GUI keys...
276 do_decrement = !do_decrement; // Called at 60Hz, so skip decrementing blink
279 if (blink) blink--; // Handle blinking stuff (Should prb go in DrawGUI)
281 flash-=2; // Handle flashing stuff (Should prb go in DrawGUI)
282 if (flash == 0xFFFF) flash = 23;
285 if (iline > 30) iline = 0; // 30 pixels high, going past by 1
288 if (dcurcol == 186) dcurdir = -1;
289 if (dcurcol == 179) dcurdir = 1;
294 // Set the refresh rate (30/60 Hz)
296 void SetRefreshRate(bool refresh)
298 game_refresh = refresh;
302 // Whether or not GUI is showing
304 bool ShowGUI(void) { return show_gui; }
309 void ActivateGUI(void) { show_gui = true; }
314 void DeactivateGUI(void) { show_gui = false; }
317 // Draw the small icons...
319 void DrawSmallIcons(WORD icon_not_to_draw)
323 BYTE * sIcons[12] = { inoguis, icoinus, ipl1sts, ipl2sts, ii30hzs, ii60hzs,
324 idipsws, ichecks, ikeycns, isnapss, iresets, ibyebys };
325 BYTE xlens[12] = { 31, 18, 32, 35, 37, 37, 29, 23, 28, 32, 19, 19 };
326 BYTE ylens[12] = { 31, 18, 19, 19, 21, 21, 23, 20, 16, 17, 20, 23 };
327 BYTE xpos[11] = { 33, 48, 63, 78, 104, 0, 184, 210, 225, 240, 255 };
328 BYTE iconidx[11] = { 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 6 };
330 if (game_refresh) iconidx[9] = 5; // 60 Hz...
332 // Draw small icons 1 to 5 on left, then 11 to 7 on right.
334 for(int i=0; i<5; i++)
336 WORD idx = i + icon_not_to_draw; // Get correct start pos.
337 if (idx > 10) idx -= 11;
339 iconmem = sIcons[iconidx[idx]];
340 xl = xlens[iconidx[idx]]; yl = ylens[iconidx[idx]];
342 DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
343 scadr += 320*((224-yl)/2); // Center vertically
344 scadr += xpos[i] - (xl/2); // Center around horiz. pos.
347 for(int yy=0; yy<yl; yy++)
349 for(int xx=0; xx<xl; xx++)
351 BYTE b = iconmem[bmpptr++];
352 if (b) my_scr[scadr+xx+yy*320] = b;
356 for(int i=10; i>5; i--)
358 WORD idx = i + icon_not_to_draw; // Get correct start pos.
359 if (idx > 10) idx -= 11;
361 iconmem = sIcons[iconidx[idx]];
362 xl = xlens[iconidx[idx]]; yl = ylens[iconidx[idx]];
364 DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
365 scadr += 320*((224-yl)/2); // Center vertically
366 scadr += xpos[i] - (xl/2); // Center around horiz. pos.
369 for(int yy=0; yy<yl; yy++)
371 for(int xx=0; xx<xl; xx++)
373 BYTE b = iconmem[bmpptr++];
374 if (b) my_scr[scadr+xx+yy*320] = b;
381 // Draw the large (selected) icon
383 void DrawLargeIcon(WORD icon)
387 BYTE * lIcons[11] = { inoguib, icoinub, ipl1stb, ipl2stb, ii30hzb, ii60hzb,
388 idipswb, ikeycnb, isnapsb, iresetb, ibyebyb };
389 BYTE xlens[11] = { 44, 45, 50, 52, 59, 59, 42, 45, 48, 58, 42 };
390 BYTE ylens[11] = { 44, 40, 33, 29, 52, 52, 34, 45, 37, 40, 50 };
392 BYTE gsubs1[24] = { 21, 21, 20, 19, 168, 168, 31, 155, 68, 68, 67, 66,
393 36, 36, 35, 34, 188, 188, 183, 181, 81, 81, 85, 80 },
394 gsubs2[24] = { 20, 20, 19, 19, 31, 31, 155, 155, 67, 67, 66, 66,
395 35, 35, 34, 34, 183, 183, 181, 181, 85, 85, 80, 80 },
396 gsubs3[24] = { 35, 34, 188, 188, 183, 181, 81, 81, 85, 80, 21, 21,
397 20, 19, 168, 168, 31, 155, 68, 68, 67, 66, 36, 36 },
398 gsubs4[24] = { 34, 34, 183, 183, 181, 181, 85, 85, 80, 80, 20, 20,
399 19, 19, 31, 31, 155, 155, 67, 67, 66, 66, 35, 35 },
400 gsubs5[24] = { 20, 20, 183, 183, 31, 31, 85, 85, 67, 67, 20, 20,
401 35, 35, 31, 31, 183, 183, 67, 67, 85, 85, 35, 35 };
403 iconmem = lIcons[icon];
404 xl = xlens[icon]; yl = ylens[icon];
410 if ((icon == REFRESH) && game_refresh)
413 xl = xlens[5]; yl = ylens[5];
415 if (icon == DIPSWITCH)
418 xl = xlens[6]; yl = ylens[6];
421 DWORD scadr = hScrollOffset + voffsets[vScrollOffset];
422 scadr += 320*((224-yl)/2); // Center vertically
423 scadr += (288-xl)/2; // Center horizontally
426 for(int yy=0; yy<yl; yy++)
428 for(int xx=0; xx<xl; xx++)
430 BYTE b = iconmem[bmpptr++];
433 if ((icon == PL1START) && (b == 235) && (num_coins) && !blink_on)
434 b = 125; // Light ON color
435 /*noguib: 44x44 [Green (hi/lo): 36/235 Orange: 168/31 Neutral:12]
436 Rainbow (ROYGBP, hi/med/lo): 21,20,19; 168, 31,155; 68,67,66;
437 36,35,34; 188,183,181; 81,85,80 */
440 BYTE fln = (23 - flash) + 1; // Want to go forward (maybe fix it?)
443 case 36: { b = gsubs1[fln]; break; }
444 case 235: { b = gsubs2[fln]; break; }
445 case 168: { b = gsubs3[fln]; break; }
446 case 31: { b = gsubs4[fln]; break; }
447 case 12: { b = gsubs5[fln]; break; }
450 if ((icon == REFRESH) && (iline == yy) && (b == 50)) b = 188;
451 my_scr[scadr+xx+yy*320] = b;
455 if (!blink) // Should go here???
457 blink_on = !blink_on; // Switch blink state
458 if (blink_on) blink = 12;
461 //if (flash == 1) flash = 23; // Reset flash value
465 // Draw the dipswitch portion of the GUI
467 void DrawDipswitch(void)
469 BYTE dseloff[16] = { 0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11, 12 };
470 BYTE * dtxt[13] = { idstext1, idstext2, idstext3, idstext4, idstext5,
471 idstext2, idstext6, idstext7, idstext8, idstext9,
472 idstext10, idstext11, idstext12 };
474 BYTE dtx[13] = { 48, 80, 96, 82, 60, 80, 76, 57, 33, 50, 62, 65, 63 },
475 dty[13] = { 7, 9, 7, 9, 7, 9, 7, 7, 7, 9, 7, 9, 7 };
476 DWORD dtxtoff[13] = { 4*320+24, 14*320-78, 25*320+24, 32*320-80,
477 39*320+24, 49*320-78,
478 4*320+24, 11*320-55, 18*320+24, 25*320-48,
479 32*320+24, 42*320-63, 53*320+24 };
483 DWORD dbase = hScrollOffset + voffsets[vScrollOffset];
484 dbase += (288-26)/2; // Center horizontally
485 dbase += 320*((224-((65*2)+8))/2); // Center vertically
487 scadr = dbase; // Reset screen address
489 for(int yy=0; yy<65; yy++)
491 for(int xx=0; xx<26; xx++)
493 BYTE b = idswitch[bmpptr++];
494 if (b) my_scr[scadr+xx+yy*320] = b;
497 scadr = dbase + (320*73); // Reset screen address
499 for(int yy=0; yy<65; yy++)
501 for(int xx=0; xx<26; xx++)
503 BYTE b = idswitch[bmpptr++];
504 if (b) my_scr[scadr+xx+yy*320] = b;
507 for(int i=0; i<16; i++)
509 scadr = dbase + (5*320+5) + i*7*320;
510 if (i>7) scadr += 17*320; // Adjust for DSW #2
512 if (gram1[0x423D+(i<<1)]) scadr += 12; // Adjust position if ON
513 for(int yy=0; yy<5; yy++)
515 for(int xx=0; xx<5; xx++)
517 my_scr[scadr++] = idsbutton[bmpptr++];
519 scadr += 315; // Adjust position...
522 BYTE dselected_text = dseloff[dswitch];
523 for(int i=0; i<13; i++)
525 if (dselected_text != i)
527 scadr = dbase + dtxtoff[i];
528 if (i>5) scadr += (73*320);
530 for(int yy=0; yy<dty[i]; yy++)
532 for(int xx=0; xx<dtx[i]; xx++)
534 BYTE b = dtxt[i][bmpptr++];
535 if (b) my_scr[scadr] = b;
538 scadr += (320-dtx[i]); // Adjust position...
542 scadr = dbase + dtxtoff[dselected_text];
543 if (dselected_text>5) scadr += (73*320);
545 for(int yy=0; yy<dty[dselected_text]; yy++)
547 for(int xx=0; xx<dtx[dselected_text]; xx++)
549 BYTE b = dtxt[dselected_text][bmpptr++];
550 if (b) my_scr[scadr] = 125;
553 scadr += (320-dtx[dselected_text]); // Adjust position...
555 if (dswitch != 16) // Draw cursor
557 scadr = dbase + (4*320+4) + dswitch*7*320;
558 if (dswitch>7) scadr += 17*320; // Adjust for DSW #2
559 for(int xx=0; xx<19; xx++) my_scr[scadr++] = dcurcol;
561 for(int xx=0; xx<5; xx++)
563 my_scr[scadr] = dcurcol; scadr += 18;
564 my_scr[scadr] = dcurcol; scadr += 302;
566 for(int xx=0; xx<19; xx++) my_scr[scadr++] = dcurcol;
571 // The actual GUI display routine
575 if (!user_selected_something) // i.e. we're not inside a selection...
577 DrawSmallIcons(selection); // 'selection' is icon *not* to draw
578 DrawLargeIcon(selection);
582 if (selection == DIPSWITCH) DrawDipswitch();
587 // User pressed left arrow handler
589 void SelectLeft(void)
594 if (!user_selected_something)
597 if (selection > 10) selection = 0;
601 if (gram1[0x423D+(dswitch<<1)]) // It's switchable...
602 {} //SpawnSound(USERSOUND, SCLICK);
604 {} //SpawnSound(USERSOUND, SUNGH);
605 gram1[0x423D+(dswitch<<1)] = 0; // & turn it off
611 // User pressed right arrow handler
613 void SelectRight(void)
618 if (!user_selected_something)
621 if (selection > 10) selection = 10; // Unsigned compare
625 if (!gram1[0x423D+(dswitch<<1)]) // It's switchable...
626 {} //SpawnSound(USERSOUND, SCLICK);
628 {} //SpawnSound(USERSOUND, SUNGH);
629 gram1[0x423D+(dswitch<<1)] = 1; // & turn it on
635 // User pressed Up arrow handler
642 if (user_selected_something)
644 if (selection == DIPSWITCH)
647 if (dswitch > 16) dswitch = 16; // Wrap non-int
648 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
655 // User pressed down arrow handler
657 void SelectDown(void)
662 if (user_selected_something)
664 if (selection == DIPSWITCH)
667 if (dswitch > 16) dswitch = 0;
668 //snd_num = dswitch; SpawnMsg(MSHOWNUMS); // Temp...
675 // User selected something! Handle it!
677 BYTE UserSelectedSomething(void)
679 //extern BYTE * gram1;
684 if (!user_selected_something) // Inside a selection? no...
686 if (selection == NOGUI) // Turn off GUI
690 if (selection == COINUP) // Coin up machine
692 gram1[0x41A5]++; // Add one coin... (prob. need sep. counter)
694 gram1[0x4189] = num_coins/10; // Should be in THUNDER.CPP?
695 gram1[0x418A] = num_coins - (gram1[0x4189]*10);
697 if (selection == PL1START) // 1 Player start
702 show_gui = false; // Shut off GUI only if coined up
704 gram1[0x418C] = 1; // Strobe start location
706 if (selection == PL2START) // 2 Player start
714 if (selection == REFRESH) // Toggle refresh rate
716 //SpawnSound(USERSOUND, SCLICK);
718 if (selection == DIPSWITCH) // Edit game settings
720 //SpawnSound(USERSOUND, SBLAH);
721 user_selected_something = true;
722 dswitch = 0; // Set at first dipswitch
724 if (selection == OPTIONS) // Edit emulator settings
727 if (selection == KEYCONFIG) // Edit game keys
730 if (selection == SNAPSHOT) // Snapshot
732 SpawnSound(USERSOUND, SCAMERA);
735 if (selection == RESET) // Reset machine
737 //SpawnSound(USERSOUND, SRESET);
739 if (selection == EXIT)
741 SpawnSound(USERSOUND, SCYA);
745 else // Selected something inside selection...
747 if (selection == DIPSWITCH)
749 if (dswitch == 16) // Selected 'back to GUI'
751 //SpawnSound(USERSOUND, SBLAH2);
752 user_selected_something = false;
756 //SpawnSound(USERSOUND, SCLICK);
757 gram1[0x423D + (dswitch<<1)] = !gram1[0x423D + (dswitch<<1)];
760 return 0xFF; // Nothing for main to do...
763 else return 0xFF; // Wasn't debounced, so return invalid
767 // Show byte passed to it
769 void ShowNumbers(int number)
771 BYTE * bnarray[16] = { bn0, bn1, bn2, bn3, bn4, bn5, bn6, bn7, bn8, bn9,
772 bnA, bnB, bnC, bnD, bnE, bnF };
773 DWORD scadr = hScrollOffset + voffsets[vScrollOffset] + 642 + 2560;
776 BYTE first_dig = number>>4, second_dig = number&0x0F;
777 for(int y=0; y<7; y++)
779 for(int x=0; x<6; x++)
781 if (bnarray[first_dig][bmpptr++] == 1) my_scr[scadr+x+y*320] = 7;
782 else my_scr[scadr+x+y*320] = 0;
785 bmpptr = 0; scadr += 6;
786 for(int y=0; y<7; y++)
788 for(int x=0; x<6; x++)
790 if (bnarray[second_dig][bmpptr++] == 1) my_scr[scadr+x+y*320] = 7;
791 else my_scr[scadr+x+y*320] = 0;
799 void SpawnMsg(BYTE msg)
801 text_life = 60; // 1 second...
802 show_text = true; // Show the damn thing...
803 show_which_msg = msg; // And tell it which message to show...
811 if (!text_life) // Kill text if it's time
817 text_life--; // Your life force is running out...
819 // Draw the message here...
820 DWORD scadr = hScrollOffset + voffsets[vScrollOffset] + 642;
823 for(int y=0; y<7; y++)
825 for(int x=0; x<21; x++)
827 if (show_which_msg == M60FPS)
829 if (bmp1[bmpptr++] == 1)
830 my_scr[scadr + x + y * 320] = 7;
832 my_scr[scadr + x + y * 320] = 0;
834 else if (show_which_msg == M30FPS)
836 if (bmp2[bmpptr++] == 1)
837 my_scr[scadr + x + y * 320] = 7;
839 my_scr[scadr + x + y * 320] = 0;
841 else if (show_which_msg == MSNAPSHOT)
843 if (bmp3[bmpptr++] == 1)
844 my_scr[scadr + x + y * 320] = 7;
846 my_scr[scadr + x + y * 320] = 0;
851 if (show_which_msg == MSHOWNUMS)
852 ShowNumbers(snd_num);
856 // Sound stuff (Will go elsewhere??? Perhaps in sound.cpp?)
858 void SpawnSound(int type, int snd, int channel/* = 0*/)
860 extern DWORD psg_lens[16];
861 extern BYTE * psg_adrs[16];
862 extern DWORD voc_lens[32];
863 extern BYTE * voc_adrs[32];
864 extern DWORD fm_lens[14];
865 extern BYTE * fm_adrs[14];
870 if (type == GAMESOUND)
872 snd--; // Will that do it??? Yes!!!
876 // 00 nn ss (nn # of repeats of sample ss)
885 spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
886 spos1 += st; // Need to add start somewhere...
901 spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1];
902 spos2 += st; // Need to add start somewhere...
908 else if (type == PSGSOUND)
910 if (snd_num & 0x10) // Second channel?
913 end_pos3 = psg_lens[snd_num & 0x0F];
914 sndp3 = psg_adrs[snd_num & 0x0F];
917 if (spos3 == end_pos3)
918 chan3_go = false; // No sound loaded, so don't do it!
920 else // First channel
923 end_pos4 = psg_lens[snd_num & 0x0F];
924 sndp4 = psg_adrs[snd_num & 0x0F];
927 if (spos4 == end_pos4)
928 chan4_go = false; // No sound loaded, so don't do it!
931 else if (type == FMSOUND)
934 end_pos5 = fm_lens[snd_num];
935 sndp5 = fm_adrs[snd_num];
938 if (spos5 == end_pos5)
939 chan5_go = false; // No sound loaded, so don't do it!
941 else if (type == USERSOUND)
944 end_pos6 = snd_lens[snd_num]; // User sound
945 sndp6 = snd_array[snd_num]; // Load pointer
951 // Sound card IRQ handler
953 void SoundFunc(void * userdata, Uint8 * buff, int num)
955 uint16 cnt = 0, sample; // 0-22 different sounds...
956 uint8 start_samp1, end_samp1, start_samp2, end_samp2;
957 uint8 samp1 = 128, samp2 = 128, samp3 = 128,
958 samp4 = 128, samp5 = 128, samp6 = 128; // Zero samples...
960 memset(buff, 128, num); // Kill sound...
962 if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go)
970 samp1 = voice_rom[spos1++];
975 samp1 = 128; // Kill channel 1 if done...
977 else if (samp1 == 0x00) // RLE compression...
979 sample1 += (float)voice_rom[spos1++] * sampleBase; // # of repeats
980 samp1 = prevSamp1; // Get last good sample
983 sample1 += sampleBase; // Keep fractional part intact
986 prevSamp1 = samp1; // Save last sample value
987 sample1 -= 1.0; // Decrement repeat counter
990 // Stretching 5KHz samples to 22KHz:
992 // 6KHz -> 22KHz: 22/6 repeats...
997 samp2 = voice_rom[spos2++];
1002 samp2 = 128; // Kill channel 2 if done...
1004 else if (samp2 == 0x00) // RLE compression...
1006 sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats
1010 sample2 += sampleBase;
1013 // Delta-X values were making the samples sound like crap...
1014 // start_samp2 += delta_x2;
1021 samp3 = sndp3[spos3++];
1022 if (spos3 == end_pos3)
1024 chan3_go = false; samp3 = 128; // Kill channel 3 if done...
1030 samp4 = sndp4[spos4++];
1031 if (spos4 == end_pos4)
1033 chan4_go = false; samp4 = 128; // Kill channel 4 if done...
1039 samp5 = sndp5[spos5++];
1040 if (spos5 == end_pos5)
1042 chan5_go = false; samp5 = 128; // Kill channel 5 if done...
1048 samp6 = sndp6[spos6++];
1050 if (spos6 == end_pos6)
1051 chan6_go = false, samp6 = 128; // Kill channel 6...
1054 sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640; // Mix 'em...
1056 if (sample & 0xFF00) // i.e., it overflowed
1057 sample = (sample&0x8000 ? 0x00 : 0xFF); // Clip it
1059 buff[cnt++] = sample; // & store it...