2003-07-28 01:44:38 +00:00
/* Copyright (C) 1994-2003 Revolution 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 .
*
* $ Header $
*/
//--------------------------------------------------------------------------------------
// BROKEN SWORD 2
//
// SOUND.CPP Contains the sound engine, fx & music functions
// Some very 'sound' code in here ;)
//
// (16Dec96 JEL)
//
//--------------------------------------------------------------------------------------
# include <stdio.h>
2003-07-28 03:12:49 +00:00
# include "stdafx.h"
2003-07-28 01:44:38 +00:00
//#include "src\driver96.h"
# include "console.h"
# include "defs.h" // for RESULT
# include "interpreter.h"
# include "protocol.h" // for FetchObjectName() for debugging FN_play_fx
# include "resman.h"
# include "sound.h"
2003-07-28 07:00:15 +00:00
# include "sword2.h"
2003-07-28 01:44:38 +00:00
//--------------------------------------------------------------------------------------
typedef struct
{
uint32 resource ; // resource id of sample
uint32 fetchId ; // Id of resource in PSX CD queue. :)
uint16 delay ; // cycles to wait before playing (or 'random chance' if FX_RANDOM)
uint8 volume ; // 0..16
int8 pan ; // -16..16
uint8 type ; // FX_SPOT, FX_RANDOM or FX_LOOP
} _fxq_entry ;
# define FXQ_LENGTH 32 // max number of fx in queue at once [DO NOT EXCEED 255]
_fxq_entry fxq [ FXQ_LENGTH ] ;
//--------------------------------------------------------------------------------------
uint32 looping_music_id = 0 ; // used to store id of tunes that loop, for save & restore
char musicDirectory [ 120 ] ;
//--------------------------------------------------------------------------------------
// local function prototypes
void Trigger_fx ( uint8 j ) ;
//--------------------------------------------------------------------------------------
// initialise the fxq by clearing all the entries
void Init_fx_queue ( void )
{
uint8 j ;
for ( j = 0 ; j < FXQ_LENGTH ; j + + ) // scan the queue
{
fxq [ j ] . resource = 0 ; // 0 resource means 'empty' slot
fxq [ j ] . fetchId = 0 ; // Not being fetched.
}
}
//--------------------------------------------------------------------------------------
// process the fxq once every game cycle
void Process_fx_queue ( void )
{
uint8 j ; // assuming FXQ_LENGTH is 255 or less
for ( j = 0 ; j < FXQ_LENGTH ; j + + ) // scan the queue
{
if ( fxq [ j ] . resource ) // if this entry isn't empty
{
if ( fxq [ j ] . type = = FX_RANDOM ) // if it's type FX_RANDOM
{
if ( rand ( ) % ( fxq [ j ] . delay ) = = 0 ) // 1 in 'delay' chance of this fx occurring
{
Trigger_fx ( j ) ; // play it
}
}
else if ( fxq [ j ] . type = = FX_SPOT )
{
if ( fxq [ j ] . delay ) // if delay is above 0
fxq [ j ] . delay - - ; // decrement delay countdown
else // if zero delay remaining
{
Trigger_fx ( j ) ; // play it
fxq [ j ] . type = FX_SPOT2 ;
}
}
else if ( fxq [ j ] . type = = FX_SPOT2 )
{
2003-07-30 19:25:31 +00:00
if ( g_sword2 - > _sound - > IsFxOpen ( j + 1 ) )
2003-07-28 01:44:38 +00:00
fxq [ j ] . resource = 0 ; // Once the Fx has finished remove it from the queue.
}
}
}
}
//--------------------------------------------------------------------------------------
void Trigger_fx ( uint8 j ) // called from Process_fx_queue only
{
uint8 * data ;
int32 id ;
uint32 rv ;
id = ( uint32 ) j + 1 ; // because 0 is not a valid id
if ( fxq [ j ] . type = = FX_SPOT )
{
data = res_man . Res_open ( fxq [ j ] . resource ) ; // load in the sample
data + = sizeof ( _standardHeader ) ;
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > PlayFx ( id , data , fxq [ j ] . volume , fxq [ j ] . pan , RDSE_FXSPOT ) ; // wav data gets copied to sound memory
2003-07-28 01:44:38 +00:00
res_man . Res_close ( fxq [ j ] . resource ) ; // release the sample
// fxq[j].resource = 0; // clear spot fx from queue
}
else // random & looped fx are already loaded into sound memory by FN_play_fx()
{ // - to be referenced by 'j', so pass NULL data
if ( fxq [ j ] . type = = FX_RANDOM )
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > PlayFx ( id , NULL , fxq [ j ] . volume , fxq [ j ] . pan , RDSE_FXSPOT ) ; // not looped
2003-07-28 01:44:38 +00:00
else // FX_LOOP
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > PlayFx ( id , NULL , fxq [ j ] . volume , fxq [ j ] . pan , RDSE_FXLOOP ) ; // looped
2003-07-28 01:44:38 +00:00
}
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
if ( rv )
Zdebug ( " SFX ERROR: PlayFx() returned %.8x (%s line %u) " , rv , __FILE__ , __LINE__ ) ;
# endif
}
//--------------------------------------------------------------------------------------
int32 FN_play_fx ( int32 * params ) // called from script only
{
// params: 0 sample resource id
// 1 type (FX_SPOT, FX_RANDOM, FX_LOOP)
// 2 delay (0..65535)
// 3 volume (0..16)
// 4 pan (-16..16)
// example script: FN_play_fx (FXWATER, FX_LOOP, 0, 10, 15);
// fx_water = result; // fx_water is just a local script flag
// .
// .
// .
// FN_stop_fx (fx_water);
uint8 j = 0 ;
uint8 * data ;
uint32 id ;
uint32 rv ;
//----------------------------------
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
_standardHeader * header ;
char type [ 10 ] ;
if ( wantSfxDebug )
{
switch ( params [ 1 ] ) // 'type'
{
case FX_SPOT :
strcpy ( type , " SPOT " ) ;
break ;
case FX_LOOP :
strcpy ( type , " LOOPED " ) ;
break ;
case FX_RANDOM :
strcpy ( type , " RANDOM " ) ;
break ;
default :
strcpy ( type , " INVALID " ) ;
}
Zdebug ( " SFX (sample= \" %s \" , vol=%d, pan=%d, delay=%d, type=%s) " , FetchObjectName ( params [ 0 ] ) , params [ 3 ] , params [ 4 ] , params [ 2 ] , type ) ;
}
2003-07-30 19:25:31 +00:00
# endif //_SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
//----------------------------------
while ( ( j < FXQ_LENGTH ) & & ( fxq [ j ] . resource ! = 0 ) )
j + + ;
if ( j = = FXQ_LENGTH )
{
return ( IR_CONT ) ;
// Con_fatal_error("ERROR: Sound queue overflow in FN_play_fx() (%s line %u)",__FILE__,__LINE__);
}
else
{
fxq [ j ] . resource = params [ 0 ] ; // wav resource id
fxq [ j ] . type = params [ 1 ] ; // FX_SPOT, FX_LOOP or FX_RANDOM
if ( fxq [ j ] . type = = FX_RANDOM ) // FX_RANDOM:
fxq [ j ] . delay = params [ 2 ] * 12 + 1 ; // 'delay' param is the intended average no. seconds between playing this effect (+1 to avoid divide-by-zero in Process_fx_queue)
else // FX_SPOT or FX_LOOP:
fxq [ j ] . delay = params [ 2 ] ; // 'delay' is no. frames to wait before playing
fxq [ j ] . volume = params [ 3 ] ; // 0..16
fxq [ j ] . pan = params [ 4 ] ; // -16..16
if ( fxq [ j ] . type = = FX_SPOT ) // spot fx
{
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
data = res_man . Res_open ( fxq [ j ] . resource ) ; // "pre-load" the sample; this gets it into memory
header = ( _standardHeader * ) data ;
if ( header - > fileType ! = WAV_FILE )
Con_fatal_error ( " FN_play_fx given invalid resource (%s line %u) " , __FILE__ , __LINE__ ) ;
# else
res_man . Res_open ( fxq [ j ] . resource ) ; // "pre-load" the sample; this gets it into memory
# endif
res_man . Res_close ( fxq [ j ] . resource ) ; // but then releases it to "age" out if the space is needed
}
else // random & looped fx
{
id = ( uint32 ) j + 1 ; // because 0 is not a valid id
data = res_man . Res_open ( fxq [ j ] . resource ) ; // load in the sample
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
header = ( _standardHeader * ) data ;
if ( header - > fileType ! = WAV_FILE )
Con_fatal_error ( " FN_play_fx given invalid resource (%s line %u) " , __FILE__ , __LINE__ ) ;
# endif
data + = sizeof ( _standardHeader ) ;
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > OpenFx ( id , data ) ; // copy it to sound memory, using position in queue as 'id'
2003-07-28 01:44:38 +00:00
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
if ( rv )
Zdebug ( " SFX ERROR: OpenFx() returned %.8x (%s line %u) " , rv , __FILE__ , __LINE__ ) ;
# endif
res_man . Res_close ( fxq [ j ] . resource ) ; // release the sample
}
}
//---------------------------------------------
// (James07uag97)
if ( fxq [ j ] . type = = FX_LOOP ) // looped fx
Trigger_fx ( j ) ; // play now, rather than in Process_fx_queue where it was getting played again & again!
//---------------------------------------------
RESULT = j ; // in case we want to call FN_stop_fx() later, to kill this fx (mainly for FX_LOOP & FX_RANDOM)
return ( IR_CONT ) ; // continue script
}
//--------------------------------------------------------------------------------------
int32 FN_sound_fetch ( int32 * params )
{
return ( IR_CONT ) ;
}
//--------------------------------------------------------------------------------------
// to alter the volume and pan of a currently playing fx
int32 FN_set_fx_vol_and_pan ( int32 * params )
{
// params 0 id of fx (ie. the id returned in 'result' from FN_play_fx
// 1 new volume (0..16)
// 2 new pan (-16..16)
// SetFxVolumePan(int32 id, uint8 vol, uint8 pan);
2003-07-30 19:25:31 +00:00
g_sword2 - > _sound - > SetFxVolumePan ( 1 + params [ 0 ] , params [ 1 ] , params [ 2 ] ) ; // driver fx_id is 1+<pos in queue>
2003-07-28 01:44:38 +00:00
// Zdebug("%d",params[2]);
return ( IR_CONT ) ;
}
//--------------------------------------------------------------------------------------
// to alter the volume of a currently playing fx
int32 FN_set_fx_vol ( int32 * params )
{
// params 0 id of fx (ie. the id returned in 'result' from FN_play_fx
// 1 new volume (0..16)
// SetFxIdVolume(int32 id, uint8 vol);
2003-07-30 19:25:31 +00:00
g_sword2 - > _sound - > SetFxIdVolume ( 1 + params [ 0 ] , params [ 1 ] ) ;
2003-07-28 01:44:38 +00:00
return ( IR_CONT ) ;
}
//--------------------------------------------------------------------------------------
int32 FN_stop_fx ( int32 * params ) // called from script only
{
// params: 0 position in queue
// This will stop looped & random fx instantly, and remove the fx from the queue.
// So although it doesn't stop spot fx, it will remove them from the queue if they haven't yet played
uint8 j = ( uint8 ) params [ 0 ] ;
uint32 id ;
uint32 rv ;
if ( ( fxq [ j ] . type = = FX_RANDOM ) | | ( fxq [ j ] . type = = FX_LOOP ) )
{
id = ( uint32 ) j + 1 ; // because 0 is not a valid id
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > CloseFx ( id ) ; // stop fx & remove sample from sound memory
2003-07-28 01:44:38 +00:00
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
if ( rv )
Zdebug ( " SFX ERROR: CloseFx() returned %.8x (%s line %u) " , rv , __FILE__ , __LINE__ ) ;
# endif
}
fxq [ j ] . resource = 0 ; // remove from queue
return ( IR_CONT ) ; // continue script
}
//--------------------------------------------------------------------------------------
int32 FN_stop_all_fx ( int32 * params ) // called from script only
{
// Stops all looped & random fx and clears the entire queue
// NO PARAMS
Clear_fx_queue ( ) ;
return ( IR_CONT ) ; // continue script
}
//--------------------------------------------------------------------------------------
// Stops all looped & random fx and clears the entire queue
void Clear_fx_queue ( void )
{
2003-07-30 19:25:31 +00:00
g_sword2 - > _sound - > ClearAllFx ( ) ; // stop all fx & remove the samples from sound memory
2003-07-28 01:44:38 +00:00
Init_fx_queue ( ) ; // clean out the queue
}
//--------------------------------------------------------------------------------------
//=============================================================================
// int32 StreamMusic(uint8 *filename, int32 loopFlag)
//
// Streams music from the file defined by filename. The loopFlag should
// be set to RDSE_FXLOOP if the music is to loop back to the start.
// Otherwise, it should be RDSE_FXSPOT.
// The return value must be checked for any problems.
//
// --------------------------------------------------------------------------
//
// int32 PauseMusic(void)
//
// Stops the music dead in it's tracks.
//
// --------------------------------------------------------------------------
//
// int32 UnpauseMusic(void)
//
// Re-starts the music from where it was stopped.
//
//=============================================================================
int32 FN_prepare_music ( int32 * params )
{
return ( IR_CONT ) ;
}
//--------------------------------------------------------------------------------------
// Start a tune playing, to play once or to loop until stopped or next one played
int32 FN_play_music ( int32 * params ) // updated by James on 10apr97
{
// params 0 tune id
// 1 loop flag (0 or 1)
char filename [ 128 ] ;
uint32 loopFlag ;
uint32 rv ; // drivers return value
// Zdebug("FN_play_music(%d)", params[0]);
if ( params [ 1 ] = = FX_LOOP ) // if it is to loop
{
loopFlag = RDSE_FXLOOP ;
looping_music_id = params [ 0 ] ; // keep a note of the id, for restarting after an interruption to gameplay
}
else // just play once
{
loopFlag = RDSE_FXSPOT ;
looping_music_id = 0 ; // don't need to restart this tune after control panel or restore
}
// add the appropriate file extension & play it
2003-08-24 12:13:03 +00:00
sprintf ( filename , " Music.clu " ) ;
2003-07-28 01:44:38 +00:00
2003-08-30 18:06:08 +00:00
rv = g_sword2 - > _sound - > StreamCompMusic ( filename , params [ 0 ] , loopFlag ) ;
2003-07-28 01:44:38 +00:00
2003-07-30 19:25:31 +00:00
# ifdef _SWORD2_DEBUG
2003-07-28 01:44:38 +00:00
if ( rv )
Zdebug ( " ERROR: StreamCompMusic(%s, %d, %d) returned error 0x%.8x " , filename , params [ 0 ] , loopFlag , rv ) ;
# endif
// Zdebug("FN_play_music(%d) returning", params[0]);
return ( IR_CONT ) ; // continue script
}
//--------------------------------------------------------------------------------------
int32 FN_stop_music ( int32 * params ) // called from script only
{
// params: none
looping_music_id = 0 ; // clear the 'looping' flag
2003-07-30 19:25:31 +00:00
g_sword2 - > _sound - > StopMusic ( ) ;
2003-07-28 01:44:38 +00:00
if ( params ) ;
return ( IR_CONT ) ; // continue script
}
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
void Kill_music ( void ) // James22aug97
{
uint8 count ;
looping_music_id = 0 ; // clear the 'looping' flag
2003-07-30 19:25:31 +00:00
g_sword2 - > _sound - > StopMusic ( ) ;
2003-07-28 01:44:38 +00:00
// THIS BIT CAUSES THE MUSIC TO STOP INSTANTLY!
for ( count = 0 ; count < 16 ; count + + )
2003-07-30 19:25:31 +00:00
g_sword2 - > _sound - > UpdateCompSampleStreaming ( ) ;
2003-07-28 01:44:38 +00:00
}
//--------------------------------------------------------------------------------------
int32 FN_check_music_playing ( int32 * params ) // James (30july97)
{
// params: none
// sets result to no. of seconds of current tune remaining
// or 0 if no music playing
2003-07-30 19:25:31 +00:00
RESULT = g_sword2 - > _sound - > MusicTimeRemaining ( ) ; // in seconds, rounded up to the nearest second
2003-07-28 01:44:38 +00:00
return ( IR_CONT ) ; // continue script
}
//--------------------------------------------------------------------------------------
void PauseAllSound ( void ) // James25july97
{
uint32 rv ; // for drivers return value
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > PauseMusic ( ) ;
2003-07-28 01:44:38 +00:00
if ( rv ! = RD_OK )
Zdebug ( " ERROR: PauseMusic() returned %.8x in PauseAllSound() " , rv ) ;
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > PauseSpeech ( ) ;
2003-07-28 01:44:38 +00:00
if ( rv ! = RD_OK )
Zdebug ( " ERROR: PauseSpeech() returned %.8x in PauseAllSound() " , rv ) ;
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > PauseFx ( ) ;
2003-07-28 01:44:38 +00:00
if ( rv ! = RD_OK )
Zdebug ( " ERROR: PauseFx() returned %.8x in PauseAllSound() " , rv ) ;
}
//--------------------------------------------------------------------------------------
void UnpauseAllSound ( void ) // James25july97
{
uint32 rv ; // for drivers return value
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > UnpauseMusic ( ) ;
2003-07-28 01:44:38 +00:00
if ( rv ! = RD_OK )
Zdebug ( " ERROR: UnpauseMusic() returned %.8x in UnpauseAllSound() " , rv ) ;
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > UnpauseSpeech ( ) ;
2003-07-28 01:44:38 +00:00
if ( rv ! = RD_OK )
Zdebug ( " ERROR: UnpauseSpeech() returned %.8x in UnpauseAllSound() " , rv ) ;
2003-07-30 19:25:31 +00:00
rv = g_sword2 - > _sound - > UnpauseFx ( ) ;
2003-07-28 01:44:38 +00:00
if ( rv ! = RD_OK )
Zdebug ( " ERROR: UnpauseFx() returned %.8x in UnpauseAllSound() " , rv ) ;
}
//--------------------------------------------------------------------------------------