/* ============== S_LoadSound The filename may be different than sfx->name in the case of a forced fallback of a player specific sound ============== */ qboolean S_LoadSound( sfx_t *sfx ) { byte *data; short *samples; snd_info_t info; // int size; // load it in data = S_CodecLoad(sfx->soundName, &info); if(!data) return qfalse; if ( info.width == 1 ) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit sound file\n", sfx->soundName); } if ( info.rate != 22050 ) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s (%.1fkHz) is not a 22kHz sound file\n", sfx->soundName, (float)info.rate / 1000.0); } samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2); //sfx->lastTimeUsed = Com_Milliseconds()+1; sfx->lastTimeUsed = S_Milliseconds()+1; // each of these compression schemes works just fine // but the 16bit quality is much nicer and with a local // install assured we can rely upon the sound memory // manager to do the right thing for us and page // sound in as needed if( sfx->soundCompressed == qtrue) { sfx->soundCompressionMethod = SND_COMPRESSION_ADPCM; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, data + info.dataofs ); S_AdpcmEncodeSound(sfx, samples); #if 0 } else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) { sfx->soundCompressionMethod = SND_COMPRESSION_MULAW; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) ); encodeMuLaw( sfx, samples); } else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) { sfx->soundCompressionMethod = SND_COMPRESSION_DAUB4; sfx->soundData = NULL; sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) ); encodeWavelet( sfx, samples); #endif } else { sfx->soundCompressionMethod = SND_COMPRESSION_16BIT; sfx->soundLength = info.samples; sfx->soundData = NULL; ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse ); } Hunk_FreeTempMemory(samples); Z_Free(data); return qtrue; }
void S_FreeOldestSound( void ) { int i, oldest, used; sfx_t *sfx; sndBuffer *buffer, *nbuffer; oldest = S_Milliseconds(); used = 0; for (i=1 ; i < s_numSfx ; i++) { sfx = &s_knownSfx[i]; if (sfx->inMemory && sfx->lastTimeUsed<oldest) { used = i; oldest = sfx->lastTimeUsed; } } sfx = &s_knownSfx[used]; Com_DPrintf("S_FreeOldestSound: freeing sound %s\n", sfx->soundName); buffer = sfx->soundData; while(buffer != NULL) { nbuffer = buffer->next; SND_free(buffer); buffer = nbuffer; } sfx->inMemory = qfalse; sfx->soundData = NULL; }
static void S_Update_(void) { unsigned endtime; int samps; static float lastTime = 0.0f; float ma, op; float thisTime, sane; static int ot = -1; if ( !s_soundStarted || s_soundMuted ) { return; } thisTime = S_Milliseconds(); // Updates s_soundtime S_GetSoundtime(); if (s_soundtime == ot) { return; } ot = s_soundtime; // clear any sound effects that end before the current time, // and start any new sounds S_ScanChannelStarts(); sane = thisTime - lastTime; if (sane<11) { sane = 11; // 85hz } ma = s_mixahead->value * dma.speed; op = s_mixPreStep->value + sane*dma.speed*0.01; if (op < ma) { ma = op; } // mix ahead of current position endtime = s_soundtime + ma; // mix to an even submission block size endtime = (endtime + dma.submission_chunk-1) & ~(dma.submission_chunk-1); // never mix more than the complete buffer samps = dma.samples >> (dma.channels-1); if (endtime - s_soundtime > samps) endtime = s_soundtime + samps; SNDDMA_BeginPainting (); S_PaintChannels (endtime); SNDDMA_Submit (); lastTime = thisTime; }
static channel_t* S_ChannelMalloc( void ) { channel_t *v; if (freelist == NULL) { return NULL; } v = freelist; freelist = *(channel_t **)freelist; v->allocTime = S_Milliseconds(); return v; }
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_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"); } }