// SND_PaintChannelFrom8 static void PaintChannelFrom8(channel_t ch, sfxcache_t sc, int count) { if (ch.leftvol > 255) { ch.leftvol = 255; } if (ch.rightvol > 255) { ch.rightvol = 255; } int lscale = ch.leftvol >> 3; int rscale = ch.rightvol >> 3; byte[] sfx = sc.data; int offset = ch.pos; for (int i = 0; i < count; i++) { int data = sfx[offset + i]; _PaintBuffer[i].left += _ScaleTable[lscale, data]; _PaintBuffer[i].right += _ScaleTable[rscale, data]; } ch.pos += count; }
// S_UpdateAmbientSounds static void UpdateAmbientSounds() { if (!_Ambient) { return; } // calc ambient sound levels if (Client.cl.worldmodel == null) { return; } mleaf_t l = Mod.PointInLeaf(ref _ListenerOrigin, Client.cl.worldmodel); if (l == null || _AmbientLevel.Value == 0) { for (int i = 0; i < Ambients.NUM_AMBIENTS; i++) { _Channels[i].sfx = null; } return; } for (int i = 0; i < Ambients.NUM_AMBIENTS; i++) { channel_t chan = _Channels[i]; chan.sfx = _AmbientSfx[i]; float vol = _AmbientLevel.Value * l.ambient_sound_level[i]; if (vol < 8) { vol = 0; } // don't adjust volume too fast if (chan.master_vol < vol) { chan.master_vol += (int)(Host.FrameTime * _AmbientFade.Value); if (chan.master_vol > vol) { chan.master_vol = (int)vol; } } else if (chan.master_vol > vol) { chan.master_vol -= (int)(Host.FrameTime * _AmbientFade.Value); if (chan.master_vol < vol) { chan.master_vol = (int)vol; } } chan.leftvol = chan.rightvol = chan.master_vol; } }
// SND_Spatialize static void Spatialize(channel_t ch) { // anything coming from the view entity will allways be full volume if (ch.entnum == Client.cl.viewentity) { ch.leftvol = ch.master_vol; ch.rightvol = ch.master_vol; return; } // calculate stereo seperation and distance attenuation sfx_t snd = ch.sfx; Vector3 source_vec = ch.origin - _ListenerOrigin; float dist = Mathlib.Normalize(ref source_vec) * ch.dist_mult; float dot = Vector3.Dot(_ListenerRight, source_vec); float rscale, lscale; if (_shm.channels == 1) { rscale = 1.0f; lscale = 1.0f; } else { rscale = 1.0f + dot; lscale = 1.0f - dot; } // add in distance effect float scale = (1.0f - dist) * rscale; ch.rightvol = (int)(ch.master_vol * scale); if (ch.rightvol < 0) { ch.rightvol = 0; } scale = (1.0f - dist) * lscale; ch.leftvol = (int)(ch.master_vol * scale); if (ch.leftvol < 0) { ch.leftvol = 0; } }
// SND_PaintChannelFrom16 static void PaintChannelFrom16(channel_t ch, sfxcache_t sc, int count) { int leftvol = ch.leftvol; int rightvol = ch.rightvol; byte[] sfx = sc.data; int offset = ch.pos * 2; // sfx = (signed short *)sc->data + ch->pos; for (int i = 0; i < count; i++) { int data = (short)((ushort)sfx[offset] + ((ushort)sfx[offset + 1] << 8)); // Uze: check is this is right!!! int left = (data * leftvol) >> 8; int right = (data * rightvol) >> 8; _PaintBuffer[i].left += left; _PaintBuffer[i].right += right; offset += 2; } ch.pos += count; }
// S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) public static void StaticSound(sfx_t sfx, ref Vector3 origin, float vol, float attenuation) { if (sfx == null) { return; } if (_TotalChannels == MAX_CHANNELS) { Con.Print("total_channels == MAX_CHANNELS\n"); return; } channel_t ss = _Channels[_TotalChannels]; _TotalChannels++; sfxcache_t sc = LoadSound(sfx); if (sc == null) { return; } if (sc.loopstart == -1) { Con.Print("Sound {0} not looped\n", sfx.name); return; } ss.sfx = sfx; ss.origin = origin; ss.master_vol = (int)vol; ss.dist_mult = (attenuation / 64) / _SoundNominalClipDist; ss.end = _PaintedTime + sc.length; Spatialize(ss); }
// S_Init (void) public static void Init() { Con.Print("\nSound Initialization\n"); if (Common.HasParam("-nosound")) { return; } for (int i = 0; i < _Channels.Length; i++) { _Channels[i] = new channel_t(); } Cmd.Add("play", Play); Cmd.Add("playvol", PlayVol); Cmd.Add("stopsound", StopAllSoundsCmd); Cmd.Add("soundlist", SoundList); Cmd.Add("soundinfo", SoundInfo_f); _IsInitialized = true; Startup(); InitScaletable(); _NumSfx = 0; Con.Print("Sound sampling rate: {0}\n", _shm.speed); // provides a tick sound until washed clean _AmbientSfx[Ambients.AMBIENT_WATER] = PrecacheSound("ambience/water1.wav"); _AmbientSfx[Ambients.AMBIENT_SKY] = PrecacheSound("ambience/wind2.wav"); StopAllSounds(true); }
// S_PaintChannels static void PaintChannels(int endtime) { while (_PaintedTime < endtime) { // if paintbuffer is smaller than DMA buffer int end = endtime; if (endtime - _PaintedTime > PAINTBUFFER_SIZE) { end = _PaintedTime + PAINTBUFFER_SIZE; } // clear the paint buffer Array.Clear(_PaintBuffer, 0, end - _PaintedTime); // paint in the channels. for (int i = 0; i < _TotalChannels; i++) { channel_t ch = _Channels[i]; if (ch.sfx == null) { continue; } if (ch.leftvol == 0 && ch.rightvol == 0) { continue; } sfxcache_t sc = LoadSound(ch.sfx); if (sc == null) { continue; } int count, ltime = _PaintedTime; while (ltime < end) { // paint up to end if (ch.end < end) { count = ch.end - ltime; } else { count = end - ltime; } if (count > 0) { if (sc.width == 1) { PaintChannelFrom8(ch, sc, count); } else { PaintChannelFrom16(ch, sc, count); } ltime += count; } // if at end of loop, restart if (ltime >= ch.end) { if (sc.loopstart >= 0) { ch.pos = sc.loopstart; ch.end = ltime + sc.length - ch.pos; } else { // channel just stopped ch.sfx = null; break; } } } } // transfer out according to DMA format TransferPaintBuffer(end); _PaintedTime = end; } }
// void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up) // // Called once each time through the main loop public static void Update(ref Vector3 origin, ref Vector3 forward, ref Vector3 right, ref Vector3 up) { if (!_IsInitialized || (_SoundBlocked > 0)) { return; } _ListenerOrigin = origin; _ListenerForward = forward; _ListenerRight = right; _ListenerUp = up; // update general area ambient sound sources UpdateAmbientSounds(); channel_t combine = null; // update spatialization for static and dynamic sounds //channel_t ch = channels + NUM_AMBIENTS; for (int i = Ambients.NUM_AMBIENTS; i < _TotalChannels; i++) { channel_t ch = _Channels[i];// channels + NUM_AMBIENTS; if (ch.sfx == null) { continue; } Spatialize(ch); // respatialize channel if (ch.leftvol == 0 && ch.rightvol == 0) { continue; } // try to combine static sounds with a previous channel of the same // sound effect so we don't mix five torches every frame if (i >= MAX_DYNAMIC_CHANNELS + Ambients.NUM_AMBIENTS) { // see if it can just use the last one if (combine != null && combine.sfx == ch.sfx) { combine.leftvol += ch.leftvol; combine.rightvol += ch.rightvol; ch.leftvol = ch.rightvol = 0; continue; } // search for one combine = _Channels[MAX_DYNAMIC_CHANNELS + Ambients.NUM_AMBIENTS];// channels + MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; int j; for (j = MAX_DYNAMIC_CHANNELS + Ambients.NUM_AMBIENTS; j < i; j++) { combine = _Channels[j]; if (combine.sfx == ch.sfx) { break; } } if (j == _TotalChannels) { combine = null; } else { if (combine != ch) { combine.leftvol += ch.leftvol; combine.rightvol += ch.rightvol; ch.leftvol = ch.rightvol = 0; } continue; } } } // // debugging output // if (_Show.Value != 0) { int total = 0; for (int i = 0; i < _TotalChannels; i++) { channel_t ch = _Channels[i]; if (ch.sfx != null && (ch.leftvol > 0 || ch.rightvol > 0)) { total++; } } Con.Print("----({0})----\n", total); } // mix some sound Update(); }
// S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) public static void StartSound(int entnum, int entchannel, sfx_t sfx, ref Vector3 origin, float fvol, float attenuation) { if (!_SoundStarted || sfx == null) { return; } if (_NoSound.Value != 0) { return; } int vol = (int)(fvol * 255); // pick a channel to play on channel_t target_chan = PickChannel(entnum, entchannel); if (target_chan == null) { return; } // spatialize //memset (target_chan, 0, sizeof(*target_chan)); target_chan.origin = origin; target_chan.dist_mult = attenuation / _SoundNominalClipDist; target_chan.master_vol = vol; target_chan.entnum = entnum; target_chan.entchannel = entchannel; Spatialize(target_chan); if (target_chan.leftvol == 0 && target_chan.rightvol == 0) { return; // not audible at all } // new channel sfxcache_t sc = LoadSound(sfx); if (sc == null) { target_chan.sfx = null; return; // couldn't load the sound's data } target_chan.sfx = sfx; target_chan.pos = 0; target_chan.end = _PaintedTime + sc.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 for (int i = Ambients.NUM_AMBIENTS; i < Ambients.NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; i++) { channel_t check = _Channels[i]; if (check == target_chan) { continue; } if (check.sfx == sfx && check.pos == 0) { int skip = Sys.Random((int)(0.1 * _shm.speed));// rand() % (int)(0.1 * shm->speed); if (skip >= target_chan.end) { skip = target_chan.end - 1; } target_chan.pos += skip; target_chan.end -= skip; break; } } }