rott/audiolib/SOURCE/PCFX.C
2002-12-25 00:00:00 +00:00

547 lines
12 KiB
C

/*
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: PCFX.C
author: James R. Dose
date: April 1, 1994
Low level routines to support PC sound effects created by Muse.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#include <dos.h>
#include <stdlib.h>
#include <conio.h>
#include "dpmi.h"
#include "task_man.h"
#include "interrup.h"
#include "pcfx.h"
#define TRUE ( 1 == 1 )
#define FALSE ( !TRUE )
static void PCFX_Service( task *Task );
static long PCFX_LengthLeft;
static char *PCFX_Sound = NULL;
static int PCFX_LastSample;
static short PCFX_Lookup[ 256 ];
static int PCFX_UseLookupFlag = FALSE;
static int PCFX_Priority;
static unsigned long PCFX_CallBackVal;
static void ( *PCFX_CallBackFunc )( unsigned long ) = NULL;
static int PCFX_TotalVolume = PCFX_MaxVolume;
static task *PCFX_ServiceTask = NULL;
static int PCFX_VoiceHandle = PCFX_MinVoiceHandle;
int PCFX_Installed = FALSE;
int PCFX_ErrorCode = PCFX_Ok;
#define PCFX_SetErrorCode( status ) \
PCFX_ErrorCode = ( status );
/*---------------------------------------------------------------------
Function: PCFX_ErrorString
Returns a pointer to the error message associated with an error
number. A -1 returns a pointer the current error.
---------------------------------------------------------------------*/
char *PCFX_ErrorString
(
int ErrorNumber
)
{
char *ErrorString;
switch( ErrorNumber )
{
case PCFX_Warning :
case PCFX_Error :
ErrorString = PCFX_ErrorString( PCFX_ErrorCode );
break;
case PCFX_Ok :
ErrorString = "PC FX ok.";
break;
case PCFX_NoVoices :
ErrorString = "No free voices available to PC FX.";
break;
case PCFX_VoiceNotFound :
ErrorString = "No voice with matching handle found.";
break;
case PCFX_DPMI_Error :
ErrorString = "DPMI Error in PCFX.";
break;
default :
ErrorString = "Unknown PC FX error code.";
break;
}
return( ErrorString );
}
/**********************************************************************
Memory locked functions:
**********************************************************************/
#define PCFX_LockStart PCFX_Stop
/*---------------------------------------------------------------------
Function: PCFX_Stop
Halts playback of the currently playing sound effect.
---------------------------------------------------------------------*/
int PCFX_Stop
(
int handle
)
{
unsigned flags;
if ( ( handle != PCFX_VoiceHandle ) || ( PCFX_Sound == NULL ) )
{
PCFX_SetErrorCode( PCFX_VoiceNotFound );
return( PCFX_Warning );
}
flags = DisableInterrupts();
// Turn off speaker
outp( 0x61, inp( 0x61 ) & 0xfc );
PCFX_Sound = NULL;
PCFX_LengthLeft = 0;
PCFX_Priority = 0;
PCFX_LastSample = 0;
RestoreInterrupts( flags );
if ( PCFX_CallBackFunc )
{
PCFX_CallBackFunc( PCFX_CallBackVal );
}
return( PCFX_Ok );
}
/*---------------------------------------------------------------------
Function: PCFX_Service
Task Manager routine to perform the playback of a sound effect.
---------------------------------------------------------------------*/
static void PCFX_Service
(
task *Task
)
{
unsigned value;
if ( PCFX_Sound )
{
if ( PCFX_UseLookupFlag )
{
value = PCFX_Lookup[ *PCFX_Sound ];
PCFX_Sound++;
}
else
{
value = *( short int * )PCFX_Sound;
PCFX_Sound += sizeof( short int );
}
if ( ( PCFX_TotalVolume > 0 ) && ( value != PCFX_LastSample ) )
{
PCFX_LastSample = value;
if ( value )
{
outp( 0x43, 0xb6 );
outp( 0x42, value );
outp( 0x42, value >> 8 );
outp( 0x61, inp( 0x61 ) | 0x3 );
}
else
{
outp( 0x61, inp( 0x61 ) & 0xfc );
}
}
if ( --PCFX_LengthLeft == 0 )
{
PCFX_Stop( PCFX_VoiceHandle );
}
}
}
/*---------------------------------------------------------------------
Function: PCFX_VoiceAvailable
Checks if a voice can be play at the specified priority.
---------------------------------------------------------------------*/
int PCFX_VoiceAvailable
(
int priority
)
{
if ( priority < PCFX_Priority )
{
return( FALSE );
}
return( TRUE );
}
/*---------------------------------------------------------------------
Function: PCFX_Play
Starts playback of a Muse sound effect.
---------------------------------------------------------------------*/
int PCFX_Play
(
PCSound *sound,
int priority,
unsigned long callbackval
)
{
unsigned flags;
if ( priority < PCFX_Priority )
{
PCFX_SetErrorCode( PCFX_NoVoices );
return( PCFX_Warning );
}
PCFX_Stop( PCFX_VoiceHandle );
PCFX_VoiceHandle++;
if ( PCFX_VoiceHandle < PCFX_MinVoiceHandle )
{
PCFX_VoiceHandle = PCFX_MinVoiceHandle;
}
flags = DisableInterrupts();
PCFX_LengthLeft = sound->length;
if ( !PCFX_UseLookupFlag )
{
PCFX_LengthLeft >>= 1;
}
PCFX_Priority = priority;
PCFX_Sound = &sound->data;
PCFX_CallBackVal = callbackval;
RestoreInterrupts( flags );
return( PCFX_VoiceHandle );
}
/*---------------------------------------------------------------------
Function: PCFX_SoundPlaying
Checks if a sound effect is currently playing.
---------------------------------------------------------------------*/
int PCFX_SoundPlaying
(
int handle
)
{
int status;
status = FALSE;
if ( ( handle == PCFX_VoiceHandle ) && ( PCFX_LengthLeft > 0 ) )
{
status = TRUE;
}
return( status );
}
/*---------------------------------------------------------------------
Function: PCFX_SetTotalVolume
Sets the total volume of the sound effects.
---------------------------------------------------------------------*/
int PCFX_SetTotalVolume
(
int volume
)
{
unsigned flags;
flags = DisableInterrupts();
volume = max( volume, 0 );
volume = min( volume, PCFX_MaxVolume );
PCFX_TotalVolume = volume;
if ( volume == 0 )
{
outp( 0x61, inp( 0x61 ) & 0xfc );
}
RestoreInterrupts( flags );
return( PCFX_Ok );
}
/*---------------------------------------------------------------------
Function: PCFX_GetTotalVolume
Returns the total volume of the sound effects.
---------------------------------------------------------------------*/
int PCFX_GetTotalVolume
(
void
)
{
return( PCFX_TotalVolume );
}
/*---------------------------------------------------------------------
Function: PCFX_LockEnd
Used for determining the length of the functions to lock in memory.
---------------------------------------------------------------------*/
static void PCFX_LockEnd
(
void
)
{
}
/*---------------------------------------------------------------------
Function: PCFX_UseLookup
Sets up a pitch lookup table for PC sound effects.
---------------------------------------------------------------------*/
void PCFX_UseLookup
(
int use,
unsigned value
)
{
int pitch;
int index;
PCFX_Stop( PCFX_VoiceHandle );
PCFX_UseLookupFlag = use;
if ( use )
{
pitch = 0;
for( index = 0; index < 256; index++ )
{
PCFX_Lookup[ index ] = pitch;
pitch += value;
}
}
}
/*---------------------------------------------------------------------
Function: PCFX_SetCallBack
Set the function to call when a voice stops.
---------------------------------------------------------------------*/
void PCFX_SetCallBack
(
void ( *function )( unsigned long )
)
{
PCFX_CallBackFunc = function;
}
/*---------------------------------------------------------------------
Function: PCFX_Init
Initializes the sound effect engine.
---------------------------------------------------------------------*/
int PCFX_Init
(
void
)
{
int status;
if ( PCFX_Installed )
{
PCFX_Shutdown();
}
status = PCFX_LockMemory();
if ( status != PCFX_Ok )
{
PCFX_UnlockMemory();
return( status );
}
PCFX_UseLookup( TRUE, 60 );
PCFX_Stop( PCFX_VoiceHandle );
PCFX_ServiceTask = TS_ScheduleTask( &PCFX_Service, 140, 2, NULL );
TS_Dispatch();
PCFX_CallBackFunc = NULL;
PCFX_Installed = TRUE;
PCFX_SetErrorCode( PCFX_Ok );
return( PCFX_Ok );
}
/*---------------------------------------------------------------------
Function: PCFX_Shutdown
Ends the use of the sound effect engine.
---------------------------------------------------------------------*/
int PCFX_Shutdown
(
void
)
{
if ( PCFX_Installed )
{
PCFX_Stop( PCFX_VoiceHandle );
TS_Terminate( PCFX_ServiceTask );
PCFX_UnlockMemory();
PCFX_Installed = FALSE;
}
PCFX_SetErrorCode( PCFX_Ok );
return( PCFX_Ok );
}
/*---------------------------------------------------------------------
Function: PCFX_UnlockMemory
Unlocks all neccessary data.
---------------------------------------------------------------------*/
void PCFX_UnlockMemory
(
void
)
{
DPMI_UnlockMemoryRegion( PCFX_LockStart, PCFX_LockEnd );
DPMI_Unlock( PCFX_LengthLeft );
DPMI_Unlock( PCFX_Sound );
DPMI_Unlock( PCFX_LastSample );
DPMI_Unlock( PCFX_Lookup );
DPMI_Unlock( PCFX_UseLookupFlag );
DPMI_Unlock( PCFX_Priority );
DPMI_Unlock( PCFX_CallBackVal );
DPMI_Unlock( PCFX_CallBackFunc );
DPMI_Unlock( PCFX_TotalVolume );
DPMI_Unlock( PCFX_ServiceTask );
DPMI_Unlock( PCFX_VoiceHandle );
DPMI_Unlock( PCFX_Installed );
DPMI_Unlock( PCFX_ErrorCode );
}
/*---------------------------------------------------------------------
Function: PCFX_LockMemory
Locks all neccessary data.
---------------------------------------------------------------------*/
int PCFX_LockMemory
(
void
)
{
int status;
status = DPMI_LockMemoryRegion( PCFX_LockStart, PCFX_LockEnd );
status |= DPMI_Lock( PCFX_LengthLeft );
status |= DPMI_Lock( PCFX_Sound );
status |= DPMI_Lock( PCFX_LastSample );
status |= DPMI_Lock( PCFX_Lookup );
status |= DPMI_Lock( PCFX_UseLookupFlag );
status |= DPMI_Lock( PCFX_Priority );
status |= DPMI_Lock( PCFX_CallBackVal );
status |= DPMI_Lock( PCFX_CallBackFunc );
status |= DPMI_Lock( PCFX_TotalVolume );
status |= DPMI_Lock( PCFX_ServiceTask );
status |= DPMI_Lock( PCFX_VoiceHandle );
status |= DPMI_Lock( PCFX_Installed );
status |= DPMI_Lock( PCFX_ErrorCode );
if ( status != DPMI_Ok )
{
PCFX_UnlockMemory();
PCFX_SetErrorCode( PCFX_DPMI_Error );
return( PCFX_Error );
}
return( PCFX_Ok );
}