/* * 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; }
/* ================= S_AL_RawSamples ================= */ static void S_AL_RawSamples(int samples, int rate, int width, int channels, const byte *data, float volume) { ALuint buffer; ALuint format; format = S_AL_Format( width, channels ); // Create the streamSource if necessary if(streamSourceHandle == -1) { S_AL_AllocateStreamChannel(); // Failed? if(streamSourceHandle == -1) { Com_Printf( S_COLOR_RED "ERROR: Can't allocate streaming streamSource\n"); return; } } // Create a buffer, and stuff the data into it qalGenBuffers(1, &buffer); qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); // Shove the data onto the streamSource qalSourceQueueBuffers(streamSource, 1, &buffer); // Volume qalSourcef (streamSource, AL_GAIN, volume * s_volume->value * s_alGain->value); }
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; }
/** * Background music playback */ void SndAl_StartBackgroundTrack( const char *intro, const char *loop ) { int i; // Stop any existing music that might be playing SndAl_StopBackgroundTrack(); if ( !intro || !intro[ 0 ] ) { intro = loop; } if ( !loop || !loop[ 0 ] ) { loop = intro; } if ( ( !intro || !intro[ 0 ] ) && ( !intro || !intro[ 0 ] ) ) { return; } // Copy the loop over strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); // Open the intro mus_stream = si.StreamOpen( intro ); if ( !mus_stream ) { return; } // Allocate a source al_mus_source_get(); if ( source_handle == -1 ) { return; } // Generate the buffers qalGenBuffers( BUFFERS, buffers ); // Queue the buffers up for ( i = 0; i < BUFFERS; i++ ) { al_mus_process( buffers[ i ] ); } qalSourceQueueBuffers( source, BUFFERS, buffers ); // Start playing qalSourcePlay( source ); mus_playing = qtrue; }
/* ================= S_StreamRawSamples Cinematic streaming ================= */ void S_StreamRawSamples (const byte *data, int samples, int rate, int width, int channels) { int processed, state, size; unsigned format, buffer; if (!s_initialized) return; if (!s_streamingChannel) return; // Unqueue and delete any processed buffers qalGetSourcei(s_streamingChannel->sourceNum, AL_BUFFERS_PROCESSED, &processed); if (processed > 0){ while (processed--){ qalSourceUnqueueBuffers(s_streamingChannel->sourceNum, 1, &buffer); qalDeleteBuffers(1, &buffer); } } // Calculate buffer size size = samples * width * channels; // Set buffer format if (width == 2) { if (channels == 2) format = AL_FORMAT_STEREO16; else format = AL_FORMAT_MONO16; } else { if (channels == 2) format = AL_FORMAT_STEREO8; else format = AL_FORMAT_MONO8; } // Upload and queue the new buffer qalGenBuffers(1, &buffer); qalBufferData(buffer, format, (byte *)data, size, rate); qalSourceQueueBuffers(s_streamingChannel->sourceNum, 1, &buffer); // Update volume qalSourcef(s_streamingChannel->sourceNum, AL_GAIN, s_sfxVolume->value); // If not playing, then do so qalGetSourcei(s_streamingChannel->sourceNum, AL_SOURCE_STATE, &state); if (state != AL_PLAYING) qalSourcePlay(s_streamingChannel->sourceNum); }
/* * Queues raw samples for playback. Used * by the background music an cinematics. */ void AL_RawSamples(int samples, int rate, int width, int channels, byte *data, float volume) { ALuint buffer; ALuint format = 0; /* Work out format */ if (width == 1) { if (channels == 1) { format = AL_FORMAT_MONO8; } else if (channels == 2) { format = AL_FORMAT_STEREO8; } } else if (width == 2) { if (channels == 1) { format = AL_FORMAT_MONO16; } else if (channels == 2) { format = AL_FORMAT_STEREO16; } } /* Create a buffer, and stuff the data into it */ qalGenBuffers(1, &buffer); qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); active_buffers++; /* set volume */ if (volume > 1.0f) { volume = 1.0f; } qalSourcef(streamSource, AL_GAIN, volume); /* Shove the data onto the streamSource */ qalSourceQueueBuffers(streamSource, 1, &buffer); /* emulate behavior of S_RawSamples for s_rawend */ s_rawend += samples; }
void AL_RawSamples( int samples, int rate, int width, int channels, byte *data, float volume ) { ALuint buffer; ALuint format; format = S_AL_Format( width, channels ); // Create a buffer, and stuff the data into it qalGenBuffers(1, &buffer); qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); active_buffers++; // set volume qalSourcef( streamSource, AL_GAIN, volume ); // Shove the data onto the streamSource qalSourceQueueBuffers(streamSource, 1, &buffer); // emulate behavior of S_RawSamples for s_rawend s_rawend += samples; }
/* ================= 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_StartBackgroundTrack ================= */ static void S_AL_StartBackgroundTrack( const char *intro, const char *loop ) { int i; qboolean issame; // Stop any existing music that might be playing S_AL_StopBackgroundTrack(); if((!intro || !*intro) && (!loop || !*loop)) return; // Allocate a musicSource S_AL_MusicSourceGet(); if(musicSourceHandle == -1) return; if (!loop || !*loop) { loop = intro; issame = qtrue; } else if(intro && *intro && !strcmp(intro, loop)) issame = qtrue; else issame = qfalse; // Copy the loop over strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); if(!issame) { // Open the intro and don't mind whether it succeeds. // The important part is the loop. intro_stream = S_CodecOpenStream(intro); } else intro_stream = NULL; mus_stream = S_CodecOpenStream(s_backgroundLoop); if(!mus_stream) { S_AL_CloseMusicFiles(); S_AL_MusicSourceFree(); return; } // Generate the musicBuffers qalGenBuffers(NUM_MUSIC_BUFFERS, musicBuffers); // Queue the musicBuffers up for(i = 0; i < NUM_MUSIC_BUFFERS; i++) { S_AL_MusicProcess(musicBuffers[i]); } qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers); // Set the initial gain property qalSourcef(musicSource, AL_GAIN, s_alGain->value * s_musicVolume->value); // Start playing qalSourcePlay(musicSource); musicPlaying = qtrue; }
void SndAl_RawSamples( int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum ) { ALuint buffer; ALuint format = AL_FORMAT_STEREO16; ALint state; // Work out AL format if ( width == 1 ) { if ( channels == 1 ) { format = AL_FORMAT_MONO8; } else if ( channels == 2 ) { format = AL_FORMAT_STEREO8; } } else if ( width == 2 ) { if ( channels == 1 ) { format = AL_FORMAT_MONO16; } else if ( channels == 2 ) { format = AL_FORMAT_STEREO16; } } // Create the source if necessary if ( source_handle == -1 ) { allocate_channel(); // Failed? if ( source_handle == -1 ) { si.Printf( PRINT_ALL, "Can't allocate streaming source\n" ); return; } } // Create a buffer, and stuff the data into it qalGenBuffers( 1, &buffer ); qalBufferData( buffer, format, data, ( samples * width * channels ), rate ); // Shove the data onto the source qalSourceQueueBuffers( source, 1, &buffer ); // Start the source playing if necessary qalGetSourcei( source, AL_SOURCE_STATE, &state ); // Volume qalSourcef( source, AL_GAIN, volume * s_volume->value * s_gain->value ); if ( !is_playing ) { qalSourcePlay( source ); is_playing = qtrue; } }
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; }
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; }