summaryrefslogtreecommitdiffstats
path: root/apps/plugins/sdl/progs/duke3d/Game/src/audiolib/blaster.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/duke3d/Game/src/audiolib/blaster.c')
-rw-r--r--apps/plugins/sdl/progs/duke3d/Game/src/audiolib/blaster.c2330
1 files changed, 2330 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/duke3d/Game/src/audiolib/blaster.c b/apps/plugins/sdl/progs/duke3d/Game/src/audiolib/blaster.c
new file mode 100644
index 0000000000..8ff3935d17
--- /dev/null
+++ b/apps/plugins/sdl/progs/duke3d/Game/src/audiolib/blaster.c
@@ -0,0 +1,2330 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+/**********************************************************************
+ module: BLASTER.C
+
+ author: James R. Dose
+ date: February 4, 1994
+
+ Low level routines to support Sound Blaster, Sound Blaster Pro,
+ Sound Blaster 16, and compatible sound cards.
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#include <dos.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "dpmi.h"
+#include "dma.h"
+#include "irq.h"
+#include "blaster.h"
+#include "_blaster.h"
+
+#define USESTACK
+
+const int BLASTER_Interrupts[ BLASTER_MaxIrq + 1 ] =
+ {
+ INVALID, INVALID, 0xa, 0xb,
+ INVALID, 0xd, INVALID, 0xf,
+ INVALID, INVALID, 0x72, 0x73,
+ 0x74, INVALID, INVALID, 0x77
+ };
+
+const int BLASTER_SampleSize[ BLASTER_MaxMixMode + 1 ] =
+ {
+ MONO_8BIT_SAMPLE_SIZE, STEREO_8BIT_SAMPLE_SIZE,
+ MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE
+ };
+
+const CARD_CAPABILITY BLASTER_CardConfig[ BLASTER_MaxCardType + 1 ] =
+ {
+ { FALSE, INVALID, INVALID, INVALID, INVALID }, // Unsupported
+ { TRUE, NO, MONO_8BIT, 4000, 23000 }, // SB 1.0
+ { TRUE, YES, STEREO_8BIT, 4000, 44100 }, // SBPro
+ { TRUE, NO, MONO_8BIT, 4000, 23000 }, // SB 2.xx
+ { TRUE, YES, STEREO_8BIT, 4000, 44100 }, // SBPro 2
+ { FALSE, INVALID, INVALID, INVALID, INVALID }, // Unsupported
+ { TRUE, YES, STEREO_16BIT, 5000, 44100 }, // SB16
+ };
+
+CARD_CAPABILITY BLASTER_Card;
+
+static void ( __interrupt __far *BLASTER_OldInt )( void );
+
+BLASTER_CONFIG BLASTER_Config =
+ {
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED
+ };
+
+static int BLASTER_Installed = FALSE;
+
+int BLASTER_Version;
+
+static char *BLASTER_DMABuffer;
+static char *BLASTER_DMABufferEnd;
+static char *BLASTER_CurrentDMABuffer;
+static int BLASTER_TotalDMABufferSize;
+
+static int BLASTER_TransferLength = 0;
+static int BLASTER_MixMode = BLASTER_DefaultMixMode;
+static int BLASTER_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE;
+static unsigned BLASTER_SampleRate = BLASTER_DefaultSampleRate;
+
+static unsigned BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+volatile int BLASTER_SoundPlaying;
+volatile int BLASTER_SoundRecording;
+
+void ( *BLASTER_CallBack )( void );
+
+static int BLASTER_IntController1Mask;
+static int BLASTER_IntController2Mask;
+
+static int BLASTER_MixerAddress = UNDEFINED;
+static int BLASTER_MixerType = 0;
+static int BLASTER_OriginalMidiVolumeLeft = 255;
+static int BLASTER_OriginalMidiVolumeRight = 255;
+static int BLASTER_OriginalVoiceVolumeLeft = 255;
+static int BLASTER_OriginalVoiceVolumeRight = 255;
+
+static int BLASTER_WaveBlasterState = 0x0F;
+
+// adequate stack size
+#define kStackSize 2048
+
+static unsigned short StackSelector = NULL;
+static unsigned long StackPointer;
+
+static unsigned short oldStackSelector;
+static unsigned long oldStackPointer;
+
+// This is defined because we can't create local variables in a
+// function that switches stacks.
+static int GlobalStatus;
+
+// These declarations are necessary to use the inline assembly pragmas.
+
+extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
+extern void SetStack(unsigned short selector,unsigned long stackptr);
+
+// This function will get the current stack selector and pointer and save
+// them off.
+#pragma aux GetStack = \
+ "mov [edi],esp" \
+ "mov ax,ss" \
+ "mov [esi],ax" \
+ parm [esi] [edi] \
+ modify [eax esi edi];
+
+// This function will set the stack selector and pointer to the specified
+// values.
+#pragma aux SetStack = \
+ "mov ss,ax" \
+ "mov esp,edx" \
+ parm [ax] [edx] \
+ modify [eax edx];
+
+int BLASTER_DMAChannel;
+
+int BLASTER_ErrorCode = BLASTER_Ok;
+
+#define BLASTER_SetErrorCode( status ) \
+ BLASTER_ErrorCode = ( status );
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_ErrorString
+
+ Returns a pointer to the error message associated with an error
+ number. A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *BLASTER_ErrorString
+ (
+ int ErrorNumber
+ )
+
+ {
+ char *ErrorString;
+
+ switch( ErrorNumber )
+ {
+ case BLASTER_Warning :
+ case BLASTER_Error :
+ ErrorString = BLASTER_ErrorString( BLASTER_ErrorCode );
+ break;
+
+ case BLASTER_Ok :
+ ErrorString = "Sound Blaster ok.";
+ break;
+
+ case BLASTER_EnvNotFound :
+ ErrorString = "BLASTER environment variable not set.";
+ break;
+
+ case BLASTER_AddrNotSet :
+ ErrorString = "Sound Blaster address not set.";
+ break;
+
+ case BLASTER_DMANotSet :
+ ErrorString = "Sound Blaster 8-bit DMA channel not set.";
+ break;
+
+ case BLASTER_DMA16NotSet :
+ ErrorString = "Sound Blaster 16-bit DMA channel not set.";
+ break;
+
+ case BLASTER_InvalidParameter :
+ ErrorString = "Invalid parameter in BLASTER environment variable.";
+ break;
+
+ case BLASTER_CardNotReady :
+ ErrorString = "Sound Blaster not responding on selected port.";
+ break;
+
+ case BLASTER_NoSoundPlaying :
+ ErrorString = "No sound playing on Sound Blaster.";
+ break;
+
+ case BLASTER_InvalidIrq :
+ ErrorString = "Invalid Sound Blaster Irq.";
+ break;
+
+ case BLASTER_UnableToSetIrq :
+ ErrorString = "Unable to set Sound Blaster IRQ. Try selecting an IRQ of 7 or below.";
+ break;
+
+ case BLASTER_DmaError :
+ ErrorString = DMA_ErrorString( DMA_Error );
+ break;
+
+ case BLASTER_NoMixer :
+ ErrorString = "Mixer not available on selected Sound Blaster card.";
+ break;
+
+ case BLASTER_DPMI_Error :
+ ErrorString = "DPMI Error in Blaster.";
+ break;
+
+ case BLASTER_OutOfMemory :
+ ErrorString = "Out of conventional memory in Blaster.";
+ break;
+
+ default :
+ ErrorString = "Unknown Sound Blaster error code.";
+ break;
+ }
+
+ return( ErrorString );
+ }
+
+
+/**********************************************************************
+
+ Memory locked functions:
+
+**********************************************************************/
+
+
+#define BLASTER_LockStart BLASTER_EnableInterrupt
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_EnableInterrupt
+
+ Enables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+void BLASTER_EnableInterrupt
+ (
+ void
+ )
+
+ {
+ int Irq;
+ int mask;
+
+ // Unmask system interrupt
+ Irq = BLASTER_Config.Interrupt;
+ if ( Irq < 8 )
+ {
+ mask = inp( 0x21 ) & ~( 1 << Irq );
+ outp( 0x21, mask );
+ }
+ else
+ {
+ mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) );
+ outp( 0xA1, mask );
+
+ mask = inp( 0x21 ) & ~( 1 << 2 );
+ outp( 0x21, mask );
+ }
+
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DisableInterrupt
+
+ Disables the triggering of the sound card interrupt.
+---------------------------------------------------------------------*/
+
+void BLASTER_DisableInterrupt
+ (
+ void
+ )
+
+ {
+ int Irq;
+ int mask;
+
+ // Restore interrupt mask
+ Irq = BLASTER_Config.Interrupt;
+ if ( Irq < 8 )
+ {
+ mask = inp( 0x21 ) & ~( 1 << Irq );
+ mask |= BLASTER_IntController1Mask & ( 1 << Irq );
+ outp( 0x21, mask );
+ }
+ else
+ {
+ mask = inp( 0x21 ) & ~( 1 << 2 );
+ mask |= BLASTER_IntController1Mask & ( 1 << 2 );
+ outp( 0x21, mask );
+
+ mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) );
+ mask |= BLASTER_IntController2Mask & ( 1 << ( Irq - 8 ) );
+ outp( 0xA1, mask );
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_ServiceInterrupt
+
+ Handles interrupt generated by sound card at the end of a voice
+ transfer. Calls the user supplied callback function.
+---------------------------------------------------------------------*/
+
+void __interrupt __far BLASTER_ServiceInterrupt
+ (
+ void
+ )
+
+ {
+ #ifdef USESTACK
+ // save stack
+ GetStack( &oldStackSelector, &oldStackPointer );
+
+ // set our stack
+ SetStack( StackSelector, StackPointer );
+ #endif
+
+ // Acknowledge interrupt
+ // Check if this is this an SB16 or newer
+ if ( BLASTER_Version >= DSP_Version4xx )
+ {
+ outp( BLASTER_Config.Address + BLASTER_MixerAddressPort,
+ MIXER_DSP4xxISR_Ack );
+
+ GlobalStatus = inp( BLASTER_Config.Address + BLASTER_MixerDataPort );
+
+ // Check if a 16-bit DMA interrupt occurred
+ if ( GlobalStatus & MIXER_16BITDMA_INT )
+ {
+ // Acknowledge 16-bit transfer interrupt
+ inp( BLASTER_Config.Address + BLASTER_16BitDMAAck );
+ }
+ else if ( GlobalStatus & MIXER_8BITDMA_INT )
+ {
+ inp( BLASTER_Config.Address + BLASTER_DataAvailablePort );
+ }
+ else
+ {
+ #ifdef USESTACK
+ // restore stack
+ SetStack( oldStackSelector, oldStackPointer );
+ #endif
+
+ // Wasn't our interrupt. Call the old one.
+ _chain_intr( BLASTER_OldInt );
+ }
+ }
+ else
+ {
+ // Older card - can't detect if an interrupt occurred.
+ inp( BLASTER_Config.Address + BLASTER_DataAvailablePort );
+ }
+
+ // Keep track of current buffer
+ BLASTER_CurrentDMABuffer += BLASTER_TransferLength;
+
+ if ( BLASTER_CurrentDMABuffer >= BLASTER_DMABufferEnd )
+ {
+ BLASTER_CurrentDMABuffer = BLASTER_DMABuffer;
+ }
+
+ // Continue playback on cards without autoinit mode
+ if ( BLASTER_Version < DSP_Version2xx )
+ {
+ if ( BLASTER_SoundPlaying )
+ {
+ BLASTER_DSP1xx_BeginPlayback( BLASTER_TransferLength );
+ }
+
+ if ( BLASTER_SoundRecording )
+ {
+ BLASTER_DSP1xx_BeginRecord( BLASTER_TransferLength );
+ }
+ }
+
+ // Call the caller's callback function
+ if ( BLASTER_CallBack != NULL )
+ {
+ BLASTER_CallBack();
+ }
+
+ #ifdef USESTACK
+ // restore stack
+ SetStack( oldStackSelector, oldStackPointer );
+ #endif
+
+ // send EOI to Interrupt Controller
+ if ( BLASTER_Config.Interrupt > 7 )
+ {
+ outp( 0xA0, 0x20 );
+ }
+
+ outp( 0x20, 0x20 );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_WriteDSP
+
+ Writes a byte of data to the sound card's DSP.
+---------------------------------------------------------------------*/
+
+int BLASTER_WriteDSP
+ (
+ unsigned data
+ )
+
+ {
+ int port;
+ unsigned count;
+ int status;
+
+ port = BLASTER_Config.Address + BLASTER_WritePort;
+
+ status = BLASTER_Error;
+
+ count = 0xFFFF;
+
+ do
+ {
+ if ( ( inp( port ) & 0x80 ) == 0 )
+ {
+ outp( port, data );
+ status = BLASTER_Ok;
+ break;
+ }
+
+ count--;
+ }
+ while( count > 0 );
+
+ if ( status != BLASTER_Ok )
+ {
+ BLASTER_SetErrorCode( BLASTER_CardNotReady );
+ }
+
+ return( status );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_ReadDSP
+
+ Reads a byte of data from the sound card's DSP.
+---------------------------------------------------------------------*/
+
+int BLASTER_ReadDSP
+ (
+ void
+ )
+
+ {
+ int port;
+ unsigned count;
+ int status;
+
+ port = BLASTER_Config.Address + BLASTER_DataAvailablePort;
+
+ status = BLASTER_Error;
+
+ count = 0xFFFF;
+
+ do
+ {
+ if ( inp( port ) & 0x80 )
+ {
+ status = inp( BLASTER_Config.Address + BLASTER_ReadPort );
+ break;
+ }
+
+ count--;
+ }
+ while( count > 0 );
+
+ if ( status == BLASTER_Error )
+ {
+ BLASTER_SetErrorCode( BLASTER_CardNotReady );
+ }
+
+ return( status );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_ResetDSP
+
+ Sends a reset command to the sound card's Digital Signal Processor
+ (DSP), causing it to perform an initialization.
+---------------------------------------------------------------------*/
+
+int BLASTER_ResetDSP
+ (
+ void
+ )
+
+ {
+ volatile int count;
+ int port;
+ int status;
+
+ port = BLASTER_Config.Address + BLASTER_ResetPort;
+
+ status = BLASTER_CardNotReady;
+
+ outp( port, 1 );
+
+/* What the hell am I doing here?
+ count = 100;
+
+ do
+ {
+ if ( inp( port ) == 255 )
+ {
+ break;
+ }
+
+ count--;
+ }
+ while( count > 0 );
+*/
+
+ count = 0x100;
+ do
+ {
+ count--;
+ }
+ while( count > 0 );
+
+ outp( port, 0 );
+
+ count = 100;
+
+ do
+ {
+ if ( BLASTER_ReadDSP() == BLASTER_Ready )
+ {
+ status = BLASTER_Ok;
+ break;
+ }
+
+ count--;
+ }
+ while( count > 0 );
+
+ return( status );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetDSPVersion
+
+ Returns the version number of the sound card's DSP.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetDSPVersion
+ (
+ void
+ )
+
+ {
+ int MajorVersion;
+ int MinorVersion;
+ int version;
+
+ BLASTER_WriteDSP( DSP_GetVersion );
+
+ MajorVersion = BLASTER_ReadDSP();
+ MinorVersion = BLASTER_ReadDSP();
+
+ if ( ( MajorVersion == BLASTER_Error ) ||
+ ( MinorVersion == BLASTER_Error ) )
+ {
+ BLASTER_SetErrorCode( BLASTER_CardNotReady );
+ return( BLASTER_Error );
+ }
+
+ version = ( MajorVersion << 8 ) + MinorVersion;
+
+ if ( version >= DSP_Version4xx )
+ {
+ BLASTER_Card.IsSupported = TRUE;
+ BLASTER_Card.HasMixer = YES;
+ BLASTER_Card.MaxMixMode = STEREO_16BIT;
+ BLASTER_Card.MinSamplingRate = 5000;
+ BLASTER_Card.MaxSamplingRate = 44100;
+ BLASTER_MixerType = SB16;
+ }
+ else if ( version >= DSP_Version3xx )
+ {
+ BLASTER_Card.IsSupported = TRUE;
+ BLASTER_Card.HasMixer = YES;
+ BLASTER_Card.MaxMixMode = STEREO_8BIT;
+ BLASTER_Card.MinSamplingRate = 4000;
+ BLASTER_Card.MaxSamplingRate = 44100;
+ BLASTER_MixerType = SBPro;
+ }
+ else if ( version >= DSP_Version2xx )
+ {
+ BLASTER_Card.IsSupported = TRUE;
+ BLASTER_Card.HasMixer = NO;
+ BLASTER_Card.MaxMixMode = MONO_8BIT;
+ BLASTER_Card.MinSamplingRate = 4000;
+ BLASTER_Card.MaxSamplingRate = 23000;
+ BLASTER_MixerType = 0;
+ }
+ else
+ {
+ // DSP_Version1xx
+ BLASTER_Card.IsSupported = TRUE;
+ BLASTER_Card.HasMixer = NO;
+ BLASTER_Card.MaxMixMode = MONO_8BIT;
+ BLASTER_Card.MinSamplingRate = 4000;
+ BLASTER_Card.MaxSamplingRate = 23000;
+ BLASTER_MixerType = 0;
+ }
+
+ return( version );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SpeakerOn
+
+ Enables output from the DAC.
+---------------------------------------------------------------------*/
+
+void BLASTER_SpeakerOn
+ (
+ void
+ )
+
+ {
+ BLASTER_WriteDSP( DSP_SpeakerOn );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SpeakerOff
+
+ Disables output from the DAC.
+---------------------------------------------------------------------*/
+
+void BLASTER_SpeakerOff
+ (
+ void
+ )
+
+ {
+ BLASTER_WriteDSP( DSP_SpeakerOff );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetPlaybackRate
+
+ Sets the rate at which the digitized sound will be played in
+ hertz.
+---------------------------------------------------------------------*/
+
+void BLASTER_SetPlaybackRate
+ (
+ unsigned rate
+ )
+
+ {
+ int LoByte;
+ int HiByte;
+
+ if ( BLASTER_Version < DSP_Version4xx )
+ {
+ int timeconstant;
+ long ActualRate;
+
+ // Send sampling rate as time constant for older Sound
+ // Blaster compatible cards.
+
+ ActualRate = rate * BLASTER_SamplePacketSize;
+ if ( ActualRate < BLASTER_Card.MinSamplingRate )
+ {
+ rate = BLASTER_Card.MinSamplingRate / BLASTER_SamplePacketSize;
+ }
+
+ if ( ActualRate > BLASTER_Card.MaxSamplingRate )
+ {
+ rate = BLASTER_Card.MaxSamplingRate / BLASTER_SamplePacketSize;
+ }
+
+ timeconstant = ( int )CalcTimeConstant( rate, BLASTER_SamplePacketSize );
+
+ // Keep track of what the actual rate is
+ BLASTER_SampleRate = ( unsigned )CalcSamplingRate( timeconstant );
+ BLASTER_SampleRate /= BLASTER_SamplePacketSize;
+
+ BLASTER_WriteDSP( DSP_SetTimeConstant );
+ BLASTER_WriteDSP( timeconstant );
+ }
+ else
+ {
+ // Send literal sampling rate for cards with DSP version
+ // 4.xx (Sound Blaster 16)
+
+ BLASTER_SampleRate = rate;
+
+ if ( BLASTER_SampleRate < BLASTER_Card.MinSamplingRate )
+ {
+ BLASTER_SampleRate = BLASTER_Card.MinSamplingRate;
+ }
+
+ if ( BLASTER_SampleRate > BLASTER_Card.MaxSamplingRate )
+ {
+ BLASTER_SampleRate = BLASTER_Card.MaxSamplingRate;
+ }
+
+ HiByte = hibyte( BLASTER_SampleRate );
+ LoByte = lobyte( BLASTER_SampleRate );
+
+ // Set playback rate
+ BLASTER_WriteDSP( DSP_Set_DA_Rate );
+ BLASTER_WriteDSP( HiByte );
+ BLASTER_WriteDSP( LoByte );
+
+ // Set recording rate
+ BLASTER_WriteDSP( DSP_Set_AD_Rate );
+ BLASTER_WriteDSP( HiByte );
+ BLASTER_WriteDSP( LoByte );
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetPlaybackRate
+
+ Returns the rate at which the digitized sound will be played in
+ hertz.
+---------------------------------------------------------------------*/
+
+unsigned BLASTER_GetPlaybackRate
+ (
+ void
+ )
+
+ {
+ return( BLASTER_SampleRate );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetMixMode
+
+ Sets the sound card to play samples in mono or stereo.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetMixMode
+ (
+ int mode
+ )
+
+ {
+ int port;
+ int data;
+ int CardType;
+
+ CardType = BLASTER_Config.Type;
+
+ mode &= BLASTER_MaxMixMode;
+
+ if ( !( BLASTER_Card.MaxMixMode & STEREO ) )
+ {
+ mode &= ~STEREO;
+ }
+
+ if ( !( BLASTER_Card.MaxMixMode & SIXTEEN_BIT ) )
+ {
+ mode &= ~SIXTEEN_BIT;
+ }
+
+ BLASTER_MixMode = mode;
+ BLASTER_SamplePacketSize = BLASTER_SampleSize[ mode ];
+
+ // For the Sound Blaster Pro, we have to set the mixer chip
+ // to play mono or stereo samples.
+
+ if ( ( CardType == SBPro ) || ( CardType == SBPro2 ) )
+ {
+ port = BLASTER_Config.Address + BLASTER_MixerAddressPort;
+ outp( port, MIXER_SBProOutputSetting );
+
+ port = BLASTER_Config.Address + BLASTER_MixerDataPort;
+
+ // Get current mode
+ data = inp( port );
+
+ // set stereo mode bit
+ if ( mode & STEREO )
+ {
+ data |= MIXER_SBProStereoFlag;
+ }
+ else
+ {
+ data &= ~MIXER_SBProStereoFlag;
+ }
+
+ // set the mode
+ outp( port, data );
+
+ BLASTER_SetPlaybackRate( BLASTER_SampleRate );
+ }
+
+ return( mode );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_StopPlayback
+
+ Ends the DMA transfer of digitized sound to the sound card.
+---------------------------------------------------------------------*/
+
+void BLASTER_StopPlayback
+ (
+ void
+ )
+
+ {
+ int DmaChannel;
+
+ // Don't allow anymore interrupts
+ BLASTER_DisableInterrupt();
+
+ if ( BLASTER_HaltTransferCommand == DSP_Reset )
+ {
+ BLASTER_ResetDSP();
+ }
+ else
+ {
+ BLASTER_WriteDSP( BLASTER_HaltTransferCommand );
+ }
+
+ // Disable the DMA channel
+ if ( BLASTER_MixMode & SIXTEEN_BIT )
+ {
+ DmaChannel = BLASTER_Config.Dma16;
+ }
+ else
+ {
+ DmaChannel = BLASTER_Config.Dma8;
+ }
+ DMA_EndTransfer( DmaChannel );
+
+ // Turn off speaker
+ BLASTER_SpeakerOff();
+
+ BLASTER_SoundPlaying = FALSE;
+ BLASTER_SoundRecording = FALSE;
+
+ BLASTER_DMABuffer = NULL;
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetupDMABuffer
+
+ Programs the DMAC for sound transfer.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetupDMABuffer
+ (
+ char *BufferPtr,
+ int BufferSize,
+ int mode
+ )
+
+ {
+ int DmaChannel;
+ int DmaStatus;
+ int errorcode;
+
+ if ( BLASTER_MixMode & SIXTEEN_BIT )
+ {
+ DmaChannel = BLASTER_Config.Dma16;
+ errorcode = BLASTER_DMA16NotSet;
+ }
+ else
+ {
+ DmaChannel = BLASTER_Config.Dma8;
+ errorcode = BLASTER_DMANotSet;
+ }
+
+ if ( DmaChannel == UNDEFINED )
+ {
+ BLASTER_SetErrorCode( errorcode );
+ return( BLASTER_Error );
+ }
+
+ DmaStatus = DMA_SetupTransfer( DmaChannel, BufferPtr, BufferSize, mode );
+ if ( DmaStatus == DMA_Error )
+ {
+ BLASTER_SetErrorCode( BLASTER_DmaError );
+ return( BLASTER_Error );
+ }
+
+ BLASTER_DMAChannel = DmaChannel;
+
+ BLASTER_DMABuffer = BufferPtr;
+ BLASTER_CurrentDMABuffer = BufferPtr;
+ BLASTER_TotalDMABufferSize = BufferSize;
+ BLASTER_DMABufferEnd = BufferPtr + BufferSize;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetCurrentPos
+
+ Returns the offset within the current sound being played.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetCurrentPos
+ (
+ void
+ )
+
+ {
+ char *CurrentAddr;
+ int DmaChannel;
+ int offset;
+
+ if ( !BLASTER_SoundPlaying )
+ {
+ BLASTER_SetErrorCode( BLASTER_NoSoundPlaying );
+ return( BLASTER_Error );
+ }
+
+ if ( BLASTER_MixMode & SIXTEEN_BIT )
+ {
+ DmaChannel = BLASTER_Config.Dma16;
+ }
+ else
+ {
+ DmaChannel = BLASTER_Config.Dma8;
+ }
+
+ if ( DmaChannel == UNDEFINED )
+ {
+ BLASTER_SetErrorCode( BLASTER_DMANotSet );
+ return( BLASTER_Error );
+ }
+
+ CurrentAddr = DMA_GetCurrentPos( DmaChannel );
+
+ offset = ( int )( ( ( unsigned long )CurrentAddr ) -
+ ( ( unsigned long )BLASTER_CurrentDMABuffer ) );
+
+ if ( BLASTER_MixMode & SIXTEEN_BIT )
+ {
+ offset >>= 1;
+ }
+
+ if ( BLASTER_MixMode & STEREO )
+ {
+ offset >>= 1;
+ }
+
+ return( offset );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DSP1xx_BeginPlayback
+
+ Starts playback of digitized sound on cards compatible with DSP
+ version 1.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP1xx_BeginPlayback
+ (
+ int length
+ )
+
+ {
+ int SampleLength;
+ int LoByte;
+ int HiByte;
+
+ SampleLength = length - 1;
+ HiByte = hibyte( SampleLength );
+ LoByte = lobyte( SampleLength );
+
+ // Program DSP to play sound
+ BLASTER_WriteDSP( DSP_Old8BitDAC );
+ BLASTER_WriteDSP( LoByte );
+ BLASTER_WriteDSP( HiByte );
+
+ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+ BLASTER_SoundPlaying = TRUE;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DSP2xx_BeginPlayback
+
+ Starts playback of digitized sound on cards compatible with DSP
+ version 2.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP2xx_BeginPlayback
+ (
+ int length
+ )
+
+ {
+ int SampleLength;
+ int LoByte;
+ int HiByte;
+
+ SampleLength = length - 1;
+ HiByte = hibyte( SampleLength );
+ LoByte = lobyte( SampleLength );
+
+ BLASTER_WriteDSP( DSP_SetBlockLength );
+ BLASTER_WriteDSP( LoByte );
+ BLASTER_WriteDSP( HiByte );
+
+ if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate <
+ ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) )
+ {
+ BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitMode );
+ BLASTER_HaltTransferCommand = DSP_Reset;
+ }
+ else
+ {
+ BLASTER_WriteDSP( DSP_8BitAutoInitMode );
+ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+ }
+
+ BLASTER_SoundPlaying = TRUE;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DSP4xx_BeginPlayback
+
+ Starts playback of digitized sound on cards compatible with DSP
+ version 4.xx, such as the Sound Blaster 16.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP4xx_BeginPlayback
+ (
+ int length
+ )
+
+ {
+ int TransferCommand;
+ int TransferMode;
+ int SampleLength;
+ int LoByte;
+ int HiByte;
+
+ if ( BLASTER_MixMode & SIXTEEN_BIT )
+ {
+ TransferCommand = DSP_16BitDAC;
+ SampleLength = ( length / 2 ) - 1;
+ BLASTER_HaltTransferCommand = DSP_Halt16bitTransfer;
+ if ( BLASTER_MixMode & STEREO )
+ {
+ TransferMode = DSP_SignedStereoData;
+ }
+ else
+ {
+ TransferMode = DSP_SignedMonoData;
+ }
+ }
+ else
+ {
+ TransferCommand = DSP_8BitDAC;
+ SampleLength = length - 1;
+ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+ if ( BLASTER_MixMode & STEREO )
+ {
+ TransferMode = DSP_UnsignedStereoData;
+ }
+ else
+ {
+ TransferMode = DSP_UnsignedMonoData;
+ }
+ }
+
+ HiByte = hibyte( SampleLength );
+ LoByte = lobyte( SampleLength );
+
+ // Program DSP to play sound
+ BLASTER_WriteDSP( TransferCommand );
+ BLASTER_WriteDSP( TransferMode );
+ BLASTER_WriteDSP( LoByte );
+ BLASTER_WriteDSP( HiByte );
+
+ BLASTER_SoundPlaying = TRUE;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_BeginBufferedPlayback
+
+ Begins multibuffered playback of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int BLASTER_BeginBufferedPlayback
+ (
+ char *BufferStart,
+ int BufferSize,
+ int NumDivisions,
+ unsigned SampleRate,
+ int MixMode,
+ void ( *CallBackFunc )( void )
+ )
+
+ {
+ int DmaStatus;
+ int TransferLength;
+
+//JIM
+// if ( BLASTER_SoundPlaying || BLASTER_SoundRecording )
+ {
+ BLASTER_StopPlayback();
+ }
+
+ BLASTER_SetMixMode( MixMode );
+
+ DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead );
+ if ( DmaStatus == BLASTER_Error )
+ {
+ return( BLASTER_Error );
+ }
+
+ BLASTER_SetPlaybackRate( SampleRate );
+
+ BLASTER_SetCallBack( CallBackFunc );
+
+ BLASTER_EnableInterrupt();
+
+ // Turn on speaker
+ BLASTER_SpeakerOn();
+
+ TransferLength = BufferSize / NumDivisions;
+ BLASTER_TransferLength = TransferLength;
+
+ // Program the sound card to start the transfer.
+ if ( BLASTER_Version < DSP_Version2xx )
+ {
+ BLASTER_DSP1xx_BeginPlayback( TransferLength );
+ }
+ else if ( BLASTER_Version < DSP_Version4xx )
+ {
+ BLASTER_DSP2xx_BeginPlayback( TransferLength );
+ }
+ else
+ {
+ BLASTER_DSP4xx_BeginPlayback( TransferLength );
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DSP4xx_BeginRecord
+
+ Starts recording of digitized sound on cards compatible with DSP
+ version 4.xx, such as the Sound Blaster 16.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP4xx_BeginRecord
+ (
+ int length
+ )
+
+ {
+ int TransferCommand;
+ int TransferMode;
+ int SampleLength;
+ int LoByte;
+ int HiByte;
+
+ TransferCommand = DSP_8BitADC;
+ SampleLength = length - 1;
+ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+ TransferMode = DSP_UnsignedMonoData;
+
+ HiByte = hibyte( SampleLength );
+ LoByte = lobyte( SampleLength );
+
+ // Program DSP to play sound
+ BLASTER_WriteDSP( TransferCommand );
+ BLASTER_WriteDSP( TransferMode );
+ BLASTER_WriteDSP( LoByte );
+ BLASTER_WriteDSP( HiByte );
+
+ BLASTER_SoundRecording = TRUE;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DSP2xx_BeginRecord
+
+ Starts recording of digitized sound on cards compatible with DSP
+ version 2.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP2xx_BeginRecord
+ (
+ int length
+ )
+
+ {
+ int SampleLength;
+ int LoByte;
+ int HiByte;
+
+ SampleLength = length - 1;
+ HiByte = hibyte( SampleLength );
+ LoByte = lobyte( SampleLength );
+
+ BLASTER_WriteDSP( DSP_SetBlockLength );
+ BLASTER_WriteDSP( LoByte );
+ BLASTER_WriteDSP( HiByte );
+
+ if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate <
+ ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) )
+ {
+ BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitRecord );
+ BLASTER_HaltTransferCommand = DSP_Reset;
+ }
+ else
+ {
+ BLASTER_WriteDSP( DSP_8BitAutoInitRecord );
+ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+ }
+
+ BLASTER_SoundRecording = TRUE;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_DSP1xx_BeginRecord
+
+ Starts recording of digitized sound on cards compatible with DSP
+ version 1.xx.
+---------------------------------------------------------------------*/
+
+int BLASTER_DSP1xx_BeginRecord
+ (
+ int length
+ )
+
+ {
+ int SampleLength;
+ int LoByte;
+ int HiByte;
+
+ SampleLength = length - 1;
+ HiByte = hibyte( SampleLength );
+ LoByte = lobyte( SampleLength );
+
+ // Program DSP to play sound
+ BLASTER_WriteDSP( DSP_Old8BitADC );
+ BLASTER_WriteDSP( LoByte );
+ BLASTER_WriteDSP( HiByte );
+
+ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer;
+
+ BLASTER_SoundRecording = TRUE;
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_BeginBufferedRecord
+
+ Begins multibuffered recording of digitized sound on the sound card.
+---------------------------------------------------------------------*/
+
+int BLASTER_BeginBufferedRecord
+ (
+ char *BufferStart,
+ int BufferSize,
+ int NumDivisions,
+ unsigned SampleRate,
+ int MixMode,
+ void ( *CallBackFunc )( void )
+ )
+
+ {
+ int DmaStatus;
+ int TransferLength;
+
+//JIM
+// if ( BLASTER_SoundPlaying || BLASTER_SoundRecording )
+ {
+ BLASTER_StopPlayback();
+ }
+
+ BLASTER_SetMixMode( MixMode );
+
+ DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite );
+ if ( DmaStatus == BLASTER_Error )
+ {
+ return( BLASTER_Error );
+ }
+
+ BLASTER_SetPlaybackRate( SampleRate );
+
+ BLASTER_SetCallBack( CallBackFunc );
+
+ BLASTER_EnableInterrupt();
+
+ // Turn off speaker
+ BLASTER_SpeakerOff();
+
+ TransferLength = BufferSize / NumDivisions;
+ BLASTER_TransferLength = TransferLength;
+
+ // Program the sound card to start the transfer.
+ if ( BLASTER_Version < DSP_Version2xx )
+ {
+ BLASTER_DSP1xx_BeginRecord( TransferLength );
+ }
+ else if ( BLASTER_Version < DSP_Version4xx )
+ {
+ BLASTER_DSP2xx_BeginRecord( TransferLength );
+ }
+ else
+ {
+ BLASTER_DSP4xx_BeginRecord( TransferLength );
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_WriteMixer
+
+ Writes a byte of data to the Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+void BLASTER_WriteMixer
+ (
+ int reg,
+ int data
+ )
+
+ {
+ outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg );
+ outp( BLASTER_MixerAddress + BLASTER_MixerDataPort, data );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_ReadMixer
+
+ Reads a byte of data from the Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_ReadMixer
+ (
+ int reg
+ )
+
+ {
+ int data;
+
+ outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg );
+ data = inp( BLASTER_MixerAddress + BLASTER_MixerDataPort );
+ return( data );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetVoiceVolume
+
+ Reads the average volume of the digitized sound channel from the
+ Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetVoiceVolume
+ (
+ void
+ )
+
+ {
+ int volume;
+ int left;
+ int right;
+
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ left = BLASTER_ReadMixer( MIXER_SBProVoice );
+ right = ( left & 0x0f ) << 4;
+ left &= 0xf0;
+ volume = ( left + right ) / 2;
+ break;
+
+ case SB16 :
+ left = BLASTER_ReadMixer( MIXER_SB16VoiceLeft );
+ right = BLASTER_ReadMixer( MIXER_SB16VoiceRight );
+ volume = ( left + right ) / 2;
+ break;
+
+ default :
+ BLASTER_SetErrorCode( BLASTER_NoMixer );
+ volume = BLASTER_Error;
+ }
+
+ return( volume );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetVoiceVolume
+
+ Sets the volume of the digitized sound channel on the Sound
+ Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetVoiceVolume
+ (
+ int volume
+ )
+
+ {
+ int data;
+ int status;
+
+ volume = min( 255, volume );
+ volume = max( 0, volume );
+
+ status = BLASTER_Ok;
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ data = ( volume & 0xf0 ) + ( volume >> 4 );
+ BLASTER_WriteMixer( MIXER_SBProVoice, data );
+ break;
+
+ case SB16 :
+ BLASTER_WriteMixer( MIXER_SB16VoiceLeft, volume & 0xf8 );
+ BLASTER_WriteMixer( MIXER_SB16VoiceRight, volume & 0xf8 );
+ break;
+
+ default :
+ BLASTER_SetErrorCode( BLASTER_NoMixer );
+ status = BLASTER_Error;
+ }
+
+ return( status );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetMidiVolume
+
+ Reads the average volume of the Midi sound channel from the
+ Sound Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetMidiVolume
+ (
+ void
+ )
+
+ {
+ int volume;
+ int left;
+ int right;
+
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ left = BLASTER_ReadMixer( MIXER_SBProMidi );
+ right = ( left & 0x0f ) << 4;
+ left &= 0xf0;
+ volume = ( left + right ) / 2;
+ break;
+
+ case SB16 :
+ left = BLASTER_ReadMixer( MIXER_SB16MidiLeft );
+ right = BLASTER_ReadMixer( MIXER_SB16MidiRight );
+ volume = ( left + right ) / 2;
+ break;
+
+ default :
+ BLASTER_SetErrorCode( BLASTER_NoMixer );
+ volume = BLASTER_Error;
+ }
+
+ return( volume );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetMidiVolume
+
+ Sets the volume of the Midi sound channel on the Sound
+ Blaster's mixer chip.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetMidiVolume
+ (
+ int volume
+ )
+
+ {
+ int data;
+ int status;
+
+ volume = min( 255, volume );
+ volume = max( 0, volume );
+
+ status = BLASTER_Ok;
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ data = ( volume & 0xf0 ) + ( volume >> 4 );
+ BLASTER_WriteMixer( MIXER_SBProMidi, data );
+ break;
+
+ case SB16 :
+ BLASTER_WriteMixer( MIXER_SB16MidiLeft, volume & 0xf8 );
+ BLASTER_WriteMixer( MIXER_SB16MidiRight, volume & 0xf8 );
+ break;
+
+ default :
+ BLASTER_SetErrorCode( BLASTER_NoMixer );
+ status = BLASTER_Error;
+ }
+
+ return( status );
+ }
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_CardHasMixer
+
+ Checks if the selected Sound Blaster card has a mixer.
+---------------------------------------------------------------------*/
+
+int BLASTER_CardHasMixer
+ (
+ void
+ )
+
+ {
+ return( BLASTER_Card.HasMixer );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SaveVoiceVolume
+
+ Saves the user's voice mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_SaveVoiceVolume
+ (
+ void
+ )
+
+ {
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ BLASTER_OriginalVoiceVolumeLeft =
+ BLASTER_ReadMixer( MIXER_SBProVoice );
+ break;
+
+ case SB16 :
+ BLASTER_OriginalVoiceVolumeLeft =
+ BLASTER_ReadMixer( MIXER_SB16VoiceLeft );
+ BLASTER_OriginalVoiceVolumeRight =
+ BLASTER_ReadMixer( MIXER_SB16VoiceRight );
+ break;
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_RestoreVoiceVolume
+
+ Restores the user's voice mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_RestoreVoiceVolume
+ (
+ void
+ )
+
+ {
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ BLASTER_WriteMixer( MIXER_SBProVoice,
+ BLASTER_OriginalVoiceVolumeLeft );
+ break;
+
+ case SB16 :
+ BLASTER_WriteMixer( MIXER_SB16VoiceLeft,
+ BLASTER_OriginalVoiceVolumeLeft );
+ BLASTER_WriteMixer( MIXER_SB16VoiceRight,
+ BLASTER_OriginalVoiceVolumeRight );
+ break;
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SaveMidiVolume
+
+ Saves the user's FM mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_SaveMidiVolume
+ (
+ void
+ )
+
+ {
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ BLASTER_OriginalMidiVolumeLeft =
+ BLASTER_ReadMixer( MIXER_SBProMidi );
+ break;
+
+ case SB16 :
+ BLASTER_OriginalMidiVolumeLeft =
+ BLASTER_ReadMixer( MIXER_SB16MidiLeft );
+ BLASTER_OriginalMidiVolumeRight =
+ BLASTER_ReadMixer( MIXER_SB16MidiRight );
+ break;
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_RestoreMidiVolume
+
+ Restores the user's FM mixer settings.
+---------------------------------------------------------------------*/
+
+void BLASTER_RestoreMidiVolume
+ (
+ void
+ )
+
+ {
+ switch( BLASTER_MixerType )
+ {
+ case SBPro :
+ case SBPro2 :
+ BLASTER_WriteMixer( MIXER_SBProMidi,
+ BLASTER_OriginalMidiVolumeLeft );
+ break;
+
+ case SB16 :
+ BLASTER_WriteMixer( MIXER_SB16MidiLeft,
+ BLASTER_OriginalMidiVolumeLeft );
+ BLASTER_WriteMixer( MIXER_SB16MidiRight,
+ BLASTER_OriginalMidiVolumeRight );
+ break;
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetEnv
+
+ Retrieves the BLASTER environment settings and returns them to
+ the caller.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetEnv
+ (
+ BLASTER_CONFIG *Config
+ )
+
+ {
+ char *Blaster;
+ char parameter;
+
+ Config->Address = UNDEFINED;
+ Config->Type = UNDEFINED;
+ Config->Interrupt = UNDEFINED;
+ Config->Dma8 = UNDEFINED;
+ Config->Dma16 = UNDEFINED;
+ Config->Midi = UNDEFINED;
+ Config->Emu = UNDEFINED;
+
+ Blaster = getenv( "BLASTER" );
+ if ( Blaster == NULL )
+ {
+ BLASTER_SetErrorCode( BLASTER_EnvNotFound );
+ return( BLASTER_Error );
+ }
+
+ while( *Blaster != 0 )
+ {
+ if ( *Blaster == ' ' )
+ {
+ Blaster++;
+ continue;
+ }
+
+ parameter = toupper( *Blaster );
+ Blaster++;
+
+ if ( !isxdigit( *Blaster ) )
+ {
+ BLASTER_SetErrorCode( BLASTER_InvalidParameter );
+ return( BLASTER_Error );
+ }
+
+ switch( parameter )
+ {
+ case BlasterEnv_Address :
+ sscanf( Blaster, "%x", &Config->Address );
+ break;
+ case BlasterEnv_Interrupt :
+ sscanf( Blaster, "%d", &Config->Interrupt );
+ break;
+ case BlasterEnv_8bitDma :
+ sscanf( Blaster, "%d", &Config->Dma8 );
+ break;
+ case BlasterEnv_Type :
+ sscanf( Blaster, "%d", &Config->Type );
+ break;
+ case BlasterEnv_16bitDma :
+ sscanf( Blaster, "%d", &Config->Dma16 );
+ break;
+ case BlasterEnv_Midi :
+ sscanf( Blaster, "%x", &Config->Midi );
+ break;
+ case BlasterEnv_EmuAddress :
+ sscanf( Blaster, "%x", &Config->Emu );
+ break;
+ default :
+ // Skip the offending data
+ // sscanf( Blaster, "%*s" );
+ break;
+ }
+
+ while( isxdigit( *Blaster ) )
+ {
+ Blaster++;
+ }
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetCardSettings
+
+ Sets up the sound card's parameters.
+---------------------------------------------------------------------*/
+
+int BLASTER_SetCardSettings
+ (
+ BLASTER_CONFIG Config
+ )
+
+ {
+ if ( BLASTER_Installed )
+ {
+ BLASTER_Shutdown();
+ }
+
+ BLASTER_Config.Address = Config.Address;
+ BLASTER_Config.Type = Config.Type;
+ BLASTER_Config.Interrupt = Config.Interrupt;
+ BLASTER_Config.Dma8 = Config.Dma8;
+ BLASTER_Config.Dma16 = Config.Dma16;
+ BLASTER_Config.Midi = Config.Midi;
+ BLASTER_Config.Emu = Config.Emu;
+ BLASTER_MixerAddress = Config.Address;
+ BLASTER_MixerType = Config.Type;
+
+ if ( BLASTER_Config.Emu == UNDEFINED )
+ {
+ BLASTER_Config.Emu = BLASTER_Config.Address + 0x400;
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetCardSettings
+
+ Sets up the sound card's parameters.
+---------------------------------------------------------------------*/
+
+int BLASTER_GetCardSettings
+ (
+ BLASTER_CONFIG *Config
+ )
+
+ {
+ if ( BLASTER_Config.Address == UNDEFINED )
+ {
+ return( BLASTER_Warning );
+ }
+ else
+ {
+ Config->Address = BLASTER_Config.Address;
+ Config->Type = BLASTER_Config.Type;
+ Config->Interrupt = BLASTER_Config.Interrupt;
+ Config->Dma8 = BLASTER_Config.Dma8;
+ Config->Dma16 = BLASTER_Config.Dma16;
+ Config->Midi = BLASTER_Config.Midi;
+ Config->Emu = BLASTER_Config.Emu;
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_GetCardInfo
+
+ Returns the maximum number of bits that can represent a sample
+ (8 or 16) and the number of channels (1 for mono, 2 for stereo).
+---------------------------------------------------------------------*/
+
+int BLASTER_GetCardInfo
+ (
+ int *MaxSampleBits,
+ int *MaxChannels
+ )
+
+ {
+ if ( BLASTER_Card.MaxMixMode & STEREO )
+ {
+ *MaxChannels = 2;
+ }
+ else
+ {
+ *MaxChannels = 1;
+ }
+
+ if ( BLASTER_Card.MaxMixMode & SIXTEEN_BIT )
+ {
+ *MaxSampleBits = 16;
+ }
+ else
+ {
+ *MaxSampleBits = 8;
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetCallBack
+
+ Specifies the user function to call at the end of a sound transfer.
+---------------------------------------------------------------------*/
+
+void BLASTER_SetCallBack
+ (
+ void ( *func )( void )
+ )
+
+ {
+ BLASTER_CallBack = func;
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_LockEnd
+
+ Used for determining the length of the functions to lock in memory.
+---------------------------------------------------------------------*/
+
+static void BLASTER_LockEnd
+ (
+ void
+ )
+
+ {
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_UnlockMemory
+
+ Unlocks all neccessary data.
+---------------------------------------------------------------------*/
+
+void BLASTER_UnlockMemory
+ (
+ void
+ )
+
+ {
+ DPMI_UnlockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd );
+ DPMI_UnlockMemory( ( void * )&BLASTER_Interrupts[ 0 ],
+ sizeof( BLASTER_Interrupts ) );
+ DPMI_UnlockMemory( ( void * )&BLASTER_SampleSize[ 0 ],
+ sizeof( BLASTER_SampleSize ) );
+ DPMI_Unlock( BLASTER_Card );
+ DPMI_Unlock( BLASTER_OldInt );
+ DPMI_Unlock( BLASTER_Config );
+ DPMI_Unlock( BLASTER_Installed );
+ DPMI_Unlock( BLASTER_Version );
+ DPMI_Unlock( BLASTER_DMABuffer );
+ DPMI_Unlock( BLASTER_DMABufferEnd );
+ DPMI_Unlock( BLASTER_CurrentDMABuffer );
+ DPMI_Unlock( BLASTER_TotalDMABufferSize );
+ DPMI_Unlock( BLASTER_TransferLength );
+ DPMI_Unlock( BLASTER_MixMode );
+ DPMI_Unlock( BLASTER_SamplePacketSize );
+ DPMI_Unlock( BLASTER_SampleRate );
+ DPMI_Unlock( BLASTER_HaltTransferCommand );
+ DPMI_Unlock( ( int )BLASTER_SoundPlaying );
+ DPMI_Unlock( ( int )BLASTER_SoundRecording );
+ DPMI_Unlock( BLASTER_CallBack );
+ DPMI_Unlock( BLASTER_IntController1Mask );
+ DPMI_Unlock( BLASTER_IntController2Mask );
+ DPMI_Unlock( BLASTER_MixerAddress );
+ DPMI_Unlock( BLASTER_MixerType );
+ DPMI_Unlock( BLASTER_OriginalMidiVolumeLeft );
+ DPMI_Unlock( BLASTER_OriginalMidiVolumeRight );
+ DPMI_Unlock( BLASTER_OriginalVoiceVolumeLeft );
+ DPMI_Unlock( BLASTER_OriginalVoiceVolumeRight );
+ DPMI_Unlock( GlobalStatus );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_LockMemory
+
+ Locks all neccessary data.
+---------------------------------------------------------------------*/
+
+int BLASTER_LockMemory
+ (
+ void
+ )
+
+ {
+ int status;
+
+ status = DPMI_LockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd );
+ status |= DPMI_LockMemory( ( void * )&BLASTER_Interrupts[ 0 ],
+ sizeof( BLASTER_Interrupts ) );
+ status |= DPMI_LockMemory( ( void * )&BLASTER_SampleSize[ 0 ],
+ sizeof( BLASTER_SampleSize ) );
+ status |= DPMI_Lock( BLASTER_Card );
+ status |= DPMI_Lock( BLASTER_OldInt );
+ status |= DPMI_Lock( BLASTER_Config );
+ status |= DPMI_Lock( BLASTER_Installed );
+ status |= DPMI_Lock( BLASTER_Version );
+ status |= DPMI_Lock( BLASTER_DMABuffer );
+ status |= DPMI_Lock( BLASTER_DMABufferEnd );
+ status |= DPMI_Lock( BLASTER_CurrentDMABuffer );
+ status |= DPMI_Lock( BLASTER_TotalDMABufferSize );
+ status |= DPMI_Lock( BLASTER_TransferLength );
+ status |= DPMI_Lock( BLASTER_MixMode );
+ status |= DPMI_Lock( BLASTER_SamplePacketSize );
+ status |= DPMI_Lock( BLASTER_SampleRate );
+ status |= DPMI_Lock( BLASTER_HaltTransferCommand );
+ status |= DPMI_Lock( ( ( int )BLASTER_SoundPlaying ) );
+ status |= DPMI_Lock( ( ( int )BLASTER_SoundRecording ) );
+ status |= DPMI_Lock( BLASTER_CallBack );
+ status |= DPMI_Lock( BLASTER_IntController1Mask );
+ status |= DPMI_Lock( BLASTER_IntController2Mask );
+ status |= DPMI_Lock( BLASTER_MixerAddress );
+ status |= DPMI_Lock( BLASTER_MixerType );
+ status |= DPMI_Lock( BLASTER_OriginalMidiVolumeLeft );
+ status |= DPMI_Lock( BLASTER_OriginalMidiVolumeRight );
+ status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeLeft );
+ status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeRight );
+ status |= DPMI_Lock( GlobalStatus );
+
+ if ( status != DPMI_Ok )
+ {
+ BLASTER_UnlockMemory();
+ BLASTER_SetErrorCode( BLASTER_DPMI_Error );
+ return( BLASTER_Error );
+ }
+
+ return( BLASTER_Ok );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: allocateTimerStack
+
+ Allocate a block of memory from conventional (low) memory and return
+ the selector (which can go directly into a segment register) of the
+ memory block or 0 if an error occured.
+---------------------------------------------------------------------*/
+
+static unsigned short allocateTimerStack
+ (
+ unsigned short size
+ )
+
+ {
+ union REGS regs;
+
+ // clear all registers
+ memset( &regs, 0, sizeof( regs ) );
+
+ // DPMI allocate conventional memory
+ regs.w.ax = 0x100;
+
+ // size in paragraphs
+ regs.w.bx = ( size + 15 ) / 16;
+
+ int386( 0x31, &regs, &regs );
+ if (!regs.w.cflag)
+ {
+ // DPMI call returns selector in dx
+ // (ax contains real mode segment
+ // which is ignored here)
+
+ return( regs.w.dx );
+ }
+
+ // Couldn't allocate memory.
+ return( NULL );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: deallocateTimerStack
+
+ Deallocate a block of conventional (low) memory given a selector to
+ it. Assumes the block was allocated with DPMI function 0x100.
+---------------------------------------------------------------------*/
+
+static void deallocateTimerStack
+ (
+ unsigned short selector
+ )
+
+ {
+ union REGS regs;
+
+ if ( selector != NULL )
+ {
+ // clear all registers
+ memset( &regs, 0, sizeof( regs ) );
+
+ regs.w.ax = 0x101;
+ regs.w.dx = selector;
+ int386( 0x31, &regs, &regs );
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_SetupWaveBlaster
+
+ Allows the WaveBlaster to play music while the Sound Blaster 16
+ plays digital sound.
+---------------------------------------------------------------------*/
+
+void BLASTER_SetupWaveBlaster
+ (
+ void
+ )
+
+ {
+
+ if ( BLASTER_MixerType == SB16 )
+ {
+ // Disable MPU401 interrupts. If they are not disabled,
+ // the SB16 will not produce sound or music.
+ BLASTER_WaveBlasterState = BLASTER_ReadMixer( MIXER_DSP4xxISR_Enable );
+ BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, MIXER_DisableMPU401Interrupts );
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_ShutdownWaveBlaster
+
+ Restores WaveBlaster mixer to original state.
+---------------------------------------------------------------------*/
+
+void BLASTER_ShutdownWaveBlaster
+ (
+ void
+ )
+
+ {
+ if ( BLASTER_MixerType == SB16 )
+ {
+ // Restore the state of MPU401 interrupts. If they are not disabled,
+ // the SB16 will not produce sound or music.
+ BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, BLASTER_WaveBlasterState );
+ }
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_Init
+
+ Initializes the sound card and prepares the module to play
+ digitized sounds.
+---------------------------------------------------------------------*/
+
+int BLASTER_Init
+ (
+ void
+ )
+
+ {
+ int Irq;
+ int Interrupt;
+ int status;
+
+ if ( BLASTER_Installed )
+ {
+ BLASTER_Shutdown();
+ }
+
+ if ( BLASTER_Config.Address == UNDEFINED )
+ {
+ BLASTER_SetErrorCode( BLASTER_AddrNotSet );
+ return( BLASTER_Error );
+ }
+
+ // Save the interrupt masks
+ BLASTER_IntController1Mask = inp( 0x21 );
+ BLASTER_IntController2Mask = inp( 0xA1 );
+
+ status = BLASTER_ResetDSP();
+ if ( status == BLASTER_Ok )
+ {
+ BLASTER_SaveVoiceVolume();
+
+ BLASTER_SoundPlaying = FALSE;
+
+ BLASTER_SetCallBack( NULL );
+
+ BLASTER_DMABuffer = NULL;
+
+ BLASTER_Version = BLASTER_GetDSPVersion();
+
+ BLASTER_SetPlaybackRate( BLASTER_DefaultSampleRate );
+ BLASTER_SetMixMode( BLASTER_DefaultMixMode );
+
+ if ( BLASTER_Config.Dma16 != UNDEFINED )
+ {
+ status = DMA_VerifyChannel( BLASTER_Config.Dma16 );
+ if ( status == DMA_Error )
+ {
+ BLASTER_SetErrorCode( BLASTER_DmaError );
+ return( BLASTER_Error );
+ }
+ }
+
+ if ( BLASTER_Config.Dma8 != UNDEFINED )
+ {
+ status = DMA_VerifyChannel( BLASTER_Config.Dma8 );
+ if ( status == DMA_Error )
+ {
+ BLASTER_SetErrorCode( BLASTER_DmaError );
+ return( BLASTER_Error );
+ }
+ }
+
+ // Install our interrupt handler
+ Irq = BLASTER_Config.Interrupt;
+ if ( !VALID_IRQ( Irq ) )
+ {
+ BLASTER_SetErrorCode( BLASTER_InvalidIrq );
+ return( BLASTER_Error );
+ }
+
+ Interrupt = BLASTER_Interrupts[ Irq ];
+ if ( Interrupt == INVALID )
+ {
+ BLASTER_SetErrorCode( BLASTER_InvalidIrq );
+ return( BLASTER_Error );
+ }
+
+ status = BLASTER_LockMemory();
+ if ( status != BLASTER_Ok )
+ {
+ BLASTER_UnlockMemory();
+ return( status );
+ }
+
+ StackSelector = allocateTimerStack( kStackSize );
+ if ( StackSelector == NULL )
+ {
+ BLASTER_UnlockMemory();
+ BLASTER_SetErrorCode( BLASTER_OutOfMemory );
+ return( BLASTER_Error );
+ }
+
+ // Leave a little room at top of stack just for the hell of it...
+ StackPointer = kStackSize - sizeof( long );
+
+ BLASTER_OldInt = _dos_getvect( Interrupt );
+ if ( Irq < 8 )
+ {
+ _dos_setvect( Interrupt, BLASTER_ServiceInterrupt );
+ }
+ else
+ {
+ status = IRQ_SetVector( Interrupt, BLASTER_ServiceInterrupt );
+ if ( status != IRQ_Ok )
+ {
+ BLASTER_UnlockMemory();
+ deallocateTimerStack( StackSelector );
+ StackSelector = NULL;
+ BLASTER_SetErrorCode( BLASTER_UnableToSetIrq );
+ return( BLASTER_Error );
+ }
+ }
+
+ BLASTER_Installed = TRUE;
+ status = BLASTER_Ok;
+ }
+
+ BLASTER_SetErrorCode( status );
+ return( status );
+ }
+
+
+/*---------------------------------------------------------------------
+ Function: BLASTER_Shutdown
+
+ Ends transfer of sound data to the sound card and restores the
+ system resources used by the card.
+---------------------------------------------------------------------*/
+
+void BLASTER_Shutdown
+ (
+ void
+ )
+
+ {
+ int Irq;
+ int Interrupt;
+
+ // Halt the DMA transfer
+ BLASTER_StopPlayback();
+
+ BLASTER_RestoreVoiceVolume();
+
+ // Reset the DSP
+ BLASTER_ResetDSP();
+
+ // Restore the original interrupt
+ Irq = BLASTER_Config.Interrupt;
+ Interrupt = BLASTER_Interrupts[ Irq ];
+ if ( Irq >= 8 )
+ {
+ IRQ_RestoreVector( Interrupt );
+ }
+ _dos_setvect( Interrupt, BLASTER_OldInt );
+
+ BLASTER_SoundPlaying = FALSE;
+
+ BLASTER_DMABuffer = NULL;
+
+ BLASTER_SetCallBack( NULL );
+
+ BLASTER_UnlockMemory();
+
+ deallocateTimerStack( StackSelector );
+ StackSelector = NULL;
+
+ BLASTER_Installed = FALSE;
+ }