659 lines
14 KiB
C
659 lines
14 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: 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 );
|
||
|
}
|