1296 lines
27 KiB
C
1296 lines
27 KiB
C
/* Catacomb 3-D Source Code
|
|
* Copyright (C) 1993-2014 Flat Rock Software
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
//
|
|
// ID Engine
|
|
// ID_SD.c - Sound Manager
|
|
// v1.1d1
|
|
// By Jason Blochowiak
|
|
//
|
|
|
|
//
|
|
// This module handles dealing with generating sound on the appropriate
|
|
// hardware
|
|
//
|
|
// Depends on: User Mgr (for parm checking)
|
|
//
|
|
// Globals:
|
|
// For User Mgr:
|
|
// SoundSourcePresent - Sound Source thingie present?
|
|
// SoundBlasterPresent - SoundBlaster card present?
|
|
// AdLibPresent - AdLib card present?
|
|
// SoundMode - What device is used for sound effects
|
|
// (Use SM_SetSoundMode() to set)
|
|
// MusicMode - What device is used for music
|
|
// (Use SM_SetMusicMode() to set)
|
|
// For Cache Mgr:
|
|
// NeedsDigitized - load digitized sounds?
|
|
// NeedsMusic - load music?
|
|
//
|
|
|
|
#pragma hdrstop // Wierdo thing with MUSE
|
|
|
|
#include <dos.h>
|
|
|
|
#ifdef _MUSE_ // Will be defined in ID_Types.h
|
|
#include "ID_SD.h"
|
|
#else
|
|
#include "ID_HEADS.H"
|
|
#endif
|
|
#pragma hdrstop
|
|
#pragma warn -pia
|
|
|
|
#define SDL_SoundFinished() {SoundNumber = SoundPriority = 0;}
|
|
|
|
// Macros for AdLib stuff
|
|
#define selreg(n) outportb(0x388,n)
|
|
#define writereg(n) outportb(0x389,n)
|
|
#define readstat() inportb(0x388)
|
|
|
|
// Global variables
|
|
boolean SoundSourcePresent,SoundBlasterPresent,AdLibPresent,
|
|
NeedsDigitized,NeedsMusic;
|
|
SDMode SoundMode;
|
|
SMMode MusicMode;
|
|
longword TimeCount;
|
|
word HackCount;
|
|
word *SoundTable; // Really * _seg *SoundTable, but that don't work
|
|
boolean ssIsTandy;
|
|
word ssPort = 2;
|
|
|
|
// Internal variables
|
|
static boolean SD_Started;
|
|
static boolean TimerDone;
|
|
static word TimerVal,TimerDelay10,TimerDelay25,TimerDelay100;
|
|
static longword TimerDivisor,TimerCount;
|
|
static char *ParmStrings[] =
|
|
{
|
|
"noal",
|
|
nil
|
|
};
|
|
static void (*SoundUserHook)(void);
|
|
static word SoundNumber,SoundPriority;
|
|
static void interrupt (*t0OldService)(void);
|
|
//static word t0CountTable[] = {8,8,8,8,40,40};
|
|
static long LocalTime;
|
|
|
|
// PC Sound variables
|
|
static byte pcLastSample,far *pcSound;
|
|
static longword pcLengthLeft;
|
|
static word pcSoundLookup[255];
|
|
|
|
// AdLib variables
|
|
static boolean alNoCheck;
|
|
static byte far *alSound;
|
|
static word alBlock;
|
|
static longword alLengthLeft;
|
|
static longword alTimeCount;
|
|
static Instrument alZeroInst;
|
|
|
|
// This table maps channel numbers to carrier and modulator op cells
|
|
static byte carriers[9] = { 3, 4, 5,11,12,13,19,20,21},
|
|
modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},
|
|
// This table maps percussive voice numbers to op cells
|
|
pcarriers[5] = {19,0xff,0xff,0xff,0xff},
|
|
pmodifiers[5] = {16,17,18,20,21};
|
|
|
|
// Sequencer variables
|
|
static boolean sqActive;
|
|
static word alFXReg;
|
|
static ActiveTrack *tracks[sqMaxTracks],
|
|
mytracks[sqMaxTracks];
|
|
static word sqMode,sqFadeStep;
|
|
static word far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;
|
|
static long sqHackTime;
|
|
|
|
// Internal routines
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
outportb(0x43,0x36); // Change timer 0
|
|
outportb(0x40,speed);
|
|
outportb(0x40,speed >> 8);
|
|
TimerDivisor = speed;
|
|
#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)
|
|
{
|
|
SDL_SetTimer0(1192030 / ints);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_TimingService() - Used by SDL_InitDelay() to determine a timing
|
|
// value for the current system that we're running on
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static void interrupt
|
|
SDL_TimingService(void)
|
|
{
|
|
TimerVal = _CX;
|
|
TimerDone++;
|
|
|
|
outportb(0x20,0x20); // Ack interrupt
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_InitDelay() - Sets up TimerDelay's for SDL_Delay()
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static void
|
|
SDL_InitDelay(void)
|
|
{
|
|
int i;
|
|
word timer;
|
|
|
|
setvect(8,SDL_TimingService); // Set to my timer 0 ISR
|
|
|
|
SDL_SetIntsPerSec(1000); // Time 1ms
|
|
|
|
for (i = 0,timer = 0;i < 10;i++) // Do timing test 10 times
|
|
{
|
|
asm xor dx,dx // Zero DX
|
|
asm mov cx,0xffff // Put starting value in CX
|
|
asm mov [TimerDone],cx // TimerDone = false - 1
|
|
startloop:
|
|
asm or [TimerDone],0
|
|
asm jnz startloop // Make sure we're at the start
|
|
loop:
|
|
asm test [TimerDone],1 // See if TimerDone flag got hit
|
|
asm jnz done // Yep - drop out of the loop
|
|
asm loop loop
|
|
done:
|
|
|
|
if (0xffff - TimerVal > timer)
|
|
timer = 0xffff - TimerVal;
|
|
}
|
|
timer += timer / 2; // Use some slop
|
|
TimerDelay10 = timer / (1000 / 10);
|
|
TimerDelay25 = timer / (1000 / 25);
|
|
TimerDelay100 = timer / (1000 / 100);
|
|
|
|
SDL_SetTimer0(0); // Reset timer 0
|
|
|
|
setvect(8,t0OldService); // Set back to old ISR
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_Delay() - Delays the specified amount of time
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static void
|
|
SDL_Delay(word delay)
|
|
{
|
|
if (!delay)
|
|
return;
|
|
|
|
asm mov cx,[delay]
|
|
loop:
|
|
asm test [TimerDone],0 // Useless code - just for timing equivilency
|
|
asm jnz done
|
|
asm loop loop
|
|
done:;
|
|
}
|
|
|
|
//
|
|
// PC Sound code
|
|
//
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_PCPlaySound() - Plays the specified sound on the PC speaker
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
#ifdef _MUSE_
|
|
void
|
|
#else
|
|
static void
|
|
#endif
|
|
SDL_PCPlaySound(PCSound far *sound)
|
|
{
|
|
asm pushf
|
|
asm cli
|
|
|
|
pcLastSample = -1;
|
|
pcLengthLeft = sound->common.length;
|
|
pcSound = sound->data;
|
|
|
|
asm popf
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
#ifdef _MUSE_
|
|
void
|
|
#else
|
|
static void
|
|
#endif
|
|
SDL_PCStopSound(void)
|
|
{
|
|
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
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_PCService() - Handles playing the next sample in a PC sound
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static void
|
|
SDL_PCService(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();
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_ShutPC() - Turns off the pc speaker
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
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
|
|
}
|
|
|
|
// 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
|
|
#if 0
|
|
SDL_Delay(TimerDelay10);
|
|
#else
|
|
asm in al, dx
|
|
asm in al, dx
|
|
asm in al, dx
|
|
asm in al, dx
|
|
asm in al, dx
|
|
asm in al, dx
|
|
#endif
|
|
|
|
asm mov dx,0x389
|
|
asm mov al,[b]
|
|
asm out dx,al
|
|
|
|
asm popf
|
|
|
|
#if 0
|
|
SDL_Delay(TimerDelay25);
|
|
#else
|
|
asm mov dx,0x388
|
|
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
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_SetInstrument() - Puts an instrument into a generator
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static void
|
|
SDL_SetInstrument(int track,int which,Instrument far *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
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
#ifdef _MUSE_
|
|
void
|
|
#else
|
|
static void
|
|
#endif
|
|
SDL_ALStopSound(void)
|
|
{
|
|
asm pushf
|
|
asm cli
|
|
|
|
(long)alSound = 0;
|
|
alOut(alFreqH + 0,0);
|
|
|
|
asm popf
|
|
}
|
|
|
|
static void
|
|
SDL_AlSetFXInst(Instrument far *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);
|
|
// DEBUG!!! - I just put this in
|
|
// alOut(alFeedCon,inst->nConn);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_ALPlaySound() - Plays the specified sound on the AdLib card
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
#ifdef _MUSE_
|
|
void
|
|
#else
|
|
static void
|
|
#endif
|
|
SDL_ALPlaySound(AdLibSound far *sound)
|
|
{
|
|
Instrument far *inst;
|
|
|
|
SDL_ALStopSound();
|
|
|
|
asm pushf
|
|
asm cli
|
|
|
|
alLengthLeft = sound->common.length;
|
|
alSound = sound->data;
|
|
alBlock = ((sound->block & 7) << 2) | 0x20;
|
|
inst = &sound->inst;
|
|
|
|
if (!(inst->mSus | inst->cSus))
|
|
{
|
|
asm popf
|
|
Quit("SDL_ALPlaySound() - Bad instrument");
|
|
}
|
|
|
|
SDL_AlSetFXInst(inst);
|
|
|
|
asm popf
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_ALSoundService() - Plays the next sample out through the AdLib card
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static 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();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SDL_SelectMeasure() - sets up sequencing variables for a given track
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
static void
|
|
SDL_SelectMeasure(ActiveTrack *track)
|
|
{
|
|
track->seq = track->moods[track->mood];
|
|
track->nextevent = 0;
|
|
}
|
|
#endif
|
|
|
|
static 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 far *)sqHack;
|
|
sqHackLen = sqHackSeqLen;
|
|
alTimeCount = sqHackTime = 0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
SDL_Delay(TimerDelay100);
|
|
|
|
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);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 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,4 // red
|
|
asm out dx,al
|
|
#endif
|
|
|
|
HackCount++;
|
|
|
|
if (MusicMode == smm_AdLib)
|
|
{
|
|
SDL_ALService();
|
|
if (!(++count & 7))
|
|
{
|
|
LocalTime++;
|
|
TimeCount++;
|
|
if (SoundUserHook)
|
|
SoundUserHook();
|
|
}
|
|
if (!(count & 3))
|
|
{
|
|
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 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
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
static void
|
|
SDL_SetTimerSpeed(void)
|
|
{
|
|
word rate;
|
|
|
|
if (MusicMode == smm_AdLib)
|
|
rate = TickBase * 8;
|
|
else
|
|
rate = TickBase * 2;
|
|
SDL_SetIntsPerSec(rate);
|
|
}
|
|
|
|
// Public routines
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SD_SetSoundMode() - Sets which sound hardware to use for sound effects
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
boolean
|
|
SD_SetSoundMode(SDMode mode)
|
|
{
|
|
boolean result;
|
|
word tableoffset;
|
|
|
|
SD_StopSound();
|
|
|
|
#ifndef _MUSE_
|
|
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;
|
|
default:
|
|
result = false;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
if (result && (mode != SoundMode))
|
|
{
|
|
SDL_ShutDevice();
|
|
SoundMode = mode;
|
|
#ifndef _MUSE_
|
|
SoundTable = (word *)(&audiosegs[tableoffset]);
|
|
#endif
|
|
SDL_StartDevice();
|
|
}
|
|
|
|
SDL_SetTimerSpeed();
|
|
|
|
return(result);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SD_SetMusicMode() - sets the device to use for background music
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
boolean
|
|
SD_SetMusicMode(SMMode mode)
|
|
{
|
|
boolean result;
|
|
|
|
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;
|
|
default:
|
|
result = false;
|
|
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;
|
|
|
|
ssIsTandy = false;
|
|
alNoCheck = false;
|
|
#ifndef _MUSE_
|
|
for (i = 1;i < _argc;i++)
|
|
{
|
|
switch (US_CheckParm(_argv[i],ParmStrings))
|
|
{
|
|
case 0: // No AdLib detection
|
|
alNoCheck = true;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SoundUserHook = 0;
|
|
|
|
t0OldService = getvect(8); // Get old timer 0 ISR
|
|
|
|
SDL_InitDelay(); // SDL_InitDelay() uses t0OldService
|
|
|
|
setvect(8,SDL_t0Service); // Set to my timer 0 ISR
|
|
LocalTime = TimeCount = alTimeCount = 0;
|
|
|
|
SD_SetSoundMode(sdm_Off);
|
|
SD_SetMusicMode(smm_Off);
|
|
|
|
if (!alNoCheck)
|
|
AdLibPresent = SDL_DetectAdLib();
|
|
|
|
for (i = 0;i < 255;i++)
|
|
pcSoundLookup[i] = i * 60;
|
|
|
|
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();
|
|
SDL_ShutDevice();
|
|
SDL_CleanDevice();
|
|
|
|
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_PlaySound() - plays the specified sound on the appropriate hardware
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
void
|
|
SD_PlaySound(soundnames sound)
|
|
{
|
|
SoundCommon far *s;
|
|
|
|
if ((SoundMode == sdm_Off) || (sound == -1))
|
|
return;
|
|
|
|
s = MK_FP(SoundTable[sound],0);
|
|
if (!s)
|
|
Quit("SD_PlaySound() - Uncached sound");
|
|
if (!s->length)
|
|
Quit("SD_PlaySound() - Zero length sound");
|
|
if (s->priority < SoundPriority)
|
|
return;
|
|
|
|
switch (SoundMode)
|
|
{
|
|
case sdm_PC:
|
|
SDL_PCPlaySound((void far *)s);
|
|
break;
|
|
case sdm_AdLib:
|
|
SDL_ALPlaySound((void far *)s);
|
|
break;
|
|
}
|
|
|
|
SoundNumber = sound;
|
|
SoundPriority = s->priority;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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)
|
|
{
|
|
switch (SoundMode)
|
|
{
|
|
case sdm_PC:
|
|
SDL_PCStopSound();
|
|
break;
|
|
case sdm_AdLib:
|
|
SDL_ALStopSound();
|
|
break;
|
|
}
|
|
|
|
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 far *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);
|
|
}
|