snd_stream_t *decoder_wav_open( const char *filename, qboolean *delay ) { snd_stream_t *stream; snd_wav_stream_t *wav_stream; stream = decoder_stream_init( &wav_decoder ); if( !stream ) return NULL; stream->isUrl = trap_FS_IsUrl( filename ); if( stream->isUrl ) return NULL; if( delay ) *delay = qfalse; stream->ptr = S_Malloc( sizeof( snd_wav_stream_t ) ); wav_stream = (snd_wav_stream_t *)stream->ptr; trap_FS_FOpenFile( filename, &wav_stream->filenum, FS_READ|FS_NOSIZE ); if( !wav_stream->filenum ) { decoder_wav_stream_shutdown( stream ); return NULL; } if( !decoder_wav_cont_open( stream ) ) { return NULL; } return stream; }
/* * S_AllocTrack */ static bgTrack_t *S_AllocTrack( const char *filename ) { bgTrack_t *track; track = S_Malloc( sizeof( *track ) + strlen( filename ) + 1 ); track->ignore = false; track->filename = (char *)( (uint8_t *)track + sizeof( *track ) ); strcpy( track->filename, filename ); track->isUrl = trap_FS_IsUrl( track->filename ); track->muteOnPause = track->isUrl; track->anext = s_bgTrackHead; s_bgTrackHead = track; return track; }
/* * S_AllocTrack */ static bgTrack_t *S_AllocTrack( const char *filename ) { bgTrack_t *track; track = S_Malloc( sizeof( *track ) + strlen( filename ) + 1 ); track->stream = NULL; track->ignore = qfalse; track->filename = (char *)((qbyte *)track + sizeof( *track )); strcpy( track->filename, filename ); track->isUrl = trap_FS_IsUrl( filename ); track->anext = s_bgTrackHead; s_bgTrackHead = track; return track; }
/* * SF_FindName */ static sfx_t *SF_FindName( const char *name ) { int i; sfx_t *sfx; if( !name ) S_Error( "SF_FindName: NULL" ); if( !name[0] != '\0' ) { assert( name[0] != '\0' ); S_Error( "SF_FindName: empty name" ); } if( strlen( name ) >= MAX_QPATH ) S_Error( "Sound name too long: %s", name ); // see if already loaded for( i = 0; i < num_sfx; i++ ) { if( !strcmp( known_sfx[i].name, name ) ) return &known_sfx[i]; } // find a free sfx for( i = 0; i < num_sfx; i++ ) { if( !known_sfx[i].name[0] ) break; } if( i == num_sfx ) { if( num_sfx == MAX_SFX ) S_Error( "S_FindName: out of sfx_t" ); num_sfx++; } sfx = &known_sfx[i]; memset( sfx, 0, sizeof( *sfx ) ); Q_strncpyz( sfx->name, name, sizeof( sfx->name ) ); sfx->isUrl = trap_FS_IsUrl( name ); return sfx; }
snd_stream_t *decoder_ogg_open( const char *filename, qboolean *delay ) { snd_stream_t *stream; snd_ogg_stream_t *ogg_stream; // Open stream = decoder_stream_init( &ogg_decoder ); if( !stream ) { Com_Printf( "Error initializing .ogg stream: %s\n", filename ); return NULL; } stream->isUrl = trap_FS_IsUrl( filename ); stream->ptr = S_Malloc( sizeof( snd_ogg_stream_t ) ); ogg_stream = (snd_ogg_stream_t *)stream->ptr; trap_FS_FOpenFile( filename, &ogg_stream->filenum, FS_READ|FS_NOSIZE ); if( !ogg_stream->filenum ) { decoder_ogg_stream_shutdown( stream ); return NULL; } if( delay ) *delay = qfalse; if( stream->isUrl && delay ) { *delay = qtrue; return stream; } if( !decoder_ogg_cont_open( stream ) ) { decoder_ogg_close( stream ); return NULL; } return stream; }
void *decoder_wav_load( const char *filename, snd_info_t *info ) { int filenum; int read; void *buffer; if( trap_FS_IsUrl( filename ) ) return NULL; trap_FS_FOpenFile( filename, &filenum, FS_READ|FS_NOSIZE ); if( !filenum ) return NULL; if( !read_wav_header( filenum, info ) ) { trap_FS_FCloseFile( filenum ); Com_Printf( "Can't understand .wav file: %s\n", filename ); return NULL; } buffer = S_Malloc( info->size ); read = trap_FS_Read( buffer, info->size, filenum ); if( read != info->size ) { S_Free( buffer ); trap_FS_FCloseFile( filenum ); Com_Printf( "Error reading .wav file: %s\n", filename ); return NULL; } byteSwapRawSamples( info->samples, info->width, info->channels, (qbyte *)buffer ); trap_FS_FCloseFile( filenum ); return buffer; }
/* * S_ReadPlaylistFile */ static bgTrack_t *S_ReadPlaylistFile( const char *filename, bool shuffle, bool loop ) { int filenum, length; char *tmpname = 0; size_t tmpname_size = 0; char *data, *line, *entry; playlistItem_t items[MAX_PLAYLIST_ITEMS]; int i, numItems = 0; length = trap_FS_FOpenFile( filename, &filenum, FS_READ ); if( length < 0 ) return NULL; // load the playlist into memory data = S_Malloc( length + 1 ); trap_FS_Read( data, length, filenum ); trap_FS_FCloseFile( filenum ); srand( time( NULL ) ); while( *data ) { size_t s; entry = data; // read the whole line for( line = data; *line != '\0' && *line != '\n'; line++ ); // continue reading from the next character, if possible data = (*line == '\0' ? line : line + 1); *line = '\0'; // trim whitespaces, tabs, etc entry = Q_trim( entry ); // special M3U entry or comment if( !*entry || *entry == '#' ) continue; if( trap_FS_IsUrl( entry ) ) { items[numItems].track = S_AllocTrack( entry ); } else { // append the entry name to playlist path s = strlen( filename ) + 1 + strlen( entry ) + 1; if( s > tmpname_size ) { if( tmpname ) S_Free( tmpname ); tmpname_size = s; tmpname = S_Malloc( tmpname_size ); } Q_strncpyz( tmpname, filename, tmpname_size ); COM_StripFilename( tmpname ); Q_strncatz( tmpname, "/", tmpname_size ); Q_strncatz( tmpname, entry, tmpname_size ); COM_SanitizeFilePath( tmpname ); items[numItems].track = S_AllocTrack( tmpname ); } if( ++numItems == MAX_PLAYLIST_ITEMS ) break; } if( tmpname ) { S_Free( tmpname ); tmpname = NULL; } if( !numItems ) return NULL; // set the playing order for( i = 0; i < numItems; i++ ) items[i].order = (shuffle ? (rand() % numItems) : i); // sort the playlist R_SortPlaylistItems( numItems, items ); // link the playlist for( i = 1; i < numItems; i++ ) { items[i-1].track->next = items[i].track; items[i].track->prev = items[i-1].track; items[i].track->loop = loop; } items[numItems-1].track->next = items[0].track; items[0].track->prev = items[numItems-1].track; items[0].track->loop = loop; return items[0].track; }
void *decoder_ogg_load( const char *filename, snd_info_t *info ) { OggVorbis_File vorbisfile; int filenum, bitstream, bytes_read, bytes_read_total; char *buffer; ov_callbacks callbacks = { ovcb_read, ovcb_seek, ovcb_close, ovcb_tell }; trap_FS_FOpenFile( filename, &filenum, FS_READ|FS_NOSIZE ); if( !filenum ) return NULL; if( trap_FS_IsUrl( filename ) ) { callbacks.seek_func = NULL; callbacks.tell_func = NULL; } qov_open_callbacks( (void *) (qintptr) filenum, &vorbisfile, NULL, 0, callbacks ); if( callbacks.seek_func && !qov_seekable( &vorbisfile ) ) { Com_Printf( "Error unsupported .ogg file (not seekable): %s\n", filename ); qov_clear( &vorbisfile ); // Does FS_FCloseFile return NULL; } if( qov_streams( &vorbisfile ) != 1 ) { Com_Printf( "Error unsupported .ogg file (multiple logical bitstreams): %s\n", filename ); qov_clear( &vorbisfile ); // Does FS_FCloseFile return NULL; } if( !read_ogg_header( vorbisfile, info ) ) { Com_Printf( "Error reading .ogg file header: %s\n", filename ); qov_clear( &vorbisfile ); // Does FS_FCloseFile return NULL; } buffer = S_Malloc( info->size ); bytes_read_total = 0; do { #ifdef ENDIAN_BIG bytes_read = qov_read( &vorbisfile, buffer+bytes_read_total, info->size-bytes_read_total, 1, 2, 1, &bitstream ); #elif defined (ENDIAN_LITTLE) bytes_read = qov_read( &vorbisfile, buffer+bytes_read_total, info->size-bytes_read_total, 0, 2, 1, &bitstream ); #else #error "runtime endianess detection support missing" #endif bytes_read_total += bytes_read; } while( bytes_read > 0 && bytes_read_total < info->size ); qov_clear( &vorbisfile ); // Does FS_FCloseFile if( !bytes_read_total ) { Com_Printf( "Error reading .ogg file: %s\n", filename ); S_Free( buffer ); return NULL; } return buffer; }
bool S_LoadBuffer( sfx_t *sfx ) { ALenum error; void *data; snd_info_t info; ALuint format; if( !sfx ) { return false; } if( sfx->filename[0] == '\0' || sfx->inMemory ) return false; if( trap_FS_IsUrl( sfx->filename ) ) return false; data = S_LoadSound( sfx->filename, &info ); if( !data ) { //Com_DPrintf( "Couldn't load %s\n", sfx->filename ); return false; } if( info.channels > 1 ) { void *temp = stereo_mono( data, &info ); if( temp ) { S_Free( data ); data = temp; } } format = S_SoundFormat( info.width, info.channels ); qalGenBuffers( 1, &sfx->buffer ); if( ( error = qalGetError() ) != AL_NO_ERROR ) { S_Free( data ); Com_Printf( "Couldn't create a sound buffer for %s (%s)\n", sfx->filename, S_ErrorMessage( error ) ); return false; } qalBufferData( sfx->buffer, format, data, info.size, info.rate ); error = qalGetError(); // If we ran out of memory, start evicting the least recently used sounds while( error == AL_OUT_OF_MEMORY ) { if( !buffer_evict() ) { S_Free( data ); Com_Printf( "Out of memory loading %s\n", sfx->filename ); return false; } // Try load it again qalGetError(); qalBufferData( sfx->buffer, format, data, info.size, info.rate ); error = qalGetError(); } // Some other error condition if( error != AL_NO_ERROR ) { S_Free( data ); Com_Printf( "Couldn't fill sound buffer for %s (%s)", sfx->filename, S_ErrorMessage( error ) ); return false; } S_Free( data ); sfx->inMemory = true; return true; }