1 // Macros for SoundBlaster stuff
\r
2 #define sbOut(n,b) outportb((n) + sbLocation,b)
\r
3 #define sbIn(n) inportb((n) + sbLocation)
\r
4 #define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80);
\r
5 #define sbReadDelay() while (sbIn(sbDataAvail) & 0x80);
\r
8 SoundBlasterPresent,SBProPresent,
\r
20 // SoundBlaster variables
\r
21 static boolean sbNoCheck,sbNoProCheck;
\r
22 static volatile boolean sbSamplePlaying;
\r
23 static byte sbOldIntMask = -1;
\r
24 static volatile byte huge *sbNextSegPtr;
\r
25 static byte sbDMA = 1,
\r
26 sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,
\r
27 sba1Vals[] = {0x87,0x83,0,0x82},
\r
28 sba2Vals[] = {0,2,0,6},
\r
29 sba3Vals[] = {1,3,0,7};
\r
30 static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,
\r
31 sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};
\r
32 static volatile dword sbNextSegLen;
\r
33 static volatile SampledSound huge *sbSamples;
\r
34 static void interrupt (*sbOldIntHand)(void);
\r
35 static byte sbpOldFMMix,sbpOldVOCMix;
\r
37 // SoundSource variables
\r
40 word ssControl,ssStatus,ssData;
\r
42 volatile byte far *ssSample;
\r
43 volatile dword ssLengthLeft;
\r
49 // SoundBlaster code
\r
52 ///////////////////////////////////////////////////////////////////////////
\r
54 // SDL_SBStopSample() - Stops any active sampled sound and causes DMA
\r
55 // requests from the SoundBlaster to cease
\r
57 ///////////////////////////////////////////////////////////////////////////
\r
63 SDL_SBStopSample(void)
\r
70 if (sbSamplePlaying)
\r
72 sbSamplePlaying = false;
\r
75 sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA
\r
77 is = inportb(0x21); // Restore interrupt mask bit
\r
78 if (sbOldIntMask & (1 << sbInterrupt))
\r
79 is |= (1 << sbInterrupt);
\r
81 is &= ~(1 << sbInterrupt);
\r
88 ///////////////////////////////////////////////////////////////////////////
\r
90 // SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster
\r
91 // Insures that the chunk doesn't cross a bank boundary, programs the DMA
\r
92 // controller, and tells the SB to start doing DMA requests for DAC
\r
94 ///////////////////////////////////////////////////////////////////////////
\r
96 SDL_SBPlaySeg(volatile byte huge *data,dword length)
\r
99 dword dataofs,uselen;
\r
102 datapage = FP_SEG(data) >> 12;
\r
103 dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);
\r
104 if (dataofs >= 0x10000)
\r
107 dataofs -= 0x10000;
\r
110 if (dataofs + uselen > 0x10000)
\r
111 uselen = 0x10000 - dataofs;
\r
115 // Program the DMA controller
\r
118 outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA
\r
119 outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte
\r
120 outportb(0x0b,0x49); // Set transfer mode for D/A conv
\r
121 outportb(sbDMAa2,(byte)dataofs); // Give LSB of address
\r
122 outportb(sbDMAa2,(byte)(dataofs >> 8)); // Give MSB of address
\r
123 outportb(sbDMAa1,(byte)datapage); // Give page of address
\r
124 outportb(sbDMAa3,(byte)uselen); // Give LSB of length
\r
125 outportb(sbDMAa3,(byte)(uselen >> 8)); // Give MSB of length
\r
126 outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA
\r
128 // Start playing the thing
\r
130 sbOut(sbWriteCmd,0x14);
\r
132 sbOut(sbWriteData,(byte)uselen);
\r
134 sbOut(sbWriteData,(byte)(uselen >> 8));
\r
137 return(uselen + 1);
\r
140 ///////////////////////////////////////////////////////////////////////////
\r
142 // SDL_SBService() - Services the SoundBlaster DMA interrupt
\r
144 ///////////////////////////////////////////////////////////////////////////
\r
145 /*static*/ void interrupt
\r
146 SDL_SBService(void)
\r
150 sbIn(sbDataAvail); // Ack interrupt to SB
\r
154 used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);
\r
155 if (sbNextSegLen <= used)
\r
156 sbNextSegPtr = nil;
\r
159 sbNextSegPtr += used;
\r
160 sbNextSegLen -= used;
\r
165 SDL_SBStopSample();
\r
166 SDL_DigitizedDone();
\r
169 outportb(0x20,0x20); // Ack interrupt
\r
172 ///////////////////////////////////////////////////////////////////////////
\r
174 // SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up
\r
175 // DMA to play the sound
\r
177 ///////////////////////////////////////////////////////////////////////////
\r
183 SDL_SBPlaySample(byte huge *data,dword len)
\r
187 SDL_SBStopSample();
\r
192 used = SDL_SBPlaySeg(data,len);
\r
194 sbNextSegPtr = nil;
\r
197 sbNextSegPtr = data + used;
\r
198 sbNextSegLen = len - used;
\r
201 // Save old interrupt status and unmask ours
\r
202 sbOldIntMask = inportb(0x21);
\r
203 outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));
\r
206 sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled
\r
208 sbSamplePlaying = true;
\r
213 ///////////////////////////////////////////////////////////////////////////
\r
215 // SDL_PositionSBP() - Sets the attenuation levels for the left and right
\r
216 // channels by using the mixer chip on the SB Pro. This hits a hole in
\r
217 // the address map for normal SBs.
\r
219 ///////////////////////////////////////////////////////////////////////////
\r
221 SDL_PositionSBP(int leftpos,int rightpos)
\r
228 leftpos = 15 - leftpos;
\r
229 rightpos = 15 - rightpos;
\r
230 v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);
\r
235 sbOut(sbpMixerAddr,sbpmVoiceVol);
\r
236 sbOut(sbpMixerData,v);
\r
241 ///////////////////////////////////////////////////////////////////////////
\r
243 // SDL_CheckSB() - Checks to see if a SoundBlaster resides at a
\r
244 // particular I/O location
\r
246 ///////////////////////////////////////////////////////////////////////////
\r
248 SDL_CheckSB(int port)
\r
252 sbLocation = port << 4; // Initialize stuff for later use
\r
254 sbOut(sbReset,true); // Reset the SoundBlaster DSP
\r
255 asm mov dx,0x388 // Wait >4usec
\r
266 sbOut(sbReset,false); // Turn off sb DSP reset
\r
267 asm mov dx,0x388 // Wait >100usec
\r
279 for (i = 0;i < 100;i++)
\r
281 if (sbIn(sbDataAvail) & 0x80) // If data is available...
\r
283 if (sbIn(sbReadData) == 0xaa) // If it matches correct value
\r
287 sbLocation = -1; // Otherwise not a SoundBlaster
\r
292 sbLocation = -1; // Retry count exceeded - fail
\r
296 ///////////////////////////////////////////////////////////////////////////
\r
298 // Checks to see if a SoundBlaster is in the system. If the port passed is
\r
299 // -1, then it scans through all possible I/O locations. If the port
\r
300 // passed is 0, then it uses the default (2). If the port is >0, then
\r
301 // it just passes it directly to SDL_CheckSB()
\r
303 ///////////////////////////////////////////////////////////////////////////
\r
305 SDL_DetectSoundBlaster(int port)
\r
309 if (port == 0) // If user specifies default, use 2
\r
313 if (SDL_CheckSB(2)) // Check default before scanning
\r
316 if (SDL_CheckSB(4)) // Check other SB Pro location before scan
\r
319 for (i = 1;i <= 6;i++) // Scan through possible SB locations
\r
321 if ((i == 2) || (i == 4))
\r
324 if (SDL_CheckSB(i)) // If found at this address,
\r
325 return(true); // return success
\r
327 return(false); // All addresses failed, return failure
\r
330 return(SDL_CheckSB(port)); // User specified address or default
\r
333 ///////////////////////////////////////////////////////////////////////////
\r
335 // SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster
\r
336 // code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).
\r
338 ///////////////////////////////////////////////////////////////////////////
\r
340 SDL_SBSetDMA(byte channel, global_game_variables_t *gvar)
\r
343 Quit(gvar, "SDL_SBSetDMA() - invalid SoundBlaster DMA channel");
\r
346 sbDMAa1 = sba1Vals[channel];
\r
347 sbDMAa2 = sba2Vals[channel];
\r
348 sbDMAa3 = sba3Vals[channel];
\r
351 ///////////////////////////////////////////////////////////////////////////
\r
353 // SDL_StartSB() - Turns on the SoundBlaster
\r
355 ///////////////////////////////////////////////////////////////////////////
\r
357 SDL_StartSB(global_game_variables_t *gvar)
\r
359 byte timevalue,test;
\r
361 sbIntVec = sbIntVectors[sbInterrupt];
\r
363 Quit(gvar, "SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");
\r
365 sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler
\r
366 setvect(sbIntVec,SDL_SBService); // Set mine
\r
369 sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker
\r
371 // Set the SoundBlaster DAC time constant for 7KHz
\r
372 timevalue = 256 - (1000000 / 7000);
\r
374 sbOut(sbWriteCmd,0x40);
\r
376 sbOut(sbWriteData,timevalue);
\r
378 SBProPresent = false;
\r
382 // Check to see if this is a SB Pro
\r
383 sbOut(sbpMixerAddr,sbpmFMVol);
\r
384 sbpOldFMMix = sbIn(sbpMixerData);
\r
385 sbOut(sbpMixerData,0xbb);
\r
386 test = sbIn(sbpMixerData);
\r
389 // Boost FM output levels to be equivilent with digitized output
\r
390 sbOut(sbpMixerData,0xff);
\r
391 test = sbIn(sbpMixerData);
\r
394 SBProPresent = true;
\r
396 // Save old Voice output levels (SB Pro)
\r
397 sbOut(sbpMixerAddr,sbpmVoiceVol);
\r
398 sbpOldVOCMix = sbIn(sbpMixerData);
\r
400 // Turn SB Pro stereo DAC off
\r
401 sbOut(sbpMixerAddr,sbpmControl);
\r
402 sbOut(sbpMixerData,0); // 0=off,2=on
\r
407 ///////////////////////////////////////////////////////////////////////////
\r
409 // SDL_ShutSB() - Turns off the SoundBlaster
\r
411 ///////////////////////////////////////////////////////////////////////////
\r
415 SDL_SBStopSample();
\r
419 // Restore FM output levels (SB Pro)
\r
420 sbOut(sbpMixerAddr,sbpmFMVol);
\r
421 sbOut(sbpMixerData,sbpOldFMMix);
\r
423 // Restore Voice output levels (SB Pro)
\r
424 sbOut(sbpMixerAddr,sbpmVoiceVol);
\r
425 sbOut(sbpMixerData,sbpOldVOCMix);
\r
428 setvect(sbIntVec,sbOldIntHand); // Set vector back
\r
436 // Sound Source Code
\r
438 ///////////////////////////////////////////////////////////////////////////
\r
440 // SDL_SSStopSample() - Stops a sample playing on the Sound Source
\r
442 ///////////////////////////////////////////////////////////////////////////
\r
448 SDL_SSStopSample(void)
\r
453 /*(long)*/ssSample = 0;
\r
458 ///////////////////////////////////////////////////////////////////////////
\r
460 // SDL_SSService() - Handles playing the next sample on the Sound Source
\r
462 ///////////////////////////////////////////////////////////////////////////
\r
464 SDL_SSService(void)
\r
467 boolean doneflag=false;
\r
473 mov dx,[ssStatus] // Check to see if FIFO is currently empty
\r
476 jnz done // Nope - don't push any more data out
\r
478 #ifdef __BORLANDC__
\r
482 #ifdef __BORLANDC__
\r
486 #ifdef __BORLANDC__
\r
496 if (!(--ssLengthLeft))
\r
498 /*(long)*/ssSample = 0;
\r
499 SDL_DigitizedDone();
\r
503 mov dx,[ssData] // Pump the value out
\r
507 mov dx,[ssControl] // Pulse printer select
\r
515 push ax // Delay a short while
\r
525 ///////////////////////////////////////////////////////////////////////////
\r
527 // SDL_SSPlaySample() - Plays the specified sample on the Sound Source
\r
529 ///////////////////////////////////////////////////////////////////////////
\r
535 SDL_SSPlaySample(byte huge *data,dword len)
\r
540 ssLengthLeft = len;
\r
541 ssSample = (volatile byte far *)data;
\r
546 ///////////////////////////////////////////////////////////////////////////
\r
548 // SDL_StartSS() - Sets up for and turns on the Sound Source
\r
550 ///////////////////////////////////////////////////////////////////////////
\r
555 ssControl = 0x27a; // If using LPT3
\r
556 else if (ssPort == 2)
\r
557 ssControl = 0x37a; // If using LPT2
\r
559 ssControl = 0x3be; // If using LPT1
\r
560 ssStatus = ssControl - 1;
\r
561 ssData = ssStatus - 1;
\r
565 ssOff = 0x0e; // Tandy wierdness
\r
567 ssOff = 0x0c; // For normal machines
\r
569 outportb(ssControl,ssOn); // Enable SS
\r
572 ///////////////////////////////////////////////////////////////////////////
\r
574 // SDL_ShutSS() - Turns off the Sound Source
\r
576 ///////////////////////////////////////////////////////////////////////////
\r
580 outportb(ssControl,ssOff);
\r
583 ///////////////////////////////////////////////////////////////////////////
\r
585 // SDL_CheckSS() - Checks to see if a Sound Source is present at the
\r
586 // location specified by the sound source variables
\r
588 ///////////////////////////////////////////////////////////////////////////
\r
592 boolean present = false, chkdone=0;
\r
595 // Turn the Sound Source on and wait awhile (4 ticks)
\r
598 lasttime = TimeCount;
\r
599 while (TimeCount < lasttime + 4)
\r
603 mov dx,[ssStatus] // Check to see if FIFO is currently empty
\r
606 jnz checkdone // Nope - Sound Source not here
\r
608 mov cx,32 // Force FIFO overflow (FIFO is 16 bytes)
\r
609 #ifdef __BORLANDC__
\r
613 #ifdef __BORLANDC__
\r
616 mov dx,[ssData] // Pump a neutral value out
\r
620 mov dx,[ssControl] // Pulse printer select
\r
628 push ax // Delay a short while before we do this again
\r
635 mov dx,[ssStatus] // Is FIFO overflowed now?
\r
638 jz checkdone // Nope, still not - Sound Source not here
\r
640 #ifdef __BORLANDC__
\r
644 #ifdef __BORLANDC__
\r
648 #ifdef __BORLANDC__
\r
656 if(!chkdone) present = true; // Yes - it's here!
\r
664 SDL_DetectSoundSource(void)
\r
666 for (ssPort = 1;ssPort <= 3;ssPort++)
\r