15 May 2012

This commit is contained in:
g-cont 2012-05-15 00:00:00 +04:00 committed by Alibek Omarov
parent 6b3e9e841e
commit ce01422c4d
21 changed files with 411 additions and 96 deletions

View File

@ -697,7 +697,8 @@ enum
kRenderTransTexture, // src*a+dest*(1-a)
kRenderGlow, // src*a+dest -- No Z buffer checks
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

View File

@ -75,14 +75,14 @@ void CL_PlayCDTrack_f( void )
if( !Q_stricmp( command, "play" ))
{
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;
looped = false;
}
else if( !Q_stricmp( command, "loop" ))
{
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;
looped = true;
}

View File

@ -2801,11 +2801,11 @@ void pfnMP3_InitStream( char *filename, int flags )
// g-cont. flag 1 is probably 'LOOP'
if( flags & 1 )
{
S_StartBackgroundTrack( filename, filename );
S_StartBackgroundTrack( filename, filename, 0 );
}
else
{
S_StartBackgroundTrack( filename, NULL );
S_StartBackgroundTrack( filename, NULL, 0 );
}
}

View File

@ -842,6 +842,17 @@ static void pfnHostEndGame( const char *szFinalMessage )
Host_EndGame( szFinalMessage );
}
/*
=========
pfnStartBackgroundTrack
=========
*/
static void pfnStartBackgroundTrack( const char *introTrack, const char *mainTrack )
{
S_StartBackgroundTrack( introTrack, mainTrack, 0 );
}
// engine callbacks
static ui_enginefuncs_t gEngfuncs =
{
@ -917,7 +928,7 @@ static ui_enginefuncs_t gEngfuncs =
Sys_ShellExecute,
Host_WriteServerConfig,
pfnChangeInstance,
S_StartBackgroundTrack,
pfnStartBackgroundTrack,
pfnHostEndGame,
Com_RandomFloat,
Com_RandomLong,

View File

@ -318,7 +318,14 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
pitch = BF_ReadByte( msg );
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
entnum = BF_ReadWord( msg );
@ -330,7 +337,7 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
BF_ReadBytes( msg, &samplePos, sizeof( samplePos ));
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
param2 = BF_ReadByte( msg );
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;
case svc_serverinfo:
CL_ServerInfo( msg );

View File

@ -800,7 +800,7 @@ void Con_Close( void );
// s_main.c
//
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_StreamSetPause( int pause );
void S_StartStreaming( void );
@ -808,7 +808,7 @@ void S_StopStreaming( void );
void S_BeginRegistration( void );
sound_t S_RegisterSound( const char *sample );
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_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 );

View File

@ -139,6 +139,7 @@ S_FreeChannel
void S_FreeChannel( channel_t *ch )
{
ch->sfx = NULL;
ch->name[0] = '\0';
ch->use_loop = 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
// sentence file do not have a leading '!'.
VOX_LoadSound( target_chan, S_SkipSoundChar( sfx->name ));
sfx = target_chan->sfx; // TEST
Q_strncpy( target_chan->name, sfx->name, sizeof( target_chan->name ));
sfx = target_chan->sfx;
pSource = sfx->cache;
}
else
{
// regular or streamed sound fx
pSource = S_LoadSound( sfx );
target_chan->name[0] = '\0';
}
if( !pSource )
@ -986,7 +988,7 @@ S_RestoreSound
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;
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->bTraced = false;
// regular or streamed sound fx
pSource = S_LoadSound( sfx );
pSource = NULL;
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 )
{
@ -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( chan != CHAN_STREAM )
{
MsgDev( D_ERROR, "S_RestoreSound: %s volume 0\n", sfx->name );
S_FreeChannel( target_chan );
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
VOX_LoadSound( ch, S_SkipSoundChar( sfx->name ));
Q_strncpy( ch->name, sfx->name, sizeof( ch->name ));
sfx = ch->sfx;
pSource = sfx->cache;
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 );
ch->sfx = sfx;
ch->isSentence = false;
ch->name[0] = '\0';
}
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] )
{
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;
VectorCopy( channels[i].origin, pout->origin );
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 )
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;
VectorCopy( channels[i].origin, pout->origin );
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 ))
{
// combined track with introduction and main loop theme
S_StartBackgroundTrack( intro, main );
S_StartBackgroundTrack( intro, main, 0 );
break;
}
else if( FS_FileExists( va( "media/%s.%s", track, ext[i] ), false ))
{
// single looped theme
S_StartBackgroundTrack( track, NULL );
S_StartBackgroundTrack( track, NULL, 0 );
break;
}
}
@ -1645,7 +1692,12 @@ void S_Music_f( void )
}
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" );
}

View File

@ -38,11 +38,19 @@ void S_CheckLerpingState( void )
S_StartBackgroundTrack
=================
*/
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack )
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long position )
{
S_StopBackgroundTrack();
if( !dma.initialized ) return;
// check for special symbols
if( introTrack && *introTrack == '*' )
introTrack = NULL;
if( mainTrack && *mainTrack == '*' )
mainTrack = NULL;
if(( !introTrack || !*introTrack ) && ( !mainTrack || !*mainTrack ))
return;
@ -54,8 +62,15 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack )
// open stream
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;
if( position != 0 )
{
// restore message, update song position
FS_SetStreamPos( s_bgTrack.stream, position );
}
S_CheckLerpingState();
}
@ -77,6 +92,38 @@ void S_StreamSetPause( int 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
@ -150,6 +197,7 @@ void S_StreamBackgroundTrack( void )
{
FS_FreeStream( s_bgTrack.stream );
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;
S_CheckLerpingState();

View File

@ -345,8 +345,8 @@ void VOX_LoadWord( channel_t *pchan )
if( pSource )
{
int start = pchan->words[pchan->wordIndex].start;
int end = pchan->words[pchan->wordIndex].end;
int start = pchan->words[pchan->wordIndex].start;
int end = pchan->words[pchan->wordIndex].end;
// apply mixer
pchan->currentWord = &pchan->pMixer;
@ -418,7 +418,7 @@ int VOX_MixDataToDevice( channel_t *pchan, int sampleCount, int outputRate, int
while( sampleCount > 0 && pchan->currentWord )
{
int outputCount = S_MixDataToDevice( pchan, sampleCount, outputRate, outputOffset );
int outputCount = S_MixDataToDevice( pchan, sampleCount, outputRate, outputOffset );
outputOffset += outputCount;
sampleCount -= outputCount;

View File

@ -141,8 +141,9 @@ typedef struct
qboolean finished;
} mixer_t;
typedef struct
typedef struct channel_s
{
char name[16]; // keept sentence name
sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume
@ -196,7 +197,8 @@ typedef struct
typedef struct
{
string loopName;
string current; // a currently playing track
string loopName; // may be empty
stream_t *stream;
int source; // may be game, menu, etc
} bg_track_t;
@ -305,6 +307,7 @@ void SND_CloseMouth( channel_t *ch );
//
void S_StreamSoundTrack( void );
void S_StreamBackgroundTrack( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
//
// s_utils.c

View File

@ -42,6 +42,7 @@ typedef struct
float length;
} sentence_t;
extern sentence_t g_Sentences[MAX_SENTENCES];
void VOX_LoadWord( struct channel_s *pchan );
void VOX_FreeWord( struct channel_s *pchan );
#endif

View File

@ -515,7 +515,7 @@ typedef enum
WF_TOTALCOUNT, // must be last
} sndformat_t;
// imagelib global settings
// soundlib global settings
typedef enum
{
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 );
wavdata_t *FS_StreamInfo( stream_t *stream );
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 );
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
uint Sound_GetApproxWavePlayLen( const char *filepath );

Binary file not shown.

Binary file not shown.

View File

@ -60,7 +60,7 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
string path, loadname;
qboolean anyformat = true;
int filesize = 0;
const loadwavformat_t *format;
const loadwavfmt_t *format;
byte *f;
Sound_Reset(); // clear old sounddata
@ -153,7 +153,7 @@ stream_t *FS_OpenStream( const char *filename )
const char *ext = FS_FileExtension( filename );
string path, loadname;
qboolean anyformat = true;
const streamformat_t *format;
const streamfmt_t *format;
stream_t *stream;
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 );
}
/*
================
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

View File

@ -28,21 +28,24 @@ GNU General Public License for more details.
typedef struct mpeg_s
{
void *state; // hidden decoder state
void *vbrtag; // valid for VBR-encoded mpegs
void *state; // hidden decoder state
void *vbrtag; // valid for VBR-encoded mpegs
int channels; // num channels
int samples; // per one second
int play_time;// stream size in milliseconds
int rate; // frequency
int outsize; // current data size
char out[8192];// temporary buffer
int channels; // num channels
int samples; // per one second
int play_time; // stream size in milliseconds
int rate; // frequency
int outsize; // current data size
char out[8192]; // temporary buffer
size_t streamsize; // size in bytes
} mpeg_t;
// mpg123 exports
int create_decoder( mpeg_t *mpg );
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 );
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 );
/*
@ -153,6 +156,7 @@ stream_t *Stream_OpenMPG( const char *filename )
// at this point we have valid stream
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
stream->file = file;
stream->pos = 0;
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpeg_t ));
@ -188,8 +192,9 @@ stream_t *Stream_OpenMPG( const char *filename )
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->pos += mpegFile->outsize;
stream->rate = mpegFile->rate;
stream->width = 2; // always 16 bit
stream->ptr = mpegFile;
@ -209,6 +214,7 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
{
// buffer handling
int bytesWritten = 0;
int result;
mpeg_t *mpg;
mpg = (mpeg_t *)stream->ptr;
@ -220,13 +226,27 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
long read_len, outsize;
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
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
}
}
@ -238,20 +258,56 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
// copy raw sample to output buffer
data = (byte *)buffer + bytesWritten;
Q_memcpy( data, &mpg->out[stream->pos], outsize );
Q_memcpy( data, &mpg->out[stream->buffsize], outsize );
bytesWritten += outsize;
mpg->outsize -= outsize;
stream->pos += outsize;
stream->buffsize += outsize;
// continue from this sample on a next call
if( bytesWritten >= needBytes )
return bytesWritten;
stream->pos = 0; // no bytes remaining
stream->buffsize = 0; // no bytes remaining
}
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

View File

@ -23,12 +23,12 @@ GNU General Public License for more details.
=============================================================================
*/
// stub
static const loadwavformat_t load_null[] =
static const loadwavfmt_t load_null[] =
{
{ NULL, NULL, NULL }
};
static const loadwavformat_t load_game[] =
static const loadwavfmt_t load_game[] =
{
{ "sound/%s%s.%s", "wav", Sound_LoadWAV },
{ "%s%s.%s", "wav", Sound_LoadWAV },
@ -45,16 +45,16 @@ static const loadwavformat_t load_game[] =
=============================================================================
*/
// 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", "wav", Stream_OpenWAV, Stream_ReadWAV, Stream_FreeWAV },
{ NULL, NULL, NULL, NULL, NULL }
{ "%s%s.%s", "mp3", Stream_OpenMPG, Stream_ReadMPG, Stream_SetPosMPG, Stream_GetPosMPG, Stream_FreeMPG },
{ "%s%s.%s", "wav", Stream_OpenWAV, Stream_ReadWAV, Stream_SetPosWAV, Stream_GetPosWAV, Stream_FreeWAV },
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
void Sound_Init( void )
@ -89,6 +89,7 @@ byte *Sound_Copy( size_t size )
out = Mem_Alloc( host.soundpool, size );
Q_memcpy( out, sound.tempbuffer, size );
return out;
}

View File

@ -298,8 +298,9 @@ Stream_OpenWAV
stream_t *Stream_OpenWAV( const char *filename )
{
stream_t *stream;
int iff_data, last_chunk;
int last_chunk = 0;
char chunkName[4];
int iff_data;
file_t *file;
short t;
@ -374,6 +375,7 @@ stream_t *Stream_OpenWAV( const char *filename )
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
stream->file = file;
stream->size = sound.samples * sound.width * sound.channels;
stream->buffsize = FS_Tell( file ); // header length
stream->channels = sound.channels;
stream->width = sound.width;
stream->rate = sound.rate;
@ -406,6 +408,37 @@ long Stream_ReadWAV( stream_t *stream, long bytes, void *buffer )
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

View File

@ -18,27 +18,29 @@ GNU General Public License for more details.
#include "common.h"
typedef struct loadwavformat_s
typedef struct loadwavfmt_s
{
const char *formatstring;
const char *ext;
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 *ext;
stream_t *(*openfunc)( const char *filename );
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 );
} streamformat_t;
} streamfmt_t;
typedef struct sndlib_s
{
const loadwavformat_t *loadformats;
const streamformat_t *streamformat; // music stream
const loadwavfmt_t *loadformats;
const streamfmt_t *streamformat; // music stream
// current sound state
int type; // sound type
@ -57,17 +59,19 @@ typedef struct sndlib_s
typedef struct stream_s
{
const streamformat_t *format; // streamformat to operate
const streamfmt_t *format; // streamformat to operate
// current stream state
file_t *file; // stream file
int width; // resolution - num bits divided by 8 (8 bit is 1, 16 bit is 2)
int rate; // stream rate
int channels; // stream channels
int type; // wavtype
size_t size; // total stream size
int pos; // keep track wav position
void *ptr;
file_t *file; // stream file
int width; // resolution - num bits divided by 8 (8 bit is 1, 16 bit is 2)
int rate; // stream rate
int channels; // stream channels
int type; // wavtype
size_t size; // total stream size
int pos; // actual track position
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 );
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 );
stream_t *Stream_OpenMPG( const char *filename );
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 );
#endif//SOUNDLIB_H

View File

@ -818,7 +818,6 @@ void SV_InitOperatorCommands( void )
Cmd_AddCommand( "restart", SV_Restart_f, "restarting current 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( "map_background", SV_MapBackground_f, "set background map" );
Cmd_AddCommand( "edicts_info", SV_EdictsInfo_f, "show 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( "killserver", SV_KillServer_f, "shutdown current server" );
}
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( "savequick", SV_QuickSave_f, "save the game to the quicksave" );
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" );
else
{
Cmd_AddCommand( "map_background", SV_MapBackground_f, "set background map" );
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( "savequick", SV_QuickSave_f, "save the game to the quicksave" );
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 )
@ -854,7 +856,6 @@ void SV_KillOperatorCommands( void )
Cmd_RemoveCommand( "restart" );
Cmd_RemoveCommand( "reload" );
Cmd_RemoveCommand( "entpatch" );
Cmd_RemoveCommand( "map_background" );
Cmd_RemoveCommand( "edicts_info" );
Cmd_RemoveCommand( "entity_info" );
@ -864,11 +865,14 @@ void SV_KillOperatorCommands( void )
Cmd_RemoveCommand( "setmaster" );
Cmd_RemoveCommand( "killserver" );
}
Cmd_RemoveCommand( "save" );
Cmd_RemoveCommand( "load" );
Cmd_RemoveCommand( "savequick" );
Cmd_RemoveCommand( "loadquick" );
Cmd_RemoveCommand( "killsave" );
Cmd_RemoveCommand( "autosave" );
else
{
Cmd_RemoveCommand( "map_background" );
Cmd_RemoveCommand( "save" );
Cmd_RemoveCommand( "load" );
Cmd_RemoveCommand( "savequick" );
Cmd_RemoveCommand( "loadquick" );
Cmd_RemoveCommand( "killsave" );
Cmd_RemoveCommand( "autosave" );
}
}

View File

@ -38,7 +38,7 @@ half-life implementation of saverestore system
#define LUMP_DECALS_OFFSET 0
#define LUMP_STATIC_OFFSET 1
#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
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 ))
return;
// TODO: allow save\restore sententces too
soundIndex = SV_SoundIndex( entry->name );
if( entry->name[0] == '!' && Q_isdigit( entry->name + 1 ))
{
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 );
if( entry->attenuation < 0.0f || entry->attenuation > 4.0f )
@ -1039,8 +1054,9 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
ClientSections_t sections;
int i, decalCount;
int id, version;
fs_offset_t header_offset;
fs_offset_t header_offset, position;
soundlist_t soundInfo[MAX_CHANNELS];
string curtrack, looptrack;
int soundCount;
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
if( soundCount != 0 )
// DYNAMIC SOUNDS SECTION (don't go across transition)
if( !svgame.globals->changelevel && ( soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS )) != 0 )
{
sections.offsets[LUMP_SOUNDS_OFFSET] = FS_Tell( pFile );
FS_Write( pFile, &soundCount, sizeof( int ));
@ -1148,7 +1162,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
{
soundlist_t *entry;
byte nameSize;
int start = FS_Tell( pFile );
entry = &soundInfo[i];
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->samplePos, sizeof( entry->samplePos ));
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
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 );
}