void AL_Update(void) { int i; channel_t *ch; vec_t orientation[6]; if (!s_active) { return; } paintedtime = cl.time; // set listener parameters qalListener3f(AL_POSITION, AL_UnpackVector(listener_origin)); AL_CopyVector(listener_forward, orientation); AL_CopyVector(listener_up, orientation + 3); qalListenerfv(AL_ORIENTATION, orientation); qalListenerf(AL_GAIN, s_volume->value); qalDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); // update spatialization for dynamic sounds ch = channels; for (i = 0; i < s_numchannels; i++, ch++) { if (!ch->sfx) continue; if (ch->autosound) { // autosounds are regenerated fresh each frame if (ch->autoframe != s_framecount) { AL_StopChannel(ch); continue; } } else { ALenum state; qalGetError(); qalGetSourcei(ch->srcnum, AL_SOURCE_STATE, &state); if (qalGetError() != AL_NO_ERROR || state == AL_STOPPED) { AL_StopChannel(ch); continue; } } #ifdef _DEBUG if (s_show->integer) { Com_Printf("%.1f %s\n", ch->master_vol, ch->sfx->name); // total++; } #endif AL_Spatialize(ch); // respatialize channel } s_framecount++; // add loopsounds AL_AddLoopSounds(); AL_IssuePlaysounds(); }
static void AL_InitUnderwaterFilter() { #if defined (__APPLE__) return; #else /* Generate a filter */ qalGenFilters(1, &underwaterFilter); if (qalGetError() != AL_NO_ERROR) { Com_Printf("Couldn't generate an OpenAL filter!\n"); return; } /* Low pass filter for underwater effect */ qalFilteri(underwaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); if (qalGetError() != AL_NO_ERROR) { Com_Printf("Low pass filter is not supported!\n"); return; } /* The effect */ qalFilterf(underwaterFilter, AL_LOWPASS_GAIN, 1.5); qalFilterf(underwaterFilter, AL_LOWPASS_GAINHF, 0.25); #endif }
void AL_PlayChannel(channel_t *ch) { sfxcache_t *sc = ch->sfx->cache; #ifdef _DEBUG if (s_show->integer > 1) Com_Printf("%s: %s\n", __func__, ch->sfx->name); #endif ch->srcnum = s_srcnums[ch - channels]; qalGetError(); qalSourcei(ch->srcnum, AL_BUFFER, sc->bufnum); //qalSourcei(ch->srcnum, AL_LOOPING, sc->loopstart == -1 ? AL_FALSE : AL_TRUE); qalSourcei(ch->srcnum, AL_LOOPING, ch->autosound ? AL_TRUE : AL_FALSE); qalSourcef(ch->srcnum, AL_GAIN, ch->master_vol); qalSourcef(ch->srcnum, AL_REFERENCE_DISTANCE, SOUND_FULLVOLUME); qalSourcef(ch->srcnum, AL_MAX_DISTANCE, 8192); qalSourcef(ch->srcnum, AL_ROLLOFF_FACTOR, ch->dist_mult * (8192 - SOUND_FULLVOLUME)); AL_Spatialize(ch); // play it qalSourcePlay(ch->srcnum); if (qalGetError() != AL_NO_ERROR) { AL_StopChannel(ch); } }
sfxcache_t *AL_UploadSfx(sfx_t *s) { sfxcache_t *sc; ALsizei size = s_info.samples * s_info.width; ALenum format = s_info.width == 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8; ALuint name; if (!size) { s->error = Q_ERR_TOO_FEW; return NULL; } qalGetError(); qalGenBuffers(1, &name); qalBufferData(name, format, s_info.data, size, s_info.rate); if (qalGetError() != AL_NO_ERROR) { s->error = Q_ERR_LIBRARY_ERROR; return NULL; } // allocate placeholder sfxcache sc = s->cache = S_Malloc(sizeof(*sc)); sc->length = s_info.samples * 1000 / s_info.rate; // in msec sc->loopstart = s_info.loopstart; sc->width = s_info.width; sc->size = size; sc->bufnum = name; return sc; }
/* * Set up the underwater filter */ static void AL_InitUnderwaterFilter() { underwaterFilter = 0; if (!(qalGenFilters && qalFilteri && qalFilterf && qalDeleteFilters)) return; /* Generate a filter */ qalGenFilters(1, &underwaterFilter); if (qalGetError() != AL_NO_ERROR) { Com_Printf("Couldn't generate an OpenAL filter!\n"); return; } /* Low pass filter for underwater effect */ qalFilteri(underwaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); if (qalGetError() != AL_NO_ERROR) { Com_Printf("Low pass filter is not supported!\n"); return; } qalFilterf(underwaterFilter, AL_LOWPASS_GAIN, AL_LOWPASS_DEFAULT_GAIN); s_underwater->modified = true; s_underwater_gain_hf->modified = true; }
/* * Initializes the OpenAL backend */ qboolean AL_Init(void) { int i; if (!QAL_Init()) { Com_Printf("ERROR: OpenAL failed to initialize.\n"); return false; } s_openal_maxgain = Cvar_Get("s_openal_maxgain", "1.0", CVAR_ARCHIVE); /* check for linear distance extension */ if (!qalIsExtensionPresent("AL_EXT_LINEAR_DISTANCE")) { Com_Printf("ERROR: Required AL_EXT_LINEAR_DISTANCE extension is missing.\n"); QAL_Shutdown(); return false; } /* generate source names */ qalGetError(); qalGenSources(1, &streamSource); if (qalGetError() != AL_NO_ERROR) { Com_Printf("ERROR: Couldn't get a single Source.\n"); QAL_Shutdown(); return false; } else { /* -1 because we already got one channel for streaming */ for (i = 0; i < MAX_CHANNELS - 1; i++) { qalGenSources(1, &s_srcnums[i]); if (qalGetError() != AL_NO_ERROR) { break; } } if (i < MIN_CHANNELS - 1) { Com_Printf("ERROR: Required at least %d sources, but got %d.\n", MIN_CHANNELS, i + 1); QAL_Shutdown(); return false; } } s_numchannels = i; AL_InitStreamSource(); AL_InitUnderwaterFilter(); Com_Printf("Number of OpenAL sources: %d\n\n", s_numchannels); return true; }
/* * Uploads a sample to OpenAL and places * a dummy entry in the frontends cache. * This is not nice but necessary for the * frontend to work. */ sfxcache_t * AL_UploadSfx ( sfx_t *s, wavinfo_t *s_info, byte *data ) { sfxcache_t *sc; ALsizei size; ALenum format; ALuint name; size = s_info->samples * s_info->width; format = s_info->width == 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8; if ( !size ) { return NULL; } qalGetError(); qalGenBuffers ( 1, &name ); qalBufferData ( name, format, data, size, s_info->rate ); active_buffers++; if ( qalGetError() != AL_NO_ERROR ) { return NULL; } /* allocate placeholder sfxcache */ sc = s->cache = Z_TagMalloc ( sizeof ( *sc ), 0 ); sc->length = s_info->samples * 1000 / s_info->rate; sc->loopstart = s_info->loopstart; sc->width = s_info->width; sc->size = size; sc->bufnum = name; return sc; }
/* * Main update function. Called every frame, * performes all necessary calculations. */ void AL_Update ( void ) { q_int32_t i; channel_t *ch; vec_t orientation[6]; paintedtime = cl.time; /* set listener (player) parameters */ AL_CopyVector ( listener_forward, orientation ); AL_CopyVector ( listener_up, orientation + 3 ); qalListenerf ( AL_GAIN, s_volume->value ); qalListenerf ( AL_MAX_GAIN, s_openal_maxgain->value ); qalDistanceModel ( AL_LINEAR_DISTANCE_CLAMPED ); qalListener3f ( AL_POSITION, AL_UnpackVector ( listener_origin ) ); qalListenerfv ( AL_ORIENTATION, orientation ); /* update spatialization for dynamic sounds */ ch = channels; for ( i = 0; i < s_numchannels; i++, ch++ ) { if ( !ch->sfx ) { continue; } if ( ch->autosound ) { /* autosounds are regenerated fresh each frame */ if ( ch->autoframe != s_framecount ) { AL_StopChannel ( ch ); continue; } } else { ALenum state; qalGetError(); qalGetSourcei ( ch->srcnum, AL_SOURCE_STATE, &state ); if ( ( qalGetError() != AL_NO_ERROR ) || ( state == AL_STOPPED ) ) { AL_StopChannel ( ch ); continue; } } if ( s_show->value ) { Com_Printf ( "%3i %s\n", ch->master_vol, ch->sfx->name ); } /* respatialize channel */ AL_Spatialize ( ch ); } s_framecount++; /* add loopsounds */ AL_AddLoopSounds(); /* add music */ #ifdef HT_WITH_OGG OGG_Stream(); #endif AL_StreamUpdate(); AL_IssuePlaysounds(); }
/* * Plays a channel (in the frontends * sense) with OpenAL. */ void AL_PlayChannel(channel_t *ch) { sfxcache_t *sc; float vol; /* Debug */ if (s_show->value > 1) { Com_Printf("%s: %s\n", __func__, ch->sfx->name); } /* Clamp volume */ vol = ch->oal_vol; if (vol > 1.0f) { vol = 1.0f; } sc = ch->sfx->cache; ch->srcnum = s_srcnums[ch - channels]; qalGetError(); qalSourcef(ch->srcnum, AL_REFERENCE_DISTANCE, SOUND_FULLVOLUME); qalSourcef(ch->srcnum, AL_MAX_DISTANCE, 8192); qalSourcef(ch->srcnum, AL_ROLLOFF_FACTOR, ch->dist_mult * (8192 - SOUND_FULLVOLUME)); qalSourcef(ch->srcnum, AL_GAIN, vol); qalSourcei(ch->srcnum, AL_BUFFER, sc->bufnum); qalSourcei(ch->srcnum, AL_LOOPING, ch->autosound ? AL_TRUE : AL_FALSE); if ((ch->entnum == -1) || (ch->entnum == cl.playernum + 1) || !ch->dist_mult) { /* anything coming from the view entity will always * be full volume and at the listeners position */ qalSource3f(ch->srcnum, AL_POSITION, 0.0f, 0.0f, 0.0f); qalSourcei(ch->srcnum, AL_SOURCE_RELATIVE, AL_TRUE); } else { /* all other sources are *not* relative */ qalSourcei(ch->srcnum, AL_SOURCE_RELATIVE, AL_FALSE); } /* Spatialize it */ AL_Spatialize(ch); /* Play it */ qalSourcePlay(ch->srcnum); /* Do not play broken channels */ if (qalGetError() != AL_NO_ERROR) { AL_StopChannel(ch); } }
/* * S_InitSources */ qboolean S_InitSources( int maxEntities, qboolean verbose ) { int i; memset( srclist, 0, sizeof( srclist ) ); src_count = 0; // Allocate as many sources as possible for( i = 0; i < MAX_SRC; i++ ) { qalGenSources( 1, &srclist[i].source ); if( qalGetError() != AL_NO_ERROR ) break; src_count++; } if( !src_count ) return qfalse; if( verbose ) Com_Printf( "allocated %d sources\n", src_count ); if( maxEntities < 1 ) return qfalse; entlist = ( sentity_t * )S_Malloc( sizeof( sentity_t ) * maxEntities ); src_inited = qtrue; return qtrue; }
void S_StopBackgroundTrack( void ) { bgTrack_t *next; if( source ) qalSourceStop( source ); if( alloced_buffers ) { qalSourceUnqueueBuffers( source, MUSIC_BUFFERS, buffers ); qalDeleteBuffers( MUSIC_BUFFERS, buffers ); alloced_buffers = queued_buffers = qfalse; } music_source_free(); qalGetError(); while( s_bgTrackHead ) { next = s_bgTrackHead->anext; S_CloseMusicTrack( s_bgTrackHead ); S_Free( s_bgTrackHead ); s_bgTrackHead = next; } s_bgTrack = NULL; s_bgTrackHead = NULL; s_bgTrackBuffering = qfalse; s_bgTrackPaused = qfalse; }
/* ================= S_AL_SrcInit ================= */ static qboolean S_AL_SrcInit( void ) { int i; int limit; ALenum error; // Clear the sources data structure memset(srcList, 0, sizeof(srcList)); srcCount = 0; // Cap s_alSources to MAX_SRC limit = s_alSources->integer; if(limit > MAX_SRC) limit = MAX_SRC; else if(limit < 16) limit = 16; // Allocate as many sources as possible for(i = 0; i < limit; i++) { qalGenSources(1, &srcList[i].alSource); if((error = qalGetError()) != AL_NO_ERROR) break; srcCount++; } // All done. Print this for informational purposes Com_Printf( "Allocated %d sources.\n", srcCount); alSourcesInitialised = qtrue; return qtrue; }
/* * Plays a channel (in the frontends * sense) with OpenAL. */ void AL_PlayChannel(channel_t *ch) { sfxcache_t *sc; float vol; /* Debug */ if (s_show->value > 1) { Com_Printf("%s: %s\n", __func__, ch->sfx->name); } /* Clamp volume */ vol = ch->oal_vol + s_volume->value; if (vol > 1.0f) { vol = 1.0f; } sc = ch->sfx->cache; ch->srcnum = s_srcnums[ch - channels]; qalGetError(); qalSourcef(ch->srcnum, AL_REFERENCE_DISTANCE, SOUND_FULLVOLUME); qalSourcef(ch->srcnum, AL_MAX_DISTANCE, 8192); qalSourcef(ch->srcnum, AL_ROLLOFF_FACTOR, ch->dist_mult * (8192 - SOUND_FULLVOLUME)); qalSourcef(ch->srcnum, AL_GAIN, vol); qalSourcei(ch->srcnum, AL_BUFFER, sc->bufnum); qalSourcei(ch->srcnum, AL_LOOPING, ch->autosound ? AL_TRUE : AL_FALSE); /* Spatialize it */ AL_Spatialize(ch); /* Play it */ qalSourcePlay(ch->srcnum); /* Do not play broken channels */ if (qalGetError() != AL_NO_ERROR) { AL_StopChannel(ch); } }
qboolean AL_Init(void) { int i; Com_DPrintf("Initializing OpenAL\n"); if (!QAL_Init()) { goto fail0; } // check for linear distance extension if (!qalIsExtensionPresent("AL_EXT_LINEAR_DISTANCE")) { Com_SetLastError("AL_EXT_LINEAR_DISTANCE extension is missing"); goto fail1; } // generate source names qalGetError(); for (i = 0; i < MAX_CHANNELS; i++) { qalGenSources(1, &s_srcnums[i]); if (qalGetError() != AL_NO_ERROR) { break; } } Com_DPrintf("Got %d AL sources\n", i); if (i < MIN_CHANNELS) { Com_SetLastError("Insufficient number of AL sources"); goto fail1; } s_numchannels = i; Com_Printf("OpenAL initialized.\n"); return qtrue; fail1: QAL_Shutdown(); fail0: Com_EPrintf("Failed to initialize OpenAL: %s\n", Com_GetLastError()); return qfalse; }
/* ================= S_AL_ClearError ================= */ static void S_AL_ClearError( qboolean quiet ) { int error = qalGetError(); if( quiet ) return; if(error != AL_NO_ERROR) Com_Printf(S_COLOR_YELLOW "WARNING: unhandled AL error: %s\n", S_AL_ErrorMsg(error)); }
static qboolean music_process( ALuint b ) { int l = 0; ALuint format; ALenum error; snd_stream_t *music_stream; start: if( s_bgTrackBuffering ) return qtrue; music_stream = s_bgTrack->stream; if( music_stream ) { l = S_ReadStream( music_stream, MUSIC_BUFFER_SIZE, decode_buffer ); } else { l = 0; } if( !l ) { bgTrack_t *cur; cur = s_bgTrack; if( !S_AdvanceBackgroundTrack( 1 ) ) { if( !S_ValidMusicFile( s_bgTrack ) ) return qfalse; } else { // we've advanced to the next track, close this one S_CloseMusicTrack( cur ); goto start; } if( !S_ResetStream( music_stream ) ) { // if failed, close the track? return qfalse; } goto start; } format = S_SoundFormat( music_stream->info.width, music_stream->info.channels ); qalBufferData( b, format, decode_buffer, l, music_stream->info.rate ); if( ( error = qalGetError() ) != AL_NO_ERROR ) return qfalse; return qtrue; }
/* * S_GetBufferLength * * Returns buffer length expressed in milliseconds */ ALuint S_GetBufferLength( ALuint buffer ) { ALint size, bits, channels, freq; qalGetBufferi( buffer, AL_SIZE, &size ); qalGetBufferi( buffer, AL_BITS, &bits ); qalGetBufferi( buffer, AL_FREQUENCY, &freq ); qalGetBufferi( buffer, AL_CHANNELS, &channels ); if( qalGetError() != AL_NO_ERROR ) { return 0; } return (ALuint)((ALfloat)(size/(bits/8)/channels) * 1000.0 / freq + 0.5f); }
qboolean AL_Init( void ) { int i; if( !QAL_Init() ) { Com_EPrintf( "OpenAL failed to initialize.\n" ); return qfalse; } // check for linear distance extension if( !qalIsExtensionPresent( "AL_EXT_LINEAR_DISTANCE" ) ) { Com_EPrintf( "Required AL_EXT_LINEAR_DISTANCE extension is missing.\n" ); goto fail; } // generate source names qalGetError(); for( i = 0; i < MAX_CHANNELS; i++ ) { qalGenSources( 1, &s_srcnums[i] ); if( qalGetError() != AL_NO_ERROR ) { break; } } if( i < MIN_CHANNELS ) { Com_EPrintf( "Required at least %d sources, but got %d.\n", MIN_CHANNELS, i ); goto fail; } s_numchannels = i; Com_Printf( "OpenAL initialized.\n" ); return qtrue; fail: QAL_Shutdown(); return qfalse; }
static void AL_InitUnderwaterFilter() { // Generate a filter qalGenFilters(1, &underwaterFilter); if (qalGetError() != AL_NO_ERROR) { Com_Printf("Couldn't generate an OpenAL filter!\n"); return; } // Low pass filter for underwater effect qalFilteri(underwaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); if (qalGetError() != AL_NO_ERROR) { Com_Printf("Low pass filter is not supported!\n"); return; } // The effect qalFilterf(underwaterFilter, AL_LOWPASS_GAIN, 1.5); qalFilterf(underwaterFilter, AL_LOWPASS_GAINHF, 0.25); }
/* ================= S_AL_BufferUnload ================= */ static void S_AL_BufferUnload(sfxHandle_t sfx) { ALenum error; if(knownSfx[sfx].filename[0] == '\0') return; if(!knownSfx[sfx].inMemory) return; // Delete it qalDeleteBuffers(1, &knownSfx[sfx].buffer); if((error = qalGetError()) != AL_NO_ERROR) Com_Printf( S_COLOR_RED "ERROR: Can't delete sound buffer for %s\n", knownSfx[sfx].filename); knownSfx[sfx].inMemory = qfalse; }
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; }
/* ================= S_AL_BufferLoad ================= */ static void S_AL_BufferLoad(sfxHandle_t sfx) { ALenum error; void *data; snd_info_t info; ALuint format; // Nothing? if(knownSfx[sfx].filename[0] == '\0') return; // Player SFX if(knownSfx[sfx].filename[0] == '*') return; // Already done? if((knownSfx[sfx].inMemory) || (knownSfx[sfx].isDefault)) return; // Try to load data = S_CodecLoad(knownSfx[sfx].filename, &info); if(!data) { S_AL_BufferUseDefault(sfx); return; } format = S_AL_Format(info.width, info.channels); // Create a buffer qalGenBuffers(1, &knownSfx[sfx].buffer); if((error = qalGetError()) != AL_NO_ERROR) { S_AL_BufferUseDefault(sfx); Z_Free(data); Com_Printf( S_COLOR_RED "ERROR: Can't create a sound buffer for %s - %s\n", knownSfx[sfx].filename, S_AL_ErrorMsg(error)); return; } // Fill the buffer if( info.size == 0 ) { // We have no data to buffer, so buffer silence byte dummyData[ 2 ] = { 0 }; qalBufferData(knownSfx[sfx].buffer, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050); } else qalBufferData(knownSfx[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( !S_AL_BufferEvict( ) ) { S_AL_BufferUseDefault(sfx); Z_Free(data); Com_Printf( S_COLOR_RED "ERROR: Out of memory loading %s\n", knownSfx[sfx].filename); return; } // Try load it again qalBufferData(knownSfx[sfx].buffer, format, data, info.size, info.rate); error = qalGetError(); } // Some other error condition if(error != AL_NO_ERROR) { S_AL_BufferUseDefault(sfx); Z_Free(data); Com_Printf( S_COLOR_RED "ERROR: Can't fill sound buffer for %s - %s\n", knownSfx[sfx].filename, S_AL_ErrorMsg(error)); return; } // Free the memory Z_Free(data); // Woo! knownSfx[sfx].inMemory = qtrue; }
/* ================= S_AL_MusicProcess ================= */ static void S_AL_MusicProcess(ALuint b) { ALenum error; int l; ALuint format; snd_stream_t *curstream; if(intro_stream) curstream = intro_stream; else curstream = mus_stream; if(!curstream) return; l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer); // Run out data to read, start at the beginning again if(l == 0) { S_CodecCloseStream(curstream); // the intro stream just finished playing so we don't need to reopen // the music stream. if(intro_stream) intro_stream = NULL; else mus_stream = S_CodecOpenStream(s_backgroundLoop); curstream = mus_stream; if(!curstream) { S_AL_StopBackgroundTrack(); return; } l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer); } format = S_AL_Format(curstream->info.width, curstream->info.channels); if( l == 0 ) { // We have no data to buffer, so buffer silence byte dummyData[ 2 ] = { 0 }; qalBufferData( b, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 ); } else qalBufferData(b, format, decode_buffer, l, curstream->info.rate); if( ( error = qalGetError( ) ) != AL_NO_ERROR ) { S_AL_StopBackgroundTrack( ); Com_Printf( S_COLOR_RED "ERROR: while buffering data for music stream - %s\n", S_AL_ErrorMsg( error ) ); return; } }
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; }
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 ); }
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; }