duke3d/audiolib/sndsrc.c

659 lines
14 KiB
C
Raw Normal View History

/*
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: SNDSRC.C
author: James R. Dose
date: March 26, 1994
Low level routines to support the Disney Sound Source.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#define STEREO 1
#define SIXTEEN_BIT 2
#define MONO_8BIT 0
#define STEREO_8BIT ( STEREO )
#define MONO_16BIT ( SIXTEEN_BIT )
#define STEREO_16BIT ( STEREO | SIXTEEN_BIT )
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
#include "dpmi.h"
#include "task_man.h"
#include "sndcards.h"
#include "user.h"
#include "sndsrc.h"
#define TRUE ( 1 == 1 )
#define FALSE ( !TRUE )
static int SS_Installed = FALSE;
static int SS_Port = SS_DefaultPort;
static int SS_OffCommand = 0xc;
static char *SS_BufferStart;
static char *SS_BufferEnd;
static char *SS_CurrentBuffer;
static int SS_BufferNum = 0;
static int SS_NumBuffers = 0;
static int SS_TotalBufferSize = 0;
static int SS_TransferLength = 0;
static int SS_CurrentLength = 0;
static char *SS_SoundPtr;
volatile int SS_SoundPlaying;
static task *SS_Timer;
void ( *SS_CallBack )( void );
int SS_ErrorCode = SS_Ok;
#define SS_SetErrorCode( status ) \
SS_ErrorCode = ( status );
/*---------------------------------------------------------------------
Function: SS_ErrorString
Returns a pointer to the error message associated with an error
number. A -1 returns a pointer the current error.
---------------------------------------------------------------------*/
char *SS_ErrorString
(
int ErrorNumber
)
{
char *ErrorString;
switch( ErrorNumber )
{
case SS_Error :
ErrorString = SS_ErrorString( SS_ErrorCode );
break;
case SS_Ok :
ErrorString = "Sound Source ok.";
break;
case SS_NotFound :
ErrorString = "Could not detect Sound Source.";
break;
case SS_NoSoundPlaying :
ErrorString = "No sound playing in SndSrc.";
break;
case SS_DPMI_Error :
ErrorString = "DPMI Error in SndSrc.";
break;
default :
ErrorString = "Unknown Sound Source error code.";
break;
}
return( ErrorString );
}
/**********************************************************************
Memory locked functions:
**********************************************************************/
#define SS_LockStart SS_ServiceInterrupt
/*---------------------------------------------------------------------
Function: SS_ServiceInterrupt
Handles interrupt generated by sound card at the end of a voice
transfer. Calls the user supplied callback function.
---------------------------------------------------------------------*/
static void SS_ServiceInterrupt
(
task *Task
)
{
int port = SS_Port;
int count;
count = 0;
while( ( inp( port + 1 ) & 0x40 ) == 0 )
{
outp( port, *SS_SoundPtr++ );
outp( port + 2, SS_OffCommand );
outp( port + 2, 4 );
SS_CurrentLength--;
if ( SS_CurrentLength == 0 )
{
// Keep track of current buffer
SS_CurrentBuffer += SS_TransferLength;
SS_BufferNum++;
if ( SS_BufferNum >= SS_NumBuffers )
{
SS_BufferNum = 0;
SS_CurrentBuffer = SS_BufferStart;
}
SS_CurrentLength = SS_TransferLength;
SS_SoundPtr = SS_CurrentBuffer;
// Call the caller's callback function
if ( SS_CallBack != NULL )
{
SS_CallBack();
}
}
count++;
// Only do at most 14 samples per tick
if ( count > 13 )
{
break;
}
}
}
/*---------------------------------------------------------------------
Function: SS_StopPlayback
Ends the transfer of digitized sound to the Sound Source.
---------------------------------------------------------------------*/
void SS_StopPlayback
(
void
)
{
if ( SS_SoundPlaying )
{
TS_Terminate( SS_Timer );
outp( SS_Port, 0x80 );
outp( SS_Port + 2, SS_OffCommand );
outp( SS_Port + 2, 4 );
SS_SoundPlaying = FALSE;
SS_BufferStart = NULL;
}
}
/*---------------------------------------------------------------------
Function: SS_GetCurrentPos
Returns the offset within the current sound being played.
---------------------------------------------------------------------*/
int SS_GetCurrentPos
(
void
)
{
int offset;
if ( !SS_SoundPlaying )
{
SS_SetErrorCode( SS_NoSoundPlaying );
return( SS_Warning );
}
offset = ( int )( ( ( unsigned long )SS_SoundPtr ) -
( ( unsigned long )SS_CurrentBuffer ) );
return( offset );
}
/*---------------------------------------------------------------------
Function: SS_LockEnd
Used for determining the length of the functions to lock in memory.
---------------------------------------------------------------------*/
static void SS_LockEnd
(
void
)
{
}
/*---------------------------------------------------------------------
Function: SS_BeginBufferedPlayback
Begins multibuffered playback of digitized sound on the Sound Source.
---------------------------------------------------------------------*/
int SS_BeginBufferedPlayback
(
char *BufferStart,
int BufferSize,
int NumDivisions,
void ( *CallBackFunc )( void )
)
{
if ( SS_SoundPlaying )
{
SS_StopPlayback();
}
SS_SetCallBack( CallBackFunc );
SS_BufferStart = BufferStart;
SS_CurrentBuffer = BufferStart;
SS_SoundPtr = BufferStart;
SS_TotalBufferSize = BufferSize;
SS_BufferEnd = BufferStart + BufferSize;
SS_TransferLength = BufferSize / NumDivisions;
SS_CurrentLength = SS_TransferLength;
SS_BufferNum = 0;
SS_NumBuffers = NumDivisions;
SS_SoundPlaying = TRUE;
// SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 438, 1, NULL );
SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 510, 1, NULL );
TS_Dispatch();
return( SS_Ok );
}
/*---------------------------------------------------------------------
Function: SS_GetPlaybackRate
Returns the rate at which the digitized sound will be played in
hertz.
---------------------------------------------------------------------*/
int SS_GetPlaybackRate
(
void
)
{
return( SS_SampleRate );
}
/*---------------------------------------------------------------------
Function: SS_SetMixMode
Sets the sound card to play samples in mono or stereo.
---------------------------------------------------------------------*/
int SS_SetMixMode
(
int mode
)
{
mode = MONO_8BIT;
return( mode );
}
/*---------------------------------------------------------------------
Function: SS_SetPort
Selects which port to use to write to the Sound Source.
---------------------------------------------------------------------*/
int SS_SetPort
(
int port
)
{
if ( SS_Installed )
{
SS_Shutdown();
}
SS_Port = port;
return( SS_Ok );
}
/*---------------------------------------------------------------------
Function: SS_SetCallBack
Specifies the user function to call at the end of a sound transfer.
---------------------------------------------------------------------*/
void SS_SetCallBack
(
void ( *func )( void )
)
{
SS_CallBack = func;
}
/*---------------------------------------------------------------------
Function: SS_TestTimer
Used as a delay in SS_TestSoundSource.
---------------------------------------------------------------------*/
void SS_TestTimer
(
task *Task
)
{
( *( int * )( Task->data ) )++;
}
/*---------------------------------------------------------------------
Function: SS_TestSoundSource
Detect if the Sound Source is located at the specified port.
---------------------------------------------------------------------*/
int SS_TestSoundSource
(
int port
)
{
int present;
task *timer;
volatile int ticks;
int i;
present = FALSE;
timer = TS_ScheduleTask( SS_TestTimer, 140, 1, &ticks );
TS_Dispatch();
outp( port + 2, 4 );
ticks = 0;
while( ticks < 4 )
{
// Do nothing for a while
}
TS_Terminate( timer );
if ( ( inp( port + 1 ) & 0x40 ) == 0 )
{
for( i = 32; i > 0; i-- )
{
outp( port, 0x80 );
outp( port + 2, SS_OffCommand );
outp( port + 2, 4 );
}
if ( inp( port + 1 ) & 0x40 )
{
present = TRUE;
}
}
outp( port + 2, SS_OffCommand );
return( present );
}
/*---------------------------------------------------------------------
Function: SS_DetectSoundSource
Detects which port the Sound Source is located.
---------------------------------------------------------------------*/
int SS_DetectSoundSource
(
void
)
{
if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT1 ) )
{
SS_Port = SS_Port1;
return( TRUE );
}
if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT2 ) )
{
SS_Port = SS_Port2;
return( TRUE );
}
if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT3 ) )
{
SS_Port = SS_Port3;
return( TRUE );
}
if ( SS_TestSoundSource( SS_Port1 ) )
{
SS_Port = SS_Port1;
return( TRUE );
}
if ( SS_TestSoundSource( SS_Port2 ) )
{
SS_Port = SS_Port2;
return( TRUE );
}
if ( SS_TestSoundSource( SS_Port3 ) )
{
SS_Port = SS_Port3;
return( TRUE );
}
return( FALSE );
}
/*---------------------------------------------------------------------
Function: SS_Init
Initializes the Sound Source prepares the module to play digitized
sounds.
---------------------------------------------------------------------*/
int SS_Init
(
int soundcard
)
{
int status;
if ( SS_Installed )
{
SS_Shutdown();
}
if ( ( soundcard == TandySoundSource ) ||
( USER_CheckParameter( SELECT_TANDY_SOUNDSOURCE ) ) )
{
// Tandy
SS_OffCommand = 0x0e;
}
else
{
// Disney
SS_OffCommand = 0x0c;
}
status = SS_DetectSoundSource();
if ( !status )
{
SS_SetErrorCode( SS_NotFound );
return( SS_Warning );
}
status = SS_LockMemory();
if ( status != SS_Ok )
{
SS_UnlockMemory();
return( status );
}
status = SS_Ok;
outp( SS_Port + 2, 4 );
SS_SoundPlaying = FALSE;
SS_SetCallBack( NULL );
SS_BufferStart = NULL;
SS_Installed = TRUE;
SS_SetErrorCode( status );
return( status );
}
/*---------------------------------------------------------------------
Function: SS_Shutdown
Ends transfer of sound data to the Sound Source.
---------------------------------------------------------------------*/
void SS_Shutdown
(
void
)
{
// Halt the transfer
SS_StopPlayback();
outp( SS_Port + 2, SS_OffCommand );
SS_SoundPlaying = FALSE;
SS_BufferStart = NULL;
SS_SetCallBack( NULL );
SS_UnlockMemory();
SS_Installed = FALSE;
}
/*---------------------------------------------------------------------
Function: SS_UnlockMemory
Unlocks all neccessary data.
---------------------------------------------------------------------*/
void SS_UnlockMemory
(
void
)
{
DPMI_UnlockMemoryRegion( SS_LockStart, SS_LockEnd );
DPMI_Unlock( SS_Installed );
DPMI_Unlock( SS_Port );
DPMI_Unlock( SS_OffCommand );
DPMI_Unlock( SS_BufferStart );
DPMI_Unlock( SS_BufferEnd );
DPMI_Unlock( SS_CurrentBuffer );
DPMI_Unlock( SS_BufferNum );
DPMI_Unlock( SS_NumBuffers );
DPMI_Unlock( SS_TotalBufferSize );
DPMI_Unlock( SS_TransferLength );
DPMI_Unlock( SS_CurrentLength );
DPMI_Unlock( SS_SoundPtr );
DPMI_Unlock( SS_SoundPlaying );
DPMI_Unlock( SS_Timer );
DPMI_Unlock( SS_CallBack );
DPMI_Unlock( SS_ErrorCode );
}
/*---------------------------------------------------------------------
Function: SS_LockMemory
Locks all neccessary data.
---------------------------------------------------------------------*/
int SS_LockMemory
(
void
)
{
int status;
status = DPMI_LockMemoryRegion( SS_LockStart, SS_LockEnd );
status |= DPMI_Lock( SS_Installed );
status |= DPMI_Lock( SS_Port );
status |= DPMI_Lock( SS_OffCommand );
status |= DPMI_Lock( SS_BufferStart );
status |= DPMI_Lock( SS_BufferEnd );
status |= DPMI_Lock( SS_CurrentBuffer );
status |= DPMI_Lock( SS_BufferNum );
status |= DPMI_Lock( SS_NumBuffers );
status |= DPMI_Lock( SS_TotalBufferSize );
status |= DPMI_Lock( SS_TransferLength );
status |= DPMI_Lock( SS_CurrentLength );
status |= DPMI_Lock( SS_SoundPtr );
status |= DPMI_Lock( SS_SoundPlaying );
status |= DPMI_Lock( SS_Timer );
status |= DPMI_Lock( SS_CallBack );
status |= DPMI_Lock( SS_ErrorCode );
if ( status != DPMI_Ok )
{
SS_UnlockMemory();
SS_SetErrorCode( SS_DPMI_Error );
return( SS_Error );
}
return( SS_Ok );
}