ID_SD.C (48057B)
1 // 2 // ID Engine 3 // ID_SD.c - Sound Manager for Wolfenstein 3D 4 // v1.2 5 // By Jason Blochowiak 6 // 7 8 // 9 // This module handles dealing with generating sound on the appropriate 10 // hardware 11 // 12 // Depends on: User Mgr (for parm checking) 13 // 14 // Globals: 15 // For User Mgr: 16 // SoundSourcePresent - Sound Source thingie present? 17 // SoundBlasterPresent - SoundBlaster card present? 18 // AdLibPresent - AdLib card present? 19 // SoundMode - What device is used for sound effects 20 // (Use SM_SetSoundMode() to set) 21 // MusicMode - What device is used for music 22 // (Use SM_SetMusicMode() to set) 23 // DigiMode - What device is used for digitized sound effects 24 // (Use SM_SetDigiDevice() to set) 25 // 26 // For Cache Mgr: 27 // NeedsDigitized - load digitized sounds? 28 // NeedsMusic - load music? 29 // 30 31 #pragma hdrstop // Wierdo thing with MUSE 32 33 #include <dos.h> 34 35 #ifdef _MUSE_ // Will be defined in ID_Types.h 36 #include "ID_SD.h" 37 #else 38 #include "ID_HEADS.H" 39 #endif 40 #pragma hdrstop 41 #pragma warn -pia 42 43 #ifdef nil 44 #undef nil 45 #endif 46 #define nil 0 47 48 #define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;} 49 50 // Macros for SoundBlaster stuff 51 #define sbOut(n,b) outportb((n) + sbLocation,b) 52 #define sbIn(n) inportb((n) + sbLocation) 53 #define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80); 54 #define sbReadDelay() while (sbIn(sbDataAvail) & 0x80); 55 56 // Macros for AdLib stuff 57 #define selreg(n) outportb(alFMAddr,n) 58 #define writereg(n) outportb(alFMData,n) 59 #define readstat() inportb(alFMStatus) 60 61 // Imports from ID_SD_A.ASM 62 extern void SDL_SetDS(void), 63 SDL_IndicatePC(boolean on); 64 extern void interrupt SDL_t0ExtremeAsmService(void), 65 SDL_t0FastAsmService(void), 66 SDL_t0SlowAsmService(void); 67 68 // Global variables 69 boolean SoundSourcePresent, 70 AdLibPresent, 71 SoundBlasterPresent,SBProPresent, 72 NeedsDigitized,NeedsMusic, 73 SoundPositioned; 74 SDMode SoundMode; 75 SMMode MusicMode; 76 SDSMode DigiMode; 77 longword TimeCount; 78 word HackCount; 79 word *SoundTable; // Really * _seg *SoundTable, but that don't work 80 boolean ssIsTandy; 81 word ssPort = 2; 82 int DigiMap[LASTSOUND]; 83 84 // Internal variables 85 static boolean SD_Started; 86 boolean nextsoundpos; 87 longword TimerDivisor,TimerCount; 88 static char *ParmStrings[] = 89 { 90 "noal", 91 "nosb", 92 "nopro", 93 "noss", 94 "sst", 95 "ss1", 96 "ss2", 97 "ss3", 98 nil 99 }; 100 static void (*SoundUserHook)(void); 101 soundnames SoundNumber,DigiNumber; 102 word SoundPriority,DigiPriority; 103 int LeftPosition,RightPosition; 104 void interrupt (*t0OldService)(void); 105 long LocalTime; 106 word TimerRate; 107 108 word NumDigi,DigiLeft,DigiPage; 109 word _seg *DigiList; 110 word DigiLastStart,DigiLastEnd; 111 boolean DigiPlaying; 112 static boolean DigiMissed,DigiLastSegment; 113 static memptr DigiNextAddr; 114 static word DigiNextLen; 115 116 // SoundBlaster variables 117 static boolean sbNoCheck,sbNoProCheck; 118 static volatile boolean sbSamplePlaying; 119 static byte sbOldIntMask = -1; 120 static volatile byte huge *sbNextSegPtr; 121 static byte sbDMA = 1, 122 sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3, 123 sba1Vals[] = {0x87,0x83,0,0x82}, 124 sba2Vals[] = {0,2,0,6}, 125 sba3Vals[] = {1,3,0,7}; 126 static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf, 127 sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1}; 128 static volatile longword sbNextSegLen; 129 static volatile SampledSound huge *sbSamples; 130 static void interrupt (*sbOldIntHand)(void); 131 static byte sbpOldFMMix,sbpOldVOCMix; 132 133 // SoundSource variables 134 boolean ssNoCheck; 135 boolean ssActive; 136 word ssControl,ssStatus,ssData; 137 byte ssOn,ssOff; 138 volatile byte far *ssSample; 139 volatile longword ssLengthLeft; 140 141 // PC Sound variables 142 volatile byte pcLastSample,far *pcSound; 143 longword pcLengthLeft; 144 word pcSoundLookup[255]; 145 146 // AdLib variables 147 boolean alNoCheck; 148 byte far *alSound; 149 word alBlock; 150 longword alLengthLeft; 151 longword alTimeCount; 152 Instrument alZeroInst; 153 154 // This table maps channel numbers to carrier and modulator op cells 155 static byte carriers[9] = { 3, 4, 5,11,12,13,19,20,21}, 156 modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18}, 157 // This table maps percussive voice numbers to op cells 158 pcarriers[5] = {19,0xff,0xff,0xff,0xff}, 159 pmodifiers[5] = {16,17,18,20,21}; 160 161 // Sequencer variables 162 boolean sqActive; 163 static word alFXReg; 164 static ActiveTrack *tracks[sqMaxTracks], 165 mytracks[sqMaxTracks]; 166 static word sqMode,sqFadeStep; 167 word far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen; 168 long sqHackTime; 169 170 // Internal routines 171 void SDL_DigitizedDone(void); 172 173 /////////////////////////////////////////////////////////////////////////// 174 // 175 // SDL_SetTimer0() - Sets system timer 0 to the specified speed 176 // 177 /////////////////////////////////////////////////////////////////////////// 178 #pragma argsused 179 static void 180 SDL_SetTimer0(word speed) 181 { 182 #ifndef TPROF // If using Borland's profiling, don't screw with the timer 183 asm pushf 184 asm cli 185 186 outportb(0x43,0x36); // Change timer 0 187 outportb(0x40,speed); 188 outportb(0x40,speed >> 8); 189 // Kludge to handle special case for digitized PC sounds 190 if (TimerDivisor == (1192030 / (TickBase * 100))) 191 TimerDivisor = (1192030 / (TickBase * 10)); 192 else 193 TimerDivisor = speed; 194 195 asm popf 196 #else 197 TimerDivisor = 0x10000; 198 #endif 199 } 200 201 /////////////////////////////////////////////////////////////////////////// 202 // 203 // SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of 204 // interrupts generated by system timer 0 per second 205 // 206 /////////////////////////////////////////////////////////////////////////// 207 static void 208 SDL_SetIntsPerSec(word ints) 209 { 210 TimerRate = ints; 211 SDL_SetTimer0(1192030 / ints); 212 } 213 214 static void 215 SDL_SetTimerSpeed(void) 216 { 217 word rate; 218 void interrupt (*isr)(void); 219 220 if ((DigiMode == sds_PC) && DigiPlaying) 221 { 222 rate = TickBase * 100; 223 isr = SDL_t0ExtremeAsmService; 224 } 225 else if 226 ( 227 (MusicMode == smm_AdLib) 228 || ((DigiMode == sds_SoundSource) && DigiPlaying) 229 ) 230 { 231 rate = TickBase * 10; 232 isr = SDL_t0FastAsmService; 233 } 234 else 235 { 236 rate = TickBase * 2; 237 isr = SDL_t0SlowAsmService; 238 } 239 240 if (rate != TimerRate) 241 { 242 setvect(8,isr); 243 SDL_SetIntsPerSec(rate); 244 TimerRate = rate; 245 } 246 } 247 248 // 249 // SoundBlaster code 250 // 251 252 /////////////////////////////////////////////////////////////////////////// 253 // 254 // SDL_SBStopSample() - Stops any active sampled sound and causes DMA 255 // requests from the SoundBlaster to cease 256 // 257 /////////////////////////////////////////////////////////////////////////// 258 #ifdef _MUSE_ 259 void 260 #else 261 static void 262 #endif 263 SDL_SBStopSample(void) 264 { 265 byte is; 266 267 asm pushf 268 asm cli 269 270 if (sbSamplePlaying) 271 { 272 sbSamplePlaying = false; 273 274 sbWriteDelay(); 275 sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA 276 277 is = inportb(0x21); // Restore interrupt mask bit 278 if (sbOldIntMask & (1 << sbInterrupt)) 279 is |= (1 << sbInterrupt); 280 else 281 is &= ~(1 << sbInterrupt); 282 outportb(0x21,is); 283 } 284 285 asm popf 286 } 287 288 /////////////////////////////////////////////////////////////////////////// 289 // 290 // SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster 291 // Insures that the chunk doesn't cross a bank boundary, programs the DMA 292 // controller, and tells the SB to start doing DMA requests for DAC 293 // 294 /////////////////////////////////////////////////////////////////////////// 295 static longword 296 SDL_SBPlaySeg(volatile byte huge *data,longword length) 297 { 298 unsigned datapage; 299 longword dataofs,uselen; 300 301 uselen = length; 302 datapage = FP_SEG(data) >> 12; 303 dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data); 304 if (dataofs >= 0x10000) 305 { 306 datapage++; 307 dataofs -= 0x10000; 308 } 309 310 if (dataofs + uselen > 0x10000) 311 uselen = 0x10000 - dataofs; 312 313 uselen--; 314 315 // Program the DMA controller 316 asm pushf 317 asm cli 318 outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA 319 outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte 320 outportb(0x0b,0x49); // Set transfer mode for D/A conv 321 outportb(sbDMAa2,(byte)dataofs); // Give LSB of address 322 outportb(sbDMAa2,(byte)(dataofs >> 8)); // Give MSB of address 323 outportb(sbDMAa1,(byte)datapage); // Give page of address 324 outportb(sbDMAa3,(byte)uselen); // Give LSB of length 325 outportb(sbDMAa3,(byte)(uselen >> 8)); // Give MSB of length 326 outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA 327 328 // Start playing the thing 329 sbWriteDelay(); 330 sbOut(sbWriteCmd,0x14); 331 sbWriteDelay(); 332 sbOut(sbWriteData,(byte)uselen); 333 sbWriteDelay(); 334 sbOut(sbWriteData,(byte)(uselen >> 8)); 335 asm popf 336 337 return(uselen + 1); 338 } 339 340 /////////////////////////////////////////////////////////////////////////// 341 // 342 // SDL_SBService() - Services the SoundBlaster DMA interrupt 343 // 344 /////////////////////////////////////////////////////////////////////////// 345 static void interrupt 346 SDL_SBService(void) 347 { 348 longword used; 349 350 sbIn(sbDataAvail); // Ack interrupt to SB 351 352 if (sbNextSegPtr) 353 { 354 used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen); 355 if (sbNextSegLen <= used) 356 sbNextSegPtr = nil; 357 else 358 { 359 sbNextSegPtr += used; 360 sbNextSegLen -= used; 361 } 362 } 363 else 364 { 365 SDL_SBStopSample(); 366 SDL_DigitizedDone(); 367 } 368 369 outportb(0x20,0x20); // Ack interrupt 370 } 371 372 /////////////////////////////////////////////////////////////////////////// 373 // 374 // SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up 375 // DMA to play the sound 376 // 377 /////////////////////////////////////////////////////////////////////////// 378 #ifdef _MUSE_ 379 void 380 #else 381 static void 382 #endif 383 SDL_SBPlaySample(byte huge *data,longword len) 384 { 385 longword used; 386 387 SDL_SBStopSample(); 388 389 asm pushf 390 asm cli 391 392 used = SDL_SBPlaySeg(data,len); 393 if (len <= used) 394 sbNextSegPtr = nil; 395 else 396 { 397 sbNextSegPtr = data + used; 398 sbNextSegLen = len - used; 399 } 400 401 // Save old interrupt status and unmask ours 402 sbOldIntMask = inportb(0x21); 403 outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt)); 404 405 sbWriteDelay(); 406 sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled 407 408 sbSamplePlaying = true; 409 410 asm popf 411 } 412 413 /////////////////////////////////////////////////////////////////////////// 414 // 415 // SDL_PositionSBP() - Sets the attenuation levels for the left and right 416 // channels by using the mixer chip on the SB Pro. This hits a hole in 417 // the address map for normal SBs. 418 // 419 /////////////////////////////////////////////////////////////////////////// 420 static void 421 SDL_PositionSBP(int leftpos,int rightpos) 422 { 423 byte v; 424 425 if (!SBProPresent) 426 return; 427 428 leftpos = 15 - leftpos; 429 rightpos = 15 - rightpos; 430 v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f); 431 432 asm pushf 433 asm cli 434 435 sbOut(sbpMixerAddr,sbpmVoiceVol); 436 sbOut(sbpMixerData,v); 437 438 asm popf 439 } 440 441 /////////////////////////////////////////////////////////////////////////// 442 // 443 // SDL_CheckSB() - Checks to see if a SoundBlaster resides at a 444 // particular I/O location 445 // 446 /////////////////////////////////////////////////////////////////////////// 447 static boolean 448 SDL_CheckSB(int port) 449 { 450 int i; 451 452 sbLocation = port << 4; // Initialize stuff for later use 453 454 sbOut(sbReset,true); // Reset the SoundBlaster DSP 455 asm mov dx,0x388 // Wait >4usec 456 asm in al, dx 457 asm in al, dx 458 asm in al, dx 459 asm in al, dx 460 asm in al, dx 461 asm in al, dx 462 asm in al, dx 463 asm in al, dx 464 asm in al, dx 465 466 sbOut(sbReset,false); // Turn off sb DSP reset 467 asm mov dx,0x388 // Wait >100usec 468 asm mov cx,100 469 usecloop: 470 asm in al,dx 471 asm loop usecloop 472 473 for (i = 0;i < 100;i++) 474 { 475 if (sbIn(sbDataAvail) & 0x80) // If data is available... 476 { 477 if (sbIn(sbReadData) == 0xaa) // If it matches correct value 478 return(true); 479 else 480 { 481 sbLocation = -1; // Otherwise not a SoundBlaster 482 return(false); 483 } 484 } 485 } 486 sbLocation = -1; // Retry count exceeded - fail 487 return(false); 488 } 489 490 /////////////////////////////////////////////////////////////////////////// 491 // 492 // Checks to see if a SoundBlaster is in the system. If the port passed is 493 // -1, then it scans through all possible I/O locations. If the port 494 // passed is 0, then it uses the default (2). If the port is >0, then 495 // it just passes it directly to SDL_CheckSB() 496 // 497 /////////////////////////////////////////////////////////////////////////// 498 static boolean 499 SDL_DetectSoundBlaster(int port) 500 { 501 int i; 502 503 if (port == 0) // If user specifies default, use 2 504 port = 2; 505 if (port == -1) 506 { 507 if (SDL_CheckSB(2)) // Check default before scanning 508 return(true); 509 510 if (SDL_CheckSB(4)) // Check other SB Pro location before scan 511 return(true); 512 513 for (i = 1;i <= 6;i++) // Scan through possible SB locations 514 { 515 if ((i == 2) || (i == 4)) 516 continue; 517 518 if (SDL_CheckSB(i)) // If found at this address, 519 return(true); // return success 520 } 521 return(false); // All addresses failed, return failure 522 } 523 else 524 return(SDL_CheckSB(port)); // User specified address or default 525 } 526 527 /////////////////////////////////////////////////////////////////////////// 528 // 529 // SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster 530 // code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()). 531 // 532 /////////////////////////////////////////////////////////////////////////// 533 void 534 SDL_SBSetDMA(byte channel) 535 { 536 if (channel > 3) 537 Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel"); 538 539 sbDMA = channel; 540 sbDMAa1 = sba1Vals[channel]; 541 sbDMAa2 = sba2Vals[channel]; 542 sbDMAa3 = sba3Vals[channel]; 543 } 544 545 /////////////////////////////////////////////////////////////////////////// 546 // 547 // SDL_StartSB() - Turns on the SoundBlaster 548 // 549 /////////////////////////////////////////////////////////////////////////// 550 static void 551 SDL_StartSB(void) 552 { 553 byte timevalue,test; 554 555 sbIntVec = sbIntVectors[sbInterrupt]; 556 if (sbIntVec < 0) 557 Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster"); 558 559 sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler 560 setvect(sbIntVec,SDL_SBService); // Set mine 561 562 sbWriteDelay(); 563 sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker 564 565 // Set the SoundBlaster DAC time constant for 7KHz 566 timevalue = 256 - (1000000 / 7000); 567 sbWriteDelay(); 568 sbOut(sbWriteCmd,0x40); 569 sbWriteDelay(); 570 sbOut(sbWriteData,timevalue); 571 572 SBProPresent = false; 573 if (sbNoProCheck) 574 return; 575 576 // Check to see if this is a SB Pro 577 sbOut(sbpMixerAddr,sbpmFMVol); 578 sbpOldFMMix = sbIn(sbpMixerData); 579 sbOut(sbpMixerData,0xbb); 580 test = sbIn(sbpMixerData); 581 if (test == 0xbb) 582 { 583 // Boost FM output levels to be equivilent with digitized output 584 sbOut(sbpMixerData,0xff); 585 test = sbIn(sbpMixerData); 586 if (test == 0xff) 587 { 588 SBProPresent = true; 589 590 // Save old Voice output levels (SB Pro) 591 sbOut(sbpMixerAddr,sbpmVoiceVol); 592 sbpOldVOCMix = sbIn(sbpMixerData); 593 594 // Turn SB Pro stereo DAC off 595 sbOut(sbpMixerAddr,sbpmControl); 596 sbOut(sbpMixerData,0); // 0=off,2=on 597 } 598 } 599 } 600 601 /////////////////////////////////////////////////////////////////////////// 602 // 603 // SDL_ShutSB() - Turns off the SoundBlaster 604 // 605 /////////////////////////////////////////////////////////////////////////// 606 static void 607 SDL_ShutSB(void) 608 { 609 SDL_SBStopSample(); 610 611 if (SBProPresent) 612 { 613 // Restore FM output levels (SB Pro) 614 sbOut(sbpMixerAddr,sbpmFMVol); 615 sbOut(sbpMixerData,sbpOldFMMix); 616 617 // Restore Voice output levels (SB Pro) 618 sbOut(sbpMixerAddr,sbpmVoiceVol); 619 sbOut(sbpMixerData,sbpOldVOCMix); 620 } 621 622 setvect(sbIntVec,sbOldIntHand); // Set vector back 623 } 624 625 // Sound Source Code 626 627 /////////////////////////////////////////////////////////////////////////// 628 // 629 // SDL_SSStopSample() - Stops a sample playing on the Sound Source 630 // 631 /////////////////////////////////////////////////////////////////////////// 632 #ifdef _MUSE_ 633 void 634 #else 635 static void 636 #endif 637 SDL_SSStopSample(void) 638 { 639 asm pushf 640 asm cli 641 642 (long)ssSample = 0; 643 644 asm popf 645 } 646 647 /////////////////////////////////////////////////////////////////////////// 648 // 649 // SDL_SSService() - Handles playing the next sample on the Sound Source 650 // 651 /////////////////////////////////////////////////////////////////////////// 652 static void 653 SDL_SSService(void) 654 { 655 boolean gotit; 656 byte v; 657 658 while (ssSample) 659 { 660 asm mov dx,[ssStatus] // Check to see if FIFO is currently empty 661 asm in al,dx 662 asm test al,0x40 663 asm jnz done // Nope - don't push any more data out 664 665 v = *ssSample++; 666 if (!(--ssLengthLeft)) 667 { 668 (long)ssSample = 0; 669 SDL_DigitizedDone(); 670 } 671 672 asm mov dx,[ssData] // Pump the value out 673 asm mov al,[v] 674 asm out dx,al 675 676 asm mov dx,[ssControl] // Pulse printer select 677 asm mov al,[ssOff] 678 asm out dx,al 679 asm push ax 680 asm pop ax 681 asm mov al,[ssOn] 682 asm out dx,al 683 684 asm push ax // Delay a short while 685 asm pop ax 686 asm push ax 687 asm pop ax 688 } 689 done:; 690 } 691 692 /////////////////////////////////////////////////////////////////////////// 693 // 694 // SDL_SSPlaySample() - Plays the specified sample on the Sound Source 695 // 696 /////////////////////////////////////////////////////////////////////////// 697 #ifdef _MUSE_ 698 void 699 #else 700 static void 701 #endif 702 SDL_SSPlaySample(byte huge *data,longword len) 703 { 704 asm pushf 705 asm cli 706 707 ssLengthLeft = len; 708 ssSample = (volatile byte far *)data; 709 710 asm popf 711 } 712 713 /////////////////////////////////////////////////////////////////////////// 714 // 715 // SDL_StartSS() - Sets up for and turns on the Sound Source 716 // 717 /////////////////////////////////////////////////////////////////////////// 718 static void 719 SDL_StartSS(void) 720 { 721 if (ssPort == 3) 722 ssControl = 0x27a; // If using LPT3 723 else if (ssPort == 2) 724 ssControl = 0x37a; // If using LPT2 725 else 726 ssControl = 0x3be; // If using LPT1 727 ssStatus = ssControl - 1; 728 ssData = ssStatus - 1; 729 730 ssOn = 0x04; 731 if (ssIsTandy) 732 ssOff = 0x0e; // Tandy wierdness 733 else 734 ssOff = 0x0c; // For normal machines 735 736 outportb(ssControl,ssOn); // Enable SS 737 } 738 739 /////////////////////////////////////////////////////////////////////////// 740 // 741 // SDL_ShutSS() - Turns off the Sound Source 742 // 743 /////////////////////////////////////////////////////////////////////////// 744 static void 745 SDL_ShutSS(void) 746 { 747 outportb(ssControl,ssOff); 748 } 749 750 /////////////////////////////////////////////////////////////////////////// 751 // 752 // SDL_CheckSS() - Checks to see if a Sound Source is present at the 753 // location specified by the sound source variables 754 // 755 /////////////////////////////////////////////////////////////////////////// 756 static boolean 757 SDL_CheckSS(void) 758 { 759 boolean present = false; 760 longword lasttime; 761 762 // Turn the Sound Source on and wait awhile (4 ticks) 763 SDL_StartSS(); 764 765 lasttime = TimeCount; 766 while (TimeCount < lasttime + 4) 767 ; 768 769 asm mov dx,[ssStatus] // Check to see if FIFO is currently empty 770 asm in al,dx 771 asm test al,0x40 772 asm jnz checkdone // Nope - Sound Source not here 773 774 asm mov cx,32 // Force FIFO overflow (FIFO is 16 bytes) 775 outloop: 776 asm mov dx,[ssData] // Pump a neutral value out 777 asm mov al,0x80 778 asm out dx,al 779 780 asm mov dx,[ssControl] // Pulse printer select 781 asm mov al,[ssOff] 782 asm out dx,al 783 asm push ax 784 asm pop ax 785 asm mov al,[ssOn] 786 asm out dx,al 787 788 asm push ax // Delay a short while before we do this again 789 asm pop ax 790 asm push ax 791 asm pop ax 792 793 asm loop outloop 794 795 asm mov dx,[ssStatus] // Is FIFO overflowed now? 796 asm in al,dx 797 asm test al,0x40 798 asm jz checkdone // Nope, still not - Sound Source not here 799 800 present = true; // Yes - it's here! 801 802 checkdone: 803 SDL_ShutSS(); 804 return(present); 805 } 806 807 static boolean 808 SDL_DetectSoundSource(void) 809 { 810 for (ssPort = 1;ssPort <= 3;ssPort++) 811 if (SDL_CheckSS()) 812 return(true); 813 return(false); 814 } 815 816 // 817 // PC Sound code 818 // 819 820 /////////////////////////////////////////////////////////////////////////// 821 // 822 // SDL_PCPlaySample() - Plays the specified sample on the PC speaker 823 // 824 /////////////////////////////////////////////////////////////////////////// 825 #ifdef _MUSE_ 826 void 827 #else 828 static void 829 #endif 830 SDL_PCPlaySample(byte huge *data,longword len) 831 { 832 asm pushf 833 asm cli 834 835 SDL_IndicatePC(true); 836 837 pcLengthLeft = len; 838 pcSound = (volatile byte far *)data; 839 840 asm popf 841 } 842 843 /////////////////////////////////////////////////////////////////////////// 844 // 845 // SDL_PCStopSample() - Stops a sample playing on the PC speaker 846 // 847 /////////////////////////////////////////////////////////////////////////// 848 #ifdef _MUSE_ 849 void 850 #else 851 static void 852 #endif 853 SDL_PCStopSample(void) 854 { 855 asm pushf 856 asm cli 857 858 (long)pcSound = 0; 859 860 SDL_IndicatePC(false); 861 862 asm in al,0x61 // Turn the speaker off 863 asm and al,0xfd // ~2 864 asm out 0x61,al 865 866 asm popf 867 } 868 869 /////////////////////////////////////////////////////////////////////////// 870 // 871 // SDL_PCPlaySound() - Plays the specified sound on the PC speaker 872 // 873 /////////////////////////////////////////////////////////////////////////// 874 #ifdef _MUSE_ 875 void 876 #else 877 static void 878 #endif 879 SDL_PCPlaySound(PCSound far *sound) 880 { 881 asm pushf 882 asm cli 883 884 pcLastSample = -1; 885 pcLengthLeft = sound->common.length; 886 pcSound = sound->data; 887 888 asm popf 889 } 890 891 /////////////////////////////////////////////////////////////////////////// 892 // 893 // SDL_PCStopSound() - Stops the current sound playing on the PC Speaker 894 // 895 /////////////////////////////////////////////////////////////////////////// 896 #ifdef _MUSE_ 897 void 898 #else 899 static void 900 #endif 901 SDL_PCStopSound(void) 902 { 903 asm pushf 904 asm cli 905 906 (long)pcSound = 0; 907 908 asm in al,0x61 // Turn the speaker off 909 asm and al,0xfd // ~2 910 asm out 0x61,al 911 912 asm popf 913 } 914 915 #if 0 916 /////////////////////////////////////////////////////////////////////////// 917 // 918 // SDL_PCService() - Handles playing the next sample in a PC sound 919 // 920 /////////////////////////////////////////////////////////////////////////// 921 static void 922 SDL_PCService(void) 923 { 924 byte s; 925 word t; 926 927 if (pcSound) 928 { 929 s = *pcSound++; 930 if (s != pcLastSample) 931 { 932 asm pushf 933 asm cli 934 935 pcLastSample = s; 936 if (s) // We have a frequency! 937 { 938 t = pcSoundLookup[s]; 939 asm mov bx,[t] 940 941 asm mov al,0xb6 // Write to channel 2 (speaker) timer 942 asm out 43h,al 943 asm mov al,bl 944 asm out 42h,al // Low byte 945 asm mov al,bh 946 asm out 42h,al // High byte 947 948 asm in al,0x61 // Turn the speaker & gate on 949 asm or al,3 950 asm out 0x61,al 951 } 952 else // Time for some silence 953 { 954 asm in al,0x61 // Turn the speaker & gate off 955 asm and al,0xfc // ~3 956 asm out 0x61,al 957 } 958 959 asm popf 960 } 961 962 if (!(--pcLengthLeft)) 963 { 964 SDL_PCStopSound(); 965 SDL_SoundFinished(); 966 } 967 } 968 } 969 #endif 970 971 /////////////////////////////////////////////////////////////////////////// 972 // 973 // SDL_ShutPC() - Turns off the pc speaker 974 // 975 /////////////////////////////////////////////////////////////////////////// 976 static void 977 SDL_ShutPC(void) 978 { 979 asm pushf 980 asm cli 981 982 pcSound = 0; 983 984 asm in al,0x61 // Turn the speaker & gate off 985 asm and al,0xfc // ~3 986 asm out 0x61,al 987 988 asm popf 989 } 990 991 // 992 // Stuff for digitized sounds 993 // 994 memptr 995 SDL_LoadDigiSegment(word page) 996 { 997 memptr addr; 998 999 #if 0 // for debugging 1000 asm mov dx,STATUS_REGISTER_1 1001 asm in al,dx 1002 asm mov dx,ATR_INDEX 1003 asm mov al,ATR_OVERSCAN 1004 asm out dx,al 1005 asm mov al,10 // bright green 1006 asm out dx,al 1007 #endif 1008 1009 addr = PM_GetSoundPage(page); 1010 PM_SetPageLock(PMSoundStart + page,pml_Locked); 1011 1012 #if 0 // for debugging 1013 asm mov dx,STATUS_REGISTER_1 1014 asm in al,dx 1015 asm mov dx,ATR_INDEX 1016 asm mov al,ATR_OVERSCAN 1017 asm out dx,al 1018 asm mov al,3 // blue 1019 asm out dx,al 1020 asm mov al,0x20 // normal 1021 asm out dx,al 1022 #endif 1023 1024 return(addr); 1025 } 1026 1027 void 1028 SDL_PlayDigiSegment(memptr addr,word len) 1029 { 1030 switch (DigiMode) 1031 { 1032 case sds_PC: 1033 SDL_PCPlaySample(addr,len); 1034 break; 1035 case sds_SoundSource: 1036 SDL_SSPlaySample(addr,len); 1037 break; 1038 case sds_SoundBlaster: 1039 SDL_SBPlaySample(addr,len); 1040 break; 1041 } 1042 } 1043 1044 void 1045 SD_StopDigitized(void) 1046 { 1047 int i; 1048 1049 asm pushf 1050 asm cli 1051 1052 DigiLeft = 0; 1053 DigiNextAddr = nil; 1054 DigiNextLen = 0; 1055 DigiMissed = false; 1056 DigiPlaying = false; 1057 DigiNumber = DigiPriority = 0; 1058 SoundPositioned = false; 1059 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) 1060 SDL_SoundFinished(); 1061 1062 switch (DigiMode) 1063 { 1064 case sds_PC: 1065 SDL_PCStopSample(); 1066 break; 1067 case sds_SoundSource: 1068 SDL_SSStopSample(); 1069 break; 1070 case sds_SoundBlaster: 1071 SDL_SBStopSample(); 1072 break; 1073 } 1074 1075 asm popf 1076 1077 for (i = DigiLastStart;i < DigiLastEnd;i++) 1078 PM_SetPageLock(i + PMSoundStart,pml_Unlocked); 1079 DigiLastStart = 1; 1080 DigiLastEnd = 0; 1081 } 1082 1083 void 1084 SD_Poll(void) 1085 { 1086 if (DigiLeft && !DigiNextAddr) 1087 { 1088 DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize); 1089 DigiLeft -= DigiNextLen; 1090 if (!DigiLeft) 1091 DigiLastSegment = true; 1092 DigiNextAddr = SDL_LoadDigiSegment(DigiPage++); 1093 } 1094 if (DigiMissed && DigiNextAddr) 1095 { 1096 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen); 1097 DigiNextAddr = nil; 1098 DigiMissed = false; 1099 if (DigiLastSegment) 1100 { 1101 DigiPlaying = false; 1102 DigiLastSegment = false; 1103 } 1104 } 1105 SDL_SetTimerSpeed(); 1106 } 1107 1108 void 1109 SD_SetPosition(int leftpos,int rightpos) 1110 { 1111 if 1112 ( 1113 (leftpos < 0) 1114 || (leftpos > 15) 1115 || (rightpos < 0) 1116 || (rightpos > 15) 1117 || ((leftpos == 15) && (rightpos == 15)) 1118 ) 1119 Quit("SD_SetPosition: Illegal position"); 1120 1121 switch (DigiMode) 1122 { 1123 case sds_SoundBlaster: 1124 SDL_PositionSBP(leftpos,rightpos); 1125 break; 1126 } 1127 } 1128 1129 void 1130 SD_PlayDigitized(word which,int leftpos,int rightpos) 1131 { 1132 word len; 1133 memptr addr; 1134 1135 if (!DigiMode) 1136 return; 1137 1138 SD_StopDigitized(); 1139 if (which >= NumDigi) 1140 Quit("SD_PlayDigitized: bad sound number"); 1141 1142 SD_SetPosition(leftpos,rightpos); 1143 1144 DigiPage = DigiList[(which * 2) + 0]; 1145 DigiLeft = DigiList[(which * 2) + 1]; 1146 1147 DigiLastStart = DigiPage; 1148 DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize); 1149 1150 len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize); 1151 addr = SDL_LoadDigiSegment(DigiPage++); 1152 1153 DigiPlaying = true; 1154 DigiLastSegment = false; 1155 1156 SDL_PlayDigiSegment(addr,len); 1157 DigiLeft -= len; 1158 if (!DigiLeft) 1159 DigiLastSegment = true; 1160 1161 SD_Poll(); 1162 } 1163 1164 void 1165 SDL_DigitizedDone(void) 1166 { 1167 if (DigiNextAddr) 1168 { 1169 SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen); 1170 DigiNextAddr = nil; 1171 DigiMissed = false; 1172 } 1173 else 1174 { 1175 if (DigiLastSegment) 1176 { 1177 DigiPlaying = false; 1178 DigiLastSegment = false; 1179 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) 1180 { 1181 SDL_SoundFinished(); 1182 } 1183 else 1184 DigiNumber = DigiPriority = 0; 1185 SoundPositioned = false; 1186 } 1187 else 1188 DigiMissed = true; 1189 } 1190 } 1191 1192 void 1193 SD_SetDigiDevice(SDSMode mode) 1194 { 1195 boolean devicenotpresent; 1196 1197 if (mode == DigiMode) 1198 return; 1199 1200 SD_StopDigitized(); 1201 1202 devicenotpresent = false; 1203 switch (mode) 1204 { 1205 case sds_SoundBlaster: 1206 if (!SoundBlasterPresent) 1207 { 1208 if (SoundSourcePresent) 1209 mode = sds_SoundSource; 1210 else 1211 devicenotpresent = true; 1212 } 1213 break; 1214 case sds_SoundSource: 1215 if (!SoundSourcePresent) 1216 devicenotpresent = true; 1217 break; 1218 } 1219 1220 if (!devicenotpresent) 1221 { 1222 if (DigiMode == sds_SoundSource) 1223 SDL_ShutSS(); 1224 1225 DigiMode = mode; 1226 1227 if (mode == sds_SoundSource) 1228 SDL_StartSS(); 1229 1230 SDL_SetTimerSpeed(); 1231 } 1232 } 1233 1234 void 1235 SDL_SetupDigi(void) 1236 { 1237 memptr list; 1238 word far *p, 1239 pg; 1240 int i; 1241 1242 PM_UnlockMainMem(); 1243 MM_GetPtr(&list,PMPageSize); 1244 PM_CheckMainMem(); 1245 p = (word far *)MK_FP(PM_GetPage(ChunksInFile - 1),0); 1246 _fmemcpy((void far *)list,(void far *)p,PMPageSize); 1247 pg = PMSoundStart; 1248 for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2) 1249 { 1250 if (pg >= ChunksInFile - 1) 1251 break; 1252 pg += (p[1] + (PMPageSize - 1)) / PMPageSize; 1253 } 1254 PM_UnlockMainMem(); 1255 MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2); 1256 _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2); 1257 MM_FreePtr(&list); 1258 NumDigi = i; 1259 1260 for (i = 0;i < LASTSOUND;i++) 1261 DigiMap[i] = -1; 1262 } 1263 1264 // AdLib Code 1265 1266 /////////////////////////////////////////////////////////////////////////// 1267 // 1268 // alOut(n,b) - Puts b in AdLib card register n 1269 // 1270 /////////////////////////////////////////////////////////////////////////// 1271 void 1272 alOut(byte n,byte b) 1273 { 1274 asm pushf 1275 asm cli 1276 1277 asm mov dx,0x388 1278 asm mov al,[n] 1279 asm out dx,al 1280 asm in al,dx 1281 asm in al,dx 1282 asm in al,dx 1283 asm in al,dx 1284 asm in al,dx 1285 asm in al,dx 1286 asm inc dx 1287 asm mov al,[b] 1288 asm out dx,al 1289 1290 asm popf 1291 1292 asm dec dx 1293 asm in al,dx 1294 asm in al,dx 1295 asm in al,dx 1296 asm in al,dx 1297 asm in al,dx 1298 asm in al,dx 1299 asm in al,dx 1300 asm in al,dx 1301 asm in al,dx 1302 asm in al,dx 1303 1304 asm in al,dx 1305 asm in al,dx 1306 asm in al,dx 1307 asm in al,dx 1308 asm in al,dx 1309 asm in al,dx 1310 asm in al,dx 1311 asm in al,dx 1312 asm in al,dx 1313 asm in al,dx 1314 1315 asm in al,dx 1316 asm in al,dx 1317 asm in al,dx 1318 asm in al,dx 1319 asm in al,dx 1320 asm in al,dx 1321 asm in al,dx 1322 asm in al,dx 1323 asm in al,dx 1324 asm in al,dx 1325 1326 asm in al,dx 1327 asm in al,dx 1328 asm in al,dx 1329 asm in al,dx 1330 asm in al,dx 1331 } 1332 1333 #if 0 1334 /////////////////////////////////////////////////////////////////////////// 1335 // 1336 // SDL_SetInstrument() - Puts an instrument into a generator 1337 // 1338 /////////////////////////////////////////////////////////////////////////// 1339 static void 1340 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive) 1341 { 1342 byte c,m; 1343 1344 if (percussive) 1345 { 1346 c = pcarriers[which]; 1347 m = pmodifiers[which]; 1348 } 1349 else 1350 { 1351 c = carriers[which]; 1352 m = modifiers[which]; 1353 } 1354 1355 tracks[track - 1]->inst = *inst; 1356 tracks[track - 1]->percussive = percussive; 1357 1358 alOut(m + alChar,inst->mChar); 1359 alOut(m + alScale,inst->mScale); 1360 alOut(m + alAttack,inst->mAttack); 1361 alOut(m + alSus,inst->mSus); 1362 alOut(m + alWave,inst->mWave); 1363 1364 // Most percussive instruments only use one cell 1365 if (c != 0xff) 1366 { 1367 alOut(c + alChar,inst->cChar); 1368 alOut(c + alScale,inst->cScale); 1369 alOut(c + alAttack,inst->cAttack); 1370 alOut(c + alSus,inst->cSus); 1371 alOut(c + alWave,inst->cWave); 1372 } 1373 1374 alOut(which + alFeedCon,inst->nConn); // DEBUG - I think this is right 1375 } 1376 #endif 1377 1378 /////////////////////////////////////////////////////////////////////////// 1379 // 1380 // SDL_ALStopSound() - Turns off any sound effects playing through the 1381 // AdLib card 1382 // 1383 /////////////////////////////////////////////////////////////////////////// 1384 #ifdef _MUSE_ 1385 void 1386 #else 1387 static void 1388 #endif 1389 SDL_ALStopSound(void) 1390 { 1391 asm pushf 1392 asm cli 1393 1394 (long)alSound = 0; 1395 alOut(alFreqH + 0,0); 1396 1397 asm popf 1398 } 1399 1400 static void 1401 SDL_AlSetFXInst(Instrument far *inst) 1402 { 1403 byte c,m; 1404 1405 m = modifiers[0]; 1406 c = carriers[0]; 1407 alOut(m + alChar,inst->mChar); 1408 alOut(m + alScale,inst->mScale); 1409 alOut(m + alAttack,inst->mAttack); 1410 alOut(m + alSus,inst->mSus); 1411 alOut(m + alWave,inst->mWave); 1412 alOut(c + alChar,inst->cChar); 1413 alOut(c + alScale,inst->cScale); 1414 alOut(c + alAttack,inst->cAttack); 1415 alOut(c + alSus,inst->cSus); 1416 alOut(c + alWave,inst->cWave); 1417 1418 // Note: Switch commenting on these lines for old MUSE compatibility 1419 // alOut(alFeedCon,inst->nConn); 1420 alOut(alFeedCon,0); 1421 } 1422 1423 /////////////////////////////////////////////////////////////////////////// 1424 // 1425 // SDL_ALPlaySound() - Plays the specified sound on the AdLib card 1426 // 1427 /////////////////////////////////////////////////////////////////////////// 1428 #ifdef _MUSE_ 1429 void 1430 #else 1431 static void 1432 #endif 1433 SDL_ALPlaySound(AdLibSound far *sound) 1434 { 1435 Instrument far *inst; 1436 byte huge *data; 1437 1438 SDL_ALStopSound(); 1439 1440 asm pushf 1441 asm cli 1442 1443 alLengthLeft = sound->common.length; 1444 data = sound->data; 1445 data++; 1446 data--; 1447 alSound = (byte far *)data; 1448 alBlock = ((sound->block & 7) << 2) | 0x20; 1449 inst = &sound->inst; 1450 1451 if (!(inst->mSus | inst->cSus)) 1452 { 1453 asm popf 1454 Quit("SDL_ALPlaySound() - Bad instrument"); 1455 } 1456 1457 SDL_AlSetFXInst(&alZeroInst); // DEBUG 1458 SDL_AlSetFXInst(inst); 1459 1460 asm popf 1461 } 1462 1463 #if 0 1464 /////////////////////////////////////////////////////////////////////////// 1465 // 1466 // SDL_ALSoundService() - Plays the next sample out through the AdLib card 1467 // 1468 /////////////////////////////////////////////////////////////////////////// 1469 //static void 1470 void 1471 SDL_ALSoundService(void) 1472 { 1473 byte s; 1474 1475 if (alSound) 1476 { 1477 s = *alSound++; 1478 if (!s) 1479 alOut(alFreqH + 0,0); 1480 else 1481 { 1482 alOut(alFreqL + 0,s); 1483 alOut(alFreqH + 0,alBlock); 1484 } 1485 1486 if (!(--alLengthLeft)) 1487 { 1488 (long)alSound = 0; 1489 alOut(alFreqH + 0,0); 1490 SDL_SoundFinished(); 1491 } 1492 } 1493 } 1494 #endif 1495 1496 #if 0 1497 void 1498 SDL_ALService(void) 1499 { 1500 byte a,v; 1501 word w; 1502 1503 if (!sqActive) 1504 return; 1505 1506 while (sqHackLen && (sqHackTime <= alTimeCount)) 1507 { 1508 w = *sqHackPtr++; 1509 sqHackTime = alTimeCount + *sqHackPtr++; 1510 asm mov dx,[w] 1511 asm mov [a],dl 1512 asm mov [v],dh 1513 alOut(a,v); 1514 sqHackLen -= 4; 1515 } 1516 alTimeCount++; 1517 if (!sqHackLen) 1518 { 1519 sqHackPtr = (word far *)sqHack; 1520 sqHackLen = sqHackSeqLen; 1521 alTimeCount = sqHackTime = 0; 1522 } 1523 } 1524 #endif 1525 1526 /////////////////////////////////////////////////////////////////////////// 1527 // 1528 // SDL_ShutAL() - Shuts down the AdLib card for sound effects 1529 // 1530 /////////////////////////////////////////////////////////////////////////// 1531 static void 1532 SDL_ShutAL(void) 1533 { 1534 asm pushf 1535 asm cli 1536 1537 alOut(alEffects,0); 1538 alOut(alFreqH + 0,0); 1539 SDL_AlSetFXInst(&alZeroInst); 1540 alSound = 0; 1541 1542 asm popf 1543 } 1544 1545 /////////////////////////////////////////////////////////////////////////// 1546 // 1547 // SDL_CleanAL() - Totally shuts down the AdLib card 1548 // 1549 /////////////////////////////////////////////////////////////////////////// 1550 static void 1551 SDL_CleanAL(void) 1552 { 1553 int i; 1554 1555 asm pushf 1556 asm cli 1557 1558 alOut(alEffects,0); 1559 for (i = 1;i < 0xf5;i++) 1560 alOut(i,0); 1561 1562 asm popf 1563 } 1564 1565 /////////////////////////////////////////////////////////////////////////// 1566 // 1567 // SDL_StartAL() - Starts up the AdLib card for sound effects 1568 // 1569 /////////////////////////////////////////////////////////////////////////// 1570 static void 1571 SDL_StartAL(void) 1572 { 1573 alFXReg = 0; 1574 alOut(alEffects,alFXReg); 1575 SDL_AlSetFXInst(&alZeroInst); 1576 } 1577 1578 /////////////////////////////////////////////////////////////////////////// 1579 // 1580 // SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster 1581 // emulating an AdLib) present 1582 // 1583 /////////////////////////////////////////////////////////////////////////// 1584 static boolean 1585 SDL_DetectAdLib(void) 1586 { 1587 byte status1,status2; 1588 int i; 1589 1590 alOut(4,0x60); // Reset T1 & T2 1591 alOut(4,0x80); // Reset IRQ 1592 status1 = readstat(); 1593 alOut(2,0xff); // Set timer 1 1594 alOut(4,0x21); // Start timer 1 1595 #if 0 1596 SDL_Delay(TimerDelay100); 1597 #else 1598 asm mov dx,0x388 1599 asm mov cx,100 1600 usecloop: 1601 asm in al,dx 1602 asm loop usecloop 1603 #endif 1604 1605 status2 = readstat(); 1606 alOut(4,0x60); 1607 alOut(4,0x80); 1608 1609 if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0)) 1610 { 1611 for (i = 1;i <= 0xf5;i++) // Zero all the registers 1612 alOut(i,0); 1613 1614 alOut(1,0x20); // Set WSE=1 1615 alOut(8,0); // Set CSM=0 & SEL=0 1616 1617 return(true); 1618 } 1619 else 1620 return(false); 1621 } 1622 1623 #if 0 1624 /////////////////////////////////////////////////////////////////////////// 1625 // 1626 // SDL_t0Service() - My timer 0 ISR which handles the different timings and 1627 // dispatches to whatever other routines are appropriate 1628 // 1629 /////////////////////////////////////////////////////////////////////////// 1630 static void interrupt 1631 SDL_t0Service(void) 1632 { 1633 static word count = 1; 1634 1635 #if 1 // for debugging 1636 asm mov dx,STATUS_REGISTER_1 1637 asm in al,dx 1638 asm mov dx,ATR_INDEX 1639 asm mov al,ATR_OVERSCAN 1640 asm out dx,al 1641 asm mov al,4 // red 1642 asm out dx,al 1643 #endif 1644 1645 HackCount++; 1646 1647 if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource)) 1648 { 1649 SDL_ALService(); 1650 SDL_SSService(); 1651 // if (!(++count & 7)) 1652 if (!(++count % 10)) 1653 { 1654 LocalTime++; 1655 TimeCount++; 1656 if (SoundUserHook) 1657 SoundUserHook(); 1658 } 1659 // if (!(count & 3)) 1660 if (!(count % 5)) 1661 { 1662 switch (SoundMode) 1663 { 1664 case sdm_PC: 1665 SDL_PCService(); 1666 break; 1667 case sdm_AdLib: 1668 SDL_ALSoundService(); 1669 break; 1670 } 1671 } 1672 } 1673 else 1674 { 1675 if (!(++count & 1)) 1676 { 1677 LocalTime++; 1678 TimeCount++; 1679 if (SoundUserHook) 1680 SoundUserHook(); 1681 } 1682 switch (SoundMode) 1683 { 1684 case sdm_PC: 1685 SDL_PCService(); 1686 break; 1687 case sdm_AdLib: 1688 SDL_ALSoundService(); 1689 break; 1690 } 1691 } 1692 1693 asm mov ax,[WORD PTR TimerCount] 1694 asm add ax,[WORD PTR TimerDivisor] 1695 asm mov [WORD PTR TimerCount],ax 1696 asm jnc myack 1697 t0OldService(); // If we overflow a word, time to call old int handler 1698 asm jmp olddone 1699 myack:; 1700 outportb(0x20,0x20); // Ack the interrupt 1701 olddone:; 1702 1703 #if 1 // for debugging 1704 asm mov dx,STATUS_REGISTER_1 1705 asm in al,dx 1706 asm mov dx,ATR_INDEX 1707 asm mov al,ATR_OVERSCAN 1708 asm out dx,al 1709 asm mov al,3 // blue 1710 asm out dx,al 1711 asm mov al,0x20 // normal 1712 asm out dx,al 1713 #endif 1714 } 1715 #endif 1716 1717 //////////////////////////////////////////////////////////////////////////// 1718 // 1719 // SDL_ShutDevice() - turns off whatever device was being used for sound fx 1720 // 1721 //////////////////////////////////////////////////////////////////////////// 1722 static void 1723 SDL_ShutDevice(void) 1724 { 1725 switch (SoundMode) 1726 { 1727 case sdm_PC: 1728 SDL_ShutPC(); 1729 break; 1730 case sdm_AdLib: 1731 SDL_ShutAL(); 1732 break; 1733 } 1734 SoundMode = sdm_Off; 1735 } 1736 1737 /////////////////////////////////////////////////////////////////////////// 1738 // 1739 // SDL_CleanDevice() - totally shuts down all sound devices 1740 // 1741 /////////////////////////////////////////////////////////////////////////// 1742 static void 1743 SDL_CleanDevice(void) 1744 { 1745 if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib)) 1746 SDL_CleanAL(); 1747 } 1748 1749 /////////////////////////////////////////////////////////////////////////// 1750 // 1751 // SDL_StartDevice() - turns on whatever device is to be used for sound fx 1752 // 1753 /////////////////////////////////////////////////////////////////////////// 1754 static void 1755 SDL_StartDevice(void) 1756 { 1757 switch (SoundMode) 1758 { 1759 case sdm_AdLib: 1760 SDL_StartAL(); 1761 break; 1762 } 1763 SoundNumber = SoundPriority = 0; 1764 } 1765 1766 // Public routines 1767 1768 /////////////////////////////////////////////////////////////////////////// 1769 // 1770 // SD_SetSoundMode() - Sets which sound hardware to use for sound effects 1771 // 1772 /////////////////////////////////////////////////////////////////////////// 1773 boolean 1774 SD_SetSoundMode(SDMode mode) 1775 { 1776 boolean result = false; 1777 word tableoffset; 1778 1779 SD_StopSound(); 1780 1781 #ifndef _MUSE_ 1782 if ((mode == sdm_AdLib) && !AdLibPresent) 1783 mode = sdm_PC; 1784 1785 switch (mode) 1786 { 1787 case sdm_Off: 1788 NeedsDigitized = false; 1789 result = true; 1790 break; 1791 case sdm_PC: 1792 tableoffset = STARTPCSOUNDS; 1793 NeedsDigitized = false; 1794 result = true; 1795 break; 1796 case sdm_AdLib: 1797 if (AdLibPresent) 1798 { 1799 tableoffset = STARTADLIBSOUNDS; 1800 NeedsDigitized = false; 1801 result = true; 1802 } 1803 break; 1804 } 1805 #else 1806 result = true; 1807 #endif 1808 1809 if (result && (mode != SoundMode)) 1810 { 1811 SDL_ShutDevice(); 1812 SoundMode = mode; 1813 #ifndef _MUSE_ 1814 SoundTable = (word *)(&audiosegs[tableoffset]); 1815 #endif 1816 SDL_StartDevice(); 1817 } 1818 1819 SDL_SetTimerSpeed(); 1820 1821 return(result); 1822 } 1823 1824 /////////////////////////////////////////////////////////////////////////// 1825 // 1826 // SD_SetMusicMode() - sets the device to use for background music 1827 // 1828 /////////////////////////////////////////////////////////////////////////// 1829 boolean 1830 SD_SetMusicMode(SMMode mode) 1831 { 1832 boolean result = false; 1833 1834 SD_FadeOutMusic(); 1835 while (SD_MusicPlaying()) 1836 ; 1837 1838 switch (mode) 1839 { 1840 case smm_Off: 1841 NeedsMusic = false; 1842 result = true; 1843 break; 1844 case smm_AdLib: 1845 if (AdLibPresent) 1846 { 1847 NeedsMusic = true; 1848 result = true; 1849 } 1850 break; 1851 } 1852 1853 if (result) 1854 MusicMode = mode; 1855 1856 SDL_SetTimerSpeed(); 1857 1858 return(result); 1859 } 1860 1861 /////////////////////////////////////////////////////////////////////////// 1862 // 1863 // SD_Startup() - starts up the Sound Mgr 1864 // Detects all additional sound hardware and installs my ISR 1865 // 1866 /////////////////////////////////////////////////////////////////////////// 1867 void 1868 SD_Startup(void) 1869 { 1870 int i; 1871 1872 if (SD_Started) 1873 return; 1874 1875 SDL_SetDS(); 1876 1877 ssIsTandy = false; 1878 ssNoCheck = false; 1879 alNoCheck = false; 1880 sbNoCheck = false; 1881 sbNoProCheck = false; 1882 #ifndef _MUSE_ 1883 for (i = 1;i < _argc;i++) 1884 { 1885 switch (US_CheckParm(_argv[i],ParmStrings)) 1886 { 1887 case 0: // No AdLib detection 1888 alNoCheck = true; 1889 break; 1890 case 1: // No SoundBlaster detection 1891 sbNoCheck = true; 1892 break; 1893 case 2: // No SoundBlaster Pro detection 1894 sbNoProCheck = true; 1895 break; 1896 case 3: 1897 ssNoCheck = true; // No Sound Source detection 1898 break; 1899 case 4: // Tandy Sound Source handling 1900 ssIsTandy = true; 1901 break; 1902 case 5: // Sound Source present at LPT1 1903 ssPort = 1; 1904 ssNoCheck = SoundSourcePresent = true; 1905 break; 1906 case 6: // Sound Source present at LPT2 1907 ssPort = 2; 1908 ssNoCheck = SoundSourcePresent = true; 1909 break; 1910 case 7: // Sound Source present at LPT3 1911 ssPort = 3; 1912 ssNoCheck = SoundSourcePresent = true; 1913 break; 1914 } 1915 } 1916 #endif 1917 1918 SoundUserHook = 0; 1919 1920 t0OldService = getvect(8); // Get old timer 0 ISR 1921 1922 LocalTime = TimeCount = alTimeCount = 0; 1923 1924 SD_SetSoundMode(sdm_Off); 1925 SD_SetMusicMode(smm_Off); 1926 1927 if (!ssNoCheck) 1928 SoundSourcePresent = SDL_DetectSoundSource(); 1929 1930 if (!alNoCheck) 1931 { 1932 AdLibPresent = SDL_DetectAdLib(); 1933 if (AdLibPresent && !sbNoCheck) 1934 { 1935 int port = -1; 1936 char *env = getenv("BLASTER"); 1937 if (env) 1938 { 1939 long temp; 1940 while (*env) 1941 { 1942 while (isspace(*env)) 1943 env++; 1944 1945 switch (toupper(*env)) 1946 { 1947 case 'A': 1948 temp = strtol(env + 1,&env,16); 1949 if 1950 ( 1951 (temp >= 0x210) 1952 && (temp <= 0x260) 1953 && (!(temp & 0x00f)) 1954 ) 1955 port = (temp - 0x200) >> 4; 1956 else 1957 Quit("SD_Startup: Unsupported address value in BLASTER"); 1958 break; 1959 case 'I': 1960 temp = strtol(env + 1,&env,10); 1961 if 1962 ( 1963 (temp >= 0) 1964 && (temp <= 10) 1965 && (sbIntVectors[temp] != -1) 1966 ) 1967 { 1968 sbInterrupt = temp; 1969 sbIntVec = sbIntVectors[sbInterrupt]; 1970 } 1971 else 1972 Quit("SD_Startup: Unsupported interrupt value in BLASTER"); 1973 break; 1974 case 'D': 1975 temp = strtol(env + 1,&env,10); 1976 if ((temp == 0) || (temp == 1) || (temp == 3)) 1977 SDL_SBSetDMA(temp); 1978 else 1979 Quit("SD_Startup: Unsupported DMA value in BLASTER"); 1980 break; 1981 default: 1982 while (isspace(*env)) 1983 env++; 1984 while (*env && !isspace(*env)) 1985 env++; 1986 break; 1987 } 1988 } 1989 } 1990 SoundBlasterPresent = SDL_DetectSoundBlaster(port); 1991 } 1992 } 1993 1994 for (i = 0;i < 255;i++) 1995 pcSoundLookup[i] = i * 60; 1996 1997 if (SoundBlasterPresent) 1998 SDL_StartSB(); 1999 2000 SDL_SetupDigi(); 2001 2002 SD_Started = true; 2003 } 2004 2005 /////////////////////////////////////////////////////////////////////////// 2006 // 2007 // SD_Default() - Sets up the default behaviour for the Sound Mgr whether 2008 // the config file was present or not. 2009 // 2010 /////////////////////////////////////////////////////////////////////////// 2011 void 2012 SD_Default(boolean gotit,SDMode sd,SMMode sm) 2013 { 2014 boolean gotsd,gotsm; 2015 2016 gotsd = gotsm = gotit; 2017 2018 if (gotsd) // Make sure requested sound hardware is available 2019 { 2020 switch (sd) 2021 { 2022 case sdm_AdLib: 2023 gotsd = AdLibPresent; 2024 break; 2025 } 2026 } 2027 if (!gotsd) 2028 { 2029 if (AdLibPresent) 2030 sd = sdm_AdLib; 2031 else 2032 sd = sdm_PC; 2033 } 2034 if (sd != SoundMode) 2035 SD_SetSoundMode(sd); 2036 2037 2038 if (gotsm) // Make sure requested music hardware is available 2039 { 2040 switch (sm) 2041 { 2042 case sdm_AdLib: 2043 gotsm = AdLibPresent; 2044 break; 2045 } 2046 } 2047 if (!gotsm) 2048 { 2049 if (AdLibPresent) 2050 sm = smm_AdLib; 2051 } 2052 if (sm != MusicMode) 2053 SD_SetMusicMode(sm); 2054 } 2055 2056 /////////////////////////////////////////////////////////////////////////// 2057 // 2058 // SD_Shutdown() - shuts down the Sound Mgr 2059 // Removes sound ISR and turns off whatever sound hardware was active 2060 // 2061 /////////////////////////////////////////////////////////////////////////// 2062 void 2063 SD_Shutdown(void) 2064 { 2065 if (!SD_Started) 2066 return; 2067 2068 SD_MusicOff(); 2069 SD_StopSound(); 2070 SDL_ShutDevice(); 2071 SDL_CleanDevice(); 2072 2073 if (SoundBlasterPresent) 2074 SDL_ShutSB(); 2075 2076 if (SoundSourcePresent) 2077 SDL_ShutSS(); 2078 2079 asm pushf 2080 asm cli 2081 2082 SDL_SetTimer0(0); 2083 2084 setvect(8,t0OldService); 2085 2086 asm popf 2087 2088 SD_Started = false; 2089 } 2090 2091 /////////////////////////////////////////////////////////////////////////// 2092 // 2093 // SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th 2094 // of a second from its timer 0 ISR 2095 // 2096 /////////////////////////////////////////////////////////////////////////// 2097 void 2098 SD_SetUserHook(void (* hook)(void)) 2099 { 2100 SoundUserHook = hook; 2101 } 2102 2103 /////////////////////////////////////////////////////////////////////////// 2104 // 2105 // SD_PositionSound() - Sets up a stereo imaging location for the next 2106 // sound to be played. Each channel ranges from 0 to 15. 2107 // 2108 /////////////////////////////////////////////////////////////////////////// 2109 void 2110 SD_PositionSound(int leftvol,int rightvol) 2111 { 2112 LeftPosition = leftvol; 2113 RightPosition = rightvol; 2114 nextsoundpos = true; 2115 } 2116 2117 /////////////////////////////////////////////////////////////////////////// 2118 // 2119 // SD_PlaySound() - plays the specified sound on the appropriate hardware 2120 // 2121 /////////////////////////////////////////////////////////////////////////// 2122 boolean 2123 SD_PlaySound(soundnames sound) 2124 { 2125 boolean ispos; 2126 SoundCommon far *s; 2127 int lp,rp; 2128 2129 lp = LeftPosition; 2130 rp = RightPosition; 2131 LeftPosition = 0; 2132 RightPosition = 0; 2133 2134 ispos = nextsoundpos; 2135 nextsoundpos = false; 2136 2137 if (sound == -1) 2138 return(false); 2139 2140 s = MK_FP(SoundTable[sound],0); 2141 if ((SoundMode != sdm_Off) && !s) 2142 Quit("SD_PlaySound() - Uncached sound"); 2143 2144 if ((DigiMode != sds_Off) && (DigiMap[sound] != -1)) 2145 { 2146 if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) 2147 { 2148 if (s->priority < SoundPriority) 2149 return(false); 2150 2151 SDL_PCStopSound(); 2152 2153 SD_PlayDigitized(DigiMap[sound],lp,rp); 2154 SoundPositioned = ispos; 2155 SoundNumber = sound; 2156 SoundPriority = s->priority; 2157 } 2158 else 2159 { 2160 asm pushf 2161 asm cli 2162 if (DigiPriority && !DigiNumber) 2163 { 2164 asm popf 2165 Quit("SD_PlaySound: Priority without a sound"); 2166 } 2167 asm popf 2168 2169 if (s->priority < DigiPriority) 2170 return(false); 2171 2172 SD_PlayDigitized(DigiMap[sound],lp,rp); 2173 SoundPositioned = ispos; 2174 DigiNumber = sound; 2175 DigiPriority = s->priority; 2176 } 2177 2178 return(true); 2179 } 2180 2181 if (SoundMode == sdm_Off) 2182 return(false); 2183 if (!s->length) 2184 Quit("SD_PlaySound() - Zero length sound"); 2185 if (s->priority < SoundPriority) 2186 return(false); 2187 2188 switch (SoundMode) 2189 { 2190 case sdm_PC: 2191 SDL_PCPlaySound((void far *)s); 2192 break; 2193 case sdm_AdLib: 2194 SDL_ALPlaySound((void far *)s); 2195 break; 2196 } 2197 2198 SoundNumber = sound; 2199 SoundPriority = s->priority; 2200 2201 return(false); 2202 } 2203 2204 /////////////////////////////////////////////////////////////////////////// 2205 // 2206 // SD_SoundPlaying() - returns the sound number that's playing, or 0 if 2207 // no sound is playing 2208 // 2209 /////////////////////////////////////////////////////////////////////////// 2210 word 2211 SD_SoundPlaying(void) 2212 { 2213 boolean result = false; 2214 2215 switch (SoundMode) 2216 { 2217 case sdm_PC: 2218 result = pcSound? true : false; 2219 break; 2220 case sdm_AdLib: 2221 result = alSound? true : false; 2222 break; 2223 } 2224 2225 if (result) 2226 return(SoundNumber); 2227 else 2228 return(false); 2229 } 2230 2231 /////////////////////////////////////////////////////////////////////////// 2232 // 2233 // SD_StopSound() - if a sound is playing, stops it 2234 // 2235 /////////////////////////////////////////////////////////////////////////// 2236 void 2237 SD_StopSound(void) 2238 { 2239 if (DigiPlaying) 2240 SD_StopDigitized(); 2241 2242 switch (SoundMode) 2243 { 2244 case sdm_PC: 2245 SDL_PCStopSound(); 2246 break; 2247 case sdm_AdLib: 2248 SDL_ALStopSound(); 2249 break; 2250 } 2251 2252 SoundPositioned = false; 2253 2254 SDL_SoundFinished(); 2255 } 2256 2257 /////////////////////////////////////////////////////////////////////////// 2258 // 2259 // SD_WaitSoundDone() - waits until the current sound is done playing 2260 // 2261 /////////////////////////////////////////////////////////////////////////// 2262 void 2263 SD_WaitSoundDone(void) 2264 { 2265 while (SD_SoundPlaying()) 2266 ; 2267 } 2268 2269 /////////////////////////////////////////////////////////////////////////// 2270 // 2271 // SD_MusicOn() - turns on the sequencer 2272 // 2273 /////////////////////////////////////////////////////////////////////////// 2274 void 2275 SD_MusicOn(void) 2276 { 2277 sqActive = true; 2278 } 2279 2280 /////////////////////////////////////////////////////////////////////////// 2281 // 2282 // SD_MusicOff() - turns off the sequencer and any playing notes 2283 // 2284 /////////////////////////////////////////////////////////////////////////// 2285 void 2286 SD_MusicOff(void) 2287 { 2288 word i; 2289 2290 2291 switch (MusicMode) 2292 { 2293 case smm_AdLib: 2294 alFXReg = 0; 2295 alOut(alEffects,0); 2296 for (i = 0;i < sqMaxTracks;i++) 2297 alOut(alFreqH + i + 1,0); 2298 break; 2299 } 2300 sqActive = false; 2301 } 2302 2303 /////////////////////////////////////////////////////////////////////////// 2304 // 2305 // SD_StartMusic() - starts playing the music pointed to 2306 // 2307 /////////////////////////////////////////////////////////////////////////// 2308 void 2309 SD_StartMusic(MusicGroup far *music) 2310 { 2311 SD_MusicOff(); 2312 asm pushf 2313 asm cli 2314 2315 if (MusicMode == smm_AdLib) 2316 { 2317 sqHackPtr = sqHack = music->values; 2318 sqHackSeqLen = sqHackLen = music->length; 2319 sqHackTime = 0; 2320 alTimeCount = 0; 2321 SD_MusicOn(); 2322 } 2323 2324 asm popf 2325 } 2326 2327 /////////////////////////////////////////////////////////////////////////// 2328 // 2329 // SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying() 2330 // to see if the fadeout is complete 2331 // 2332 /////////////////////////////////////////////////////////////////////////// 2333 void 2334 SD_FadeOutMusic(void) 2335 { 2336 switch (MusicMode) 2337 { 2338 case smm_AdLib: 2339 // DEBUG - quick hack to turn the music off 2340 SD_MusicOff(); 2341 break; 2342 } 2343 } 2344 2345 /////////////////////////////////////////////////////////////////////////// 2346 // 2347 // SD_MusicPlaying() - returns true if music is currently playing, false if 2348 // not 2349 // 2350 /////////////////////////////////////////////////////////////////////////// 2351 boolean 2352 SD_MusicPlaying(void) 2353 { 2354 boolean result; 2355 2356 switch (MusicMode) 2357 { 2358 case smm_AdLib: 2359 result = false; 2360 // DEBUG - not written 2361 break; 2362 default: 2363 result = false; 2364 } 2365 2366 return(result); 2367 }