/* * S_Spatialize */ static void S_SpatializeChannel( channel_t *ch ) { vec3_t origin, velocity; if( ch->fixed_origin ) { VectorCopy( ch->origin, origin ); VectorClear( velocity ); } else { VectorCopy( s_ent_spatialization[ch->entnum].origin, origin ); VectorCopy( s_ent_spatialization[ch->entnum].velocity, velocity ); } if( s_pseudoAcoustics->value ) { S_SpatializeOriginHQ( origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol, &ch->lpf_lcoeff, &ch->lpf_rcoeff, &ch->ldelay, &ch->rdelay ); } else { S_SpatializeOrigin( origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol ); ch->lpf_lcoeff = ch->lpf_rcoeff = 0.0f; ch->ldelay = ch->rdelay = 0; } }
/* ============ S_Respatialize Change the volumes of all the playing sounds for changes in their positions ============ */ void SOrig_Respatialize( int entityNum, const vec3_t head, vec3_t axis[ 3 ], int inwater ) { int i; channel_t *ch; vec3_t origin; if ( !s_soundStarted || s_soundMuted ) { return; } listener_number = entityNum; VectorCopy( head, listener_origin ); VectorCopy( axis[ 0 ], listener_axis[ 0 ] ); VectorCopy( axis[ 1 ], listener_axis[ 1 ] ); VectorCopy( axis[ 2 ], listener_axis[ 2 ] ); // update spatialization for dynamic sounds ch = s_channels; for ( i = 0; i < MAX_CHANNELS; i++, ch++ ) { if ( !ch->thesfx ) { continue; } // anything coming from the view entity will always be full volume if ( ch->entnum == listener_number ) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; } else { if ( ch->fixed_origin ) { VectorCopy( ch->origin, origin ); } else { VectorCopy( loopSounds[ ch->entnum ].origin, origin ); } S_SpatializeOrigin( origin, ch->master_vol, &ch->leftvol, &ch->rightvol ); } } // add loopsounds S_AddLoopSounds(); }
/* ================= S_Spatialize ================= */ static void S_Spatialize(channel_t *ch) { vec3_t origin; // anything coming from the view entity will always be full volume if (ch->entnum == cl.playernum+1) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; return; } if (ch->fixed_origin) VectorCopy (ch->origin, origin); else CL_GetEntitySoundOrigin (ch->entnum, origin); S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol); }
/* ============ S_Base_Respatialize Change the volumes of all the playing sounds for changes in their positions ============ */ static void S_Base_Respatialize( int entityNum, const vec3_t head, const vec3_t axis[3], int inwater ) { int i; channel_t *ch; vec3_t origin; if ( !s_soundStarted || s_soundMuted ) { return; } listener_number = entityNum; //Com_Printf("%s() %d\n", __FUNCTION__, entityNum); VectorCopy(head, listener_origin); VectorCopy(axis[0], listener_axis[0]); VectorCopy(axis[1], listener_axis[1]); VectorCopy(axis[2], listener_axis[2]); // update spatialization for dynamic sounds ch = s_channels; for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { if ( !ch->thesfx ) { continue; } // local and first person sounds will always be full volume if (ch->fullVolume) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; } else { if (ch->fixed_origin) { VectorCopy( ch->origin, origin ); } else { VectorCopy( loopSounds[ ch->entnum ].origin, origin ); } S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol); } } // add loopsounds S_AddLoopSounds (); }
/* Change the volumes of all the playing sounds for changes in their positions */ static void S_Base_Respatialize(int entityNum, const Vec3 head, Vec3 axis[3], int inwater) { int i; Channel *ch; Vec3 origin; UNUSED(inwater); if(!s_soundStarted || s_soundMuted) return; listener_number = entityNum; copyv3(head, listener_origin); copyv3(axis[0], listener_axis[0]); copyv3(axis[1], listener_axis[1]); copyv3(axis[2], listener_axis[2]); /* update spatialization for dynamic sounds */ ch = s_channels; for(i = 0; i < MAX_CHANNELS; i++, ch++) { if(!ch->thesfx) continue; /* anything coming from the view entity will always be full volume */ if(ch->entnum == listener_number) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; } else { if(ch->fixed_origin) copyv3(ch->origin, origin); else copyv3(loopSounds[ ch->entnum ].origin, origin); S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol); } } S_AddLoopSounds (); }
/* ================== AddLoopSounds Entities with a ->sound field will generated looped sounds that are automatically started, stopped, and merged together as the entities are sent to the client ================== */ static void AddLoopSounds() { int i; int num; clEntityState_t *ent; if (cl_paused->integer) return; if (cls.state != ca_active) return; if (!cl.sound_ambient) return; int sounds[MAX_EDICTS]; for (i = 0; i < cl.frame.num_entities; i++) { num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); ent = &cl_parse_entities[num]; sounds[i] = ent->sound; } float atten = SOUND_LOOPATTENUATE2; if (bspfile.type == map_q3) atten = SOUND_LOOPATTENUATE3; for (i = 0; i < cl.frame.num_entities; i++) { if (!sounds[i]) continue; sfx_t *sfx = cl.sound_precache[sounds[i]]; if (!sfx) continue; // bad sound effect sfxcache_t *sc = sfx->cache; if (!sc) continue; num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); ent = &cl_parse_entities[num]; // find the total contribution of all sounds of this type int left_total, right_total; S_SpatializeOrigin(ent->origin, 255.0, atten, &left_total, &right_total); for (int j = i + 1; j < cl.frame.num_entities; j++) { if (sounds[j] != sounds[i]) continue; sounds[j] = 0; // don't check this again later num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1); ent = &cl_parse_entities[num]; int left, right; S_SpatializeOrigin(ent->origin, 255.0, atten, &left, &right); left_total += left; right_total += right; } if (left_total == 0 && right_total == 0) continue; // not audible // allocate a channel channel_t *ch = S_PickChannel(0, 0); if (!ch) return; if (left_total > 255) left_total = 255; if (right_total > 255) right_total = 255; ch->leftvol = left_total; ch->rightvol = right_total; ch->autosound = true; // remove next frame ch->sfx = sfx; ch->pos = paintedtime % sc->length; ch->end = paintedtime + sc->length - ch->pos; } }
/* ================== S_AddLoopSounds Spatialize all of the looping sounds. All sounds are on the same cycle, so any duplicates can just sum up the channel multipliers. ================== */ void S_AddLoopSounds (void) { int i, j, time; int left_total, right_total, left, right; channel_t *ch; loopSound_t *loop, *loop2; static int loopFrame; numLoopChannels = 0; time = Com_Milliseconds(); loopFrame++; for ( i = 0 ; i < MAX_GENTITIES ; i++) { loop = &loopSounds[i]; if ( !loop->active || loop->mergeFrame == loopFrame ) { continue; // already merged into an earlier sound } if (loop->kill) { S_SpatializeOrigin( loop->origin, 127, &left_total, &right_total); // 3d } else { S_SpatializeOrigin( loop->origin, 90, &left_total, &right_total); // sphere } loop->sfx->lastTimeUsed = time; for (j=(i+1); j< MAX_GENTITIES ; j++) { loop2 = &loopSounds[j]; if ( !loop2->active || loop2->doppler || loop2->sfx != loop->sfx) { continue; } loop2->mergeFrame = loopFrame; if (loop2->kill) { S_SpatializeOrigin( loop2->origin, 127, &left, &right); // 3d } else { S_SpatializeOrigin( loop2->origin, 90, &left, &right); // sphere } loop2->sfx->lastTimeUsed = time; left_total += left; right_total += right; } if (left_total == 0 && right_total == 0) { continue; // not audible } // allocate a channel ch = &loop_channels[numLoopChannels]; if (left_total > 255) { left_total = 255; } if (right_total > 255) { right_total = 255; } ch->master_vol = 127; ch->leftvol = left_total; ch->rightvol = right_total; ch->thesfx = loop->sfx; ch->doppler = loop->doppler; ch->dopplerScale = loop->dopplerScale; ch->oldDopplerScale = loop->oldDopplerScale; ch->fullVolume = qfalse; numLoopChannels++; if (numLoopChannels == MAX_CHANNELS) { return; } } }
/* ================== S_AddLoopSounds Entities with a ->sound field will generated looped sounds that are automatically started, stopped, and merged together as the entities are sent to the client ================== */ void S_AddLoopSounds (void) { int i, j; int sounds[MAX_EDICTS]; int left, right, left_total, right_total; channel_t *ch; sfx_t *sfx; sfxcache_t *sc; int num; vec3_t origin_v; // Knightmare added entity_state_t *ent; if (cl_paused->value) return; if (cls.state != ca_active) return; if (!cl.sound_prepped) return; for (i=0 ; i<cl.frame.num_entities ; i++) { num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); ent = &cl_parse_entities[num]; sounds[i] = ent->sound; } for (i=0 ; i<cl.frame.num_entities ; i++) { if (!sounds[i]) continue; sfx = cl.sound_precache[sounds[i]]; if (!sfx) continue; // bad sound effect sc = sfx->cache; if (!sc) continue; num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); ent = &cl_parse_entities[num]; // Knightmare- find correct origin for bmodels without origin brushes if (ent->solid == 31) // special value for bmodels { cmodel_t *cmodel; qboolean outofbounds = false; int k; cmodel = cl.model_clip[ent->modelindex]; if (cmodel) { for (k=0; k<3; k++) if (ent->origin[k] < cmodel->mins[k] || ent->origin[k] > cmodel->maxs[k]) outofbounds = true; } if (cmodel && outofbounds) { for (k=0; k<3; k++) origin_v[k] = ent->origin[k]+0.5*(cmodel->mins[k]+cmodel->maxs[k]); } else VectorCopy (ent->origin, origin_v); } else VectorCopy (ent->origin, origin_v); // find the total contribution of all sounds of this type S_SpatializeOrigin (origin_v, 255.0, SOUND_LOOPATTENUATE, // Knightmare changed, was ent->origin &left_total, &right_total); for (j=i+1 ; j<cl.frame.num_entities ; j++) { if (sounds[j] != sounds[i]) continue; sounds[j] = 0; // don't check this again later num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1); ent = &cl_parse_entities[num]; S_SpatializeOrigin (origin_v, 255.0, SOUND_LOOPATTENUATE, // Knightmare changed, was ent->origin &left, &right); left_total += left; right_total += right; } if (left_total == 0 && right_total == 0) continue; // not audible // allocate a channel ch = S_PickChannel(0, 0); if (!ch) return; if (left_total > 255) left_total = 255; if (right_total > 255) right_total = 255; ch->leftvol = left_total; ch->rightvol = right_total; ch->autosound = true; // remove next frame ch->sfx = sfx; ch->pos = paintedtime % sc->length; ch->end = paintedtime + sc->length - ch->pos; } }
/** * @brief Spatialize all of the looping sounds. * All sounds are on the same cycle, so any duplicates can just * sum up the channel multipliers. */ void S_AddLoopSounds(void) { int i, j, time; int left_total, right_total, left, right; channel_t *ch; loopSound_t *loop, *loop2; static int loopFrame; if (!s_soundStarted || s_soundMuted) { return; } numLoopChannels = 0; time = Sys_Milliseconds(); loopFrame++; for (i = 0 ; i < numLoopSounds; i++) { loop = &loopSounds[i]; if (!loop->active || loop->mergeFrame == loopFrame) { continue; // already merged into an earlier sound } if (loop->kill) { S_SpatializeOrigin(loop->origin, 127, &left_total, &right_total, loop->range, qfalse); // 3d } else { S_SpatializeOrigin(loop->origin, 90, &left_total, &right_total, loop->range, qfalse); // sphere } // adjust according to volume left_total = (int)((float)loop->volume * (float)left_total / 256.0); right_total = (int)((float)loop->volume * (float)right_total / 256.0); loop->sfx->lastTimeUsed = time; for (j = (i + 1); j < MAX_GENTITIES ; j++) { loop2 = &loopSounds[j]; if (!loop2->active || loop2->doppler || loop2->sfx != loop->sfx) { continue; } loop2->mergeFrame = loopFrame; if (loop2->kill) { S_SpatializeOrigin(loop2->origin, 127, &left, &right, loop->range, qfalse); // 3d } else { S_SpatializeOrigin(loop2->origin, 90, &left, &right, loop->range, qfalse); // sphere } // adjust according to volume left = (int)((float)loop2->volume * (float)left / 256.0); right = (int)((float)loop2->volume * (float)right / 256.0); loop2->sfx->lastTimeUsed = time; left_total += left; right_total += right; } if (left_total == 0 && right_total == 0) { continue; // not audible } // allocate a channel ch = &loop_channels[numLoopChannels]; if (left_total > 255) { left_total = 255; } if (right_total > 255) { right_total = 255; } ch->master_vol = 127; ch->leftvol = left_total; ch->rightvol = right_total; ch->thesfx = loop->sfx; ch->doppler = loop->doppler; ch->dopplerScale = loop->dopplerScale; ch->oldDopplerScale = loop->oldDopplerScale; ch->startSample = loop->startSample; // allow offsetting of sound samples numLoopChannels++; if (numLoopChannels == MAX_CHANNELS) { Com_Printf("S_AddLoopSounds warning: MAX_CHANNELS %i reached - loop sound dropped\n", MAX_CHANNELS); return; } } }
void S_UpdateStreamingSounds(void) { int bufferSamples; int fileSamples; byte raw[30000]; // just enough to fit in a mac stack frame int fileBytes; int rs; int i, j; float lvol, rvol; float streamingVol; streamingSound_t *ss; for (i = 0; i < MAX_STREAMING_SOUNDS; i++) { ss = &streamingSounds[i]; if (!ss->stream) { continue; } // don't bother playing anything if musicvolume is 0 if (i == 0 && s_musicVolume->value <= 0.0f) { continue; } // get the raw stream index j = RAW_STREAM(i); // see how many samples should be copied into the raw buffer if (s_rawend[j] < s_soundtime) { s_rawend[j] = s_soundtime; } while (s_rawend[j] < s_soundtime + MAX_RAW_SAMPLES) { bufferSamples = MAX_RAW_SAMPLES - (s_rawend[j] - s_soundtime); // decide how much data needs to be read from the file fileSamples = bufferSamples * ss->stream->info.rate / dma.speed; if (!fileSamples) { break; } // our max buffer size fileBytes = fileSamples * (ss->stream->info.width * ss->stream->info.channels); if (fileBytes > sizeof(raw)) { fileBytes = sizeof(raw); fileSamples = fileBytes / (ss->stream->info.width * ss->stream->info.channels); } // read stream rs = S_CodecReadStream(ss->stream, fileBytes, raw); if (rs < fileBytes) { fileSamples = rs / (ss->stream->info.width * ss->stream->info.channels); } // calculate the streaming volume based on stream fade and global fade streamingVol = S_GetStreamingFade(ss); // stop the stream if we had faded out of existence if (streamingVol == 0.0f) { S_StopStreamingSound(i); break; } streamingVol *= s_volCurrent; if (rs > 0) { if (i == 0) { lvol = rvol = s_musicVolume->value * streamingVol; } else { // attenuate if required if (ss->entnum >= 0 && ss->attenuation) { int r, l; S_SpatializeOrigin(entityPositions[ss->entnum], s_volume->value * 255.0f, &l, &r, SOUND_RANGE_DEFAULT, qfalse); if ((lvol = ((float)l / 255.0f)) > 1.0f) { lvol = 1.0f; } if ((rvol = ((float)r / 255.0f)) > 1.0f) { rvol = 1.0f; } lvol *= streamingVol; rvol *= streamingVol; } else { lvol = rvol = streamingVol; } } // add to raw buffer S_Base_RawSamples(j, fileSamples, ss->stream->info.rate, ss->stream->info.width, ss->stream->info.channels, raw, lvol, rvol); } else { if (s_debugStreams->integer) { Com_Printf("STREAM %d: ending...\n", i); Com_Printf("Queue stream: %s\nLoopStream: %s\n", ss->queueStream, ss->loopStream); } // special case for music track queue if (i == 0 && ss->queueStreamType && *ss->queueStream) { switch (ss->queueStreamType) { case QUEUED_PLAY_ONCE_SILENT: break; case QUEUED_PLAY_ONCE: S_StartBackgroundTrack(ss->queueStream, ss->name, 0); break; case QUEUED_PLAY_LOOPED: S_StartBackgroundTrack(ss->queueStream, ss->queueStream, 0); break; } // queue is done, clear it ss->queueStream[0] = '\0'; ss->queueStreamType = 0; break; } // loop if (*ss->loopStream) { // TODO: Implement a rewind? char loopStream[MAX_QPATH]; Q_strncpyz(loopStream, ss->loopStream, MAX_QPATH); S_StartStreamingSoundEx(loopStream, loopStream, ss->entnum, ss->channel, i == 0, i == 0 ? 0 : ss->attenuation); } else { S_FreeStreamingSound(i); } break; } } } }
static void S_AddLoopSounds (void) { int i, j, time; int left_total, right_total, left, right; channel_t *ch; loopSound_t *loop, *loop2; int numLoopSoundsPresent; static int loopFrame = 0; numLoopSoundsPresent = 0; for (i = 0; i < MAX_LOOP_SOUNDS; i++) { const loopSound_t *ls; ls = &loopSounds[i]; if (ls->active) { LoopSoundsPresent[numLoopSoundsPresent] = i; numLoopSoundsPresent++; //Com_Printf("loopSound %d: '%s'\n", i, ls->sfx->soundName); } } //Com_Printf("^5numLoopSoundsPresent %d\n", numLoopSoundsPresent); numLoopChannels = 0; time = S_Milliseconds(); loopFrame++; //for ( i = 0 ; i < MAX_LOOP_SOUNDS ; i++) { for (i = 0; i < numLoopSoundsPresent; i++) { //loop = &loopSounds[i]; loop = &loopSounds[LoopSoundsPresent[i]]; if ( !loop->active || loop->mergeFrame == loopFrame ) { continue; // already merged into an earlier sound } if (loop->kill) { S_SpatializeOrigin( loop->origin, 127, &left_total, &right_total); // 3d } else { S_SpatializeOrigin( loop->origin, 90, &left_total, &right_total); // sphere } loop->sfx->lastTimeUsed = time; //FIXME linked list for loop sounds #if 1 //FIXME omg //for (j=(i+1); j< MAX_LOOP_SOUNDS ; j++) { for (j = i + 1; j < numLoopSoundsPresent; j++) { //loop2 = &loopSounds[j]; loop2 = &loopSounds[LoopSoundsPresent[j]]; if ( !loop2->active || loop2->doppler || loop2->sfx != loop->sfx) { continue; } loop2->mergeFrame = loopFrame; //Com_Printf("^5testing loop %d %d\n", i, j); if (loop2->kill) { S_SpatializeOrigin( loop2->origin, 127, &left, &right); // 3d } else { S_SpatializeOrigin( loop2->origin, 90, &left, &right); // sphere } loop2->sfx->lastTimeUsed = time; left_total += left; right_total += right; } #endif if (left_total == 0 && right_total == 0) { continue; // not audible } // allocate a channel if (numLoopChannels >= MAX_CHANNELS) { Com_Printf(S_COLOR_YELLOW "%s() max loop channels %d\n", __FUNCTION__, numLoopChannels); return; } ch = &loop_channels[numLoopChannels]; if (left_total > 255) { left_total = 255; } if (right_total > 255) { right_total = 255; } ch->master_vol = 127; ch->leftvol = left_total; ch->rightvol = right_total; ch->thesfx = loop->sfx; ch->doppler = loop->doppler; ch->dopplerScale = loop->dopplerScale; ch->oldDopplerScale = loop->oldDopplerScale; numLoopChannels++; } }
/* * S_AddLoopSounds */ static void S_AddLoopSounds( void ) { int i, j; int left, right, left_total, right_total; channel_t *ch; sfx_t *sfx; sfxcache_t *sc; for( i = 0; i < num_loopsfx; i++ ) { if( !loop_sfx[i].sfx ) continue; sfx = loop_sfx[i].sfx; sc = sfx->cache; if( !sc ) continue; // find the total contribution of all sounds of this type if( loop_sfx[i].attenuation ) { S_SpatializeOrigin( S_LoopSoundOrigin( &loop_sfx[i] ), loop_sfx[i].volume, loop_sfx[i].attenuation, &left_total, &right_total ); for( j = i+1; j < num_loopsfx; j++ ) { if( loop_sfx[j].sfx != loop_sfx[i].sfx ) continue; if( loop_sfx[j].entnum == loop_sfx[i].entnum ) { loop_sfx[j].sfx = NULL; // don't check this again later continue; } loop_sfx[j].sfx = NULL; // don't check this again later S_SpatializeOrigin( S_LoopSoundOrigin( &loop_sfx[j] ), loop_sfx[i].volume, loop_sfx[i].attenuation, &left, &right ); left_total += left; right_total += right; } if( left_total == 0 && right_total == 0 ) continue; // not audible } else { for( j = i+1; j < num_loopsfx; j++ ) { if( loop_sfx[j].sfx != loop_sfx[i].sfx ) continue; if( loop_sfx[j].entnum == loop_sfx[i].entnum ) { loop_sfx[j].sfx = NULL; // don't check this again later continue; } } left_total = loop_sfx[i].volume; right_total = loop_sfx[i].volume; } // allocate a channel ch = S_PickChannel( 0, 0 ); if( !ch ) return; if( left_total > 255 ) left_total = 255; if( right_total > 255 ) right_total = 255; ch->leftvol = left_total; ch->rightvol = right_total; ch->autosound = true; // remove next frame ch->sfx = sfx; ch->pos = paintedtime % sc->length; ch->end = paintedtime + sc->length - ch->pos; } num_loopsfx = 0; }
/* ============ S_Base_RawSamples Music streaming ============ */ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_channels, const byte *data, float volume, int entityNum) { int i; int src, dst; float scale; int intVolumeLeft, intVolumeRight; portable_samplepair_t *rawsamples; if ( !s_soundStarted || s_soundMuted ) { return; } if ( (stream < 0) || (stream >= MAX_RAW_STREAMS) ) { return; } rawsamples = s_rawsamples[stream]; if ( s_muted->integer ) { intVolumeLeft = intVolumeRight = 0; } else { int leftvol, rightvol; if ( entityNum >= 0 && entityNum < MAX_GENTITIES ) { // support spatialized raw streams, e.g. for VoIP S_SpatializeOrigin( loopSounds[ entityNum ].origin, 256, &leftvol, &rightvol ); } else { leftvol = rightvol = 256; } intVolumeLeft = leftvol * volume * s_volume->value; intVolumeRight = rightvol * volume * s_volume->value; } if ( s_rawend[stream] < s_soundtime ) { Com_DPrintf( "S_Base_RawSamples: resetting minimum: %i < %i\n", s_rawend[stream], s_soundtime ); s_rawend[stream] = s_soundtime; } scale = (float)rate / dma.speed; //Com_Printf ("%i < %i < %i\n", s_soundtime, s_paintedtime, s_rawend[stream]); if (s_channels == 2 && width == 2) { if (scale == 1.0) { // optimized case for (i=0 ; i<samples ; i++) { dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; rawsamples[dst].left = ((short *)data)[i*2] * intVolumeLeft; rawsamples[dst].right = ((short *)data)[i*2+1] * intVolumeRight; } } else { for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; rawsamples[dst].left = ((short *)data)[src*2] * intVolumeLeft; rawsamples[dst].right = ((short *)data)[src*2+1] * intVolumeRight; } } } else if (s_channels == 1 && width == 2) { for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; rawsamples[dst].left = ((short *)data)[src] * intVolumeLeft; rawsamples[dst].right = ((short *)data)[src] * intVolumeRight; } } else if (s_channels == 2 && width == 1) { intVolumeLeft *= 256; intVolumeRight *= 256; for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; rawsamples[dst].left = ((char *)data)[src*2] * intVolumeLeft; rawsamples[dst].right = ((char *)data)[src*2+1] * intVolumeRight; } } else if (s_channels == 1 && width == 1) { intVolumeLeft *= 256; intVolumeRight *= 256; for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend[stream]&(MAX_RAW_SAMPLES-1); s_rawend[stream]++; rawsamples[dst].left = (((byte *)data)[src]-128) * intVolumeLeft; rawsamples[dst].right = (((byte *)data)[src]-128) * intVolumeRight; } } if ( s_rawend[stream] > s_soundtime + MAX_RAW_SAMPLES ) { Com_DPrintf( "S_Base_RawSamples: overflowed %i > %i\n", s_rawend[stream], s_soundtime ); } }
/* ============ S_Update Called once each time through the main loop ============ */ void S_Base_Update( void ) { int i; vec3_t origin; int total; channel_t *ch; if ( !s_soundStarted || s_soundMuted ) { // Com_DPrintf ("not started or muted\n"); return; } // update spatialization for dynamic sounds if (respatialize) { respatialize = qfalse; ch = s_channels; for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { if ( !ch->thesfx ) { continue; } // local and first person sounds will always be full volume if (ch->fullVolume) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; } else { if (ch->fixed_origin) { VectorCopy( ch->origin, origin ); } else { VectorCopy( loopSounds[ ch->entnum ].origin, origin ); } S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol); } } // add loopsounds S_AddLoopSounds (); } // // debugging output // if ( s_show->integer == 2 ) { total = 0; ch = s_channels; for (i=0 ; i<MAX_CHANNELS; i++, ch++) { if (ch->thesfx && (ch->leftvol || ch->rightvol) ) { Com_Printf ("%d %d %s\n", ch->leftvol, ch->rightvol, ch->thesfx->soundName); total++; } } Com_Printf ("----(%i)---- painted: %i\n", total, s_paintedtime); } // add raw data from streamed samples S_UpdateBackgroundTrack(); // mix some sound S_Update_(); }
/* * Spatialize all of the looping sounds. * All sounds are on the same cycle, so any duplicates can just * sum up the channel multipliers. */ static void S_AddLoopSounds(void) { int i, j, time; int left_total, right_total, left, right; Channel *ch; Loopsnd *loop, *loop2; static int loopFrame; numLoopChannels = 0; time = commillisecs(); loopFrame++; for(i = 0; i < MAX_GENTITIES; i++) { loop = &loopSounds[i]; if(!loop->active || loop->mergeFrame == loopFrame) continue; /* already merged into an earlier sound */ if(loop->kill) S_SpatializeOrigin(loop->origin, 127, &left_total, &right_total); /* 3d */ else S_SpatializeOrigin(loop->origin, 90, &left_total, &right_total); /* sphere */ loop->sfx->lastTimeUsed = time; for(j=(i+1); j< MAX_GENTITIES; j++) { loop2 = &loopSounds[j]; if(!loop2->active || loop2->doppler || loop2->sfx != loop->sfx) continue; loop2->mergeFrame = loopFrame; if(loop2->kill) S_SpatializeOrigin(loop2->origin, 127, &left, &right); /* 3d */ else S_SpatializeOrigin(loop2->origin, 90, &left, &right); /* sphere */ loop2->sfx->lastTimeUsed = time; left_total += left; right_total += right; } if(left_total == 0 && right_total == 0) continue; /* not audible */ /* allocate a channel */ ch = &loop_channels[numLoopChannels]; if(left_total > 255) left_total = 255; if(right_total > 255) right_total = 255; ch->master_vol = 127; ch->leftvol = left_total; ch->rightvol = right_total; ch->thesfx = loop->sfx; ch->doppler = loop->doppler; ch->dopplerScale = loop->dopplerScale; ch->oldDopplerScale = loop->oldDopplerScale; numLoopChannels++; if(numLoopChannels == MAX_CHANNELS) return; } }
/* ================== S_AddLoopSounds Entities with a ->sound field will generated looped sounds that are automatically started, stopped, and merged together as the entities are sent to the client ================== */ static void S_AddLoopSounds (void) { int i, j; int sounds[MAX_EDICTS]; int left, right, left_total, right_total; channel_t *ch; sfx_t *sfx; sfxcache_t *sc; int num; entity_state_t *ent; vec3_t origin; if (cl_paused->integer || cls.state != ca_active || !cl.sound_prepped) return; for (i=0 ; i<cl.frame.num_entities ; i++) { num = (cl.frame.parse_entities + i) & PARSE_ENTITIES_MASK; ent = &cl_parse_entities[num]; sounds[i] = ent->sound; } for (i=0 ; i<cl.frame.num_entities ; i++) { if (!sounds[i]) continue; sfx = cl.sound_precache[sounds[i]]; if (!sfx) continue; // bad sound effect sc = sfx->cache; if (!sc || sc->length <= 0) continue; num = (cl.frame.parse_entities + i) & PARSE_ENTITIES_MASK; ent = &cl_parse_entities[num]; CL_GetEntitySoundOrigin (ent->number, origin); // find the total contribution of all sounds of this type S_SpatializeOrigin (origin, 255.0f, SOUND_LOOPATTENUATE, &left_total, &right_total); for (j=i+1 ; j<cl.frame.num_entities ; j++) { if (sounds[j] != sounds[i]) continue; sounds[j] = 0; // don't check this again later num = (cl.frame.parse_entities + j) & PARSE_ENTITIES_MASK; ent = &cl_parse_entities[num]; S_SpatializeOrigin (ent->origin, 255.0f, SOUND_LOOPATTENUATE, &left, &right); left_total += left; right_total += right; } if (left_total == 0 && right_total == 0) continue; // not audible // allocate a channel ch = S_PickChannel(0, 0); if (!ch) return; if (left_total > 255) left_total = 255; if (right_total > 255) right_total = 255; ch->leftvol = left_total; ch->rightvol = right_total; ch->autosound = true; // remove next frame ch->sfx = sfx; ch->pos = paintedtime % sc->length; ch->end = paintedtime + sc->length - ch->pos; } }
/* ==================== S_Base_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 ==================== */ static void S_Base_StartSound (const vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle) { channel_t *ch; sfx_t *sfx; int i, oldest, chosen, time; int inplay, allowed; if ( !s_soundStarted || s_soundMuted ) { return; } if ( !origin && ( entityNum < 0 || entityNum >= MAX_GENTITIES ) ) { Com_Error( ERR_DROP, "S_StartSound: bad entitynum %i", entityNum ); } if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) { Com_Printf( S_COLOR_YELLOW "S_StartSound: handle %i out of range\n", sfxHandle ); return; } sfx = &s_knownSfx[ sfxHandle ]; if (sfx->inMemory == qfalse) { S_memoryLoad(sfx); } if ( s_show->integer == 1 ) { Com_Printf("%f %i : %s (%d -> %d)\n", (float)cl.serverTime + Overf, s_paintedtime, sfx->soundName, listener_number, entityNum); } time = S_Milliseconds(); // Com_Printf("playing %s\n", sfx->soundName); // pick a channel to play on allowed = s_maxSoundInstances->integer; if (allowed < 0) { // old q3 code allowed = 4; if (entityNum == listener_number) { allowed = 8; } } ch = s_channels; inplay = 0; for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) { if (ch->entnum == entityNum && ch->thesfx == sfx) { if (time - ch->allocTime < 50) { //Com_Printf("^2%f double sound start '%s' last played (%d) length %f\n", (float)cl.serverTime + Overf, sfx->soundName, time - ch->allocTime, (float)sfx->soundLength / (float)dma.speed); } if (time - ch->allocTime < s_maxSoundRepeatTime->integer) { //if (time - ch->allocTime < (int)((float)sfx->soundLength / (float)dma.speed * 1000.0)) { if (s_showMiss->integer) { Com_Printf("^3%f double sound start '%s' last played (%d) length %f\n", (float)cl.serverTime + Overf, sfx->soundName, time - ch->allocTime, (float)sfx->soundLength / (float)dma.speed); } return; } inplay++; } } //Com_Printf("inplay %d\n", inplay); if (inplay > 4) { //Com_Printf("^5%f inplay > x %d > %d '%s'\n", (float)cl.serverTime + Overf, inplay, allowed, sfx->soundName); } if (inplay > allowed) { if (s_showMiss->integer > 1) { Com_Printf("^1%f inplay > allowed %d > %d '%s' ent %d ch %d/%d\n", (float)cl.serverTime + Overf, inplay, allowed, sfx->soundName, entityNum, entchannel, listener_number); } return; } sfx->lastTimeUsed = time; ch = S_ChannelMalloc(); // entityNum, entchannel); if (!ch) { if (s_showMiss->integer > 2) { Com_Printf("^1%f %s() couldn't allocate channel\n", (float)cl.serverTime + Overf, __FUNCTION__); } ch = s_channels; oldest = sfx->lastTimeUsed; chosen = -1; for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { if (ch->entnum != listener_number && ch->entnum == entityNum && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) { oldest = ch->allocTime; chosen = i; } } if (chosen == -1) { ch = s_channels; for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { if (ch->entnum != listener_number && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) { oldest = ch->allocTime; chosen = i; } } if (chosen == -1) { ch = s_channels; if (ch->entnum == listener_number) { for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) { if (ch->allocTime<oldest) { oldest = ch->allocTime; chosen = i; } } } if (chosen == -1) { Com_Printf("dropping sound\n"); return; } } } ch = &s_channels[chosen]; ch->allocTime = sfx->lastTimeUsed; //Com_Printf("use old\n"); } else { //Com_Printf("alloc\n"); } if (origin) { VectorCopy (origin, ch->origin); ch->fixed_origin = qtrue; } else { ch->fixed_origin = qfalse; } ch->master_vol = 127; ch->leftvol = 127; ch->rightvol = 127; ch->entnum = entityNum; ch->thesfx = sfx; ch->startSample = START_SAMPLE_IMMEDIATE; ch->entchannel = entchannel; ch->leftvol = ch->master_vol; // these will get calced at next spatialize ch->rightvol = ch->master_vol; // unless the game isn't running ch->doppler = qfalse; if (ch->entnum != listener_number) { if (ch->fixed_origin) { S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol); } } else { //Com_Printf("dont respa!!!\n"); } }