void VOX_LoadWord( channel_t *pchan ) { if( pchan->words[pchan->wordIndex].sfx ) { wavdata_t *pSource = S_LoadSound( pchan->words[pchan->wordIndex].sfx ); if( pSource ) { int start = pchan->words[pchan->wordIndex].start; int end = pchan->words[pchan->wordIndex].end; // apply mixer pchan->currentWord = &pchan->pMixer; pchan->currentWord->pData = pSource; // don't allow overlapped ranges if( end <= start ) end = 0; if( start || end ) { int sampleCount = pSource->samples; if( start ) { S_SetSampleStart( pchan, pSource, (int)(sampleCount * 0.01f * start)); } if( end ) { S_SetSampleEnd( pchan, pSource, (int)(sampleCount * 0.01f * end)); } } } } }
void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) { channel_t *ss; sfxcache_t *sc; if (!shm || !sfx || s_nosound.value) return; if (total_channels == MAX_CHANNELS) { Com_Printf ("total_channels == MAX_CHANNELS\n"); return; } ss = &channels[total_channels]; total_channels++; sc = S_LoadSound (sfx); if (!sc) return; if (sc->loopstart == -1) { Com_Printf ("Sound %s not looped\n", sfx->name); return; } ss->sfx = sfx; VectorCopy (origin, ss->origin); ss->master_vol = (int) vol; ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist; ss->end = paintedtime + (int) sc->total_length; SND_Spatialize (ss); }
void S_EndRegistration(void) { int i; sfx_t *sfx; // free any sounds not from this registration sequence for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) { if (!sfx->Name[0]) continue; if (sfx->registration_sequence != s_registration_sequence) { // don't need this sound if (sfx->cache) // it is possible to have a leftover appFree(sfx->cache); // from a server that didn't finish loading memset(sfx, 0, sizeof(*sfx)); } } // load everything in for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) { if (!sfx->Name[0]) continue; S_LoadSound(sfx); } s_registering = false; }
void S_memoryLoad(sfx_t *sfx) { // load the sound file if ( !S_LoadSound ( sfx ) ) { // Com_Printf( S_COLOR_YELLOW "WARNING: couldn't load sound: %s\n", sfx->soundName ); sfx->defaultSound = qtrue; } sfx->inMemory = qtrue; }
void S_memoryLoad(sfx_t *sfx) { // load the sound file if (!S_LoadSound(sfx)) { sfx->defaultSound = qtrue; } sfx->inMemory = qtrue; }
void S_memoryLoad(Sfx *sfx) { /* load the sound file */ if(!S_LoadSound (sfx)) /* comprintf( S_COLOR_YELLOW "WARNING: couldn't load sound: %s\n", sfx->soundName ); */ sfx->defaultSound = qtrue; sfx->inMemory = qtrue; }
void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) { channel_t *target_chan, *check; sfxcache_t *sc; int ch_idx, skip; if (!shm || !sfx || s_nosound.value) return; // pick a channel to play on target_chan = SND_PickChannel(entnum, entchannel); if (!target_chan) return; // spatialize memset (target_chan, 0, sizeof(*target_chan)); VectorCopy(origin, target_chan->origin); target_chan->dist_mult = attenuation / sound_nominal_clip_dist; target_chan->master_vol = (int) (fvol * 255); target_chan->entnum = entnum; target_chan->entchannel = entchannel; SND_Spatialize(target_chan); if (!target_chan->leftvol && !target_chan->rightvol) return; // not audible at all // new channel sc = S_LoadSound (sfx); if (!sc) { target_chan->sfx = NULL; return; // couldn't load the sound's data } target_chan->sfx = sfx; target_chan->pos = 0.0; target_chan->end = paintedtime + (int) sc->total_length; // if an identical sound has also been started this frame, offset the pos // a bit to keep it from just making the first one louder check = &channels[NUM_AMBIENTS]; for (ch_idx=NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; ch_idx++, check++) { if (check == target_chan) continue; if (check->sfx == sfx && !check->pos) { skip = rand () % (int)(0.1 * shm->format.speed); if (skip >= target_chan->end) skip = target_chan->end - 1; target_chan->pos += skip; target_chan->end -= skip; break; } } }
/* ================== S_RegisterSound ================== */ sfx_t *S_RegisterSound (const char *name) { sfx_t *sfx; if (!sound_started) return NULL; sfx = S_FindName (name, true); if (!s_registering) S_LoadSound(sfx); return sfx; }
/* * S_StartSound */ static void S_StartSound( sfx_t *sfx, const vec3_t origin, int entnum, int entchannel, float fvol, float attenuation ) { sfxcache_t *sc; int vol; playsound_t *ps, *sort; if( !sfx ) return; // make sure the sound is loaded sc = S_LoadSound( sfx ); if( !sc ) return; // couldn't load the sound's data vol = fvol*255; // make the playsound_t ps = S_AllocPlaysound(); if( !ps ) return; if( origin ) { VectorCopy( origin, ps->origin ); ps->fixed_origin = true; } else ps->fixed_origin = false; ps->entnum = entnum; ps->entchannel = entchannel; ps->attenuation = attenuation; ps->volume = vol; ps->sfx = sfx; ps->begin = paintedtime; // sort into the pending sound list for( sort = s_pendingplays.next; sort != &s_pendingplays && sort->begin <= ps->begin; sort = sort->next ) ; ps->next = sort; ps->prev = sort->prev; ps->next->prev = ps; ps->prev->next = ps; }
/* ================== S_PrecacheSound ================== */ sfx_t *S_PrecacheSound (char *name) { sfx_t *sfx; if (!sound_started || nosound.value) return NULL; sfx = S_FindName (name); // cache it in if (precache.value) S_LoadSound (sfx); return sfx; }
/* ================== S_RegisterSound ================== */ sfx_t *S_RegisterSound (char *name) { sfx_t *sfx; if (!sound_started) return NULL; sfx = S_FindName (name, true); sfx->registration_sequence = s_registration_sequence; if (!s_registering) S_LoadSound (sfx); return sfx; }
sfx_t *S_RegisterSound(const char *name) { if (!sound_started) return NULL; sfx_t *sfx = S_FindName(name, true); sfx->registration_sequence = s_registration_sequence; if (!s_registering) S_LoadSound(sfx); else if (name[0] != '#' && name[0] != '*' && !GFileSystem->FileExists(va("sound/%s", name))) sfx->absent = true; return sfx; }
/* ================== S_PrecacheSound ================== */ sfx_t *S_PrecacheSound (char *name) { sfx_t *sfx; if (!snd_initialized) return NULL; sfx = S_FindName (name); // cache it in if (!s_nosound.value || s_precache.value) S_LoadSound (sfx); return sfx; }
static void I_OGGMus_PlayNext (int looping) { const char *track; sfx_t *cd_sfx, *sfx; wavinfo_t *info = 0; if (!play_list) return; if (PL_Type (play_list) == QFString) { track = PL_String (play_list); play_pos = 0; } else { play_pos++; if (play_pos >= PL_A_NumObjects (play_list)) play_pos = 0; track = PL_String (PL_ObjectAtIndex (play_list, play_pos)); looping = 0; } if (cd_channel) { S_ChannelStop (cd_channel); cd_channel = 0; } if (!(cd_channel = S_AllocChannel ())) return; if (!(cd_sfx = S_LoadSound (track)) || !(sfx = cd_sfx->open (cd_sfx))) { S_ChannelStop (cd_channel); cd_channel = 0; return; } Sys_Printf ("Playing: %s.\n", track); if (sfx->wavinfo) info = sfx->wavinfo (sfx); if (info) { if (looping == true) info->loopstart = 0; else info->loopstart = -1; } cd_channel->sfx = sfx; set_volume (); playing = true; }
/* ===================== S_EndRegistration ===================== */ void S_EndRegistration (void) { int i; sfx_t *sfx; // load everything in for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) { if (!sfx->name[0]) continue; S_LoadSound (sfx); } Hunk_End(&hunk_snd); s_registering = false; }
/* ===================== S_EndRegistration ===================== */ void S_EndRegistration (void) { int i; sfx_t *sfx; int size; // free any sounds not from this registration sequence for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) { if (!sfx->name[0]) continue; if (sfx->registration_sequence != s_registration_sequence) { // don't need this sound if (sfx->cache) // it is possible to have a leftover Z_Free (sfx->cache); // from a server that didn't finish loading memset (sfx, 0, sizeof(*sfx)); } else { // make sure it is paged in if (sfx->cache) { size = sfx->cache->length*sfx->cache->width; Com_PageInMemory ((byte *)sfx->cache, size); } } } // load everything in for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) { if (!sfx->name[0]) continue; S_LoadSound (sfx); } s_registering = false; // Knightmare added // S_EndRegistration is only called while the refresh is prepped // during a sound resart, so we can use this to restart the music track if (cls.state == ca_active && cl.refresh_prepped && !CDAudio_Active()) CL_PlayBackgroundTrack (); }
sfx_t *S_PrecacheSound (char *name) { sfx_t *sfx; if (!snd_initialized || s_nosound.value) return NULL; if (name == NULL || name[0] == 0) return NULL; sfx = S_FindName (name); if (sfx == NULL) return NULL; // cache it in if (s_precache.value) S_LoadSound (sfx); return sfx; }
/* =============== S_IssuePlaysound Take the next playsound and begin it on the channel This is never called directly by S_Play*, but only by the update loop. =============== */ void S_IssuePlaysound (playsound_t *ps) { channel_t *ch; sfxcache_t *sc; if (s_show->integer) Com_Printf ("Issue %i\n", ps->begin); // pick a channel to play on ch = S_PickChannel(ps->entnum, ps->entchannel); if (!ch) { S_FreePlaysound(ps); return; } sc = S_LoadSound(ps->sfx); if (!sc || sc->length <= 0) { S_FreePlaysound(ps); return; } // spatialize if (ps->attenuation == ATTN_STATIC) ch->dist_mult = ps->attenuation * 0.001f; else ch->dist_mult = ps->attenuation * 0.0005f; ch->master_vol = ps->volume; ch->entnum = ps->entnum; ch->entchannel = ps->entchannel; ch->sfx = ps->sfx; VectorCopy (ps->origin, ch->origin); ch->fixed_origin = ps->fixed_origin; S_Spatialize(ch); ch->pos = 0; ch->end = paintedtime + sc->length; // free the playsound S_FreePlaysound(ps); }
/* * SF_RegisterSound */ sfx_t *SF_RegisterSound( const char *name ) { sfx_t *sfx; int sfxnum; assert( name ); sfx = SF_FindName( name ); if( sfx->registration_sequence != s_registration_sequence ) { sfx->registration_sequence = s_registration_sequence; // evenly balance the load between two threads during registration sfxnum = sfx - known_sfx; if( !s_registering || sfxnum & 1 ) { S_IssueLoadSfxCmd( s_cmdPipe, sfxnum ); } else { S_LoadSound( sfx ); } } return sfx; }
/* ===================== S_EndRegistration ===================== */ void S_EndRegistration(void) { int i; sfx_t * sfx; int size; // free any sounds not from this registration sequence for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) { if (!sfx->name[0]) continue; if (sfx->registration_sequence != s_registration_sequence) { // don't need this sound if (sfx->cache) // it is possible to have a leftover Z_Free(sfx->cache); // from a server that didn't finish loading memset(sfx, 0, sizeof(*sfx)); } else { // make sure it is paged in if (sfx->cache) { size = sfx->cache->length * sfx->cache->width; Com_PageInMemory((byte *)sfx->cache, size); } } } // load everything in for (i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++) { if (!sfx->name[0]) continue; S_LoadSound(sfx); } s_registering = false; }
/* =============== S_IssuePlaysound Take the next playsound and begin it on the channel This is never called directly by S_Play*, but only by the update loop. =============== */ void S_IssuePlaysound(playsound_t *ps) { channel_t *ch; sfxcache_t *sc; if (s_show->integer) appPrintf("Sound: %s begin:%d ent:%d chn:%d\n", *ps->sfx->Name, ps->begin, ps->entnum, ps->entchannel); // pick a channel to play on ch = S_PickChannel(ps->entnum, ps->entchannel); if (!ch) { S_FreePlaysound(ps); return; } // spatialize if (ps->attenuation == ATTN_STATIC) ch->dist_mult = ps->attenuation * 0.001f; // will be fixed value: 0.003f else ch->dist_mult = ps->attenuation * 0.0005f; ch->master_vol = ps->volume; ch->entnum = ps->entnum; ch->entchannel = ps->entchannel; ch->sfx = ps->sfx; ch->origin = ps->origin; ch->fixed_origin = ps->fixed_origin; S_Spatialize(ch); ch->pos = 0; sc = S_LoadSound(ch->sfx); ch->end = paintedtime + sc->length; // free the playsound S_FreePlaysound(ps); }
/* ================= S_StaticSound ================= */ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) { channel_t *ss; sfxcache_t *sc; if (!sfx) return; if (total_channels == MAX_CHANNELS) { Con_Printf ("StaticSound: MAX_CHANNELS reached\n"); Con_Printf (" failed at (%.2f, %.2f, %.2f)\n",origin[0],origin[1],origin[2]); return; } ss = &channels[total_channels]; total_channels++; sc = S_LoadSound (sfx); if (!sc) return; if (sc->loopstart == -1) { Con_Printf ("Sound %s not looped\n", sfx->name); return; } ss->sfx = sfx; VectorCopy (origin, ss->origin); ss->master_vol = vol; ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist; ss->end = paintedtime + sc->length; SND_Spatialize (ss); }
/* ===================== S_EndRegistration ===================== */ void S_EndRegistration (void) { int i; sfx_t *sfx, *entry, **back; int size; unsigned int hash; // free any sounds not from this registration sequence for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) { if (!sfx->name[0]) continue; if (sfx->registration_sequence == s_registration_sequence) { #ifdef USE_OPENAL if(sfx->cache && !alSound) { // make sure it is paged in #else if(sfx->cache) { // make sure it is paged in #endif size = sfx->cache->length * sfx->cache->width * sfx->cache->channels; Com_PageInMemory( (byte *)sfx->cache, size); } continue; } hash = Com_HashKey (sfx->name, SND_HASH_SIZE); // delete it from hash table for( back=&sfx_hash[hash], entry=sfx_hash[hash]; entry; back=&entry->hashNext, entry=entry->hashNext ) { if( entry == sfx ) { *back = entry->hashNext; break; } } if (sfx->cache) { // it is possible to have a leftover #ifdef USE_OPENAL if(alSound) ALSnd_DeleteBuffer(sfx->cache); #endif Z_Free (sfx->cache); // from a server that didn't finish loading } if (sfx->truename) Z_Free (sfx->truename); memset (sfx, 0, sizeof(*sfx)); } // load everything in for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) { if (!sfx->name[0]) continue; S_LoadSound (sfx); } s_registering = false; } //============================================================================= /* ================= S_PickChannel ================= */ static channel_t *S_PickChannel(int entnum, int entchannel) { int ch_idx; int first_to_die = -1; int life_left = 0x7fffffff; channel_t *ch; if (entchannel < 0) Com_Error(ERR_DROP, "S_PickChannel: entchannel < 0"); // Check for replacement sound, or find the best one to replace for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++) { if (entchannel != 0 // channel 0 never overrides && channels[ch_idx].entnum == entnum && channels[ch_idx].entchannel == entchannel) { // always override sound from same entity first_to_die = ch_idx; break; } // don't let monster sounds override player sounds if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx) continue; if (channels[ch_idx].end - paintedtime < life_left) { life_left = channels[ch_idx].end - paintedtime; first_to_die = ch_idx; } } if (first_to_die == -1) return NULL; ch = &channels[first_to_die]; memset (ch, 0, sizeof(*ch)); return ch; }
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; }
/* ==================== S_StartSound Validates the parms and ques the sound up if pos is NULL, the sound will be dynamically sourced from the entity Entchannel 0 will never override a playing sound ==================== */ void S_StartSound(const CVec3 *origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs) { if (!sound_started) return; if (!sfx) return; if (sfx->Name[0] == '*') sfx = GetPlayerSound(&cl_entities[entnum].current, sfx->Name); // make sure the sound is loaded sfxcache_t *sc = S_LoadSound(sfx); if (!sc) return; // couldn't load the sound's data int vol = appRound(fvol*255); // make the playsound_t playsound_t *ps = S_AllocPlaysound(); if (!ps) return; if (origin) { ps->origin = *origin; ps->fixed_origin = true; } else ps->fixed_origin = false; ps->entnum = entnum; ps->entchannel = entchannel; ps->attenuation = attenuation; ps->volume = vol; ps->sfx = sfx; // drift s_beginofs int start = appRound(cl.frame.servertime / 1000.0f * dma.speed + s_beginofs); if (start < paintedtime) { start = paintedtime; s_beginofs = start - appRound(cl.frame.servertime / 1000.0f * dma.speed); } else if (start > paintedtime + 0.3 * dma.speed) { start = appRound(paintedtime + 0.1 * dma.speed); s_beginofs = start - appRound(cl.frame.servertime / 1000.0f * dma.speed); } else { s_beginofs-=10; } if (!timeofs) ps->begin = paintedtime; else ps->begin = appRound(start + timeofs * dma.speed); // sort into the pending sound list playsound_t *sort; for (sort = s_pendingplays.next; sort != &s_pendingplays && sort->begin < ps->begin; sort = sort->next) ; // empty ps->next = sort; ps->prev = sort->prev; ps->next->prev = ps; ps->prev->next = ps; }
void S_MixToBuffer(void *stream, unsigned int bufferframes) { int channelindex; channel_t *ch; int totalmixframes; unsigned char *outbytes = (unsigned char *) stream; sfx_t *sfx; portable_sampleframe_t *paint; int wantframes; int i; int count; int fetched; int fetch; int istartframe; int iendframe; int ilengthframes; int totallength; int loopstart; int indexfrac; int indexfracstep; #define S_FETCHBUFFERSIZE 4096 float fetchsampleframes[S_FETCHBUFFERSIZE*2]; const float *fetchsampleframe; float vol[SND_LISTENERS]; float lerp[2]; float sample[3]; double posd; double speedd; float maxvol; qboolean looping; qboolean silent; // mix as many times as needed to fill the requested buffer while (bufferframes) { // limit to the size of the paint buffer totalmixframes = min(bufferframes, PAINTBUFFER_SIZE); // clear the paint buffer memset(paintbuffer, 0, totalmixframes * sizeof(paintbuffer[0])); // paint in the channels. // channels with zero volumes still advance in time but don't paint. ch = channels; // cppcheck complains here but it is wrong, channels is a channel_t[MAX_CHANNELS] and not an int for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++) { sfx = ch->sfx; if (sfx == NULL) continue; if (!S_LoadSound (sfx, true)) continue; if (ch->flags & CHANNELFLAG_PAUSED) continue; if (!sfx->total_length) continue; // copy the channel information to the stack for reference, otherwise the // values might change during a mix if the spatializer is updating them // (note: this still may get some old and some new values!) posd = ch->position; speedd = ch->mixspeed * sfx->format.speed / snd_renderbuffer->format.speed; for (i = 0;i < SND_LISTENERS;i++) vol[i] = ch->volume[i]; // check total volume level, because we can skip some code on silent sounds but other code must still run (position updates mainly) maxvol = 0; for (i = 0;i < SND_LISTENERS;i++) if(vol[i] > maxvol) maxvol = vol[i]; switch(snd_renderbuffer->format.width) { case 1: // 8bpp silent = maxvol < (1.0f / (256.0f)); // so silent it has zero effect break; case 2: // 16bpp silent = maxvol < (1.0f / (65536.0f)); // so silent it has zero effect break; default: // floating point silent = maxvol < 1.0e-13f; // 130 dB is difference between hearing // threshold and a jackhammer from // working distance. // therefore, anyone who turns up // volume so much they notice this // cutoff, likely already has their // ear-drums blown out anyway. break; } // when doing prologic mixing, some channels invert one side if (ch->prologic_invert == -1) vol[1] *= -1.0f; // get some sfx info in a consistent form totallength = sfx->total_length; loopstart = (int)sfx->loopstart < totallength ? (int)sfx->loopstart : ((ch->flags & CHANNELFLAG_FORCELOOP) ? 0 : totallength); looping = loopstart < totallength; // do the actual paint now (may skip work if silent) paint = paintbuffer; istartframe = 0; for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count) { // check if this is a delayed sound if (posd < 0) { // for a delayed sound we have to eat into the delay first count = (int)floor(-posd / speedd) + 1; count = bound(1, count, wantframes); // let the for loop iterator apply the skip continue; } // compute a fetch size that won't overflow our buffer count = wantframes; for (;;) { istartframe = (int)floor(posd); iendframe = (int)floor(posd + (count-1) * speedd); ilengthframes = count > 1 ? (iendframe - istartframe + 2) : 2; if (ilengthframes <= S_FETCHBUFFERSIZE) break; // reduce count by 25% and try again count -= count >> 2; } // zero whole fetch buffer for safety // (floating point noise from uninitialized memory = HORRIBLE) // otherwise we would only need to clear the excess if (!silent) memset(fetchsampleframes, 0, ilengthframes*sfx->format.channels*sizeof(fetchsampleframes[0])); // if looping, do multiple fetches fetched = 0; for (;;) { fetch = min(ilengthframes - fetched, totallength - istartframe); if (fetch > 0) { if (!silent) sfx->fetcher->getsamplesfloat(ch, sfx, istartframe, fetch, fetchsampleframes + fetched*sfx->format.channels); istartframe += fetch; fetched += fetch; } if (istartframe == totallength && looping && fetched < ilengthframes) { // loop and fetch some more posd += loopstart - totallength; istartframe = loopstart; } else { break; } } // set up our fixedpoint resampling variables (float to int conversions are expensive so do not do one per sampleframe) fetchsampleframe = fetchsampleframes; indexfrac = (int)floor((posd - floor(posd)) * 65536.0); indexfracstep = (int)floor(speedd * 65536.0); if (!silent) { if (sfx->format.channels == 2) { // music is stereo #if SND_LISTENERS != 8 #error the following code only supports up to 8 channels, update it #endif if (snd_speakerlayout.channels > 2) { // surround mixing for (i = 0;i < count;i++, paint++) { lerp[1] = indexfrac * (1.0f / 65536.0f); lerp[0] = 1.0f - lerp[1]; sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1]; sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1]; sample[2] = (sample[0] + sample[1]) * 0.5f; paint->sample[0] += sample[0] * vol[0]; paint->sample[1] += sample[1] * vol[1]; paint->sample[2] += sample[0] * vol[2]; paint->sample[3] += sample[1] * vol[3]; paint->sample[4] += sample[2] * vol[4]; paint->sample[5] += sample[2] * vol[5]; paint->sample[6] += sample[0] * vol[6]; paint->sample[7] += sample[1] * vol[7]; indexfrac += indexfracstep; fetchsampleframe += 2 * (indexfrac >> 16); indexfrac &= 0xFFFF; } } else { // stereo mixing for (i = 0;i < count;i++, paint++) { lerp[1] = indexfrac * (1.0f / 65536.0f); lerp[0] = 1.0f - lerp[1]; sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1]; sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1]; paint->sample[0] += sample[0] * vol[0]; paint->sample[1] += sample[1] * vol[1]; indexfrac += indexfracstep; fetchsampleframe += 2 * (indexfrac >> 16); indexfrac &= 0xFFFF; } } } else if (sfx->format.channels == 1) { // most sounds are mono #if SND_LISTENERS != 8 #error the following code only supports up to 8 channels, update it #endif if (snd_speakerlayout.channels > 2) { // surround mixing for (i = 0;i < count;i++, paint++) { lerp[1] = indexfrac * (1.0f / 65536.0f); lerp[0] = 1.0f - lerp[1]; sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1]; paint->sample[0] += sample[0] * vol[0]; paint->sample[1] += sample[0] * vol[1]; paint->sample[2] += sample[0] * vol[2]; paint->sample[3] += sample[0] * vol[3]; paint->sample[4] += sample[0] * vol[4]; paint->sample[5] += sample[0] * vol[5]; paint->sample[6] += sample[0] * vol[6]; paint->sample[7] += sample[0] * vol[7]; indexfrac += indexfracstep; fetchsampleframe += (indexfrac >> 16); indexfrac &= 0xFFFF; } } else { // stereo mixing for (i = 0;i < count;i++, paint++) { lerp[1] = indexfrac * (1.0f / 65536.0f); lerp[0] = 1.0f - lerp[1]; sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1]; paint->sample[0] += sample[0] * vol[0]; paint->sample[1] += sample[0] * vol[1]; indexfrac += indexfracstep; fetchsampleframe += (indexfrac >> 16); indexfrac &= 0xFFFF; } } } } }
int32_t S_PlaySound3D(int32_t num, int32_t i, const vec3_t *pos) { int32_t j = VM_OnEventWithReturn(EVENT_SOUND, i, screenpeek, num); if (j == -1 && num != -1) // check that the user returned -1, but only if -1 wasn't playing already (in which case, warn) return -1; num = j; const DukePlayer_t *const myps = g_player[myconnectindex].ps; if ((unsigned)num > (unsigned)g_maxSoundPos || ((g_sounds[num].m & SF_ADULT) && ud.lockout) || !ud.config.SoundToggle || (unsigned)i >= MAXSPRITES || !FX_VoiceAvailable(g_sounds[num].pr) || (myps->timebeforeexit > 0 && myps->timebeforeexit <= GAMETICSPERSEC * 3) || (myps->gm & MODE_MENU)) return -1; int32_t voice; if (g_sounds[num].m & SF_DTAG) // Duke-Tag sound { if ((voice = S_PlaySound(num)) <= FX_Ok) return -1; j = 0; while (j < MAXSOUNDINSTANCES && g_sounds[num].SoundOwner[j].voice != voice) j++; if (EDUKE32_PREDICT_FALSE(j >= MAXSOUNDINSTANCES)) { OSD_Printf(OSD_ERROR "%s %d: WTF?\n", __FILE__, __LINE__); return -1; } g_sounds[num].SoundOwner[j].ow = i; return voice; } // Duke talk if (g_sounds[num].m & SF_TALK) { if ((g_netServer || ud.multimode > 1) && PN == APLAYER && P_Get(i) != screenpeek) // other player sound { if (!(ud.config.VoiceToggle&4)) return -1; } else if (!(ud.config.VoiceToggle&1)) return -1; // don't play if any Duke talk sounds are already playing for (j=0; j<g_maxSoundPos; ++j) if ((g_sounds[j].m & SF_TALK) && g_sounds[j].num > 0) return -1; } int32_t sndist, sndang; int32_t explosionp = S_CalcDistAndAng(i, num, CAMERA(sect), CAMERA(ang), &CAMERA(pos), pos, &sndist, &sndang); int32_t pitch = S_GetPitch(num); const DukePlayer_t *peekps = g_player[screenpeek].ps; #ifdef SPLITSCREEN_MOD_HACKS if (g_fakeMultiMode==2) { // splitscreen HACK if (g_player[1].ps->i == i) peekps = g_player[1].ps; } #endif if (peekps->sound_pitch) pitch += peekps->sound_pitch; if (explosionp) { if (peekps->cursectnum > -1 && sector[peekps->cursectnum].lotag == ST_2_UNDERWATER) pitch -= 1024; } else { if (sndist > 32767 && PN != MUSICANDSFX && (g_sounds[num].m & (SF_LOOP|SF_MSFX)) == 0) return -1; if (peekps->cursectnum > -1 && sector[peekps->cursectnum].lotag == ST_2_UNDERWATER && (g_sounds[num].m & SF_TALK) == 0) pitch = -768; } if (g_sounds[num].num > 0 && PN != MUSICANDSFX) S_StopEnvSound(num, i); if (g_sounds[num].ptr == 0) { if (S_LoadSound(num) == 0) return -1; } else { if (g_soundlocks[num] < 200) g_soundlocks[num] = 200; else g_soundlocks[num]++; } j = S_GetSlot(num); if (j >= MAXSOUNDINSTANCES) { g_soundlocks[num]--; return -1; } { const int32_t repeatp = (g_sounds[num].m & SF_LOOP); const int32_t ambsfxp = S_IsAmbientSFX(i); if (repeatp && (g_sounds[num].m & SF_ONEINST_INTERNAL) && g_sounds[num].num > 0) { g_soundlocks[num]--; return -1; } if (repeatp && !ambsfxp) { voice = FX_PlayLoopedAuto(g_sounds[num].ptr, g_sounds[num].soundsiz, 0, -1, pitch, FX_VOLUME(sndist>>6), FX_VOLUME(sndist>>6), 0, // XXX: why is 'right' 0? g_sounds[num].pr, (num * MAXSOUNDINSTANCES) + j); } else {
/* ==================== S_StartSound Validates the parms and ques the sound up if pos is NULL, the sound will be dynamically sourced from the entity Entchannel 0 will never override a playing sound ==================== */ void S_StartSound(const vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs) { sfxcache_t *sc; playsound_t *ps, *sort; int start; if (!sound_started) return; if (!sfx) return; if (sfx->name[0] == '*') { if(entnum < 1 || entnum >= MAX_EDICTS ) { Com_Error( ERR_DROP, "S_StartSound: bad entnum: %d", entnum ); } sfx = S_RegisterSexedSound(cl_entities[entnum].current.number, sfx->name); } // make sure the sound is loaded sc = S_LoadSound (sfx); if (!sc || sc->length <= 0) return; // couldn't load the sound's data // make the playsound_t ps = S_AllocPlaysound (); if (!ps) return; if (origin) { VectorCopy (origin, ps->origin); ps->fixed_origin = true; } else ps->fixed_origin = false; ps->entnum = entnum; ps->entchannel = entchannel; ps->attenuation = attenuation; ps->sfx = sfx; #ifdef USE_OPENAL if(alSound) { ps->volume = fvol*fvol; ps->begin = cl.time + (int)(timeofs * 1000); } else #endif { ps->volume = fvol*255; // drift s_beginofs start = cl.serverTime * 0.001f * dma.speed + s_beginofs; if (start < paintedtime) { start = paintedtime; s_beginofs = start - (cl.serverTime * 0.001f * dma.speed); } else if (start > paintedtime + 0.3f * dma.speed) { start = paintedtime + 0.1f * dma.speed; s_beginofs = start - (cl.serverTime * 0.001f * dma.speed); } else { s_beginofs -= 10; } if (!timeofs) ps->begin = paintedtime; else ps->begin = start + timeofs * dma.speed; } // sort into the pending sound list for (sort = s_pendingplays.next; sort != &s_pendingplays && sort->begin < ps->begin ; sort = sort->next) ; ps->next = sort; ps->prev = sort->prev; ps->next->prev = ps; ps->prev->next = ps; }
/* ==================== S_StartSound Validates the parms and ques the sound up if pos is NULL, the sound will be dynamically sourced from the entity Entchannel 0 will never override a playing sound ==================== */ void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs) { sfxcache_t *sc; int vol; playsound_t *ps, *sort; int start; if (!sound_started) return; if (!sfx) return; if (sfx->name[0] == '*') sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name); // make sure the sound is loaded sc = S_LoadSound (sfx); if (!sc) return; // couldn't load the sound's data vol = fvol*255; // make the playsound_t ps = S_AllocPlaysound (); if (!ps) return; if (origin) { VectorCopy (origin, ps->origin); ps->fixed_origin = true; } else ps->fixed_origin = false; ps->entnum = entnum; ps->entchannel = entchannel; ps->attenuation = attenuation; ps->volume = vol; ps->sfx = sfx; // drift s_beginofs start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs; if (start < paintedtime) { start = paintedtime; s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed); } else if (start > paintedtime + 0.3 * dma.speed) { start = paintedtime + 0.1 * dma.speed; s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed); } else { s_beginofs-=10; } if (!timeofs) ps->begin = paintedtime; else ps->begin = start + timeofs * dma.speed; // sort into the pending sound list for (sort = s_pendingplays.next ; sort != &s_pendingplays && sort->begin < ps->begin ; sort = sort->next) ; ps->next = sort; ps->prev = sort->prev; ps->next->prev = ps; ps->prev->next = ps; }