123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- // snd_dma.c -- main control for any streaming sound output device
- #include "client.h"
- #include "snd_loc.h"
- void S_Play(void);
- void S_SoundList(void);
- void S_Update_();
- void S_StopAllSounds(void);
- // =======================================================================
- // Internal sound data & structures
- // =======================================================================
- // only begin attenuating sound volumes when outside the FULLVOLUME range
- #define SOUND_FULLVOLUME 80
- #define SOUND_LOOPATTENUATE 0.003
- int s_registration_sequence;
- channel_t channels[MAX_CHANNELS];
- qboolean snd_initialized = false;
- int sound_started=0;
- dma_t dma;
- vec3_t listener_origin;
- vec3_t listener_forward;
- vec3_t listener_right;
- vec3_t listener_up;
- qboolean s_registering;
- int soundtime; // sample PAIRS
- int paintedtime; // sample PAIRS
- // during registration it is possible to have more sounds
- // than could actually be referenced during gameplay,
- // because we don't want to free anything until we are
- // sure we won't need it.
- #define MAX_SFX (MAX_SOUNDS*2)
- sfx_t known_sfx[MAX_SFX];
- int num_sfx;
- #define MAX_PLAYSOUNDS 128
- playsound_t s_playsounds[MAX_PLAYSOUNDS];
- playsound_t s_freeplays;
- playsound_t s_pendingplays;
- int s_beginofs;
- cvar_t *s_volume;
- cvar_t *s_testsound;
- cvar_t *s_loadas8bit;
- cvar_t *s_khz;
- cvar_t *s_show;
- cvar_t *s_mixahead;
- cvar_t *s_primary;
- int s_rawend;
- portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
- // ====================================================================
- // User-setable variables
- // ====================================================================
- void S_SoundInfo_f(void)
- {
- if (!sound_started)
- {
- Com_Printf ("sound system not started\n");
- return;
- }
-
- Com_Printf("%5d stereo\n", dma.channels - 1);
- Com_Printf("%5d samples\n", dma.samples);
- Com_Printf("%5d samplepos\n", dma.samplepos);
- Com_Printf("%5d samplebits\n", dma.samplebits);
- Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
- Com_Printf("%5d speed\n", dma.speed);
- Com_Printf("0x%x dma buffer\n", dma.buffer);
- }
- /*
- ================
- S_Init
- ================
- */
- void S_Init (void)
- {
- cvar_t *cv;
- Com_Printf("\n------- sound initialization -------\n");
- cv = Cvar_Get ("s_initsound", "1", 0);
- if (!cv->value)
- Com_Printf ("not initializing.\n");
- else
- {
- s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
- s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
- s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
- s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
- s_show = Cvar_Get ("s_show", "0", 0);
- s_testsound = Cvar_Get ("s_testsound", "0", 0);
- s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific
- Cmd_AddCommand("play", S_Play);
- Cmd_AddCommand("stopsound", S_StopAllSounds);
- Cmd_AddCommand("soundlist", S_SoundList);
- Cmd_AddCommand("soundinfo", S_SoundInfo_f);
- if (!SNDDMA_Init())
- return;
- S_InitScaletable ();
- sound_started = 1;
- num_sfx = 0;
- soundtime = 0;
- paintedtime = 0;
- Com_Printf ("sound sampling rate: %i\n", dma.speed);
- S_StopAllSounds ();
- }
- Com_Printf("------------------------------------\n");
- }
- // =======================================================================
- // Shutdown sound engine
- // =======================================================================
- void S_Shutdown(void)
- {
- int i;
- sfx_t *sfx;
- if (!sound_started)
- return;
- SNDDMA_Shutdown();
- sound_started = 0;
- Cmd_RemoveCommand("play");
- Cmd_RemoveCommand("stopsound");
- Cmd_RemoveCommand("soundlist");
- Cmd_RemoveCommand("soundinfo");
- // free all sounds
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- if (sfx->cache)
- Z_Free (sfx->cache);
- memset (sfx, 0, sizeof(*sfx));
- }
- num_sfx = 0;
- }
- // =======================================================================
- // Load a sound
- // =======================================================================
- /*
- ==================
- S_FindName
- ==================
- */
- sfx_t *S_FindName (char *name, qboolean create)
- {
- int i;
- sfx_t *sfx;
- if (!name)
- Com_Error (ERR_FATAL, "S_FindName: NULL\n");
- if (!name[0])
- Com_Error (ERR_FATAL, "S_FindName: empty name\n");
- if (strlen(name) >= MAX_QPATH)
- Com_Error (ERR_FATAL, "Sound name too long: %s", name);
- // see if already loaded
- for (i=0 ; i < num_sfx ; i++)
- if (!strcmp(known_sfx[i].name, name))
- {
- return &known_sfx[i];
- }
- if (!create)
- return NULL;
- // find a free sfx
- for (i=0 ; i < num_sfx ; i++)
- if (!known_sfx[i].name[0])
- // registration_sequence < s_registration_sequence)
- break;
- if (i == num_sfx)
- {
- if (num_sfx == MAX_SFX)
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- num_sfx++;
- }
-
- sfx = &known_sfx[i];
- memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->name, name);
- sfx->registration_sequence = s_registration_sequence;
-
- return sfx;
- }
- /*
- ==================
- S_AliasName
- ==================
- */
- sfx_t *S_AliasName (char *aliasname, char *truename)
- {
- sfx_t *sfx;
- char *s;
- int i;
- s = Z_Malloc (MAX_QPATH);
- strcpy (s, truename);
- // find a free sfx
- for (i=0 ; i < num_sfx ; i++)
- if (!known_sfx[i].name[0])
- break;
- if (i == num_sfx)
- {
- if (num_sfx == MAX_SFX)
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- num_sfx++;
- }
-
- sfx = &known_sfx[i];
- memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->name, aliasname);
- sfx->registration_sequence = s_registration_sequence;
- sfx->truename = s;
- return sfx;
- }
- /*
- =====================
- S_BeginRegistration
- =====================
- */
- void S_BeginRegistration (void)
- {
- s_registration_sequence++;
- s_registering = true;
- }
- /*
- ==================
- 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;
- }
- /*
- =====================
- 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_PickChannel
- =================
- */
- channel_t *S_PickChannel(int entnum, int entchannel)
- {
- int ch_idx;
- int first_to_die;
- int life_left;
- 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
- first_to_die = -1;
- life_left = 0x7fffffff;
- 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;
- }
- /*
- =================
- S_SpatializeOrigin
- Used for spatializing channels and autosounds
- =================
- */
- void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
- {
- vec_t dot;
- vec_t dist;
- vec_t lscale, rscale, scale;
- vec3_t source_vec;
- if (cls.state != ca_active)
- {
- *left_vol = *right_vol = 255;
- return;
- }
- // calculate stereo seperation and distance attenuation
- VectorSubtract(origin, listener_origin, source_vec);
- dist = VectorNormalize(source_vec);
- dist -= SOUND_FULLVOLUME;
- if (dist < 0)
- dist = 0; // close enough to be at full volume
- dist *= dist_mult; // different attenuation levels
-
- dot = DotProduct(listener_right, source_vec);
- if (dma.channels == 1 || !dist_mult)
- { // no attenuation = no spatialization
- rscale = 1.0;
- lscale = 1.0;
- }
- else
- {
- rscale = 0.5 * (1.0 + dot);
- lscale = 0.5*(1.0 - dot);
- }
- // add in distance effect
- scale = (1.0 - dist) * rscale;
- *right_vol = (int) (master_vol * scale);
- if (*right_vol < 0)
- *right_vol = 0;
- scale = (1.0 - dist) * lscale;
- *left_vol = (int) (master_vol * scale);
- if (*left_vol < 0)
- *left_vol = 0;
- }
- /*
- =================
- S_Spatialize
- =================
- */
- 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_AllocPlaysound
- =================
- */
- playsound_t *S_AllocPlaysound (void)
- {
- playsound_t *ps;
- ps = s_freeplays.next;
- if (ps == &s_freeplays)
- return NULL; // no free playsounds
- // unlink from freelist
- ps->prev->next = ps->next;
- ps->next->prev = ps->prev;
-
- return ps;
- }
- /*
- =================
- S_FreePlaysound
- =================
- */
- void S_FreePlaysound (playsound_t *ps)
- {
- // unlink from channel
- ps->prev->next = ps->next;
- ps->next->prev = ps->prev;
- // add to free list
- ps->next = s_freeplays.next;
- s_freeplays.next->prev = ps;
- ps->prev = &s_freeplays;
- s_freeplays.next = ps;
- }
- /*
- ===============
- 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->value)
- 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;
- }
- // spatialize
- if (ps->attenuation == ATTN_STATIC)
- ch->dist_mult = ps->attenuation * 0.001;
- else
- ch->dist_mult = ps->attenuation * 0.0005;
- 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;
- sc = S_LoadSound (ch->sfx);
- ch->end = paintedtime + sc->length;
- // free the playsound
- S_FreePlaysound (ps);
- }
- struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
- {
- int n;
- char *p;
- struct sfx_s *sfx;
- FILE *f;
- char model[MAX_QPATH];
- char sexedFilename[MAX_QPATH];
- char maleFilename[MAX_QPATH];
- // determine what model the client is using
- model[0] = 0;
- n = CS_PLAYERSKINS + ent->number - 1;
- if (cl.configstrings[n][0])
- {
- p = strchr(cl.configstrings[n], '\\');
- if (p)
- {
- p += 1;
- strcpy(model, p);
- p = strchr(model, '/');
- if (p)
- *p = 0;
- }
- }
- // if we can't figure it out, they're male
- if (!model[0])
- strcpy(model, "male");
- // see if we already know of the model specific sound
- Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
- sfx = S_FindName (sexedFilename, false);
- if (!sfx)
- {
- // no, so see if it exists
- FS_FOpenFile (&sexedFilename[1], &f);
- if (f)
- {
- // yes, close the file and register it
- FS_FCloseFile (f);
- sfx = S_RegisterSound (sexedFilename);
- }
- else
- {
- // no, revert to the male sound in the pak0.pak
- Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
- sfx = S_AliasName (sexedFilename, maleFilename);
- }
- }
- return sfx;
- }
- // =======================================================================
- // Start a sound effect
- // =======================================================================
- /*
- ====================
- 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;
- }
- /*
- ==================
- S_StartLocalSound
- ==================
- */
- void S_StartLocalSound (char *sound)
- {
- sfx_t *sfx;
- if (!sound_started)
- return;
-
- sfx = S_RegisterSound (sound);
- if (!sfx)
- {
- Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
- return;
- }
- S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
- }
- /*
- ==================
- S_ClearBuffer
- ==================
- */
- void S_ClearBuffer (void)
- {
- int clear;
-
- if (!sound_started)
- return;
- s_rawend = 0;
- if (dma.samplebits == 8)
- clear = 0x80;
- else
- clear = 0;
- SNDDMA_BeginPainting ();
- if (dma.buffer)
- memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
- SNDDMA_Submit ();
- }
- /*
- ==================
- S_StopAllSounds
- ==================
- */
- void S_StopAllSounds(void)
- {
- int i;
- if (!sound_started)
- return;
- // clear all the playsounds
- memset(s_playsounds, 0, sizeof(s_playsounds));
- s_freeplays.next = s_freeplays.prev = &s_freeplays;
- s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
- for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
- {
- s_playsounds[i].prev = &s_freeplays;
- s_playsounds[i].next = s_freeplays.next;
- s_playsounds[i].prev->next = &s_playsounds[i];
- s_playsounds[i].next->prev = &s_playsounds[i];
- }
- // clear all the channels
- memset(channels, 0, sizeof(channels));
- S_ClearBuffer ();
- }
- /*
- ==================
- 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;
- 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];
- // find the total contribution of all sounds of this type
- S_SpatializeOrigin (ent->origin, 255.0, 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)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
- S_SpatializeOrigin (ent->origin, 255.0, 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_RawSamples
- Cinematic streaming and voice over network
- ============
- */
- void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
- {
- int i;
- int src, dst;
- float scale;
- if (!sound_started)
- return;
- if (s_rawend < paintedtime)
- s_rawend = paintedtime;
- scale = (float)rate / dma.speed;
- //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
- if (channels == 2 && width == 2)
- {
- if (scale == 1.0)
- { // optimized case
- for (i=0 ; i<samples ; i++)
- {
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[i*2]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[i*2+1]) << 8;
- }
- }
- else
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[src*2]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[src*2+1]) << 8;
- }
- }
- }
- else if (channels == 1 && width == 2)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[src]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[src]) << 8;
- }
- }
- else if (channels == 2 && width == 1)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- ((char *)data)[src*2] << 16;
- s_rawsamples[dst].right =
- ((char *)data)[src*2+1] << 16;
- }
- }
- else if (channels == 1 && width == 1)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- (((byte *)data)[src]-128) << 16;
- s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
- }
- }
- }
- //=============================================================================
- /*
- ============
- S_Update
- Called once each time through the main loop
- ============
- */
- void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
- {
- int i;
- int total;
- channel_t *ch;
- channel_t *combine;
- if (!sound_started)
- return;
- // if the laoding plaque is up, clear everything
- // out to make sure we aren't looping a dirty
- // dma buffer while loading
- if (cls.disable_screen)
- {
- S_ClearBuffer ();
- return;
- }
- // rebuild scale tables if volume is modified
- if (s_volume->modified)
- S_InitScaletable ();
- VectorCopy(origin, listener_origin);
- VectorCopy(forward, listener_forward);
- VectorCopy(right, listener_right);
- VectorCopy(up, listener_up);
- combine = NULL;
- // update spatialization for dynamic sounds
- ch = channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++)
- {
- if (!ch->sfx)
- continue;
- if (ch->autosound)
- { // autosounds are regenerated fresh each frame
- memset (ch, 0, sizeof(*ch));
- continue;
- }
- S_Spatialize(ch); // respatialize channel
- if (!ch->leftvol && !ch->rightvol)
- {
- memset (ch, 0, sizeof(*ch));
- continue;
- }
- }
- // add loopsounds
- S_AddLoopSounds ();
- //
- // debugging output
- //
- if (s_show->value)
- {
- total = 0;
- ch = channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++)
- if (ch->sfx && (ch->leftvol || ch->rightvol) )
- {
- Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
- total++;
- }
-
- Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
- }
- // mix some sound
- S_Update_();
- }
- void GetSoundtime(void)
- {
- int samplepos;
- static int buffers;
- static int oldsamplepos;
- int fullsamples;
-
- fullsamples = dma.samples / dma.channels;
- // it is possible to miscount buffers if it has wrapped twice between
- // calls to S_Update. Oh well.
- samplepos = SNDDMA_GetDMAPos();
- if (samplepos < oldsamplepos)
- {
- buffers++; // buffer wrapped
-
- if (paintedtime > 0x40000000)
- { // time to chop things off to avoid 32 bit limits
- buffers = 0;
- paintedtime = fullsamples;
- S_StopAllSounds ();
- }
- }
- oldsamplepos = samplepos;
- soundtime = buffers*fullsamples + samplepos/dma.channels;
- }
- void S_Update_(void)
- {
- unsigned endtime;
- int samps;
- if (!sound_started)
- return;
- SNDDMA_BeginPainting ();
- if (!dma.buffer)
- return;
- // Updates DMA time
- GetSoundtime();
- // check to make sure that we haven't overshot
- if (paintedtime < soundtime)
- {
- Com_DPrintf ("S_Update_ : overflow\n");
- paintedtime = soundtime;
- }
- // mix ahead of current position
- endtime = soundtime + s_mixahead->value * dma.speed;
- //endtime = (soundtime + 4096) & ~4095;
- // mix to an even submission block size
- endtime = (endtime + dma.submission_chunk-1)
- & ~(dma.submission_chunk-1);
- samps = dma.samples >> (dma.channels-1);
- if (endtime - soundtime > samps)
- endtime = soundtime + samps;
- S_PaintChannels (endtime);
- SNDDMA_Submit ();
- }
- /*
- ===============================================================================
- console functions
- ===============================================================================
- */
- void S_Play(void)
- {
- int i;
- char name[256];
- sfx_t *sfx;
-
- i = 1;
- while (i<Cmd_Argc())
- {
- if (!strrchr(Cmd_Argv(i), '.'))
- {
- strcpy(name, Cmd_Argv(i));
- strcat(name, ".wav");
- }
- else
- strcpy(name, Cmd_Argv(i));
- sfx = S_RegisterSound(name);
- S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
- i++;
- }
- }
- void S_SoundList(void)
- {
- int i;
- sfx_t *sfx;
- sfxcache_t *sc;
- int size, total;
- total = 0;
- for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
- {
- if (!sfx->registration_sequence)
- continue;
- sc = sfx->cache;
- if (sc)
- {
- size = sc->length*sc->width*(sc->stereo+1);
- total += size;
- if (sc->loopstart >= 0)
- Com_Printf ("L");
- else
- Com_Printf (" ");
- Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
- }
- else
- {
- if (sfx->name[0] == '*')
- Com_Printf(" placeholder : %s\n", sfx->name);
- else
- Com_Printf(" not loaded : %s\n", sfx->name);
- }
- }
- Com_Printf ("Total resident: %i\n", total);
- }
|