bool S_UnloadBuffer( sfx_t *sfx ) { ALenum error; if( !sfx ) { return false; } if( sfx->filename[0] == '\0' || sfx->isLocked || !sfx->inMemory ) return false; qalDeleteBuffers( 1, &sfx->buffer ); if( ( error = qalGetError() ) != AL_NO_ERROR ) { Com_Printf( "Couldn't delete sound buffer for %s (%s)", sfx->filename, S_ErrorMessage( error ) ); sfx->isLocked = true; return false; } sfx->inMemory = false; return true; }
void S_StartBackgroundTrack( const char *intro, const char *loop ) { int count; const char *ext; bgTrack_t *t, f; bgTrack_t *introTrack, *loopTrack; ALenum error; int mode = 0; // Stop any existing music that might be playing S_StopBackgroundTrack(); if( !intro || !intro[0] ) return; s_bgTrackPaused = qfalse; ext = COM_FileExtension( intro ); if( ext && !Q_stricmp( ext, ".m3u" ) ) { // mode bits: // 1 - shuffle // 2 - loop the selected track if( loop && loop[0] ) mode = atoi( loop ); if( S_ReadPlaylistFile( intro, mode & 1 ? qtrue : qfalse ) ) goto start_playback; } // the intro track loops unless another loop track has been specified introTrack = S_AllocTrack( intro ); introTrack->next = introTrack->prev = introTrack; if( loop && loop[0] && Q_stricmp( intro, loop ) ) { loopTrack = S_AllocTrack( loop ); if( S_OpenMusicTrack( loopTrack ) ) { S_CloseMusicTrack( loopTrack ); loopTrack->next = introTrack->next = introTrack->prev = loopTrack; loopTrack->prev = introTrack; } } s_bgTrack = introTrack; start_playback: // this effectively precaches the first 15 scheduled tracks in the playlist for( count = 0, t = s_bgTrack; count < 15 && t && t != s_bgTrack; count++ ) { if( !t->isUrl ) { S_OpenMusicTrack( t ); if( t->next == t || t->next == s_bgTrack ) break; // break on an endless loop or full cycle if( !t->ignore && ( mode & 2 ) ) { // no point in precaching the whole playlist when we're only going // to loop one single track break; } } t = t->next; } // start playback with the first valid track if( count > 1 ) { memset( &f, 0, sizeof( f ) ); f.next = s_bgTrack; s_bgTrack = S_NextMusicTrack( &f ); } else { S_OpenMusicTrack( s_bgTrack ); } if( !s_bgTrack || s_bgTrack->ignore ) { S_StopBackgroundTrack(); return; } if( mode & 2 ) { // loop the same track over and over s_bgTrack->next = s_bgTrack->prev = s_bgTrack; } music_source_get(); if( !src ) { Com_Printf( "Error couldn't get source for music\n" ); S_StopBackgroundTrack(); return; } alloced_buffers = qfalse; queued_buffers = qfalse; qalGenBuffers( MUSIC_BUFFERS, buffers ); if( ( error = qalGetError() ) != AL_NO_ERROR ) { Com_Printf( "Error couldn't generate music buffers (%s)\n", S_ErrorMessage( error ) ); S_StopBackgroundTrack(); return; } alloced_buffers = qtrue; }
void S_UpdateMusic( void ) { int i, processed; ALint state; ALenum error; ALuint b; int num_processed_buffers; ALuint processed_buffers[MUSIC_BUFFERS]; if( !s_bgTrack ) return; if( !s_musicvolume->value && !s_bgTrack->isUrl ) return; if( s_bgTrackPaused || s_bgTrackLocked ) return; if( s_bgTrackBuffering ) { if( S_EoStream( s_bgTrack->stream ) ) { // we should now advance to the next track S_CloseMusicTrack( s_bgTrack ); } else { if( S_FTellSteam( s_bgTrack->stream ) < BACKGROUND_TRACK_BUFFERING_SIZE ) return; // in case we delayed openening to let the stream be cached for a while, // start actually reading from it now if( !S_ContOpenStream( s_bgTrack->stream ) ) { // let music_process do the dirty job of advancing to the next track S_CloseMusicTrack( s_bgTrack ); s_bgTrack->ignore = qtrue; } } s_bgTrackBuffering = qfalse; } if( !queued_buffers ) { // if we haven't queued any buffers yet, do it now num_processed_buffers = MUSIC_BUFFERS; memcpy( processed_buffers, buffers, sizeof( buffers ) ); } else { num_processed_buffers = 0; processed = 0; qalGetSourcei( source, AL_BUFFERS_PROCESSED, &processed ); while( processed-- ) { qalSourceUnqueueBuffers( source, 1, &b ); processed_buffers[num_processed_buffers++] = b; } } for( i = 0; i < num_processed_buffers; i++ ) { b = processed_buffers[i]; if( !music_process( b ) ) { Com_Printf( "Error processing music data\n" ); S_StopBackgroundTrack(); return; } qalSourceQueueBuffers( source, 1, &b ); if( ( error = qalGetError() ) != AL_NO_ERROR ) { Com_Printf( "Couldn't queue music data (%s)\n", S_ErrorMessage( error ) ); S_StopBackgroundTrack(); return; } } // If it's not still playing, give it a kick qalGetSourcei( source, AL_SOURCE_STATE, &state ); if( !queued_buffers || state != AL_PLAYING ) { queued_buffers = qtrue; qalSourcePlay( source ); } if( s_musicvolume->modified ) qalSourcef( source, AL_GAIN, s_musicvolume->value ); }
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; }