15 May 2012
This commit is contained in:
parent
6b3e9e841e
commit
ce01422c4d
|
@ -697,7 +697,8 @@ enum
|
||||||
kRenderTransTexture, // src*a+dest*(1-a)
|
kRenderTransTexture, // src*a+dest*(1-a)
|
||||||
kRenderGlow, // src*a+dest -- No Z buffer checks
|
kRenderGlow, // src*a+dest -- No Z buffer checks
|
||||||
kRenderTransAlpha, // src*srca+dest*(1-srca)
|
kRenderTransAlpha, // src*srca+dest*(1-srca)
|
||||||
kRenderTransAdd // src*a+dest
|
kRenderTransAdd, // src*a+dest
|
||||||
|
kRenderWorldGlow, // Same as kRenderGlow but not fixed size in screen space
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|
|
@ -75,14 +75,14 @@ void CL_PlayCDTrack_f( void )
|
||||||
if( !Q_stricmp( command, "play" ))
|
if( !Q_stricmp( command, "play" ))
|
||||||
{
|
{
|
||||||
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
|
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
|
||||||
S_StartBackgroundTrack( clgame.cdtracks[track-1], NULL );
|
S_StartBackgroundTrack( clgame.cdtracks[track-1], NULL, 0 );
|
||||||
paused = false;
|
paused = false;
|
||||||
looped = false;
|
looped = false;
|
||||||
}
|
}
|
||||||
else if( !Q_stricmp( command, "loop" ))
|
else if( !Q_stricmp( command, "loop" ))
|
||||||
{
|
{
|
||||||
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
|
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
|
||||||
S_StartBackgroundTrack( clgame.cdtracks[track-1], clgame.cdtracks[track-1] );
|
S_StartBackgroundTrack( clgame.cdtracks[track-1], clgame.cdtracks[track-1], 0 );
|
||||||
paused = false;
|
paused = false;
|
||||||
looped = true;
|
looped = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2801,11 +2801,11 @@ void pfnMP3_InitStream( char *filename, int flags )
|
||||||
// g-cont. flag 1 is probably 'LOOP'
|
// g-cont. flag 1 is probably 'LOOP'
|
||||||
if( flags & 1 )
|
if( flags & 1 )
|
||||||
{
|
{
|
||||||
S_StartBackgroundTrack( filename, filename );
|
S_StartBackgroundTrack( filename, filename, 0 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
S_StartBackgroundTrack( filename, NULL );
|
S_StartBackgroundTrack( filename, NULL, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -842,6 +842,17 @@ static void pfnHostEndGame( const char *szFinalMessage )
|
||||||
Host_EndGame( szFinalMessage );
|
Host_EndGame( szFinalMessage );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========
|
||||||
|
pfnStartBackgroundTrack
|
||||||
|
|
||||||
|
=========
|
||||||
|
*/
|
||||||
|
static void pfnStartBackgroundTrack( const char *introTrack, const char *mainTrack )
|
||||||
|
{
|
||||||
|
S_StartBackgroundTrack( introTrack, mainTrack, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
// engine callbacks
|
// engine callbacks
|
||||||
static ui_enginefuncs_t gEngfuncs =
|
static ui_enginefuncs_t gEngfuncs =
|
||||||
{
|
{
|
||||||
|
@ -917,7 +928,7 @@ static ui_enginefuncs_t gEngfuncs =
|
||||||
Sys_ShellExecute,
|
Sys_ShellExecute,
|
||||||
Host_WriteServerConfig,
|
Host_WriteServerConfig,
|
||||||
pfnChangeInstance,
|
pfnChangeInstance,
|
||||||
S_StartBackgroundTrack,
|
pfnStartBackgroundTrack,
|
||||||
pfnHostEndGame,
|
pfnHostEndGame,
|
||||||
Com_RandomFloat,
|
Com_RandomFloat,
|
||||||
Com_RandomLong,
|
Com_RandomLong,
|
||||||
|
|
|
@ -318,7 +318,14 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
|
||||||
pitch = BF_ReadByte( msg );
|
pitch = BF_ReadByte( msg );
|
||||||
else pitch = PITCH_NORM;
|
else pitch = PITCH_NORM;
|
||||||
|
|
||||||
handle = cl.sound_index[sound]; // see precached sound
|
if( flags & SND_SENTENCE )
|
||||||
|
{
|
||||||
|
char sentenceName[32];
|
||||||
|
|
||||||
|
Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
|
||||||
|
handle = S_RegisterSound( sentenceName );
|
||||||
|
}
|
||||||
|
else handle = cl.sound_index[sound]; // see precached sound
|
||||||
|
|
||||||
// entity reletive
|
// entity reletive
|
||||||
entnum = BF_ReadWord( msg );
|
entnum = BF_ReadWord( msg );
|
||||||
|
@ -330,7 +337,7 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
|
||||||
BF_ReadBytes( msg, &samplePos, sizeof( samplePos ));
|
BF_ReadBytes( msg, &samplePos, sizeof( samplePos ));
|
||||||
BF_ReadBytes( msg, &forcedEnd, sizeof( forcedEnd ));
|
BF_ReadBytes( msg, &forcedEnd, sizeof( forcedEnd ));
|
||||||
|
|
||||||
S_RestoreSound( pos, entnum, chan, handle, volume, attn, pitch, flags, samplePos, forcedEnd );
|
S_RestoreSound( pos, entnum, chan, handle, volume, attn, pitch, flags, samplePos, forcedEnd, wordIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1506,7 +1513,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||||
param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum
|
param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum
|
||||||
param2 = BF_ReadByte( msg );
|
param2 = BF_ReadByte( msg );
|
||||||
param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum
|
param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum
|
||||||
S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1] );
|
S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0 );
|
||||||
break;
|
break;
|
||||||
case svc_serverinfo:
|
case svc_serverinfo:
|
||||||
CL_ServerInfo( msg );
|
CL_ServerInfo( msg );
|
||||||
|
|
|
@ -800,7 +800,7 @@ void Con_Close( void );
|
||||||
// s_main.c
|
// s_main.c
|
||||||
//
|
//
|
||||||
void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data );
|
void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data );
|
||||||
void S_StartBackgroundTrack( const char *intro, const char *loop );
|
void S_StartBackgroundTrack( const char *intro, const char *loop, long position );
|
||||||
void S_StopBackgroundTrack( void );
|
void S_StopBackgroundTrack( void );
|
||||||
void S_StreamSetPause( int pause );
|
void S_StreamSetPause( int pause );
|
||||||
void S_StartStreaming( void );
|
void S_StartStreaming( void );
|
||||||
|
@ -808,7 +808,7 @@ void S_StopStreaming( void );
|
||||||
void S_BeginRegistration( void );
|
void S_BeginRegistration( void );
|
||||||
sound_t S_RegisterSound( const char *sample );
|
sound_t S_RegisterSound( const char *sample );
|
||||||
void S_EndRegistration( void );
|
void S_EndRegistration( void );
|
||||||
void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end );
|
void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end, int wordIndex );
|
||||||
void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags );
|
void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags );
|
||||||
void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, float attn, int pitch, int flags );
|
void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, float attn, int pitch, int flags );
|
||||||
void S_FadeClientVolume( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds );
|
void S_FadeClientVolume( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds );
|
||||||
|
|
|
@ -139,6 +139,7 @@ S_FreeChannel
|
||||||
void S_FreeChannel( channel_t *ch )
|
void S_FreeChannel( channel_t *ch )
|
||||||
{
|
{
|
||||||
ch->sfx = NULL;
|
ch->sfx = NULL;
|
||||||
|
ch->name[0] = '\0';
|
||||||
ch->use_loop = false;
|
ch->use_loop = false;
|
||||||
ch->isSentence = false;
|
ch->isSentence = false;
|
||||||
|
|
||||||
|
@ -926,14 +927,15 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
|
||||||
// prepended with a '!'. Sentence names stored in the
|
// prepended with a '!'. Sentence names stored in the
|
||||||
// sentence file do not have a leading '!'.
|
// sentence file do not have a leading '!'.
|
||||||
VOX_LoadSound( target_chan, S_SkipSoundChar( sfx->name ));
|
VOX_LoadSound( target_chan, S_SkipSoundChar( sfx->name ));
|
||||||
|
Q_strncpy( target_chan->name, sfx->name, sizeof( target_chan->name ));
|
||||||
sfx = target_chan->sfx; // TEST
|
sfx = target_chan->sfx;
|
||||||
pSource = sfx->cache;
|
pSource = sfx->cache;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// regular or streamed sound fx
|
// regular or streamed sound fx
|
||||||
pSource = S_LoadSound( sfx );
|
pSource = S_LoadSound( sfx );
|
||||||
|
target_chan->name[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !pSource )
|
if( !pSource )
|
||||||
|
@ -986,7 +988,7 @@ S_RestoreSound
|
||||||
Restore a sound effect for the given entity on the given channel
|
Restore a sound effect for the given entity on the given channel
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end )
|
void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end, int wordIndex )
|
||||||
{
|
{
|
||||||
wavdata_t *pSource;
|
wavdata_t *pSource;
|
||||||
sfx_t *sfx = NULL;
|
sfx_t *sfx = NULL;
|
||||||
|
@ -1040,8 +1042,46 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
|
||||||
target_chan->ob_gain_target = 0.0f;
|
target_chan->ob_gain_target = 0.0f;
|
||||||
target_chan->bTraced = false;
|
target_chan->bTraced = false;
|
||||||
|
|
||||||
// regular or streamed sound fx
|
pSource = NULL;
|
||||||
pSource = S_LoadSound( sfx );
|
|
||||||
|
if( S_TestSoundChar( sfx->name, '!' ))
|
||||||
|
{
|
||||||
|
// this is a sentence
|
||||||
|
// link all words and load the first word
|
||||||
|
// NOTE: sentence names stored in the cache lookup are
|
||||||
|
// prepended with a '!'. Sentence names stored in the
|
||||||
|
// sentence file do not have a leading '!'.
|
||||||
|
VOX_LoadSound( target_chan, S_SkipSoundChar( sfx->name ));
|
||||||
|
|
||||||
|
// save the sentencename for future save\restores
|
||||||
|
Q_strncpy( target_chan->name, sfx->name, sizeof( target_chan->name ));
|
||||||
|
|
||||||
|
// not a first word in sentence!
|
||||||
|
if( wordIndex != 0 )
|
||||||
|
{
|
||||||
|
VOX_FreeWord( target_chan ); // release first loaded word
|
||||||
|
target_chan->wordIndex = wordIndex; // restore current word
|
||||||
|
VOX_LoadWord( target_chan );
|
||||||
|
|
||||||
|
if( target_chan->currentWord )
|
||||||
|
{
|
||||||
|
target_chan->sfx = target_chan->words[target_chan->wordIndex].sfx;
|
||||||
|
sfx = target_chan->sfx;
|
||||||
|
pSource = sfx->cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfx = target_chan->sfx;
|
||||||
|
pSource = sfx->cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// regular or streamed sound fx
|
||||||
|
pSource = S_LoadSound( sfx );
|
||||||
|
target_chan->name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
if( !pSource )
|
if( !pSource )
|
||||||
{
|
{
|
||||||
|
@ -1062,6 +1102,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
|
||||||
// if this is a streaming sound, play the whole thing.
|
// if this is a streaming sound, play the whole thing.
|
||||||
if( chan != CHAN_STREAM )
|
if( chan != CHAN_STREAM )
|
||||||
{
|
{
|
||||||
|
MsgDev( D_ERROR, "S_RestoreSound: %s volume 0\n", sfx->name );
|
||||||
S_FreeChannel( target_chan );
|
S_FreeChannel( target_chan );
|
||||||
return; // not audible at all
|
return; // not audible at all
|
||||||
}
|
}
|
||||||
|
@ -1137,6 +1178,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
|
||||||
|
|
||||||
// link all words and load the first word
|
// link all words and load the first word
|
||||||
VOX_LoadSound( ch, S_SkipSoundChar( sfx->name ));
|
VOX_LoadSound( ch, S_SkipSoundChar( sfx->name ));
|
||||||
|
Q_strncpy( ch->name, sfx->name, sizeof( ch->name ));
|
||||||
sfx = ch->sfx;
|
sfx = ch->sfx;
|
||||||
pSource = sfx->cache;
|
pSource = sfx->cache;
|
||||||
fvox = 1;
|
fvox = 1;
|
||||||
|
@ -1147,6 +1189,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
|
||||||
pSource = S_LoadSound( sfx );
|
pSource = S_LoadSound( sfx );
|
||||||
ch->sfx = sfx;
|
ch->sfx = sfx;
|
||||||
ch->isSentence = false;
|
ch->isSentence = false;
|
||||||
|
ch->name[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !pSource )
|
if( !pSource )
|
||||||
|
@ -1212,7 +1255,9 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
|
||||||
{
|
{
|
||||||
if( channels[i].entchannel == CHAN_STATIC && channels[i].sfx && channels[i].sfx->name[0] )
|
if( channels[i].entchannel == CHAN_STATIC && channels[i].sfx && channels[i].sfx->name[0] )
|
||||||
{
|
{
|
||||||
Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name ));
|
if( channels[i].isSentence && channels[i].name[0] )
|
||||||
|
Q_strncpy( pout->name, channels[i].name, sizeof( pout->name ));
|
||||||
|
else Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name ));
|
||||||
pout->entnum = channels[i].entnum;
|
pout->entnum = channels[i].entnum;
|
||||||
VectorCopy( channels[i].origin, pout->origin );
|
VectorCopy( channels[i].origin, pout->origin );
|
||||||
pout->volume = (float)channels[i].master_vol / 255.0f;
|
pout->volume = (float)channels[i].master_vol / 255.0f;
|
||||||
|
@ -1257,7 +1302,9 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
|
||||||
if( channels[i].entchannel == CHAN_STATIC && looped )
|
if( channels[i].entchannel == CHAN_STATIC && looped )
|
||||||
continue; // never serialize static looped sounds. It will be restoring in game code
|
continue; // never serialize static looped sounds. It will be restoring in game code
|
||||||
|
|
||||||
Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name ));
|
if( channels[i].isSentence && channels[i].name[0] )
|
||||||
|
Q_strncpy( pout->name, channels[i].name, sizeof( pout->name ));
|
||||||
|
else Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name ));
|
||||||
pout->entnum = channels[i].entnum;
|
pout->entnum = channels[i].entnum;
|
||||||
VectorCopy( channels[i].origin, pout->origin );
|
VectorCopy( channels[i].origin, pout->origin );
|
||||||
pout->volume = (float)channels[i].master_vol / 255.0f;
|
pout->volume = (float)channels[i].master_vol / 255.0f;
|
||||||
|
@ -1631,13 +1678,13 @@ void S_Music_f( void )
|
||||||
&& FS_FileExists( va( "media/%s.%s", main, ext[i] ), false ))
|
&& FS_FileExists( va( "media/%s.%s", main, ext[i] ), false ))
|
||||||
{
|
{
|
||||||
// combined track with introduction and main loop theme
|
// combined track with introduction and main loop theme
|
||||||
S_StartBackgroundTrack( intro, main );
|
S_StartBackgroundTrack( intro, main, 0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if( FS_FileExists( va( "media/%s.%s", track, ext[i] ), false ))
|
else if( FS_FileExists( va( "media/%s.%s", track, ext[i] ), false ))
|
||||||
{
|
{
|
||||||
// single looped theme
|
// single looped theme
|
||||||
S_StartBackgroundTrack( track, NULL );
|
S_StartBackgroundTrack( track, NULL, 0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1645,7 +1692,12 @@ void S_Music_f( void )
|
||||||
}
|
}
|
||||||
else if( c == 3 )
|
else if( c == 3 )
|
||||||
{
|
{
|
||||||
S_StartBackgroundTrack( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
S_StartBackgroundTrack( Cmd_Argv( 1 ), Cmd_Argv( 2 ), 0 );
|
||||||
|
}
|
||||||
|
else if( c == 4 && Q_atoi( Cmd_Argv( 3 )) != 0 )
|
||||||
|
{
|
||||||
|
// restore command for singleplayer: all arguments are valid
|
||||||
|
S_StartBackgroundTrack( Cmd_Argv( 1 ), Cmd_Argv( 2 ), Q_atoi( Cmd_Argv( 3 )));
|
||||||
}
|
}
|
||||||
else Msg( "Usage: music <musicfile> [loopfile]\n" );
|
else Msg( "Usage: music <musicfile> [loopfile]\n" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,19 @@ void S_CheckLerpingState( void )
|
||||||
S_StartBackgroundTrack
|
S_StartBackgroundTrack
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack )
|
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long position )
|
||||||
{
|
{
|
||||||
S_StopBackgroundTrack();
|
S_StopBackgroundTrack();
|
||||||
|
|
||||||
if( !dma.initialized ) return;
|
if( !dma.initialized ) return;
|
||||||
|
|
||||||
|
// check for special symbols
|
||||||
|
if( introTrack && *introTrack == '*' )
|
||||||
|
introTrack = NULL;
|
||||||
|
|
||||||
|
if( mainTrack && *mainTrack == '*' )
|
||||||
|
mainTrack = NULL;
|
||||||
|
|
||||||
if(( !introTrack || !*introTrack ) && ( !mainTrack || !*mainTrack ))
|
if(( !introTrack || !*introTrack ) && ( !mainTrack || !*mainTrack ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -54,8 +62,15 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack )
|
||||||
|
|
||||||
// open stream
|
// open stream
|
||||||
s_bgTrack.stream = FS_OpenStream( va( "media/%s", introTrack ));
|
s_bgTrack.stream = FS_OpenStream( va( "media/%s", introTrack ));
|
||||||
|
Q_strncpy( s_bgTrack.current, introTrack, sizeof( s_bgTrack.current ));
|
||||||
s_bgTrack.source = cls.key_dest;
|
s_bgTrack.source = cls.key_dest;
|
||||||
|
|
||||||
|
if( position != 0 )
|
||||||
|
{
|
||||||
|
// restore message, update song position
|
||||||
|
FS_SetStreamPos( s_bgTrack.stream, position );
|
||||||
|
}
|
||||||
|
|
||||||
S_CheckLerpingState();
|
S_CheckLerpingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +92,38 @@ void S_StreamSetPause( int pause )
|
||||||
s_listener.stream_paused = pause;
|
s_listener.stream_paused = pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
S_StreamGetCurrentState
|
||||||
|
|
||||||
|
save\restore code
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position )
|
||||||
|
{
|
||||||
|
if( !s_bgTrack.stream )
|
||||||
|
return false; // not active
|
||||||
|
|
||||||
|
if( currentTrack )
|
||||||
|
{
|
||||||
|
if( s_bgTrack.current[0] )
|
||||||
|
Q_strncpy( currentTrack, s_bgTrack.current, MAX_STRING );
|
||||||
|
else Q_strncpy( currentTrack, "*", MAX_STRING ); // no track
|
||||||
|
}
|
||||||
|
|
||||||
|
if( loopTrack )
|
||||||
|
{
|
||||||
|
if( s_bgTrack.loopName[0] )
|
||||||
|
Q_strncpy( loopTrack, s_bgTrack.loopName, MAX_STRING );
|
||||||
|
else Q_strncpy( loopTrack, "*", MAX_STRING ); // no track
|
||||||
|
}
|
||||||
|
|
||||||
|
if( position )
|
||||||
|
*position = FS_GetStreamPos( s_bgTrack.stream );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
S_StreamBackgroundTrack
|
S_StreamBackgroundTrack
|
||||||
|
@ -150,6 +197,7 @@ void S_StreamBackgroundTrack( void )
|
||||||
{
|
{
|
||||||
FS_FreeStream( s_bgTrack.stream );
|
FS_FreeStream( s_bgTrack.stream );
|
||||||
s_bgTrack.stream = FS_OpenStream( va( "media/%s", s_bgTrack.loopName ));
|
s_bgTrack.stream = FS_OpenStream( va( "media/%s", s_bgTrack.loopName ));
|
||||||
|
Q_strncpy( s_bgTrack.current, s_bgTrack.loopName, sizeof( s_bgTrack.current ));
|
||||||
|
|
||||||
if( !s_bgTrack.stream ) return;
|
if( !s_bgTrack.stream ) return;
|
||||||
S_CheckLerpingState();
|
S_CheckLerpingState();
|
||||||
|
|
|
@ -345,8 +345,8 @@ void VOX_LoadWord( channel_t *pchan )
|
||||||
|
|
||||||
if( pSource )
|
if( pSource )
|
||||||
{
|
{
|
||||||
int start = pchan->words[pchan->wordIndex].start;
|
int start = pchan->words[pchan->wordIndex].start;
|
||||||
int end = pchan->words[pchan->wordIndex].end;
|
int end = pchan->words[pchan->wordIndex].end;
|
||||||
|
|
||||||
// apply mixer
|
// apply mixer
|
||||||
pchan->currentWord = &pchan->pMixer;
|
pchan->currentWord = &pchan->pMixer;
|
||||||
|
@ -418,7 +418,7 @@ int VOX_MixDataToDevice( channel_t *pchan, int sampleCount, int outputRate, int
|
||||||
|
|
||||||
while( sampleCount > 0 && pchan->currentWord )
|
while( sampleCount > 0 && pchan->currentWord )
|
||||||
{
|
{
|
||||||
int outputCount = S_MixDataToDevice( pchan, sampleCount, outputRate, outputOffset );
|
int outputCount = S_MixDataToDevice( pchan, sampleCount, outputRate, outputOffset );
|
||||||
|
|
||||||
outputOffset += outputCount;
|
outputOffset += outputCount;
|
||||||
sampleCount -= outputCount;
|
sampleCount -= outputCount;
|
||||||
|
|
|
@ -141,8 +141,9 @@ typedef struct
|
||||||
qboolean finished;
|
qboolean finished;
|
||||||
} mixer_t;
|
} mixer_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct channel_s
|
||||||
{
|
{
|
||||||
|
char name[16]; // keept sentence name
|
||||||
sfx_t *sfx; // sfx number
|
sfx_t *sfx; // sfx number
|
||||||
|
|
||||||
int leftvol; // 0-255 left volume
|
int leftvol; // 0-255 left volume
|
||||||
|
@ -196,7 +197,8 @@ typedef struct
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
string loopName;
|
string current; // a currently playing track
|
||||||
|
string loopName; // may be empty
|
||||||
stream_t *stream;
|
stream_t *stream;
|
||||||
int source; // may be game, menu, etc
|
int source; // may be game, menu, etc
|
||||||
} bg_track_t;
|
} bg_track_t;
|
||||||
|
@ -305,6 +307,7 @@ void SND_CloseMouth( channel_t *ch );
|
||||||
//
|
//
|
||||||
void S_StreamSoundTrack( void );
|
void S_StreamSoundTrack( void );
|
||||||
void S_StreamBackgroundTrack( void );
|
void S_StreamBackgroundTrack( void );
|
||||||
|
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
|
||||||
|
|
||||||
//
|
//
|
||||||
// s_utils.c
|
// s_utils.c
|
||||||
|
|
|
@ -42,6 +42,7 @@ typedef struct
|
||||||
float length;
|
float length;
|
||||||
} sentence_t;
|
} sentence_t;
|
||||||
|
|
||||||
extern sentence_t g_Sentences[MAX_SENTENCES];
|
void VOX_LoadWord( struct channel_s *pchan );
|
||||||
|
void VOX_FreeWord( struct channel_s *pchan );
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -515,7 +515,7 @@ typedef enum
|
||||||
WF_TOTALCOUNT, // must be last
|
WF_TOTALCOUNT, // must be last
|
||||||
} sndformat_t;
|
} sndformat_t;
|
||||||
|
|
||||||
// imagelib global settings
|
// soundlib global settings
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
SL_USE_LERPING = BIT(0), // lerping sounds during resample
|
SL_USE_LERPING = BIT(0), // lerping sounds during resample
|
||||||
|
@ -558,6 +558,8 @@ void FS_FreeSound( wavdata_t *pack );
|
||||||
stream_t *FS_OpenStream( const char *filename );
|
stream_t *FS_OpenStream( const char *filename );
|
||||||
wavdata_t *FS_StreamInfo( stream_t *stream );
|
wavdata_t *FS_StreamInfo( stream_t *stream );
|
||||||
long FS_ReadStream( stream_t *stream, int bytes, void *buffer );
|
long FS_ReadStream( stream_t *stream, int bytes, void *buffer );
|
||||||
|
long FS_SetStreamPos( stream_t *stream, long newpos );
|
||||||
|
long FS_GetStreamPos( stream_t *stream );
|
||||||
void FS_FreeStream( stream_t *stream );
|
void FS_FreeStream( stream_t *stream );
|
||||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
|
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
|
||||||
uint Sound_GetApproxWavePlayLen( const char *filepath );
|
uint Sound_GetApproxWavePlayLen( const char *filepath );
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -60,7 +60,7 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
|
||||||
string path, loadname;
|
string path, loadname;
|
||||||
qboolean anyformat = true;
|
qboolean anyformat = true;
|
||||||
int filesize = 0;
|
int filesize = 0;
|
||||||
const loadwavformat_t *format;
|
const loadwavfmt_t *format;
|
||||||
byte *f;
|
byte *f;
|
||||||
|
|
||||||
Sound_Reset(); // clear old sounddata
|
Sound_Reset(); // clear old sounddata
|
||||||
|
@ -153,7 +153,7 @@ stream_t *FS_OpenStream( const char *filename )
|
||||||
const char *ext = FS_FileExtension( filename );
|
const char *ext = FS_FileExtension( filename );
|
||||||
string path, loadname;
|
string path, loadname;
|
||||||
qboolean anyformat = true;
|
qboolean anyformat = true;
|
||||||
const streamformat_t *format;
|
const streamfmt_t *format;
|
||||||
stream_t *stream;
|
stream_t *stream;
|
||||||
|
|
||||||
Sound_Reset(); // clear old streaminfo
|
Sound_Reset(); // clear old streaminfo
|
||||||
|
@ -240,6 +240,36 @@ long FS_ReadStream( stream_t *stream, int bytes, void *buffer )
|
||||||
return stream->format->readfunc( stream, bytes, buffer );
|
return stream->format->readfunc( stream, bytes, buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
FS_GetStreamPos
|
||||||
|
|
||||||
|
get stream position (in bytes)
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
long FS_GetStreamPos( stream_t *stream )
|
||||||
|
{
|
||||||
|
if( !stream || !stream->format || !stream->format->getposfunc )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return stream->format->getposfunc( stream );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
FS_SetStreamPos
|
||||||
|
|
||||||
|
get stream position (in bytes)
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
long FS_SetStreamPos( stream_t *stream, long newpos )
|
||||||
|
{
|
||||||
|
if( !stream || !stream->format || !stream->format->setposfunc )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return stream->format->setposfunc( stream, newpos );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
FS_FreeStream
|
FS_FreeStream
|
||||||
|
|
|
@ -28,21 +28,24 @@ GNU General Public License for more details.
|
||||||
|
|
||||||
typedef struct mpeg_s
|
typedef struct mpeg_s
|
||||||
{
|
{
|
||||||
void *state; // hidden decoder state
|
void *state; // hidden decoder state
|
||||||
void *vbrtag; // valid for VBR-encoded mpegs
|
void *vbrtag; // valid for VBR-encoded mpegs
|
||||||
|
|
||||||
int channels; // num channels
|
int channels; // num channels
|
||||||
int samples; // per one second
|
int samples; // per one second
|
||||||
int play_time;// stream size in milliseconds
|
int play_time; // stream size in milliseconds
|
||||||
int rate; // frequency
|
int rate; // frequency
|
||||||
int outsize; // current data size
|
int outsize; // current data size
|
||||||
char out[8192];// temporary buffer
|
char out[8192]; // temporary buffer
|
||||||
|
size_t streamsize; // size in bytes
|
||||||
} mpeg_t;
|
} mpeg_t;
|
||||||
|
|
||||||
// mpg123 exports
|
// mpg123 exports
|
||||||
int create_decoder( mpeg_t *mpg );
|
int create_decoder( mpeg_t *mpg );
|
||||||
int read_mpeg_header( mpeg_t *mpg, const char *data, long bufsize, long streamsize );
|
int read_mpeg_header( mpeg_t *mpg, const char *data, long bufsize, long streamsize );
|
||||||
int read_mpeg_stream( mpeg_t *mpg, const char *data, long bufsize );
|
int read_mpeg_stream( mpeg_t *mpg, const char *data, long bufsize );
|
||||||
|
extern int set_current_pos( mpeg_t *mpg, int newpos, int (*pfnSeek)( void*, long, int ), void *file );
|
||||||
|
int get_current_pos( mpeg_t *mpg, int curpos );
|
||||||
void close_decoder( mpeg_t *mpg );
|
void close_decoder( mpeg_t *mpg );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -153,6 +156,7 @@ stream_t *Stream_OpenMPG( const char *filename )
|
||||||
// at this point we have valid stream
|
// at this point we have valid stream
|
||||||
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
|
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
|
||||||
stream->file = file;
|
stream->file = file;
|
||||||
|
stream->pos = 0;
|
||||||
|
|
||||||
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpeg_t ));
|
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpeg_t ));
|
||||||
|
|
||||||
|
@ -188,8 +192,9 @@ stream_t *Stream_OpenMPG( const char *filename )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->pos = 0; // how many samples left from previous frame
|
stream->buffsize = 0; // how many samples left from previous frame
|
||||||
stream->channels = mpegFile->channels;
|
stream->channels = mpegFile->channels;
|
||||||
|
stream->pos += mpegFile->outsize;
|
||||||
stream->rate = mpegFile->rate;
|
stream->rate = mpegFile->rate;
|
||||||
stream->width = 2; // always 16 bit
|
stream->width = 2; // always 16 bit
|
||||||
stream->ptr = mpegFile;
|
stream->ptr = mpegFile;
|
||||||
|
@ -209,6 +214,7 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
|
||||||
{
|
{
|
||||||
// buffer handling
|
// buffer handling
|
||||||
int bytesWritten = 0;
|
int bytesWritten = 0;
|
||||||
|
int result;
|
||||||
mpeg_t *mpg;
|
mpeg_t *mpg;
|
||||||
|
|
||||||
mpg = (mpeg_t *)stream->ptr;
|
mpg = (mpeg_t *)stream->ptr;
|
||||||
|
@ -220,13 +226,27 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
|
||||||
long read_len, outsize;
|
long read_len, outsize;
|
||||||
byte *data;
|
byte *data;
|
||||||
|
|
||||||
if( !stream->pos )
|
if( !stream->buffsize )
|
||||||
{
|
{
|
||||||
if( read_mpeg_stream( mpg, NULL, 0 ) != MP3_OK )
|
if( stream->timejump )
|
||||||
|
{
|
||||||
|
stream->timejump = false;
|
||||||
|
read_len = FS_Read( stream->file, tempbuff, sizeof( tempbuff ));
|
||||||
|
result = read_mpeg_stream( mpg, tempbuff, read_len );
|
||||||
|
bytesWritten = 0;
|
||||||
|
}
|
||||||
|
else result = read_mpeg_stream( mpg, NULL, 0 );
|
||||||
|
|
||||||
|
stream->pos += mpg->outsize;
|
||||||
|
|
||||||
|
if( result != MP3_OK )
|
||||||
{
|
{
|
||||||
// if there are no bytes remainig so we can decompress the new frame
|
// if there are no bytes remainig so we can decompress the new frame
|
||||||
read_len = FS_Read( stream->file, tempbuff, sizeof( tempbuff ));
|
read_len = FS_Read( stream->file, tempbuff, sizeof( tempbuff ));
|
||||||
if( read_mpeg_stream( mpg, tempbuff, read_len ) != MP3_OK )
|
result = read_mpeg_stream( mpg, tempbuff, read_len );
|
||||||
|
stream->pos += mpg->outsize;
|
||||||
|
|
||||||
|
if( result != MP3_OK )
|
||||||
break; // there was end of the stream
|
break; // there was end of the stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,20 +258,56 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
|
||||||
|
|
||||||
// copy raw sample to output buffer
|
// copy raw sample to output buffer
|
||||||
data = (byte *)buffer + bytesWritten;
|
data = (byte *)buffer + bytesWritten;
|
||||||
Q_memcpy( data, &mpg->out[stream->pos], outsize );
|
Q_memcpy( data, &mpg->out[stream->buffsize], outsize );
|
||||||
bytesWritten += outsize;
|
bytesWritten += outsize;
|
||||||
mpg->outsize -= outsize;
|
mpg->outsize -= outsize;
|
||||||
stream->pos += outsize;
|
stream->buffsize += outsize;
|
||||||
|
|
||||||
// continue from this sample on a next call
|
// continue from this sample on a next call
|
||||||
if( bytesWritten >= needBytes )
|
if( bytesWritten >= needBytes )
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
|
|
||||||
stream->pos = 0; // no bytes remaining
|
stream->buffsize = 0; // no bytes remaining
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Stream_SetPosMPG
|
||||||
|
|
||||||
|
assume stream is valid
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
long Stream_SetPosMPG( stream_t *stream, long newpos )
|
||||||
|
{
|
||||||
|
// update stream pos for right work GetPos function
|
||||||
|
int newPos = set_current_pos( stream->ptr, newpos, FS_Seek, stream->file );
|
||||||
|
|
||||||
|
if( newPos != -1 )
|
||||||
|
{
|
||||||
|
stream->pos = newPos;
|
||||||
|
stream->timejump = true;
|
||||||
|
stream->buffsize = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// failed to seek for some reasons
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Stream_GetPosMPG
|
||||||
|
|
||||||
|
assume stream is valid
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
long Stream_GetPosMPG( stream_t *stream )
|
||||||
|
{
|
||||||
|
return get_current_pos( stream->ptr, stream->pos );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Stream_FreeMPG
|
Stream_FreeMPG
|
||||||
|
|
|
@ -23,12 +23,12 @@ GNU General Public License for more details.
|
||||||
=============================================================================
|
=============================================================================
|
||||||
*/
|
*/
|
||||||
// stub
|
// stub
|
||||||
static const loadwavformat_t load_null[] =
|
static const loadwavfmt_t load_null[] =
|
||||||
{
|
{
|
||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const loadwavformat_t load_game[] =
|
static const loadwavfmt_t load_game[] =
|
||||||
{
|
{
|
||||||
{ "sound/%s%s.%s", "wav", Sound_LoadWAV },
|
{ "sound/%s%s.%s", "wav", Sound_LoadWAV },
|
||||||
{ "%s%s.%s", "wav", Sound_LoadWAV },
|
{ "%s%s.%s", "wav", Sound_LoadWAV },
|
||||||
|
@ -45,16 +45,16 @@ static const loadwavformat_t load_game[] =
|
||||||
=============================================================================
|
=============================================================================
|
||||||
*/
|
*/
|
||||||
// stub
|
// stub
|
||||||
static const streamformat_t stream_null[] =
|
static const streamfmt_t stream_null[] =
|
||||||
{
|
{
|
||||||
{ NULL, NULL, NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const streamformat_t stream_game[] =
|
static const streamfmt_t stream_game[] =
|
||||||
{
|
{
|
||||||
{ "%s%s.%s", "mp3", Stream_OpenMPG, Stream_ReadMPG, Stream_FreeMPG },
|
{ "%s%s.%s", "mp3", Stream_OpenMPG, Stream_ReadMPG, Stream_SetPosMPG, Stream_GetPosMPG, Stream_FreeMPG },
|
||||||
{ "%s%s.%s", "wav", Stream_OpenWAV, Stream_ReadWAV, Stream_FreeWAV },
|
{ "%s%s.%s", "wav", Stream_OpenWAV, Stream_ReadWAV, Stream_SetPosWAV, Stream_GetPosWAV, Stream_FreeWAV },
|
||||||
{ NULL, NULL, NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
void Sound_Init( void )
|
void Sound_Init( void )
|
||||||
|
@ -89,6 +89,7 @@ byte *Sound_Copy( size_t size )
|
||||||
|
|
||||||
out = Mem_Alloc( host.soundpool, size );
|
out = Mem_Alloc( host.soundpool, size );
|
||||||
Q_memcpy( out, sound.tempbuffer, size );
|
Q_memcpy( out, sound.tempbuffer, size );
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,8 +298,9 @@ Stream_OpenWAV
|
||||||
stream_t *Stream_OpenWAV( const char *filename )
|
stream_t *Stream_OpenWAV( const char *filename )
|
||||||
{
|
{
|
||||||
stream_t *stream;
|
stream_t *stream;
|
||||||
int iff_data, last_chunk;
|
int last_chunk = 0;
|
||||||
char chunkName[4];
|
char chunkName[4];
|
||||||
|
int iff_data;
|
||||||
file_t *file;
|
file_t *file;
|
||||||
short t;
|
short t;
|
||||||
|
|
||||||
|
@ -374,6 +375,7 @@ stream_t *Stream_OpenWAV( const char *filename )
|
||||||
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
|
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
|
||||||
stream->file = file;
|
stream->file = file;
|
||||||
stream->size = sound.samples * sound.width * sound.channels;
|
stream->size = sound.samples * sound.width * sound.channels;
|
||||||
|
stream->buffsize = FS_Tell( file ); // header length
|
||||||
stream->channels = sound.channels;
|
stream->channels = sound.channels;
|
||||||
stream->width = sound.width;
|
stream->width = sound.width;
|
||||||
stream->rate = sound.rate;
|
stream->rate = sound.rate;
|
||||||
|
@ -406,6 +408,37 @@ long Stream_ReadWAV( stream_t *stream, long bytes, void *buffer )
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Stream_SetPosWAV
|
||||||
|
|
||||||
|
assume stream is valid
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
long Stream_SetPosWAV( stream_t *stream, long newpos )
|
||||||
|
{
|
||||||
|
// NOTE: stream->pos it's real file position without header size
|
||||||
|
if( FS_Seek( stream->file, stream->buffsize + newpos, SEEK_SET ) != -1 )
|
||||||
|
{
|
||||||
|
stream->pos = newpos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Stream_GetPosWAV
|
||||||
|
|
||||||
|
assume stream is valid
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
long Stream_GetPosWAV( stream_t *stream )
|
||||||
|
{
|
||||||
|
return stream->pos;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Stream_FreeWAV
|
Stream_FreeWAV
|
||||||
|
|
|
@ -18,27 +18,29 @@ GNU General Public License for more details.
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
typedef struct loadwavformat_s
|
typedef struct loadwavfmt_s
|
||||||
{
|
{
|
||||||
const char *formatstring;
|
const char *formatstring;
|
||||||
const char *ext;
|
const char *ext;
|
||||||
qboolean (*loadfunc)( const char *name, const byte *buffer, size_t filesize );
|
qboolean (*loadfunc)( const char *name, const byte *buffer, size_t filesize );
|
||||||
} loadwavformat_t;
|
} loadwavfmt_t;
|
||||||
|
|
||||||
typedef struct streamformat_s
|
typedef struct streamfmt_s
|
||||||
{
|
{
|
||||||
const char *formatstring;
|
const char *formatstring;
|
||||||
const char *ext;
|
const char *ext;
|
||||||
|
|
||||||
stream_t *(*openfunc)( const char *filename );
|
stream_t *(*openfunc)( const char *filename );
|
||||||
long (*readfunc)( stream_t *stream, long bytes, void *buffer );
|
long (*readfunc)( stream_t *stream, long bytes, void *buffer );
|
||||||
|
long (*setposfunc)( stream_t *stream, long newpos );
|
||||||
|
long (*getposfunc)( stream_t *stream );
|
||||||
void (*freefunc)( stream_t *stream );
|
void (*freefunc)( stream_t *stream );
|
||||||
} streamformat_t;
|
} streamfmt_t;
|
||||||
|
|
||||||
typedef struct sndlib_s
|
typedef struct sndlib_s
|
||||||
{
|
{
|
||||||
const loadwavformat_t *loadformats;
|
const loadwavfmt_t *loadformats;
|
||||||
const streamformat_t *streamformat; // music stream
|
const streamfmt_t *streamformat; // music stream
|
||||||
|
|
||||||
// current sound state
|
// current sound state
|
||||||
int type; // sound type
|
int type; // sound type
|
||||||
|
@ -57,17 +59,19 @@ typedef struct sndlib_s
|
||||||
|
|
||||||
typedef struct stream_s
|
typedef struct stream_s
|
||||||
{
|
{
|
||||||
const streamformat_t *format; // streamformat to operate
|
const streamfmt_t *format; // streamformat to operate
|
||||||
|
|
||||||
// current stream state
|
// current stream state
|
||||||
file_t *file; // stream file
|
file_t *file; // stream file
|
||||||
int width; // resolution - num bits divided by 8 (8 bit is 1, 16 bit is 2)
|
int width; // resolution - num bits divided by 8 (8 bit is 1, 16 bit is 2)
|
||||||
int rate; // stream rate
|
int rate; // stream rate
|
||||||
int channels; // stream channels
|
int channels; // stream channels
|
||||||
int type; // wavtype
|
int type; // wavtype
|
||||||
size_t size; // total stream size
|
size_t size; // total stream size
|
||||||
int pos; // keep track wav position
|
int pos; // actual track position
|
||||||
void *ptr;
|
void *ptr; // internal decoder state
|
||||||
|
int buffsize; // cached buffer size
|
||||||
|
qboolean timejump; // true if position is changed
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -116,9 +120,13 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize );
|
||||||
//
|
//
|
||||||
stream_t *Stream_OpenWAV( const char *filename );
|
stream_t *Stream_OpenWAV( const char *filename );
|
||||||
long Stream_ReadWAV( stream_t *stream, long bytes, void *buffer );
|
long Stream_ReadWAV( stream_t *stream, long bytes, void *buffer );
|
||||||
|
long Stream_SetPosWAV( stream_t *stream, long newpos );
|
||||||
|
long Stream_GetPosWAV( stream_t *stream );
|
||||||
void Stream_FreeWAV( stream_t *stream );
|
void Stream_FreeWAV( stream_t *stream );
|
||||||
stream_t *Stream_OpenMPG( const char *filename );
|
stream_t *Stream_OpenMPG( const char *filename );
|
||||||
long Stream_ReadMPG( stream_t *stream, long bytes, void *buffer );
|
long Stream_ReadMPG( stream_t *stream, long bytes, void *buffer );
|
||||||
|
long Stream_SetPosMPG( stream_t *stream, long newpos );
|
||||||
|
long Stream_GetPosMPG( stream_t *stream );
|
||||||
void Stream_FreeMPG( stream_t *stream );
|
void Stream_FreeMPG( stream_t *stream );
|
||||||
|
|
||||||
#endif//SOUNDLIB_H
|
#endif//SOUNDLIB_H
|
|
@ -818,7 +818,6 @@ void SV_InitOperatorCommands( void )
|
||||||
Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" );
|
Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" );
|
||||||
Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" );
|
Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" );
|
||||||
Cmd_AddCommand( "entpatch", SV_EntPatch_f, "write entity patch to allow external editing" );
|
Cmd_AddCommand( "entpatch", SV_EntPatch_f, "write entity patch to allow external editing" );
|
||||||
Cmd_AddCommand( "map_background", SV_MapBackground_f, "set background map" );
|
|
||||||
Cmd_AddCommand( "edicts_info", SV_EdictsInfo_f, "show info about edicts" );
|
Cmd_AddCommand( "edicts_info", SV_EdictsInfo_f, "show info about edicts" );
|
||||||
Cmd_AddCommand( "entity_info", SV_EntityInfo_f, "show more info about edicts" );
|
Cmd_AddCommand( "entity_info", SV_EntityInfo_f, "show more info about edicts" );
|
||||||
|
|
||||||
|
@ -827,13 +826,16 @@ void SV_InitOperatorCommands( void )
|
||||||
Cmd_AddCommand( "say", SV_ConSay_f, "send a chat message to everyone on the server" );
|
Cmd_AddCommand( "say", SV_ConSay_f, "send a chat message to everyone on the server" );
|
||||||
Cmd_AddCommand( "killserver", SV_KillServer_f, "shutdown current server" );
|
Cmd_AddCommand( "killserver", SV_KillServer_f, "shutdown current server" );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Cmd_AddCommand( "save", SV_Save_f, "save the game to a file" );
|
{
|
||||||
Cmd_AddCommand( "load", SV_Load_f, "load a saved game file" );
|
Cmd_AddCommand( "map_background", SV_MapBackground_f, "set background map" );
|
||||||
Cmd_AddCommand( "savequick", SV_QuickSave_f, "save the game to the quicksave" );
|
Cmd_AddCommand( "save", SV_Save_f, "save the game to a file" );
|
||||||
Cmd_AddCommand( "loadquick", SV_QuickLoad_f, "load a quick-saved game file" );
|
Cmd_AddCommand( "load", SV_Load_f, "load a saved game file" );
|
||||||
Cmd_AddCommand( "killsave", SV_DeleteSave_f, "delete a saved game file and saveshot" );
|
Cmd_AddCommand( "savequick", SV_QuickSave_f, "save the game to the quicksave" );
|
||||||
Cmd_AddCommand( "autosave", SV_AutoSave_f, "save the game to 'autosave' file" );
|
Cmd_AddCommand( "loadquick", SV_QuickLoad_f, "load a quick-saved game file" );
|
||||||
|
Cmd_AddCommand( "killsave", SV_DeleteSave_f, "delete a saved game file and saveshot" );
|
||||||
|
Cmd_AddCommand( "autosave", SV_AutoSave_f, "save the game to 'autosave' file" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_KillOperatorCommands( void )
|
void SV_KillOperatorCommands( void )
|
||||||
|
@ -854,7 +856,6 @@ void SV_KillOperatorCommands( void )
|
||||||
Cmd_RemoveCommand( "restart" );
|
Cmd_RemoveCommand( "restart" );
|
||||||
Cmd_RemoveCommand( "reload" );
|
Cmd_RemoveCommand( "reload" );
|
||||||
Cmd_RemoveCommand( "entpatch" );
|
Cmd_RemoveCommand( "entpatch" );
|
||||||
Cmd_RemoveCommand( "map_background" );
|
|
||||||
Cmd_RemoveCommand( "edicts_info" );
|
Cmd_RemoveCommand( "edicts_info" );
|
||||||
Cmd_RemoveCommand( "entity_info" );
|
Cmd_RemoveCommand( "entity_info" );
|
||||||
|
|
||||||
|
@ -864,11 +865,14 @@ void SV_KillOperatorCommands( void )
|
||||||
Cmd_RemoveCommand( "setmaster" );
|
Cmd_RemoveCommand( "setmaster" );
|
||||||
Cmd_RemoveCommand( "killserver" );
|
Cmd_RemoveCommand( "killserver" );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Cmd_RemoveCommand( "save" );
|
{
|
||||||
Cmd_RemoveCommand( "load" );
|
Cmd_RemoveCommand( "map_background" );
|
||||||
Cmd_RemoveCommand( "savequick" );
|
Cmd_RemoveCommand( "save" );
|
||||||
Cmd_RemoveCommand( "loadquick" );
|
Cmd_RemoveCommand( "load" );
|
||||||
Cmd_RemoveCommand( "killsave" );
|
Cmd_RemoveCommand( "savequick" );
|
||||||
Cmd_RemoveCommand( "autosave" );
|
Cmd_RemoveCommand( "loadquick" );
|
||||||
|
Cmd_RemoveCommand( "killsave" );
|
||||||
|
Cmd_RemoveCommand( "autosave" );
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -38,7 +38,7 @@ half-life implementation of saverestore system
|
||||||
#define LUMP_DECALS_OFFSET 0
|
#define LUMP_DECALS_OFFSET 0
|
||||||
#define LUMP_STATIC_OFFSET 1
|
#define LUMP_STATIC_OFFSET 1
|
||||||
#define LUMP_SOUNDS_OFFSET 2
|
#define LUMP_SOUNDS_OFFSET 2
|
||||||
#define LUMP_RESERVED 3 // g-cont. lump reserved for me
|
#define LUMP_MUSIC_OFFSET 3
|
||||||
#define NUM_CLIENT_OFFSETS 4
|
#define NUM_CLIENT_OFFSETS 4
|
||||||
|
|
||||||
void (__cdecl *pfnSaveGameComment)( char *buffer, int max_length ) = NULL;
|
void (__cdecl *pfnSaveGameComment)( char *buffer, int max_length ) = NULL;
|
||||||
|
@ -502,8 +502,23 @@ void RestoreSound( soundlist_t *entry )
|
||||||
if(( BF_GetNumBytesWritten( &sv.signon ) + 20 ) >= BF_GetMaxBytes( &sv.signon ))
|
if(( BF_GetNumBytesWritten( &sv.signon ) + 20 ) >= BF_GetMaxBytes( &sv.signon ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: allow save\restore sententces too
|
if( entry->name[0] == '!' && Q_isdigit( entry->name + 1 ))
|
||||||
soundIndex = SV_SoundIndex( entry->name );
|
{
|
||||||
|
flags |= SND_SENTENCE;
|
||||||
|
soundIndex = Q_atoi( entry->name + 1 );
|
||||||
|
}
|
||||||
|
else if( entry->name[0] == '#' && Q_isdigit( entry->name + 1 ))
|
||||||
|
{
|
||||||
|
flags |= SND_SENTENCE;
|
||||||
|
soundIndex = Q_atoi( entry->name + 1 ) + 1536;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// precache_sound can be used twice: cache sounds when loading
|
||||||
|
// and return sound index when server is active
|
||||||
|
soundIndex = SV_SoundIndex( entry->name );
|
||||||
|
}
|
||||||
|
|
||||||
ent = EDICT_NUM( entry->entnum );
|
ent = EDICT_NUM( entry->entnum );
|
||||||
|
|
||||||
if( entry->attenuation < 0.0f || entry->attenuation > 4.0f )
|
if( entry->attenuation < 0.0f || entry->attenuation > 4.0f )
|
||||||
|
@ -1039,8 +1054,9 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
|
||||||
ClientSections_t sections;
|
ClientSections_t sections;
|
||||||
int i, decalCount;
|
int i, decalCount;
|
||||||
int id, version;
|
int id, version;
|
||||||
fs_offset_t header_offset;
|
fs_offset_t header_offset, position;
|
||||||
soundlist_t soundInfo[MAX_CHANNELS];
|
soundlist_t soundInfo[MAX_CHANNELS];
|
||||||
|
string curtrack, looptrack;
|
||||||
int soundCount;
|
int soundCount;
|
||||||
|
|
||||||
Q_snprintf( name, sizeof( name ), "save/%s.HL2", level );
|
Q_snprintf( name, sizeof( name ), "save/%s.HL2", level );
|
||||||
|
@ -1135,10 +1151,8 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS );
|
// DYNAMIC SOUNDS SECTION (don't go across transition)
|
||||||
|
if( !svgame.globals->changelevel && ( soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS )) != 0 )
|
||||||
// DYNAMIC SOUNDS SECTION
|
|
||||||
if( soundCount != 0 )
|
|
||||||
{
|
{
|
||||||
sections.offsets[LUMP_SOUNDS_OFFSET] = FS_Tell( pFile );
|
sections.offsets[LUMP_SOUNDS_OFFSET] = FS_Tell( pFile );
|
||||||
FS_Write( pFile, &soundCount, sizeof( int ));
|
FS_Write( pFile, &soundCount, sizeof( int ));
|
||||||
|
@ -1148,7 +1162,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
|
||||||
{
|
{
|
||||||
soundlist_t *entry;
|
soundlist_t *entry;
|
||||||
byte nameSize;
|
byte nameSize;
|
||||||
int start = FS_Tell( pFile );
|
|
||||||
entry = &soundInfo[i];
|
entry = &soundInfo[i];
|
||||||
|
|
||||||
nameSize = Q_strlen( entry->name ) + 1;
|
nameSize = Q_strlen( entry->name ) + 1;
|
||||||
|
@ -1165,9 +1179,28 @@ int start = FS_Tell( pFile );
|
||||||
FS_Write( pFile, &entry->wordIndex, sizeof( entry->wordIndex ));
|
FS_Write( pFile, &entry->wordIndex, sizeof( entry->wordIndex ));
|
||||||
FS_Write( pFile, &entry->samplePos, sizeof( entry->samplePos ));
|
FS_Write( pFile, &entry->samplePos, sizeof( entry->samplePos ));
|
||||||
FS_Write( pFile, &entry->forcedEnd, sizeof( entry->forcedEnd ));
|
FS_Write( pFile, &entry->forcedEnd, sizeof( entry->forcedEnd ));
|
||||||
Msg( "Write sound %s, %d bytes\n", entry->name, FS_Tell( pFile ) - start );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BACKGROUND MUSIC SECTION (don't go across transition)
|
||||||
|
if( !svgame.globals->changelevel && S_StreamGetCurrentState( curtrack, looptrack, &position ))
|
||||||
|
{
|
||||||
|
byte nameSize;
|
||||||
|
|
||||||
|
sections.offsets[LUMP_MUSIC_OFFSET] = FS_Tell( pFile );
|
||||||
|
|
||||||
|
// write current track
|
||||||
|
nameSize = Q_strlen( curtrack ) + 1;
|
||||||
|
FS_Write( pFile, &nameSize, sizeof( nameSize ));
|
||||||
|
FS_Write( pFile, curtrack, nameSize );
|
||||||
|
|
||||||
|
// write loop track
|
||||||
|
nameSize = Q_strlen( looptrack ) + 1;
|
||||||
|
FS_Write( pFile, &nameSize, sizeof( nameSize ));
|
||||||
|
FS_Write( pFile, looptrack, nameSize );
|
||||||
|
|
||||||
|
// write current track position
|
||||||
|
FS_Write( pFile, &position, sizeof( position ));
|
||||||
|
}
|
||||||
|
|
||||||
// AT END
|
// AT END
|
||||||
FS_Seek( pFile, header_offset, SEEK_SET );
|
FS_Seek( pFile, header_offset, SEEK_SET );
|
||||||
|
@ -1338,6 +1371,31 @@ void SV_LoadClientState( SAVERESTOREDATA *pSaveData, const char *level, qboolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: music automatically goes across transition, never restore it on changelevel
|
||||||
|
if( sections.offsets[LUMP_MUSIC_OFFSET] != -1 && !adjacent )
|
||||||
|
{
|
||||||
|
string curtrack, looptrack;
|
||||||
|
int position;
|
||||||
|
byte nameSize;
|
||||||
|
|
||||||
|
// jump to music description
|
||||||
|
FS_Seek( pFile, sections.offsets[LUMP_MUSIC_OFFSET], SEEK_SET );
|
||||||
|
|
||||||
|
// read current track
|
||||||
|
FS_Read( pFile, &nameSize, sizeof( nameSize ));
|
||||||
|
FS_Read( pFile, curtrack, nameSize );
|
||||||
|
|
||||||
|
// read loop track
|
||||||
|
FS_Read( pFile, &nameSize, sizeof( nameSize ));
|
||||||
|
FS_Read( pFile, looptrack, nameSize );
|
||||||
|
|
||||||
|
// read current track position
|
||||||
|
FS_Read( pFile, &position, sizeof( position ));
|
||||||
|
|
||||||
|
BF_WriteByte( &sv.signon, svc_stufftext );
|
||||||
|
BF_WriteString( &sv.signon, va( "music %s %s %i\n", curtrack, looptrack, position ));
|
||||||
|
}
|
||||||
|
|
||||||
FS_Close( pFile );
|
FS_Close( pFile );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue