Commit 55edef7f authored by Steven Fuller's avatar Steven Fuller

More cleanups (id_vl.c)

parent 7d7c4678
......@@ -2,26 +2,6 @@
#include "id_heads.h"
#define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;}
// Macros for SoundBlaster stuff
#define sbOut(n,b) outportb((n) + sbLocation,b)
#define sbIn(n) inportb((n) + sbLocation)
#define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80);
#define sbReadDelay() while (sbIn(sbDataAvail) & 0x80);
// Macros for AdLib stuff
#define selreg(n) outportb(alFMAddr,n)
#define writereg(n) outportb(alFMData,n)
#define readstat() inportb(alFMStatus)
// Imports from ID_SD_A.ASM
extern void SDL_SetDS(void),
SDL_IndicatePC(boolean on);
extern void interrupt SDL_t0ExtremeAsmService(void),
SDL_t0FastAsmService(void),
SDL_t0SlowAsmService(void);
// Global variables
boolean SoundSourcePresent,
AdLibPresent,
......@@ -54,7 +34,6 @@ static char *ParmStrings[] =
"ss3",
nil
};
static void (*SoundUserHook)(void);
soundnames SoundNumber,DigiNumber;
word SoundPriority,DigiPriority;
int LeftPosition,RightPosition;
......@@ -81,9 +60,8 @@ static byte sbDMA = 1,
sba3Vals[] = {1,3,0,7};
static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,
sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};
static volatile longword sbNextSegLen;
static volatile SampledSound *sbSamples;
static void interrupt (*sbOldIntHand)(void);
static longword sbNextSegLen;
static SampledSound *sbSamples;
static byte sbpOldFMMix,sbpOldVOCMix;
// SoundSource variables
......@@ -91,8 +69,8 @@ static byte sbpOldFMMix,sbpOldVOCMix;
boolean ssActive;
word ssControl,ssStatus,ssData;
byte ssOn,ssOff;
volatile byte *ssSample;
volatile longword ssLengthLeft;
byte *ssSample;
longword ssLengthLeft;
// PC Sound variables
volatile byte pcLastSample, *pcSound;
......@@ -126,2143 +104,196 @@ static word sqMode,sqFadeStep;
// Internal routines
void SDL_DigitizedDone(void);
///////////////////////////////////////////////////////////////////////////
//
// SDL_SetTimer0() - Sets system timer 0 to the specified speed
//
///////////////////////////////////////////////////////////////////////////
#pragma argsused
static void
SDL_SetTimer0(word speed)
{
#ifndef TPROF // If using Borland's profiling, don't screw with the timer
asm pushf
asm cli
outportb(0x43,0x36); // Change timer 0
outportb(0x40,speed);
outportb(0x40,speed >> 8);
// Kludge to handle special case for digitized PC sounds
if (TimerDivisor == (1192030 / (TickBase * 100)))
TimerDivisor = (1192030 / (TickBase * 10));
else
TimerDivisor = speed;
asm popf
#else
TimerDivisor = 0x10000;
#endif
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
// interrupts generated by system timer 0 per second
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_SetIntsPerSec(word ints)
{
TimerRate = ints;
SDL_SetTimer0(1192030 / ints);
}
static void
SDL_SetTimerSpeed(void)
void SD_StopDigitized(void)
{
word rate;
void interrupt (*isr)(void);
if ((DigiMode == sds_PC) && DigiPlaying)
{
rate = TickBase * 100;
isr = SDL_t0ExtremeAsmService;
}
else if
(
(MusicMode == smm_AdLib)
|| ((DigiMode == sds_SoundSource) && DigiPlaying)
)
{
rate = TickBase * 10;
isr = SDL_t0FastAsmService;
}
else
{
rate = TickBase * 2;
isr = SDL_t0SlowAsmService;
}
if (rate != TimerRate)
{
setvect(8,isr);
SDL_SetIntsPerSec(rate);
TimerRate = rate;
}
}
//
// SoundBlaster code
//
///////////////////////////////////////////////////////////////////////////
//
// SDL_SBStopSample() - Stops any active sampled sound and causes DMA
// requests from the SoundBlaster to cease
//
///////////////////////////////////////////////////////////////////////////
static void SDL_SBStopSample(void)
void SD_Poll(void)
{
byte is;
asm pushf
asm cli
if (sbSamplePlaying)
{
sbSamplePlaying = false;
sbWriteDelay();
sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA
is = inportb(0x21); // Restore interrupt mask bit
if (sbOldIntMask & (1 << sbInterrupt))
is |= (1 << sbInterrupt);
else
is &= ~(1 << sbInterrupt);
outportb(0x21,is);
}
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster
// Insures that the chunk doesn't cross a bank boundary, programs the DMA
// controller, and tells the SB to start doing DMA requests for DAC
//
///////////////////////////////////////////////////////////////////////////
static longword
SDL_SBPlaySeg(volatile byte *data,longword length)
void SD_SetPosition(int leftpos,int rightpos)
{
unsigned datapage;
longword dataofs,uselen;
uselen = length;
datapage = FP_SEG(data) >> 12;
dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);
if (dataofs >= 0x10000)
{
datapage++;
dataofs -= 0x10000;
}
if (dataofs + uselen > 0x10000)
uselen = 0x10000 - dataofs;
uselen--;
// Program the DMA controller
asm pushf
asm cli
outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA
outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte
outportb(0x0b,0x49); // Set transfer mode for D/A conv
outportb(sbDMAa2,(byte)dataofs); // Give LSB of address
outportb(sbDMAa2,(byte)(dataofs >> 8)); // Give MSB of address
outportb(sbDMAa1,(byte)datapage); // Give page of address
outportb(sbDMAa3,(byte)uselen); // Give LSB of length
outportb(sbDMAa3,(byte)(uselen >> 8)); // Give MSB of length
outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA
// Start playing the thing
sbWriteDelay();
sbOut(sbWriteCmd,0x14);
sbWriteDelay();
sbOut(sbWriteData,(byte)uselen);
sbWriteDelay();
sbOut(sbWriteData,(byte)(uselen >> 8));
asm popf
return(uselen + 1);
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_SBService() - Services the SoundBlaster DMA interrupt
//
///////////////////////////////////////////////////////////////////////////
static void interrupt
SDL_SBService(void)
void SD_PlayDigitized(word which,int leftpos,int rightpos)
{
longword used;
sbIn(sbDataAvail); // Ack interrupt to SB
if (sbNextSegPtr)
{
used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);
if (sbNextSegLen <= used)
sbNextSegPtr = nil;
else
{
sbNextSegPtr += used;
sbNextSegLen -= used;
}
}
else
{
SDL_SBStopSample();
SDL_DigitizedDone();
}
outportb(0x20,0x20); // Ack interrupt
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up
// DMA to play the sound
//
///////////////////////////////////////////////////////////////////////////
static void SDL_SBPlaySample(byte *data,longword len)
void SDL_DigitizedDone(void)
{
longword used;
SDL_SBStopSample();
asm pushf
asm cli
used = SDL_SBPlaySeg(data,len);
if (len <= used)
sbNextSegPtr = nil;
else
{
sbNextSegPtr = data + used;
sbNextSegLen = len - used;
}
// Save old interrupt status and unmask ours
sbOldIntMask = inportb(0x21);
outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));
sbWriteDelay();
sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled
sbSamplePlaying = true;
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_PositionSBP() - Sets the attenuation levels for the left and right
// channels by using the mixer chip on the SB Pro. This hits a hole in
// the address map for normal SBs.
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_PositionSBP(int leftpos,int rightpos)
void SD_SetDigiDevice(SDSMode mode)
{
byte v;
if (!SBProPresent)
return;
leftpos = 15 - leftpos;
rightpos = 15 - rightpos;
v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);
asm pushf
asm cli
sbOut(sbpMixerAddr,sbpmVoiceVol);
sbOut(sbpMixerData,v);
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_CheckSB() - Checks to see if a SoundBlaster resides at a
// particular I/O location
//
///////////////////////////////////////////////////////////////////////////
static boolean
SDL_CheckSB(int port)
{
int i;
sbLocation = port << 4; // Initialize stuff for later use
sbOut(sbReset,true); // Reset the SoundBlaster DSP
asm mov dx,0x388 // Wait >4usec
asm in al, dx
asm in al, dx
asm in al, dx
asm in al, dx
asm in al, dx
asm in al, dx
asm in al, dx
asm in al, dx
asm in al, dx
sbOut(sbReset,false); // Turn off sb DSP reset
asm mov dx,0x388 // Wait >100usec
asm mov cx,100
usecloop:
asm in al,dx
asm loop usecloop
for (i = 0;i < 100;i++)
{
if (sbIn(sbDataAvail) & 0x80) // If data is available...
{
if (sbIn(sbReadData) == 0xaa) // If it matches correct value
return(true);
else
{
sbLocation = -1; // Otherwise not a SoundBlaster
return(false);
}
}
}
sbLocation = -1; // Retry count exceeded - fail
return(false);
}
// Public routines
///////////////////////////////////////////////////////////////////////////
//
// Checks to see if a SoundBlaster is in the system. If the port passed is
// -1, then it scans through all possible I/O locations. If the port
// passed is 0, then it uses the default (2). If the port is >0, then
// it just passes it directly to SDL_CheckSB()
// SD_SetSoundMode() - Sets which sound hardware to use for sound effects
//
///////////////////////////////////////////////////////////////////////////
static boolean
SDL_DetectSoundBlaster(int port)
boolean SD_SetSoundMode(SDMode mode)
{
int i;
if (port == 0) // If user specifies default, use 2
port = 2;
if (port == -1)
{
if (SDL_CheckSB(2)) // Check default before scanning
return(true);
if (SDL_CheckSB(4)) // Check other SB Pro location before scan
return(true);
for (i = 1;i <= 6;i++) // Scan through possible SB locations
{
if ((i == 2) || (i == 4))
continue;
if (SDL_CheckSB(i)) // If found at this address,
return(true); // return success
}
return(false); // All addresses failed, return failure
}
else
return(SDL_CheckSB(port)); // User specified address or default
return false;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster
// code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).
// SD_SetMusicMode() - sets the device to use for background music
//
///////////////////////////////////////////////////////////////////////////
void
SDL_SBSetDMA(byte channel)
boolean SD_SetMusicMode(SMMode mode)
{
if (channel > 3)
Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel");
sbDMA = channel;
sbDMAa1 = sba1Vals[channel];
sbDMAa2 = sba2Vals[channel];
sbDMAa3 = sba3Vals[channel];
return false;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_StartSB() - Turns on the SoundBlaster
// SD_Startup() - starts up the Sound Mgr
// Detects all additional sound hardware and installs my ISR
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_StartSB(void)
void SD_Startup(void)
{
byte timevalue,test;
sbIntVec = sbIntVectors[sbInterrupt];
if (sbIntVec < 0)
Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");
sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler
setvect(sbIntVec,SDL_SBService); // Set mine
sbWriteDelay();
sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker
// Set the SoundBlaster DAC time constant for 7KHz
timevalue = 256 - (1000000 / 7000);
sbWriteDelay();
sbOut(sbWriteCmd,0x40);
sbWriteDelay();
sbOut(sbWriteData,timevalue);
SBProPresent = false;
if (sbNoProCheck)
if (SD_Started)
return;
// Check to see if this is a SB Pro
sbOut(sbpMixerAddr,sbpmFMVol);
sbpOldFMMix = sbIn(sbpMixerData);
sbOut(sbpMixerData,0xbb);
test = sbIn(sbpMixerData);
if (test == 0xbb)
{
// Boost FM output levels to be equivilent with digitized output
sbOut(sbpMixerData,0xff);
test = sbIn(sbpMixerData);
if (test == 0xff)
{
SBProPresent = true;
// Save old Voice output levels (SB Pro)
sbOut(sbpMixerAddr,sbpmVoiceVol);
sbpOldVOCMix = sbIn(sbpMixerData);
// Turn SB Pro stereo DAC off
sbOut(sbpMixerAddr,sbpmControl);
sbOut(sbpMixerData,0); // 0=off,2=on
}
}
SD_Started = true;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_ShutSB() - Turns off the SoundBlaster
// SD_Shutdown() - shuts down the Sound Mgr
// Removes sound ISR and turns off whatever sound hardware was active
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_ShutSB(void)
void SD_Shutdown(void)
{
SDL_SBStopSample();
if (SBProPresent)
{
// Restore FM output levels (SB Pro)
sbOut(sbpMixerAddr,sbpmFMVol);
sbOut(sbpMixerData,sbpOldFMMix);
if (!SD_Started)
return;
// Restore Voice output levels (SB Pro)
sbOut(sbpMixerAddr,sbpmVoiceVol);
sbOut(sbpMixerData,sbpOldVOCMix);
}
SD_MusicOff();
SD_StopSound();
setvect(sbIntVec,sbOldIntHand); // Set vector back
SD_Started = false;
}
// Sound Source Code
///////////////////////////////////////////////////////////////////////////
//
// SDL_SSStopSample() - Stops a sample playing on the Sound Source
// SD_PositionSound() - Sets up a stereo imaging location for the next
// sound to be played. Each channel ranges from 0 to 15.
//
///////////////////////////////////////////////////////////////////////////
static void SDL_SSStopSample(void)
void SD_PositionSound(int leftvol,int rightvol)
{
asm pushf
asm cli
(long)ssSample = 0;
asm popf
LeftPosition = leftvol;
RightPosition = rightvol;
nextsoundpos = true;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_SSService() - Handles playing the next sample on the Sound Source
// SD_PlaySound() - plays the specified sound on the appropriate hardware
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_SSService(void)
boolean SD_PlaySound(soundnames sound)
{
boolean gotit;
byte v;
while (ssSample)
{
asm mov dx,[ssStatus] // Check to see if FIFO is currently empty
asm in al,dx
asm test al,0x40
asm jnz done // Nope - don't push any more data out
v = *ssSample++;
if (!(--ssLengthLeft))
{
(long)ssSample = 0;
SDL_DigitizedDone();
}
asm mov dx,[ssData] // Pump the value out
asm mov al,[v]
asm out dx,al
asm mov dx,[ssControl] // Pulse printer select
asm mov al,[ssOff]
asm out dx,al
asm push ax
asm pop ax
asm mov al,[ssOn]
asm out dx,al
asm push ax // Delay a short while
asm pop ax
asm push ax
asm pop ax
}
done:;
}
boolean ispos;
int lp,rp;
///////////////////////////////////////////////////////////////////////////
//
// SDL_SSPlaySample() - Plays the specified sample on the Sound Source
//
///////////////////////////////////////////////////////////////////////////
static void SDL_SSPlaySample(byte *data,longword len)
{
asm pushf
asm cli
lp = LeftPosition;
rp = RightPosition;
LeftPosition = 0;
RightPosition = 0;
ssLengthLeft = len;
ssSample = (volatile byte *)data;
ispos = nextsoundpos;
nextsoundpos = false;
asm popf
return false;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_StartSS() - Sets up for and turns on the Sound Source
// SD_SoundPlaying() - returns the sound number that's playing, or 0 if
// no sound is playing
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_StartSS(void)
word SD_SoundPlaying(void)
{
if (ssPort == 3)
ssControl = 0x27a; // If using LPT3
else if (ssPort == 2)
ssControl = 0x37a; // If using LPT2
else
ssControl = 0x3be; // If using LPT1
ssStatus = ssControl - 1;
ssData = ssStatus - 1;
ssOn = 0x04;
if (ssIsTandy)
ssOff = 0x0e; // Tandy wierdness
else
ssOff = 0x0c; // For normal machines
outportb(ssControl,ssOn); // Enable SS
return false;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_ShutSS() - Turns off the Sound Source
// SD_StopSound() - if a sound is playing, stops it
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_ShutSS(void)
void SD_StopSound(void)
{
outportb(ssControl,ssOff);
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_CheckSS() - Checks to see if a Sound Source is present at the
// location specified by the sound source variables
// SD_WaitSoundDone() - waits until the current sound is done playing
//
///////////////////////////////////////////////////////////////////////////
static boolean
SDL_CheckSS(void)
void SD_WaitSoundDone(void)
{
boolean present = false;
longword lasttime;
// Turn the Sound Source on and wait awhile (4 ticks)
SDL_StartSS();
lasttime = TimeCount;
while (TimeCount < lasttime + 4)
while (SD_SoundPlaying())
;
asm mov dx,[ssStatus] // Check to see if FIFO is currently empty
asm in al,dx
asm test al,0x40
asm jnz checkdone // Nope - Sound Source not here
asm mov cx,32 // Force FIFO overflow (FIFO is 16 bytes)
outloop:
asm mov dx,[ssData] // Pump a neutral value out
asm mov al,0x80
asm out dx,al
asm mov dx,[ssControl] // Pulse printer select
asm mov al,[ssOff]
asm out dx,al
asm push ax
asm pop ax
asm mov al,[ssOn]
asm out dx,al
asm push ax // Delay a short while before we do this again
asm pop ax
asm push ax
asm pop ax
asm loop outloop
asm mov dx,[ssStatus] // Is FIFO overflowed now?
asm in al,dx
asm test al,0x40
asm jz checkdone // Nope, still not - Sound Source not here
present = true; // Yes - it's here!
checkdone:
SDL_ShutSS();
return(present);
}
static boolean
SDL_DetectSoundSource(void)
{
for (ssPort = 1;ssPort <= 3;ssPort++)
if (SDL_CheckSS())
return(true);
return(false);
}
//
// PC Sound code
//
///////////////////////////////////////////////////////////////////////////
//
// SDL_PCPlaySample() - Plays the specified sample on the PC speaker
//
///////////////////////////////////////////////////////////////////////////
static void SDL_PCPlaySample(byte *data,longword len)
{
asm pushf
asm cli
SDL_IndicatePC(true);
pcLengthLeft = len;
pcSound = (volatile byte *)data;
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_PCStopSample() - Stops a sample playing on the PC speaker
// SD_MusicOn() - turns on the sequencer
//
///////////////////////////////////////////////////////////////////////////
static void SDL_PCStopSample(void)
void SD_MusicOn(void)
{
asm pushf
asm cli
(long)pcSound = 0;
SDL_IndicatePC(false);
asm in al,0x61 // Turn the speaker off
asm and al,0xfd // ~2
asm out 0x61,al
asm popf
sqActive = true;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_PCPlaySound() - Plays the specified sound on the PC speaker
// SD_MusicOff() - turns off the sequencer and any playing notes
//
///////////////////////////////////////////////////////////////////////////
static void SDL_PCPlaySound(PCSound *sound)
void SD_MusicOff(void)
{
asm pushf
asm cli
pcLastSample = -1;
pcLengthLeft = sound->common.length;
pcSound = sound->data;
asm popf
sqActive = false;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
// SD_StartMusic() - starts playing the music pointed to
//
///////////////////////////////////////////////////////////////////////////
static void SDL_PCStopSound(void)
void SD_StartMusic(MusicGroup *music)
{
asm pushf
asm cli
(long)pcSound = 0;
asm in al,0x61 // Turn the speaker off
asm and al,0xfd // ~2
asm out 0x61,al
asm popf
SD_MusicOff();
}
#if 0
///////////////////////////////////////////////////////////////////////////
//
// SDL_PCService() - Handles playing the next sample in a PC sound
// SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
// to see if the fadeout is complete
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_PCService(void)
void SD_FadeOutMusic(void)
{
byte s;
word t;
if (pcSound)
{
s = *pcSound++;
if (s != pcLastSample)
{
asm pushf
asm cli
pcLastSample = s;
if (s) // We have a frequency!
{
t = pcSoundLookup[s];
asm mov bx,[t]
asm mov al,0xb6 // Write to channel 2 (speaker) timer
asm out 43h,al
asm mov al,bl
asm out 42h,al // Low byte
asm mov al,bh
asm out 42h,al // High byte
asm in al,0x61 // Turn the speaker & gate on
asm or al,3
asm out 0x61,al
}
else // Time for some silence
{
asm in al,0x61 // Turn the speaker & gate off
asm and al,0xfc // ~3
asm out 0x61,al
}
asm popf
}
if (!(--pcLengthLeft))
{
SDL_PCStopSound();
SDL_SoundFinished();
}
}
}
#endif
///////////////////////////////////////////////////////////////////////////
//
// SDL_ShutPC() - Turns off the pc speaker
// SD_MusicPlaying() - returns true if music is currently playing, false if
// not
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_ShutPC(void)
{
asm pushf
asm cli
pcSound = 0;
asm in al,0x61 // Turn the speaker & gate off
asm and al,0xfc // ~3
asm out 0x61,al
asm popf
}
//
// Stuff for digitized sounds
//
memptr
SDL_LoadDigiSegment(word page)
{
memptr addr;
#if 0 // for debugging
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,ATR_OVERSCAN
asm out dx,al
asm mov al,10 // bright green
asm out dx,al
#endif
addr = PM_GetSoundPage(page);
PM_SetPageLock(PMSoundStart + page,pml_Locked);
#if 0 // for debugging
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,ATR_OVERSCAN
asm out dx,al
asm mov al,3 // blue
asm out dx,al
asm mov al,0x20 // normal
asm out dx,al
#endif
return(addr);
}
void
SDL_PlayDigiSegment(memptr addr,word len)
{
switch (DigiMode)
{
case sds_PC:
SDL_PCPlaySample(addr,len);
break;
case sds_SoundSource:
SDL_SSPlaySample(addr,len);
break;
case sds_SoundBlaster:
SDL_SBPlaySample(addr,len);
break;
}
}
void
SD_StopDigitized(void)
{
int i;
asm pushf
asm cli
DigiLeft = 0;
DigiNextAddr = nil;
DigiNextLen = 0;
DigiMissed = false;
DigiPlaying = false;
DigiNumber = DigiPriority = 0;
SoundPositioned = false;
if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
SDL_SoundFinished();
switch (DigiMode)
{
case sds_PC:
SDL_PCStopSample();
break;
case sds_SoundSource:
SDL_SSStopSample();
break;
case sds_SoundBlaster:
SDL_SBStopSample();
break;
}
asm popf
for (i = DigiLastStart;i < DigiLastEnd;i++)
PM_SetPageLock(i + PMSoundStart,pml_Unlocked);
DigiLastStart = 1;
DigiLastEnd = 0;
}
void
SD_Poll(void)
{
if (DigiLeft && !DigiNextAddr)
{
DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
DigiLeft -= DigiNextLen;
if (!DigiLeft)
DigiLastSegment = true;
DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);
}
if (DigiMissed && DigiNextAddr)
{
SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
DigiNextAddr = nil;
DigiMissed = false;
if (DigiLastSegment)
{
DigiPlaying = false;
DigiLastSegment = false;
}
}
SDL_SetTimerSpeed();
}
void
SD_SetPosition(int leftpos,int rightpos)
boolean SD_MusicPlaying(void)
{
if
(
(leftpos < 0)
|| (leftpos > 15)
|| (rightpos < 0)
|| (rightpos > 15)
|| ((leftpos == 15) && (rightpos == 15))
)
Quit("SD_SetPosition: Illegal position");
switch (DigiMode)
{
case sds_SoundBlaster:
SDL_PositionSBP(leftpos,rightpos);
break;
}
}
void
SD_PlayDigitized(word which,int leftpos,int rightpos)
{
word len;
memptr addr;
if (!DigiMode)
return;
SD_StopDigitized();
if (which >= NumDigi)
Quit("SD_PlayDigitized: bad sound number");
SD_SetPosition(leftpos,rightpos);
DigiPage = DigiList[(which * 2) + 0];
DigiLeft = DigiList[(which * 2) + 1];
DigiLastStart = DigiPage;
DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);
len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
addr = SDL_LoadDigiSegment(DigiPage++);
DigiPlaying = true;
DigiLastSegment = false;
SDL_PlayDigiSegment(addr,len);
DigiLeft -= len;
if (!DigiLeft)
DigiLastSegment = true;
SD_Poll();
}
void
SDL_DigitizedDone(void)
{
if (DigiNextAddr)
{
SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
DigiNextAddr = nil;
DigiMissed = false;
}
else
{
if (DigiLastSegment)
{
DigiPlaying = false;
DigiLastSegment = false;
if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
{
SDL_SoundFinished();
}
else
DigiNumber = DigiPriority = 0;
SoundPositioned = false;
}
else
DigiMissed = true;
}
}
void
SD_SetDigiDevice(SDSMode mode)
{
boolean devicenotpresent;
if (mode == DigiMode)
return;
SD_StopDigitized();
devicenotpresent = false;
switch (mode)
{
case sds_SoundBlaster:
if (!SoundBlasterPresent)
{
if (SoundSourcePresent)
mode = sds_SoundSource;
else
devicenotpresent = true;
}
break;
case sds_SoundSource:
if (!SoundSourcePresent)
devicenotpresent = true;
break;
}
if (!devicenotpresent)
{
if (DigiMode == sds_SoundSource)
SDL_ShutSS();
DigiMode = mode;
if (mode == sds_SoundSource)
SDL_StartSS();
SDL_SetTimerSpeed();
}
}
void
SDL_SetupDigi(void)
{
memptr list;
word *p,
pg;
int i;
PM_UnlockMainMem();
MM_GetPtr(&list,PMPageSize);
PM_CheckMainMem();
p = (word *)MK_FP(PM_GetPage(ChunksInFile - 1),0);
_fmemcpy((void *)list,(void *)p,PMPageSize);
pg = PMSoundStart;
for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2)
{
if (pg >= ChunksInFile - 1)
break;
pg += (p[1] + (PMPageSize - 1)) / PMPageSize;
}
PM_UnlockMainMem();
MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2);
_fmemcpy((void *)DigiList,(void *)list,i * sizeof(word) * 2);
MM_FreePtr(&list);
NumDigi = i;
for (i = 0;i < LASTSOUND;i++)
DigiMap[i] = -1;
}
// AdLib Code
///////////////////////////////////////////////////////////////////////////
//
// alOut(n,b) - Puts b in AdLib card register n
//
///////////////////////////////////////////////////////////////////////////
void
alOut(byte n,byte b)
{
asm pushf
asm cli
asm mov dx,0x388
asm mov al,[n]
asm out dx,al
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm inc dx
asm mov al,[b]
asm out dx,al
asm popf
asm dec dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
asm in al,dx
}
#if 0
///////////////////////////////////////////////////////////////////////////
//
// SDL_SetInstrument() - Puts an instrument into a generator
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_SetInstrument(int track,int which,Instrument *inst,boolean percussive)
{
byte c,m;
if (percussive)
{
c = pcarriers[which];
m = pmodifiers[which];
}
else
{
c = carriers[which];
m = modifiers[which];
}
tracks[track - 1]->inst = *inst;
tracks[track - 1]->percussive = percussive;
alOut(m + alChar,inst->mChar);
alOut(m + alScale,inst->mScale);
alOut(m + alAttack,inst->mAttack);
alOut(m + alSus,inst->mSus);
alOut(m + alWave,inst->mWave);
// Most percussive instruments only use one cell
if (c != 0xff)
{
alOut(c + alChar,inst->cChar);
alOut(c + alScale,inst->cScale);
alOut(c + alAttack,inst->cAttack);
alOut(c + alSus,inst->cSus);
alOut(c + alWave,inst->cWave);
}
alOut(which + alFeedCon,inst->nConn); // DEBUG - I think this is right
}
#endif
///////////////////////////////////////////////////////////////////////////
//
// SDL_ALStopSound() - Turns off any sound effects playing through the
// AdLib card
//
///////////////////////////////////////////////////////////////////////////
static void SDL_ALStopSound(void)
{
asm pushf
asm cli
(long)alSound = 0;
alOut(alFreqH + 0,0);
asm popf
}
static void
SDL_AlSetFXInst(Instrument *inst)
{
byte c,m;
m = modifiers[0];
c = carriers[0];
alOut(m + alChar,inst->mChar);
alOut(m + alScale,inst->mScale);
alOut(m + alAttack,inst->mAttack);
alOut(m + alSus,inst->mSus);
alOut(m + alWave,inst->mWave);
alOut(c + alChar,inst->cChar);
alOut(c + alScale,inst->cScale);
alOut(c + alAttack,inst->cAttack);
alOut(c + alSus,inst->cSus);
alOut(c + alWave,inst->cWave);
// Note: Switch commenting on these lines for old MUSE compatibility
// alOut(alFeedCon,inst->nConn);
alOut(alFeedCon,0);
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_ALPlaySound() - Plays the specified sound on the AdLib card
//
///////////////////////////////////////////////////////////////////////////
static void SDL_ALPlaySound(AdLibSound *sound)
{
Instrument *inst;
byte *data;
SDL_ALStopSound();
asm pushf
asm cli
alLengthLeft = sound->common.length;
data = sound->data;
data++;
data--;
alSound = (byte *)data;
alBlock = ((sound->block & 7) << 2) | 0x20;
inst = &sound->inst;
if (!(inst->mSus | inst->cSus))
{
asm popf
Quit("SDL_ALPlaySound() - Bad instrument");
}
SDL_AlSetFXInst(&alZeroInst); // DEBUG
SDL_AlSetFXInst(inst);
asm popf
}
#if 0
///////////////////////////////////////////////////////////////////////////
//
// SDL_ALSoundService() - Plays the next sample out through the AdLib card
//
///////////////////////////////////////////////////////////////////////////
//static void
void
SDL_ALSoundService(void)
{
byte s;
if (alSound)
{
s = *alSound++;
if (!s)
alOut(alFreqH + 0,0);
else
{
alOut(alFreqL + 0,s);
alOut(alFreqH + 0,alBlock);
}
if (!(--alLengthLeft))
{
(long)alSound = 0;
alOut(alFreqH + 0,0);
SDL_SoundFinished();
}
}
}
#endif
#if 0
void
SDL_ALService(void)
{
byte a,v;
word w;
if (!sqActive)
return;
while (sqHackLen && (sqHackTime <= alTimeCount))
{
w = *sqHackPtr++;
sqHackTime = alTimeCount + *sqHackPtr++;
asm mov dx,[w]
asm mov [a],dl
asm mov [v],dh
alOut(a,v);
sqHackLen -= 4;
}
alTimeCount++;
if (!sqHackLen)
{
sqHackPtr = (word *)sqHack;
sqHackLen = sqHackSeqLen;
alTimeCount = sqHackTime = 0;
}
}
#endif
///////////////////////////////////////////////////////////////////////////
//
// SDL_ShutAL() - Shuts down the AdLib card for sound effects
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_ShutAL(void)
{
asm pushf
asm cli
alOut(alEffects,0);
alOut(alFreqH + 0,0);
SDL_AlSetFXInst(&alZeroInst);
alSound = 0;
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_CleanAL() - Totally shuts down the AdLib card
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_CleanAL(void)
{
int i;
asm pushf
asm cli
alOut(alEffects,0);
for (i = 1;i < 0xf5;i++)
alOut(i,0);
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_StartAL() - Starts up the AdLib card for sound effects
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_StartAL(void)
{
alFXReg = 0;
alOut(alEffects,alFXReg);
SDL_AlSetFXInst(&alZeroInst);
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
// emulating an AdLib) present
//
///////////////////////////////////////////////////////////////////////////
static boolean
SDL_DetectAdLib(void)
{
byte status1,status2;
int i;
alOut(4,0x60); // Reset T1 & T2
alOut(4,0x80); // Reset IRQ
status1 = readstat();
alOut(2,0xff); // Set timer 1
alOut(4,0x21); // Start timer 1
#if 0
SDL_Delay(TimerDelay100);
#else
asm mov dx,0x388
asm mov cx,100
usecloop:
asm in al,dx
asm loop usecloop
#endif
status2 = readstat();
alOut(4,0x60);
alOut(4,0x80);
if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))
{
for (i = 1;i <= 0xf5;i++) // Zero all the registers
alOut(i,0);
alOut(1,0x20); // Set WSE=1
alOut(8,0); // Set CSM=0 & SEL=0
return(true);
}
else
return(false);
}
#if 0
///////////////////////////////////////////////////////////////////////////
//
// SDL_t0Service() - My timer 0 ISR which handles the different timings and
// dispatches to whatever other routines are appropriate
//
///////////////////////////////////////////////////////////////////////////
static void interrupt
SDL_t0Service(void)
{
static word count = 1;
#if 1 // for debugging
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,ATR_OVERSCAN
asm out dx,al
asm mov al,4 // red
asm out dx,al
#endif
HackCount++;
if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))
{
SDL_ALService();
SDL_SSService();
// if (!(++count & 7))
if (!(++count % 10))
{
LocalTime++;
TimeCount++;
if (SoundUserHook)
SoundUserHook();
}
// if (!(count & 3))
if (!(count % 5))
{
switch (SoundMode)
{
case sdm_PC:
SDL_PCService();
break;
case sdm_AdLib:
SDL_ALSoundService();
break;
}
}
}
else
{
if (!(++count & 1))
{
LocalTime++;
TimeCount++;
if (SoundUserHook)
SoundUserHook();
}
switch (SoundMode)
{
case sdm_PC:
SDL_PCService();
break;
case sdm_AdLib:
SDL_ALSoundService();
break;
}
}
asm mov ax,[WORD PTR TimerCount]
asm add ax,[WORD PTR TimerDivisor]
asm mov [WORD PTR TimerCount],ax
asm jnc myack
t0OldService(); // If we overflow a word, time to call old int handler
asm jmp olddone
myack:;
outportb(0x20,0x20); // Ack the interrupt
olddone:;
#if 1 // for debugging
asm mov dx,STATUS_REGISTER_1
asm in al,dx
asm mov dx,ATR_INDEX
asm mov al,ATR_OVERSCAN
asm out dx,al
asm mov al,3 // blue
asm out dx,al
asm mov al,0x20 // normal
asm out dx,al
#endif
}
#endif
////////////////////////////////////////////////////////////////////////////
//
// SDL_ShutDevice() - turns off whatever device was being used for sound fx
//
////////////////////////////////////////////////////////////////////////////
static void
SDL_ShutDevice(void)
{
switch (SoundMode)
{
case sdm_PC:
SDL_ShutPC();
break;
case sdm_AdLib:
SDL_ShutAL();
break;
}
SoundMode = sdm_Off;
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_CleanDevice() - totally shuts down all sound devices
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_CleanDevice(void)
{
if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
SDL_CleanAL();
}
///////////////////////////////////////////////////////////////////////////
//
// SDL_StartDevice() - turns on whatever device is to be used for sound fx
//
///////////////////////////////////////////////////////////////////////////
static void
SDL_StartDevice(void)
{
switch (SoundMode)
{
case sdm_AdLib:
SDL_StartAL();
break;
}
SoundNumber = SoundPriority = 0;
}
// Public routines
///////////////////////////////////////////////////////////////////////////
//
// SD_SetSoundMode() - Sets which sound hardware to use for sound effects
//
///////////////////////////////////////////////////////////////////////////
boolean
SD_SetSoundMode(SDMode mode)
{
boolean result = false;
word tableoffset;
SD_StopSound();
if ((mode == sdm_AdLib) && !AdLibPresent)
mode = sdm_PC;
switch (mode)
{
case sdm_Off:
NeedsDigitized = false;
result = true;
break;
case sdm_PC:
tableoffset = STARTPCSOUNDS;
NeedsDigitized = false;
result = true;
break;
case sdm_AdLib:
if (AdLibPresent)
{
tableoffset = STARTADLIBSOUNDS;
NeedsDigitized = false;
result = true;
}
break;
}
if (result && (mode != SoundMode))
{
SDL_ShutDevice();
SoundMode = mode;
SoundTable = (word *)(&audiosegs[tableoffset]);
SDL_StartDevice();
}
SDL_SetTimerSpeed();
return(result);
}
///////////////////////////////////////////////////////////////////////////
//
// SD_SetMusicMode() - sets the device to use for background music
//
///////////////////////////////////////////////////////////////////////////
boolean
SD_SetMusicMode(SMMode mode)
{
boolean result = false;
SD_FadeOutMusic();
while (SD_MusicPlaying())
;
switch (mode)
{
case smm_Off:
NeedsMusic = false;
result = true;
break;
case smm_AdLib:
if (AdLibPresent)
{
NeedsMusic = true;
result = true;
}
break;
}
if (result)
MusicMode = mode;
SDL_SetTimerSpeed();
return(result);
}
///////////////////////////////////////////////////////////////////////////
//
// SD_Startup() - starts up the Sound Mgr
// Detects all additional sound hardware and installs my ISR
//
///////////////////////////////////////////////////////////////////////////
void
SD_Startup(void)
{
int i;
if (SD_Started)
return;
SDL_SetDS();
ssIsTandy = false;
ssNoCheck = false;
alNoCheck = false;
sbNoCheck = false;
sbNoProCheck = false;
for (i = 1;i < _argc;i++)
{
switch (US_CheckParm(_argv[i],ParmStrings))
{
case 0: // No AdLib detection
alNoCheck = true;
break;
case 1: // No SoundBlaster detection
sbNoCheck = true;
break;
case 2: // No SoundBlaster Pro detection
sbNoProCheck = true;
break;
case 3:
ssNoCheck = true; // No Sound Source detection
break;
case 4: // Tandy Sound Source handling
ssIsTandy = true;
break;
case 5: // Sound Source present at LPT1
ssPort = 1;
ssNoCheck = SoundSourcePresent = true;
break;
case 6: // Sound Source present at LPT2
ssPort = 2;
ssNoCheck = SoundSourcePresent = true;
break;
case 7: // Sound Source present at LPT3
ssPort = 3;
ssNoCheck = SoundSourcePresent = true;
break;
}
}
SoundUserHook = 0;
t0OldService = getvect(8); // Get old timer 0 ISR
LocalTime = TimeCount = alTimeCount = 0;
SD_SetSoundMode(sdm_Off);
SD_SetMusicMode(smm_Off);
if (!ssNoCheck)
SoundSourcePresent = SDL_DetectSoundSource();
if (!alNoCheck)
{
AdLibPresent = SDL_DetectAdLib();
if (AdLibPresent && !sbNoCheck)
{
int port = -1;
char *env = getenv("BLASTER");
if (env)
{
long temp;
while (*env)
{
while (isspace(*env))
env++;
switch (toupper(*env))
{
case 'A':
temp = strtol(env + 1,&env,16);
if
(
(temp >= 0x210)
&& (temp <= 0x260)
&& (!(temp & 0x00f))
)
port = (temp - 0x200) >> 4;
else
Quit("SD_Startup: Unsupported address value in BLASTER");
break;
case 'I':
temp = strtol(env + 1,&env,10);
if
(
(temp >= 0)
&& (temp <= 10)
&& (sbIntVectors[temp] != -1)
)
{
sbInterrupt = temp;
sbIntVec = sbIntVectors[sbInterrupt];
}
else
Quit("SD_Startup: Unsupported interrupt value in BLASTER");
break;
case 'D':
temp = strtol(env + 1,&env,10);
if ((temp == 0) || (temp == 1) || (temp == 3))
SDL_SBSetDMA(temp);
else
Quit("SD_Startup: Unsupported DMA value in BLASTER");
break;
default:
while (isspace(*env))
env++;
while (*env && !isspace(*env))
env++;
break;
}
}
}
SoundBlasterPresent = SDL_DetectSoundBlaster(port);
}
}
for (i = 0;i < 255;i++)
pcSoundLookup[i] = i * 60;
if (SoundBlasterPresent)
SDL_StartSB();
SDL_SetupDigi();
SD_Started = true;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_Default() - Sets up the default behaviour for the Sound Mgr whether
// the config file was present or not.
//
///////////////////////////////////////////////////////////////////////////
void
SD_Default(boolean gotit,SDMode sd,SMMode sm)
{
boolean gotsd,gotsm;
gotsd = gotsm = gotit;
if (gotsd) // Make sure requested sound hardware is available
{
switch (sd)
{
case sdm_AdLib:
gotsd = AdLibPresent;
break;
}
}
if (!gotsd)
{
if (AdLibPresent)
sd = sdm_AdLib;
else
sd = sdm_PC;
}
if (sd != SoundMode)
SD_SetSoundMode(sd);
if (gotsm) // Make sure requested music hardware is available
{
switch (sm)
{
case sdm_AdLib:
gotsm = AdLibPresent;
break;
}
}
if (!gotsm)
{
if (AdLibPresent)
sm = smm_AdLib;
}
if (sm != MusicMode)
SD_SetMusicMode(sm);
}
///////////////////////////////////////////////////////////////////////////
//
// SD_Shutdown() - shuts down the Sound Mgr
// Removes sound ISR and turns off whatever sound hardware was active
//
///////////////////////////////////////////////////////////////////////////
void
SD_Shutdown(void)
{
if (!SD_Started)
return;
SD_MusicOff();
SD_StopSound();
SDL_ShutDevice();
SDL_CleanDevice();
if (SoundBlasterPresent)
SDL_ShutSB();
if (SoundSourcePresent)
SDL_ShutSS();
asm pushf
asm cli
SDL_SetTimer0(0);
setvect(8,t0OldService);
asm popf
SD_Started = false;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th
// of a second from its timer 0 ISR
//
///////////////////////////////////////////////////////////////////////////
void
SD_SetUserHook(void (* hook)(void))
{
SoundUserHook = hook;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_PositionSound() - Sets up a stereo imaging location for the next
// sound to be played. Each channel ranges from 0 to 15.
//
///////////////////////////////////////////////////////////////////////////
void
SD_PositionSound(int leftvol,int rightvol)
{
LeftPosition = leftvol;
RightPosition = rightvol;
nextsoundpos = true;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_PlaySound() - plays the specified sound on the appropriate hardware
//
///////////////////////////////////////////////////////////////////////////
boolean
SD_PlaySound(soundnames sound)
{
boolean ispos;
SoundCommon *s;
int lp,rp;
lp = LeftPosition;
rp = RightPosition;
LeftPosition = 0;
RightPosition = 0;
ispos = nextsoundpos;
nextsoundpos = false;
if (sound == -1)
return(false);
s = MK_FP(SoundTable[sound],0);
if ((SoundMode != sdm_Off) && !s)
Quit("SD_PlaySound() - Uncached sound");
if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
{
if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
{
if (s->priority < SoundPriority)
return(false);
SDL_PCStopSound();
SD_PlayDigitized(DigiMap[sound],lp,rp);
SoundPositioned = ispos;
SoundNumber = sound;
SoundPriority = s->priority;
}
else
{
asm pushf
asm cli
if (DigiPriority && !DigiNumber)
{
asm popf
Quit("SD_PlaySound: Priority without a sound");
}
asm popf
if (s->priority < DigiPriority)
return(false);
SD_PlayDigitized(DigiMap[sound],lp,rp);
SoundPositioned = ispos;
DigiNumber = sound;
DigiPriority = s->priority;
}
return(true);
}
if (SoundMode == sdm_Off)
return(false);
if (!s->length)
Quit("SD_PlaySound() - Zero length sound");
if (s->priority < SoundPriority)
return(false);
switch (SoundMode)
{
case sdm_PC:
SDL_PCPlaySound((void *)s);
break;
case sdm_AdLib:
SDL_ALPlaySound((void *)s);
break;
}
SoundNumber = sound;
SoundPriority = s->priority;
return(false);
}
///////////////////////////////////////////////////////////////////////////
//
// SD_SoundPlaying() - returns the sound number that's playing, or 0 if
// no sound is playing
//
///////////////////////////////////////////////////////////////////////////
word
SD_SoundPlaying(void)
{
boolean result = false;
switch (SoundMode)
{
case sdm_PC:
result = pcSound? true : false;
break;
case sdm_AdLib:
result = alSound? true : false;
break;
}
if (result)
return(SoundNumber);
else
return(false);
}
///////////////////////////////////////////////////////////////////////////
//
// SD_StopSound() - if a sound is playing, stops it
//
///////////////////////////////////////////////////////////////////////////
void
SD_StopSound(void)
{
if (DigiPlaying)
SD_StopDigitized();
switch (SoundMode)
{
case sdm_PC:
SDL_PCStopSound();
break;
case sdm_AdLib:
SDL_ALStopSound();
break;
}
SoundPositioned = false;
SDL_SoundFinished();
}
///////////////////////////////////////////////////////////////////////////
//
// SD_WaitSoundDone() - waits until the current sound is done playing
//
///////////////////////////////////////////////////////////////////////////
void
SD_WaitSoundDone(void)
{
while (SD_SoundPlaying())
;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_MusicOn() - turns on the sequencer
//
///////////////////////////////////////////////////////////////////////////
void
SD_MusicOn(void)
{
sqActive = true;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_MusicOff() - turns off the sequencer and any playing notes
//
///////////////////////////////////////////////////////////////////////////
void
SD_MusicOff(void)
{
word i;
switch (MusicMode)
{
case smm_AdLib:
alFXReg = 0;
alOut(alEffects,0);
for (i = 0;i < sqMaxTracks;i++)
alOut(alFreqH + i + 1,0);
break;
}
sqActive = false;
}
///////////////////////////////////////////////////////////////////////////
//
// SD_StartMusic() - starts playing the music pointed to
//
///////////////////////////////////////////////////////////////////////////
void
SD_StartMusic(MusicGroup *music)
{
SD_MusicOff();
asm pushf
asm cli
if (MusicMode == smm_AdLib)
{
sqHackPtr = sqHack = music->values;
sqHackSeqLen = sqHackLen = music->length;
sqHackTime = 0;
alTimeCount = 0;
SD_MusicOn();
}
asm popf
}
///////////////////////////////////////////////////////////////////////////
//
// SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
// to see if the fadeout is complete
//
///////////////////////////////////////////////////////////////////////////
void
SD_FadeOutMusic(void)
{
switch (MusicMode)
{
case smm_AdLib:
// DEBUG - quick hack to turn the music off
SD_MusicOff();
break;
}
}
///////////////////////////////////////////////////////////////////////////
//
// SD_MusicPlaying() - returns true if music is currently playing, false if
// not
//
///////////////////////////////////////////////////////////////////////////
boolean
SD_MusicPlaying(void)
{
boolean result;
switch (MusicMode)
{
case smm_AdLib:
result = false;
// DEBUG - not written
break;
default:
result = false;
}
return(result);
return false;
}
//
// ID Engine
// ID_SD.h - Sound Manager Header
// Version for Wolfenstein
// By Jason Blochowiak
//
#ifndef __ID_SD__
#define __ID_SD__
void alOut(byte n,byte b);
#ifndef __ID_SD_H__
#define __ID_SD_H__
#define TickBase 70 // 70Hz per tick - used as a base for timer 0
typedef enum {
sdm_Off,
sdm_PC, sdm_AdLib
sdm_PC,sdm_AdLib,
} SDMode;
typedef enum {
smm_Off, smm_AdLib
smm_Off,smm_AdLib
} SMMode;
typedef enum {
sds_Off,sds_PC,sds_SoundSource,sds_SoundBlaster
......@@ -222,5 +213,6 @@ extern void SD_SetDigiDevice(SDSMode),
SD_StopDigitized(void),
SD_Poll(void);
#elif
#error "fix me TODO"
#endif
;
; ID_SD_A.ASM
; Id Sound Manager assembly stuff
.286C
IDEAL
MODEL MEDIUM,C
JUMPS
INCLUDE 'ID_SD.EQU'
DEBUG = 0
EXTRN SDL_DigitizedDone:FAR
EXTRN alOut:FAR
;============================================================================
DATASEG
EXTRN sqActive:WORD
EXTRN ssSample:DWORD
EXTRN ssLengthLeft:WORD
EXTRN ssControl:WORD
EXTRN ssStatus:WORD
EXTRN ssData:WORD
EXTRN ssOn:BYTE
EXTRN ssOff:BYTE
EXTRN pcSound:DWORD
EXTRN pcLengthLeft:WORD
EXTRN pcLastSample:BYTE
EXTRN pcSoundLookup:WORD
EXTRN alSound:DWORD
EXTRN alBlock:WORD
EXTRN alLengthLeft:WORD
EXTRN alTimeCount:DWORD
EXTRN sqHack:DWORD
EXTRN sqHackPtr:DWORD
EXTRN sqHackLen:WORD
EXTRN sqHackSeqLen:WORD
EXTRN sqHackTime:DWORD
EXTRN HackCount:WORD
EXTRN TimeCount:WORD
EXTRN LocalTime:WORD
EXTRN TimerCount:WORD
EXTRN TimerDivisor:WORD
EXTRN t0OldService:DWORD
EXTRN SoundMode:WORD
EXTRN DigiMode:WORD
EXTRN SoundNumber:WORD
EXTRN SoundPriority:WORD
count_time dw ?
count_fx dw ?
pcdtab db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
db 10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b
;============================================================================
CODESEG
MyDS dw ?
pcindicate dw ?
extreme dw ?
PROC SDL_SetDS
PUBLIC SDL_SetDS
mov ax,ds
mov [cs:MyDS],ds
ret
ENDP
;
; COMMONSTART
; Macro used for common prefix code
;
MACRO COMMONSTART
IF DEBUG
push dx
push ax
mov dx,STATUS_REGISTER_1
in al,dx
mov dx,ATR_INDEX
mov al,ATR_OVERSCAN
out dx,al
mov al,4 ; red
out dx,al
ENDIF
push ds
push ax
mov ds,[cs:MyDS]
inc [HackCount]
ENDM
;
; DOFX
; Macro used to do the sound effects code
;
MACRO DOFX
les di,[pcSound] ; PC sound effects
mov ax,es
or ax,di
jz @@nopc ; nil pointer - no PC sound effect going
mov bl,[es:di] ; Get the byte
inc [WORD PTR pcSound] ; Increment pointer
cmp [pcLastSample],bl ; Is this sample the same as last?
jz @@pcsame ; Yep - don't do anything
mov [pcLastSample],bl ; No, save it for next time
or bl,bl
jz @@pcoff ; If 0, turn sounds off
xor bh,bh
shl bx,1
mov bx,[pcSoundLookup+bx] ; Use byte as index into frequency table
mov al,0b6h ; Write to channel 2 (speaker) timer
out pcTAccess,al
mov al,bl
out pcTimer,al ; Low byte
mov al,bh
out pcTimer,al ; High byte
in al,pcSpeaker ; Turn the speaker & gate on
or al,3
out pcSpeaker,al
jmp @@pcsame
@@pcoff:
in al,pcSpeaker ; Turn the speaker & gate off
and al,0fch ; ~3
out pcSpeaker,al
@@pcsame:
dec [pcLengthLeft] ; Decrement length
jnz @@nopc ; If not 0, we're not done with the sound
mov ax,0
mov [WORD PTR pcSound],ax ; Zero the pointer
mov [WORD PTR pcSound + 2],ax
mov [SoundNumber],ax ; Indicate no sound
mov [SoundPriority],ax ; with no priority
in al,pcSpeaker ; Turn the speaker off
and al,0fdh ; ~2
out pcSpeaker,al
@@nopc:
les di,[alSound] ; AdLib sound effects
mov ax,es
or ax,di
jz @@noal ; nil pointer - no AdLib effect going
xor ah,ah
mov al,[es:di]
or al,al
jz @@aldone
CALL alOut C,alFreqL,ax
mov ax,[alBlock]
@@aldone:
CALL alOut C,alFreqH,ax
inc [WORD PTR alSound]
dec [alLengthLeft]
jnz @@noal
mov ax,0
mov [WORD PTR alSound],ax ; Zero the pointer
mov [WORD PTR alSound + 2],ax
mov [SoundNumber],ax ; Indicate no sound
mov [SoundPriority],ax ; with no priority
CALL alOut C,alFreqH,ax ; Turn off the sound
@@noal:
ENDM
;
;
;
MACRO TIME
cmp [count_time],2
jb @@notime
add [LocalTime],1
adc [LocalTime+2],0
add [TimeCount],1
adc [TimeCount+2],0
mov [count_time],0
@@notime:
ENDM
;
; COMMONEND
; Macro used for common suffix code
;
MACRO COMMONEND
@@fullexit:
pop es
popa
@@nosave:
mov ax,[TimerDivisor]
add [TimerCount],ax
jnc @@myack
pushf
call [t0OldService]
jmp @@out
@@myack:
mov al,20h
out 20h,al
@@out:
pop ax
pop ds
IF DEBUG
mov dx,STATUS_REGISTER_1
in al,dx
mov dx,ATR_INDEX
mov al,ATR_OVERSCAN
out dx,al
mov al,3 ; blue
out dx,al
mov al,20h ; normal
out dx,al
pop ax
pop dx
ENDIF
iret
ENDM
;
; SDL_IndicatePC
;
PROC SDL_IndicatePC on:WORD
PUBLIC SDL_IndicatePC
mov ax,[on]
mov [cs:pcindicate],ax
ret
ENDP
;
; SDL_t0ExtremeAsmService
; Timer 0 ISR 7000Hz interrupts
;
PROC SDL_t0ExtremeAsmService
PUBLIC SDL_t0ExtremeAsmService
push ax
mov al,[BYTE PTR cs:pcindicate]
or al,al
jz @@done
push ds
push es
pusha
mov ds,[cs:MyDS]
les di,[pcSound]
mov ax,es
or ax,di
jz @@donereg ; nil pointer
mov bl,[es:di] ; Get the byte
inc [WORD PTR pcSound] ; Increment pointer
and bl,11100000b ; Nuke some of the precision (DEBUG - do this in the table)
xor bh,bh
mov ah,[pcdtab+bx] ; Translate the byte
in al,pcSpeaker
and al,11111100b
or al,ah
out pcSpeaker,al
dec [pcLengthLeft]
jnz @@donereg
mov [WORD PTR pcSound],0 ; We're done with this sample
mov [WORD PTR pcSound+2],0
in al,pcSpeaker
and al,11111100b
out pcSpeaker,al
call SDL_DigitizedDone
@@donereg:
popa
pop es
pop ds
@@done:
inc [cs:extreme]
cmp [cs:extreme],10
jae @@tofast
mov al,20h
out 20h,al
pop ax
iret
@@tofast:
mov [cs:extreme],0
pop ax
; jmp SDL_t0FastAsmService ; Drops through to SDL_t0FastAsmService
ENDP
;
; SDL_t0FastAsmService
; Timer 0 ISR for 700Hz interrupts
;
PROC SDL_t0FastAsmService
PUBLIC SDL_t0FastAsmService
COMMONSTART
inc [count_fx] ; Time to do PC/AdLib effects & time?
cmp [count_fx],5
jae @@dofull
mov ax,[sqActive] ; Is the sequencer active?
or ax,ax
jnz @@dofull
mov ax,[WORD PTR ssSample] ; Is there a sample for the Sound Src?
or ax,[WORD PTR ssSample+2]
jz @@nosave
@@dofull:
pusha
push es
cmp [count_fx],5
jb @@nofx
mov [count_fx],0
DOFX
inc [count_time]
TIME
@@nofx:
mov ax,[sqActive]
or ax,ax
jz @@nosq
mov ax,[sqHackLen]
or ax,ax
jz @@sqdone
les di,[sqHackPtr]
@@sqloop:
mov ax,[WORD PTR sqHackTime+2]
cmp ax,[WORD PTR alTimeCount+2]
ja @@sqdone
mov ax,[WORD PTR sqHackTime]
cmp ax,[WORD PTR alTimeCount]
ja @@sqdone
mov ax,[es:di+2] ; Get time to next event
add ax,[WORD PTR alTimeCount]
mov [WORD PTR sqHackTime],ax
mov ax,[WORD PTR alTimeCount+2]
adc ax,0
mov [WORD PTR sqHackTime+2],ax
mov ax,[es:di] ; Get register/value pair
xor bh,bh
mov bl,ah
xor ah,ah
CALL alOut C,ax,bx
add di,4
mov [WORD PTR sqHackPtr],di
sub [sqHackLen],4
jnz @@sqloop
@@sqdone:
add [WORD PTR alTimeCount],1
adc [WORD PTR alTimeCount+2],0
mov ax,[sqHackLen]
or ax,ax
jnz @@nosq
mov ax,[WORD PTR sqHack] ; Copy pointer
mov [WORD PTR sqHackPtr],ax
mov ax,[WORD PTR sqHack+2]
mov [WORD PTR sqHackPtr+2],ax
mov ax,[sqHackSeqLen] ; Copy length
mov [sqHackLen],ax
mov ax,0
mov [WORD PTR alTimeCount],ax ; Reset time counts
mov [WORD PTR alTimeCount+2],ax
mov [WORD PTR sqHackTime],ax
mov [WORD PTR sqHackTime+2],ax
@@nosq:
les di,[ssSample] ; Get pointer to Sound Source sample
mov ax,es
or ax,di
jz @@ssdone ; If nil, skip this
@@ssloop:
mov dx,[ssStatus] ; Check to see if FIFO has any empty slots
in al,dx
test al,40h
jnz @@ssdone ; Nope - don't push any more data out
mov dx,[ssData]
mov al,[es:di] ; al = *ssSample
out dx,al ; Pump the value out
mov dx,[ssControl] ; Pulse printer select
mov al,[ssOff]
out dx,al
push ax
pop ax
mov al,[ssOn]
out dx,al
push ax ; Delay a short while
pop ax
inc di
mov [WORD PTR ssSample],di ; ssSample++
dec [ssLengthLeft]
jnz @@ssloop
mov [WORD PTR ssSample],0 ; We're done with this sample
mov [WORD PTR ssSample+2],0
call SDL_DigitizedDone
@@ssdone:
COMMONEND
ENDP
;
; SDL_t0SlowAsmService
; Timer 0 ISR for 140Hz interrupts
;
PROC SDL_t0SlowAsmService
PUBLIC SDL_t0SlowAsmService
IF DEBUG
push dx
push ax
mov dx,STATUS_REGISTER_1
in al,dx
mov dx,ATR_INDEX
mov al,ATR_OVERSCAN
out dx,al
mov al,4 ; red
out dx,al
ENDIF
push ds
push ax
mov ds,[cs:MyDS]
inc [count_time]
TIME
mov ax,[WORD PTR pcSound] ; Is there a PC sound effect going?
or ax,[WORD PTR pcSound+2]
jnz @@dofull
mov ax,[WORD PTR alSound] ; Is there an AdLib sound effect going?
or ax,[WORD PTR alSound+2]
jz @@nosave
@@dofull:
pusha
push es
DOFX
COMMONEND
ENDP
END
/* id_vl.c */
#include <dos.h>
#include <alloc.h>
#include <mem.h>
#include <string.h>
#include "id_heads.h"
//
// SC_INDEX is expected to stay at SC_MAPMASK for proper operation
//
unsigned bufferofs;
unsigned displayofs;
......@@ -20,46 +12,22 @@ unsigned ylookup[MAXSCANLINES];
boolean screenfaded;
boolean fastpalette; // if true, use outsb to set
byte palette1[256][3],far palette2[256][3];
//===========================================================================
int VL_VideoID (void);
void VL_SetCRTC (int crtc);
void VL_WaitVBL (int vbls);
byte palette1[256][3], palette2[256][3];
//===========================================================================
void VL_WaitVBL(int vbls)
{
}
/*
=======================
=
= VL_Startup // WOLFENSTEIN HACK
= VL_Startup
=
=======================
*/
static char *ParmStrings[] = {"HIDDENCARD",""};
void VL_Startup (void)
{
int i,videocard;
asm cld;
videocard = VL_VideoID ();
for (i = 1;i < _argc;i++)
if (US_CheckParm(_argv[i],ParmStrings) == 0)
{
videocard = 5;
break;
}
if (videocard != 5)
Quit ("Improper video card! If you really have a VGA card that I am not \n"
"detecting, use the -HIDDENCARD command line parameter!");
}
/*
......@@ -72,40 +40,6 @@ Quit ("Improper video card! If you really have a VGA card that I am not \n"
void VL_Shutdown (void)
{
VL_SetTextMode ();
}
/*
=======================
=
= VL_SetVGAPlaneMode
=
=======================
*/
void VL_SetVGAPlaneMode (void)
{
asm mov ax,0x13
asm int 0x10
VL_DePlaneVGA ();
VGAMAPMASK(15);
VL_SetLineWidth (40);
}
/*
=======================
=
= VL_SetTextMode
=
=======================
*/
void VL_SetTextMode (void)
{
asm mov ax,3
asm int 0x10
}
//===========================================================================
......@@ -122,143 +56,8 @@ asm int 0x10
void VL_ClearVideo (byte color)
{
asm mov dx,GC_INDEX
asm mov al,GC_MODE
asm out dx,al
asm inc dx
asm in al,dx
asm and al,0xfc // write mode 0 to store directly to video
asm out dx,al
asm mov dx,SC_INDEX
asm mov ax,SC_MAPMASK+15*256
asm out dx,ax // write through all four planes
asm mov ax,SCREENSEG
asm mov es,ax
asm mov al,[color]
asm mov ah,al
asm mov cx,0x8000 // 0x8000 words, clearing 8 video bytes/word
asm xor di,di
asm rep stosw
}
/*
=============================================================================
VGA REGISTER MANAGEMENT ROUTINES
=============================================================================
*/
/*
=================
=
= VL_DePlaneVGA
=
=================
*/
void VL_DePlaneVGA (void)
{
//
// change CPU addressing to non linear mode
//
//
// turn off chain 4 and odd/even
//
outportb (SC_INDEX,SC_MEMMODE);
outportb (SC_INDEX+1,(inportb(SC_INDEX+1)&~8)|4);
outportb (SC_INDEX,SC_MAPMASK); // leave this set throughought
//
// turn off odd/even and set write mode 0
//
outportb (GC_INDEX,GC_MODE);
outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~0x13);
//
// turn off chain
//
outportb (GC_INDEX,GC_MISCELLANEOUS);
outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~2);
//
// clear the entire buffer space, because int 10h only did 16 k / plane
//
VL_ClearVideo (0);
//
// change CRTC scanning from doubleword to byte mode, allowing >64k scans
//
outportb (CRTC_INDEX,CRTC_UNDERLINE);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)&~0x40);
outportb (CRTC_INDEX,CRTC_MODE);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)|0x40);
}
//===========================================================================
/*
====================
=
= VL_SetLineWidth
=
= Line witdh is in WORDS, 40 words is normal width for vgaplanegr
=
====================
*/
void VL_SetLineWidth (unsigned width)
{
int i,offset;
//
// set wide virtual screen
//
outport (CRTC_INDEX,CRTC_OFFSET+width*256);
//
// set up lookup tables
//
linewidth = width*2;
offset = 0;
for (i=0;i<MAXSCANLINES;i++)
{
ylookup[i]=offset;
offset += linewidth;
}
}
/*
====================
=
= VL_SetSplitScreen
=
====================
*/
void VL_SetSplitScreen (int linenum)
{
VL_WaitVBL (1);
linenum=linenum*2-1;
outportb (CRTC_INDEX,CRTC_LINECOMPARE);
outportb (CRTC_INDEX+1,linenum % 256);
outportb (CRTC_INDEX,CRTC_OVERFLOW);
outportb (CRTC_INDEX+1, 1+16*(linenum/256));
outportb (CRTC_INDEX,CRTC_MAXSCANLINE);
outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));
}
/*
=============================================================================
......@@ -280,15 +79,6 @@ void VL_SetSplitScreen (int linenum)
void VL_FillPalette (int red, int green, int blue)
{
int i;
outportb (PEL_WRITE_ADR,0);
for (i=0;i<256;i++)
{
outportb (PEL_DATA,red);
outportb (PEL_DATA,green);
outportb (PEL_DATA,blue);
}
}
//===========================================================================
......@@ -301,12 +91,8 @@ void VL_FillPalette (int red, int green, int blue)
=================
*/
void VL_SetColor (int color, int red, int green, int blue)
void VL_SetColor(int color, int red, int green, int blue)
{
outportb (PEL_WRITE_ADR,color);
outportb (PEL_DATA,red);
outportb (PEL_DATA,green);
outportb (PEL_DATA,blue);
}
//===========================================================================
......@@ -319,12 +105,8 @@ void VL_SetColor (int color, int red, int green, int blue)
=================
*/
void VL_GetColor (int color, int *red, int *green, int *blue)
void VL_GetColor(int color, int *red, int *green, int *blue)
{
outportb (PEL_READ_ADR,color);
*red = inportb (PEL_DATA);
*green = inportb (PEL_DATA);
*blue = inportb (PEL_DATA);
}
//===========================================================================
......@@ -340,47 +122,8 @@ void VL_GetColor (int color, int *red, int *green, int *blue)
=================
*/
void VL_SetPalette (byte far *palette)
void VL_SetPalette(byte *palette)
{
int i;
// outportb (PEL_WRITE_ADR,0);
// for (i=0;i<768;i++)
// outportb(PEL_DATA,*palette++);
asm mov dx,PEL_WRITE_ADR
asm mov al,0
asm out dx,al
asm mov dx,PEL_DATA
asm lds si,[palette]
asm test [ss:fastpalette],1
asm jz slowset
//
// set palette fast for cards that can take it
//
asm mov cx,768
asm rep outsb
asm jmp done
//
// set palette slowly for some video cards
//
slowset:
asm mov cx,256
setloop:
asm lodsb
asm out dx,al
asm lodsb
asm out dx,al
asm lodsb
asm out dx,al
asm loop setloop
done:
asm mov ax,ss
asm mov ds,ax
}
......@@ -397,13 +140,8 @@ done:
=================
*/
void VL_GetPalette (byte far *palette)
void VL_GetPalette(byte *palette)
{
int i;
outportb (PEL_READ_ADR,0);
for (i=0;i<768;i++)
*palette++ = inportb(PEL_DATA);
}
......@@ -419,14 +157,14 @@ void VL_GetPalette (byte far *palette)
=================
*/
void VL_FadeOut (int start, int end, int red, int green, int blue, int steps)
void VL_FadeOut(int start, int end, int red, int green, int blue, int steps)
{
int i,j,orig,delta;
byte far *origptr, far *newptr;
byte *origptr, *newptr;
VL_WaitVBL(1);
VL_GetPalette (&palette1[0][0]);
_fmemcpy (palette2,palette1,768);
memcpy (palette2,palette1,768);
//
// fade through intermediate frames
......@@ -469,13 +207,13 @@ void VL_FadeOut (int start, int end, int red, int green, int blue, int steps)
=================
*/
void VL_FadeIn (int start, int end, byte far *palette, int steps)
void VL_FadeIn(int start, int end, byte *palette, int steps)
{
int i,j,delta;
VL_WaitVBL(1);
VL_GetPalette (&palette1[0][0]);
_fmemcpy (&palette2[0][0],&palette1[0][0],sizeof(palette1));
memcpy (&palette2[0][0],&palette1[0][0],sizeof(palette1));
start *= 3;
end = end*3+2;
......@@ -502,34 +240,6 @@ void VL_FadeIn (int start, int end, byte far *palette, int steps)
screenfaded = false;
}
/*
=================
=
= VL_TestPaletteSet
=
= Sets the palette with outsb, then reads it in and compares
= If it compares ok, fastpalette is set to true.
=
=================
*/
void VL_TestPaletteSet (void)
{
int i;
for (i=0;i<768;i++)
palette1[0][i] = i;
fastpalette = true;
VL_SetPalette (&palette1[0][0]);
VL_GetPalette (&palette2[0][0]);
if (_fmemcmp (&palette1[0][0],&palette2[0][0],768))
fastpalette = false;
}
/*
==================
=
......@@ -540,15 +250,8 @@ void VL_TestPaletteSet (void)
void VL_ColorBorder (int color)
{
_AH=0x10;
_AL=1;
_BH=color;
geninterrupt (0x10);
bordercolor = color;
}
/*
=============================================================================
......@@ -569,14 +272,9 @@ byte rightmasks[4] = {1,3,7,15};
=================
*/
void VL_Plot (int x, int y, int color)
void VL_Plot(int x, int y, int color)
{
byte mask;
mask = pixmasks[x&3];
VGAMAPMASK(mask);
*(byte far *)MK_FP(SCREENSEG,bufferofs+(ylookup[y]+(x>>2))) = color;
VGAMAPMASK(15);
*(gfxbuf + 320 * y + x) = color;
}
/*
......@@ -587,43 +285,11 @@ void VL_Plot (int x, int y, int color)
=================
*/
void VL_Hlin (unsigned x, unsigned y, unsigned width, unsigned color)
void VL_Hlin(unsigned x, unsigned y, unsigned width, unsigned color)
{
unsigned xbyte;
byte far *dest;
byte leftmask,rightmask;
int midbytes;
xbyte = x>>2;
leftmask = leftmasks[x&3];
rightmask = rightmasks[(x+width-1)&3];
midbytes = ((x+width+3)>>2) - xbyte - 2;
dest = MK_FP(SCREENSEG,bufferofs+ylookup[y]+xbyte);
if (midbytes<0)
{
// all in one byte
VGAMAPMASK(leftmask&rightmask);
*dest = color;
VGAMAPMASK(15);
return;
}
VGAMAPMASK(leftmask);
*dest++ = color;
VGAMAPMASK(15);
_fmemset (dest,color,midbytes);
dest+=midbytes;
VGAMAPMASK(rightmask);
*dest = color;
VGAMAPMASK(15);
memset(gfxbuf + 320 * y + x, color, width);
}
/*
=================
=
......@@ -634,23 +300,13 @@ void VL_Hlin (unsigned x, unsigned y, unsigned width, unsigned color)
void VL_Vlin (int x, int y, int height, int color)
{
byte far *dest,mask;
mask = pixmasks[x&3];
VGAMAPMASK(mask);
dest = MK_FP(SCREENSEG,bufferofs+ylookup[y]+(x>>2));
while (height--)
{
*dest = color;
dest += linewidth;
byte *ptr = gfxbuf + 320 * y + x;
while (height--) {
*ptr = color;
ptr += 320;
}
VGAMAPMASK(15);
}
/*
=================
=
......@@ -659,48 +315,13 @@ void VL_Vlin (int x, int y, int height, int color)
=================
*/
void VL_Bar (int x, int y, int width, int height, int color)
void VL_Bar(int x, int y, int width, int height, int color)
{
byte far *dest;
byte leftmask,rightmask;
int midbytes,linedelta;
leftmask = leftmasks[x&3];
rightmask = rightmasks[(x+width-1)&3];
midbytes = ((x+width+3)>>2) - (x>>2) - 2;
linedelta = linewidth-(midbytes+1);
dest = MK_FP(SCREENSEG,bufferofs+ylookup[y]+(x>>2));
if (midbytes<0)
{
// all in one byte
VGAMAPMASK(leftmask&rightmask);
while (height--)
{
*dest = color;
dest += linewidth;
}
VGAMAPMASK(15);
return;
}
while (height--)
{
VGAMAPMASK(leftmask);
*dest++ = color;
VGAMAPMASK(15);
_fmemset (dest,color,midbytes);
dest+=midbytes;
VGAMAPMASK(rightmask);
*dest = color;
dest+=linedelta;
byte *ptr = gfxbuf + 320 * y + x;
while (height--) {
memset(ptr, color, width);
ptr += 320;
}
VGAMAPMASK(15);
}
/*
......@@ -719,8 +340,9 @@ void VL_Bar (int x, int y, int width, int height, int color)
=================
*/
void VL_MemToLatch (byte far *source, int width, int height, unsigned dest)
void VL_MemToLatch (byte *source, int width, int height, word dest)
{
#if 0
unsigned count;
byte plane,mask;
......@@ -742,6 +364,7 @@ asm mov ds,ax
source+= count;
}
#endif
}
......@@ -758,25 +381,13 @@ asm mov ds,ax
=================
*/
void VL_MemToScreen (byte far *source, int width, int height, int x, int y)
void VL_MemToScreen(byte *source, int width, int height, int x, int y)
{
byte far *screen,far *dest,mask;
int plane;
width>>=2;
dest = MK_FP(SCREENSEG,bufferofs+ylookup[y]+(x>>2) );
mask = 1 << (x&3);
for (plane = 0; plane<4; plane++)
{
VGAMAPMASK(mask);
mask <<= 1;
if (mask == 16)
mask = 1;
screen = dest;
for (y=0;y<height;y++,screen+=linewidth,source+=width)
memcpy (screen,source,width);
byte *ptr = gfxbuf + 320 * y + x;
while(height--) {
memcpy(ptr, source, width);
source += width;
ptr += 320;
}
}
......@@ -792,6 +403,7 @@ void VL_MemToScreen (byte far *source, int width, int height, int x, int y)
void VL_LatchToScreen (unsigned source, int width, int height, int x, int y)
{
#if 0
VGAWRITEMODE(1);
VGAMAPMASK(15);
......@@ -823,6 +435,7 @@ asm mov ax,ss
asm mov ds,ax
VGAWRITEMODE(0);
#endif
}
/* ======================================================================== */
......
......@@ -138,7 +138,7 @@ void VL_Bar (int x, int y, int width, int height, int color);
void VL_MungePic (byte *source, unsigned width, unsigned height);
void VL_DrawPicBare (int x, int y, byte *pic, int width, int height);
void VL_MemToLatch (byte *source, int width, int height, unsigned dest);
void VL_MemToLatch (byte *source, int width, int height, word dest);
void VL_ScreenToScreen (unsigned source, unsigned dest,int width, int height);
void VL_MemToScreen (byte *source, int width, int height, int x, int y);
......
; ID_VL.ASM
IDEAL
MODEL MEDIUM,C
INCLUDE 'ID_VL.EQU'
SCREENSEG = 0a000h
DATASEG
EXTRN TimeCount:WORD ; incremented every 70th of a second
EXTRN linewidth:WORD
starttime dw ?
CODESEG
;===========================================================================
;==============
;
; VL_WaitVBL ******** NEW *********
;
; Wait for the vertical retrace (returns before the actual vertical sync)
;
;==============
PROC VL_WaitVBL num:WORD
PUBLIC VL_WaitVBL
@@wait:
mov dx,STATUS_REGISTER_1
mov cx,[num]
;
; wait for a display signal to make sure the raster isn't in the middle
; of a sync
;
@@waitnosync:
in al,dx
test al,8
jnz @@waitnosync
@@waitsync:
in al,dx
test al,8
jz @@waitsync
loop @@waitnosync
ret
ENDP
;===========================================================================
;==============
;
; VL_SetCRTC
;
;==============
PROC VL_SetCRTC crtc:WORD
PUBLIC VL_SetCRTC
;
; wait for a display signal to make sure the raster isn't in the middle
; of a sync
;
cli
mov dx,STATUS_REGISTER_1
@@waitdisplay:
in al,dx
test al,1 ;1 = display is disabled (HBL / VBL)
jnz @@waitdisplay
;
; set CRTC start
;
; for some reason, my XT's EGA card doesn't like word outs to the CRTC
; index...
;
mov cx,[crtc]
mov dx,CRTC_INDEX
mov al,0ch ;start address high register
out dx,al
inc dx
mov al,ch
out dx,al
dec dx
mov al,0dh ;start address low register
out dx,al
mov al,cl
inc dx
out dx,al
sti
ret
ENDP
;===========================================================================
;==============
;
; VL_SetScreen
;
;==============
PROC VL_SetScreen crtc:WORD, pel:WORD
PUBLIC VL_SetScreen
mov cx,[timecount] ; if timecount goes up by two, the retrace
add cx,2 ; period was missed (an interrupt covered it)
mov dx,STATUS_REGISTER_1
;
; wait for a display signal to make sure the raster isn't in the middle
; of a sync
;
@@waitdisplay:
in al,dx
test al,1 ;1 = display is disabled (HBL / VBL)
jnz @@waitdisplay
@@loop:
sti
jmp $+2
cli
cmp [timecount],cx ; will only happen if an interrupt is
jae @@setcrtc ; straddling the entire retrace period
;
; when several succesive display not enableds occur,
; the bottom of the screen has been hit
;
in al,dx
test al,8
jnz @@waitdisplay
test al,1
jz @@loop
in al,dx
test al,8
jnz @@waitdisplay
test al,1
jz @@loop
in al,dx
test al,8
jnz @@waitdisplay
test al,1
jz @@loop
in al,dx
test al,8
jnz @@waitdisplay
test al,1
jz @@loop
in al,dx
test al,8
jnz @@waitdisplay
test al,1
jz @@loop
@@setcrtc:
;
; set CRTC start
;
; for some reason, my XT's EGA card doesn't like word outs to the CRTC
; index...
;
mov cx,[crtc]
mov dx,CRTC_INDEX
mov al,0ch ;start address high register
out dx,al
inc dx
mov al,ch
out dx,al
dec dx
mov al,0dh ;start address low register
out dx,al
mov al,cl
inc dx
out dx,al
;
; set horizontal panning
;
mov dx,ATR_INDEX
mov al,ATR_PELPAN or 20h
out dx,al
jmp $+2
mov al,[BYTE pel] ;pel pan value
out dx,al
sti
ret
ENDP
;===========================================================================
;============================================================================
;
; VL_ScreenToScreen
;
; Basic block copy routine. Copies one block of screen memory to another,
; using write mode 1 (sets it and returns with write mode 0). bufferofs is
; NOT accounted for.
;
;============================================================================
PROC VL_ScreenToScreen source:WORD, dest:WORD, wide:WORD, height:WORD
PUBLIC VL_ScreenToScreen
USES SI,DI
pushf
cli
mov dx,SC_INDEX
mov ax,SC_MAPMASK+15*256
out dx,ax
mov dx,GC_INDEX
mov al,GC_MODE
out dx,al
inc dx
in al,dx
and al,NOT 3
or al,1
out dx,al
popf
mov bx,[linewidth]
sub bx,[wide]
mov ax,SCREENSEG
mov es,ax
mov ds,ax
mov si,[source]
mov di,[dest] ;start at same place in all planes
mov dx,[height] ;scan lines to draw
mov ax,[wide]
@@lineloop:
mov cx,ax
rep movsb
add si,bx
add di,bx
dec dx
jnz @@lineloop
mov dx,GC_INDEX+1
in al,dx
and al,NOT 3
out dx,al
mov ax,ss
mov ds,ax ;restore turbo's data segment
ret
ENDP
;===========================================================================
MASM
;
;
; Name: VL_VideoID
;
; Function: Detects the presence of various video subsystems
;
; int VideoID;
;
; Subsystem ID values:
; 0 = (none)
; 1 = MDA
; 2 = CGA
; 3 = EGA
; 4 = MCGA
; 5 = VGA
; 80h = HGC
; 81h = HGC+
; 82h = Hercules InColor
;
;
;
;
; Equates
;
;
VIDstruct STRUC ; corresponds to C data structure
Video0Type DB ? ; first subsystem type
Display0Type DB ? ; display attached to first subsystem
Video1Type DB ? ; second subsystem type
Display1Type DB ? ; display attached to second subsystem
VIDstruct ENDS
Device0 EQU word ptr Video0Type[di]
Device1 EQU word ptr Video1Type[di]
MDA EQU 1 ; subsystem types
CGA EQU 2
EGA EQU 3
MCGA EQU 4
VGA EQU 5
HGC EQU 80h
HGCPlus EQU 81h
InColor EQU 82h
MDADisplay EQU 1 ; display types
CGADisplay EQU 2
EGAColorDisplay EQU 3
PS2MonoDisplay EQU 4
PS2ColorDisplay EQU 5
TRUE EQU 1
FALSE EQU 0
;
;
; Program
;
;
Results VIDstruct <> ;results go here!
EGADisplays DB CGADisplay ; 0000b, 0001b (EGA switch values)
DB EGAColorDisplay ; 0010b, 0011b
DB MDADisplay ; 0100b, 0101b
DB CGADisplay ; 0110b, 0111b
DB EGAColorDisplay ; 1000b, 1001b
DB MDADisplay ; 1010b, 1011b
DCCtable DB 0,0 ; translate table for INT 10h func 1Ah
DB MDA,MDADisplay
DB CGA,CGADisplay
DB 0,0
DB EGA,EGAColorDisplay
DB EGA,MDADisplay
DB 0,0
DB VGA,PS2MonoDisplay
DB VGA,PS2ColorDisplay
DB 0,0
DB MCGA,EGAColorDisplay
DB MCGA,PS2MonoDisplay
DB MCGA,PS2ColorDisplay
TestSequence DB TRUE ; this list of flags and addresses
DW FindPS2 ; determines the order in which this
; program looks for the various
EGAflag DB ? ; subsystems
DW FindEGA
CGAflag DB ?
DW FindCGA
Monoflag DB ?
DW FindMono
NumberOfTests EQU ($-TestSequence)/3
PUBLIC VL_VideoID
VL_VideoID PROC
push bp ; preserve caller registers
mov bp,sp
push ds
push si
push di
push cs
pop ds
ASSUME DS:@Code
; initialize the data structure that will contain the results
lea di,Results ; DS:DI -> start of data structure
mov Device0,0 ; zero these variables
mov Device1,0
; look for the various subsystems using the subroutines whose addresses are
; tabulated in TestSequence; each subroutine sets flags in TestSequence
; to indicate whether subsequent subroutines need to be called
mov byte ptr CGAflag,TRUE
mov byte ptr EGAflag,TRUE
mov byte ptr Monoflag,TRUE
mov cx,NumberOfTests
mov si,offset TestSequence
@@L01: lodsb ; AL := flag
test al,al
lodsw ; AX := subroutine address
jz @@L02 ; skip subroutine if flag is false
push si
push cx
call ax ; call subroutine to detect subsystem
pop cx
pop si
@@L02: loop @@L01
; determine which subsystem is active
call FindActive
mov al,Results.Video0Type
mov ah,0 ; was: Results.Display0Type
pop di ; restore caller registers and return
pop si
pop ds
mov sp,bp
pop bp
ret
VL_VideoID ENDP
;
; FindPS2
;
; This subroutine uses INT 10H function 1Ah to determine the video BIOS
; Display Combination Code (DCC) for each video subsystem present.
;
FindPS2 PROC near
mov ax,1A00h
int 10h ; call video BIOS for info
cmp al,1Ah
jne @@L13 ; exit if function not supported (i.e.,
; no MCGA or VGA in system)
; convert BIOS DCCs into specific subsystems & displays
mov cx,bx
xor bh,bh ; BX := DCC for active subsystem
or ch,ch
jz @@L11 ; jump if only one subsystem present
mov bl,ch ; BX := inactive DCC
add bx,bx
mov ax,[bx+offset DCCtable]
mov Device1,ax
mov bl,cl
xor bh,bh ; BX := active DCC
@@L11: add bx,bx
mov ax,[bx+offset DCCtable]
mov Device0,ax
; reset flags for subsystems that have been ruled out
mov byte ptr CGAflag,FALSE
mov byte ptr EGAflag,FALSE
mov byte ptr Monoflag,FALSE
lea bx,Video0Type[di] ; if the BIOS reported an MDA ...
cmp byte ptr [bx],MDA
je @@L12
lea bx,Video1Type[di]
cmp byte ptr [bx],MDA
jne @@L13
@@L12: mov word ptr [bx],0 ; ... Hercules can't be ruled out
mov byte ptr Monoflag,TRUE
@@L13: ret
FindPS2 ENDP
;
; FindEGA
;
; Look for an EGA. This is done by making a call to an EGA BIOS function
; which doesn't exist in the default (MDA, CGA) BIOS.
FindEGA PROC near ; Caller: AH = flags
; Returns: AH = flags
; Video0Type and
; Display0Type updated
mov bl,10h ; BL := 10h (return EGA info)
mov ah,12h ; AH := INT 10H function number
int 10h ; call EGA BIOS for info
; if EGA BIOS is present,
; BL <> 10H
; CL = switch setting
cmp bl,10h
je @@L22 ; jump if EGA BIOS not present
mov al,cl
shr al,1 ; AL := switches/2
mov bx,offset EGADisplays
xlat ; determine display type from switches
mov ah,al ; AH := display type
mov al,EGA ; AL := subystem type
call FoundDevice
cmp ah,MDADisplay
je @@L21 ; jump if EGA has a monochrome display
mov CGAflag,FALSE ; no CGA if EGA has color display
jmp short @@L22
@@L21: mov Monoflag,FALSE ; EGA has a mono display, so MDA and
; Hercules are ruled out
@@L22: ret
FindEGA ENDP
;
; FindCGA
;
; This is done by looking for the CGA's 6845 CRTC at I/O port 3D4H.
;
FindCGA PROC near ; Returns: VIDstruct updated
mov dx,3D4h ; DX := CRTC address port
call Find6845
jc @@L31 ; jump if not present
mov al,CGA
mov ah,CGADisplay
call FoundDevice
@@L31: ret
FindCGA ENDP
;
; FindMono
;
; This is done by looking for the MDA's 6845 CRTC at I/O port 3B4H. If
; a 6845 is found, the subroutine distinguishes between an MDA
; and a Hercules adapter by monitoring bit 7 of the CRT Status byte.
; This bit changes on Hercules adapters but does not change on an MDA.
;
; The various Hercules adapters are identified by bits 4 through 6 of
; the CRT Status value:
;
; 000b = HGC
; 001b = HGC+
; 101b = InColor card
;
FindMono PROC near ; Returns: VIDstruct updated
mov dx,3B4h ; DX := CRTC address port
call Find6845
jc @@L44 ; jump if not present
mov dl,0BAh ; DX := 3BAh (status port)
in al,dx
and al,80h
mov ah,al ; AH := bit 7 (vertical sync on HGC)
mov cx,8000h ; do this 32768 times
@@L41: in al,dx
and al,80h ; isolate bit 7
cmp ah,al
loope @@L41 ; wait for bit 7 to change
jne @@L42 ; if bit 7 changed, it's a Hercules
mov al,MDA ; if bit 7 didn't change, it's an MDA
mov ah,MDADisplay
call FoundDevice
jmp short @@L44
@@L42: in al,dx
mov dl,al ; DL := value from status port
and dl,01110000b ; mask bits 4 thru 6
mov ah,MDADisplay ; assume it's a monochrome display
mov al,HGCPlus ; look for an HGC+
cmp dl,00010000b
je @@L43 ; jump if it's an HGC+
mov al,HGC ; look for an InColor card or HGC
cmp dl,01010000b
jne @@L43 ; jump if it's not an InColor card
mov al,InColor ; it's an InColor card
mov ah,EGAColorDisplay
@@L43: call FoundDevice
@@L44: ret
FindMono ENDP
;
; Find6845
;
; This routine detects the presence of the CRTC on a MDA, CGA or HGC.
; The technique is to write and read register 0Fh of the chip (cursor
; low). If the same value is read as written, assume the chip is
; present at the specified port addr.
;
Find6845 PROC near ; Caller: DX = port addr
; Returns: cf set if not present
mov al,0Fh
out dx,al ; select 6845 reg 0Fh (Cursor Low)
inc dx
in al,dx ; AL := current Cursor Low value
mov ah,al ; preserve in AH
mov al,66h ; AL := arbitrary value
out dx,al ; try to write to 6845
mov cx,100h
@@L51: loop @@L51 ; wait for 6845 to respond
in al,dx
xchg ah,al ; AH := returned value
; AL := original value
out dx,al ; restore original value
cmp ah,66h ; test whether 6845 responded
je @@L52 ; jump if it did (cf is reset)
stc ; set carry flag if no 6845 present
@@L52: ret
Find6845 ENDP
;
; FindActive
;
; This subroutine stores the currently active device as Device0. The
; current video mode determines which subsystem is active.
;
FindActive PROC near
cmp word ptr Device1,0
je @@L63 ; exit if only one subsystem
cmp Video0Type[di],4 ; exit if MCGA or VGA present
jge @@L63 ; (INT 10H function 1AH
cmp Video1Type[di],4 ; already did the work)
jge @@L63
mov ah,0Fh
int 10h ; AL := current BIOS video mode
and al,7
cmp al,7 ; jump if monochrome
je @@L61 ; (mode 7 or 0Fh)
cmp Display0Type[di],MDADisplay
jne @@L63 ; exit if Display0 is color
jmp short @@L62
@@L61: cmp Display0Type[di],MDADisplay
je @@L63 ; exit if Display0 is monochrome
@@L62: mov ax,Device0 ; make Device0 currently active
xchg ax,Device1
mov Device0,ax
@@L63: ret
FindActive ENDP
;
; FoundDevice
;
; This routine updates the list of subsystems.
;
FoundDevice PROC near ; Caller: AH = display #
; AL = subsystem #
; Destroys: BX
lea bx,Video0Type[di]
cmp byte ptr [bx],0
je @@L71 ; jump if 1st subsystem
lea bx,Video1Type[di] ; must be 2nd subsystem
@@L71: mov [bx],ax ; update list entry
ret
FoundDevice ENDP
IDEAL
END
......@@ -686,29 +686,13 @@ void SignonScreen (void) // VGA version
{
unsigned segstart,seglength;
VL_SetVGAPlaneMode ();
VL_TestPaletteSet ();
VL_SetPalette (&gamepal);
if (!virtualreality)
{
VW_SetScreen(0x8000,0);
VL_MungePic (&introscn,320,200);
VL_MemToScreen (&introscn,320,200,0,0);
VW_SetScreen(0,0);
}
//
// reclaim the memory from the linked in signon screen
//
segstart = FP_SEG(&introscn);
seglength = 64000/16;
if (FP_OFF(&introscn))
{
segstart++;
seglength--;
}
MML_UseSpace (segstart,seglength);
}
......
......@@ -625,18 +625,6 @@ void CP_ReadThis(void)
////////////////////////////////////////////////////////////////////
void BossKey(void)
{
SD_MusicOff();
_AX = 3;
geninterrupt(0x10);
printf("C>");
while (!Keyboard[sc_Escape])
IN_ClearKeysDown();
SD_MusicOn();
VL_SetVGAPlaneMode ();
VL_TestPaletteSet ();
VL_SetPalette (&gamepal);
LoadLatchMem();
}
#endif
#endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment