aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/sound
diff options
context:
space:
mode:
authorRene Stoeckel <[email protected]>2004-09-22 19:22:16 +0000
committerRene Stoeckel <[email protected]>2004-09-22 19:22:16 +0000
commitc4fcffe436fbfb5b0f3b7be2e5ee103ec74932f7 (patch)
tree7c9439ab1d9f5a4fd61bd57c755069007b23e0b6 /src/jake2/sound
parentbcb4ac6eefb425d5b0a90009da506361d5739e75 (diff)
major refactoring in game, server and client package
Diffstat (limited to 'src/jake2/sound')
-rw-r--r--src/jake2/sound/joal/JOALSoundImpl.java7
-rw-r--r--src/jake2/sound/jsound/SND_DMA.java2306
-rw-r--r--src/jake2/sound/jsound/SND_MIX.java935
3 files changed, 1607 insertions, 1641 deletions
diff --git a/src/jake2/sound/joal/JOALSoundImpl.java b/src/jake2/sound/joal/JOALSoundImpl.java
index 3072c6b..72a36cc 100644
--- a/src/jake2/sound/joal/JOALSoundImpl.java
+++ b/src/jake2/sound/joal/JOALSoundImpl.java
@@ -2,13 +2,14 @@
* JOALSoundImpl.java
* Copyright (C) 2004
*
- * $Id: JOALSoundImpl.java,v 1.4 2004-09-19 09:12:20 hzi Exp $
+ * $Id: JOALSoundImpl.java,v 1.5 2004-09-22 19:22:15 salomo Exp $
*/
package jake2.sound.joal;
import jake2.Defines;
import jake2.Globals;
import jake2.client.CL;
+import jake2.client.CL_ents;
import jake2.game.*;
import jake2.qcommon.*;
import jake2.sound.*;
@@ -357,7 +358,7 @@ public final class JOALSoundImpl implements Sound {
changeEnv = true;
}
- if ((Game.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) {
+ if ((GameBase.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) {
changeEnv = currentEnv != EAX.EAX_ENVIRONMENT_UNDERWATER;
currentEnv = EAX.EAX_ENVIRONMENT_UNDERWATER;
} else {
@@ -483,7 +484,7 @@ public final class JOALSoundImpl implements Sound {
Math3D.VectorCopy(listenerOrigin, sourceOrigin);
break;
case Channel.DYNAMIC:
- CL.GetEntitySoundOrigin(ch.entity, entityOrigin);
+ CL_ents.GetEntitySoundOrigin(ch.entity, entityOrigin);
convertVector(entityOrigin, sourceOrigin);
break;
case Channel.FIXED:
diff --git a/src/jake2/sound/jsound/SND_DMA.java b/src/jake2/sound/jsound/SND_DMA.java
index 9fe7930..daadb57 100644
--- a/src/jake2/sound/jsound/SND_DMA.java
+++ b/src/jake2/sound/jsound/SND_DMA.java
@@ -2,1196 +2,1158 @@
* S_DMA.java
* Copyright (C) 2004
*
- * $Id: SND_DMA.java,v 1.1 2004-07-09 06:50:48 hzi Exp $
+ * $Id: SND_DMA.java,v 1.2 2004-09-22 19:22:09 salomo Exp $
*/
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ 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 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.
+ 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.
+ 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.
+ 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.
-*/
+ */
// Created on 26.01.2004 by RST.
-
package jake2.sound.jsound;
import jake2.Defines;
-import jake2.client.CL;
-import jake2.game.*;
-import jake2.qcommon.*;
-import jake2.sound.*;
+import jake2.client.CL_ents;
+import jake2.game.Cmd;
+import jake2.game.cvar_t;
+import jake2.game.entity_state_t;
+import jake2.qcommon.Com;
+import jake2.qcommon.Cvar;
+import jake2.qcommon.FS;
+import jake2.qcommon.xcommand_t;
+import jake2.sound.WaveLoader;
+import jake2.sound.sfx_t;
+import jake2.sound.sfxcache_t;
+import jake2.util.Math3D;
import jake2.util.Vargs;
import java.io.IOException;
import java.io.RandomAccessFile;
-
-
/**
- * SND_DMA
- * TODO implement sound system
+ * SND_DMA TODO implement sound system
*/
public class SND_DMA extends SND_MIX {
-//// =======================================================================
-//// Internal sound data & structures
-//// =======================================================================
-//
-//// only begin attenuating sound volumes when outside the FULLVOLUME range
- static final int SOUND_FULLVOLUME = 80;
- static final float SOUND_LOOPATTENUATE = 0.003f;
- static int s_registration_sequence;
-
- static boolean sound_started = false;
-
- static float[] listener_origin = {0, 0, 0};
- static float[] listener_forward = {0, 0, 0};
- static float[] listener_right = {0, 0, 0};
- static float[] listener_up = {0, 0, 0};
-
- static boolean s_registering;
-
- static int soundtime; // 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.
- static final int MAX_SFX = (MAX_SOUNDS*2);
- static sfx_t[] known_sfx = new sfx_t[MAX_SFX];
- static {
- for (int i = 0; i< known_sfx.length; i++)
- known_sfx[i] = new sfx_t();
- }
- static int num_sfx;
-
- static final int MAX_PLAYSOUNDS = 128;
- static playsound_t[] s_playsounds = new playsound_t[MAX_PLAYSOUNDS];
- static {
- for( int i = 0; i < MAX_PLAYSOUNDS; i++) {
- s_playsounds[i] = new playsound_t();
- }
- }
- static playsound_t s_freeplays = new playsound_t();
-
- static int s_beginofs;
-
- static cvar_t s_testsound;
- static cvar_t s_loadas8bit;
- static cvar_t s_khz;
- static cvar_t s_show;
- static cvar_t s_mixahead;
- static cvar_t s_primary;
-//
-//
-// int s_rawend;
-// portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
-//
-//
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-
- static void SoundInfo_f() {
- if (!sound_started) {
- Com.Printf("sound system not started\n");
- return;
- }
-
- Com.Printf("%5d stereo\n", new Vargs(1).add(dma.channels - 1));
- Com.Printf("%5d samples\n", new Vargs(1).add(dma.samples));
- //Com.Printf("%5d samplepos\n", new Vargs(1).add(dma.samplepos));
- Com.Printf("%5d samplebits\n", new Vargs(1).add(dma.samplebits));
- Com.Printf("%5d submission_chunk\n", new Vargs(1).add(dma.submission_chunk));
- Com.Printf("%5d speed\n", new Vargs(1).add(dma.speed));
- }
-
- /*
- ================
- S_Init
- ================
- */
- public static void Init() {
- cvar_t cv;
-
- Com.Printf("\n------- sound initialization -------\n");
-
- cv = Cvar.Get("s_initsound", "0", 0);
- if (cv.value == 0.0f)
- 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", new xcommand_t() {
- public void execute() {
- Play();
- }
- });
- Cmd.AddCommand("stopsound", new xcommand_t() {
- public void execute() {
- StopAllSounds();
- }
- });
- Cmd.AddCommand("soundlist", new xcommand_t() {
- public void execute() {
- SoundList();
- }
- });
- Cmd.AddCommand("soundinfo", new xcommand_t() {
- public void execute() {
- SoundInfo_f();
- }
- });
-
- if (!SNDDMA_Init())
- return;
-
- InitScaletable();
-
- sound_started = true;
- num_sfx = 0;
-
- soundtime = 0;
- paintedtime = 0;
-
- Com.Printf("sound sampling rate: " + dma.speed + "\n");
-
- StopAllSounds();
- }
- Com.Printf("------------------------------------\n");
- }
-
-
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
-
- public static void Shutdown() {
- int i;
- sfx_t[] sfx;
-
- if (!sound_started)
- return;
-
- SNDDMA_Shutdown();
-
- sound_started = false;
-
- 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++) {
- if (sfx[i].name == null)
- continue;
-
- //memset (sfx, 0, sizeof(*sfx));
- sfx[i].clear();
- }
-
- num_sfx = 0;
- }
-
-// =======================================================================
-// Load a sound
-// =======================================================================
-
- /*
- ==================
- S_FindName
-
- ==================
- */
- static sfx_t FindName(String name, boolean create) {
- int i;
- sfx_t sfx = null;
-
- if (name == null)
- Com.Error(ERR_FATAL, "S_FindName: NULL\n");
- if (name.length() == 0)
- Com.Error(ERR_FATAL, "S_FindName: empty name\n");
-
- if (name.length() >= MAX_QPATH)
- Com.Error(ERR_FATAL, "Sound name too long: " + name);
-
- // see if already loaded
- for (i = 0; i < num_sfx; i++)
- if (name.equals(known_sfx[i].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 == null)
- // 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));
- sfx.clear();
- sfx.name = name;
- sfx.registration_sequence = s_registration_sequence;
-
- return sfx;
- }
-
- /*
- ==================
- S_AliasName
-
- ==================
- */
- static sfx_t AliasName(String aliasname, String truename)
- {
- sfx_t sfx = null;
-// 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 == null)
- 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.name = aliasname;
- sfx.registration_sequence = s_registration_sequence;
- sfx.truename = truename;
-
- return sfx;
- }
-
-
- /*
- =====================
- S_BeginRegistration
-
- =====================
- */
- public static void BeginRegistration() {
- s_registration_sequence++;
- s_registering = true;
- }
-
- /*
- ==================
- S_RegisterSound
-
- ==================
- */
- public static sfx_t RegisterSound(String name) {
- sfx_t sfx = null;
-
- if (!sound_started)
- return null;
-
- sfx = FindName(name, true);
- sfx.registration_sequence = s_registration_sequence;
-
- if (!s_registering)
- WaveLoader.LoadSound(sfx);
-
- return sfx;
- }
-
-
- /*
- =====================
- S_EndRegistration
-
- =====================
- */
- public static void EndRegistration() {
- int i;
- sfx_t sfx;
- int size;
-
- // free any sounds not from this registration sequence
- for (i = 0; i < num_sfx; i++) {
- sfx = known_sfx[i];
- if (sfx.name == null)
- continue;
- if (sfx.registration_sequence != s_registration_sequence) { // don't need this sound
- //memset (sfx, 0, sizeof(*sfx));
- sfx.clear();
- } 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; i < num_sfx; i++) {
- sfx = known_sfx[i];
- if (sfx.name == null)
- continue;
- WaveLoader.LoadSound(sfx);
- }
-
- s_registering = false;
- }
-
-
-// =============================================================================
-
- /*
- =================
- S_PickChannel
- =================
- */
- static channel_t 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 != null)
- 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));
- ch.clear();
-
- return ch;
- }
-
- /*
- =================
- S_SpatializeOrigin
-
- Used for spatializing channels and autosounds
- =================
- */
- static void SpatializeOrigin(float[] origin, float master_vol, float dist_mult, channel_t ch)
- {
- float dot;
- float dist;
- float lscale, rscale, scale;
- float[] source_vec = {0, 0, 0};
-
- if (cls.state != ca_active)
- {
- ch.leftvol = ch.rightvol = 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 == 0.0f)
- { // no attenuation = no spatialization
- rscale = 1.0f;
- lscale = 1.0f;
- }
- else
- {
- rscale = 0.5f * (1.0f + dot);
- lscale = 0.5f * (1.0f - dot);
- }
-
- // add in distance effect
- scale = (1.0f - dist) * rscale;
- ch.rightvol = (int) (master_vol * scale);
- if (ch.rightvol < 0)
- ch.rightvol = 0;
-
- scale = (1.0f - dist) * lscale;
- ch.leftvol = (int) (master_vol * scale);
- if (ch.leftvol < 0)
- ch.leftvol = 0;
- }
-
- /*
- =================
- S_Spatialize
- =================
- */
- static void Spatialize(channel_t ch)
- {
- float[] origin = {0, 0, 0};
-
- // 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);
-
- SpatializeOrigin(origin, (float)ch.master_vol, ch.dist_mult, ch);
- }
-
- /*
- =================
- S_AllocPlaysound
- =================
- */
- static playsound_t AllocPlaysound ()
- {
- 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
- =================
- */
- static void 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.
- ===============
- */
- static void IssuePlaysound (playsound_t ps)
- {
- channel_t ch;
- sfxcache_t sc;
-
- if (s_show.value != 0.0f)
- Com.Printf("Issue " + ps.begin + "\n");
- // pick a channel to play on
- ch = PickChannel(ps.entnum, ps.entchannel);
- if (ch == null)
- {
- 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 = (int)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;
-
- Spatialize(ch);
-
- ch.pos = 0;
- sc = WaveLoader.LoadSound(ch.sfx);
- ch.end = paintedtime + sc.length;
-
- // free the playsound
- FreePlaysound(ps);
- }
-
- static sfx_t RegisterSexedSound(entity_state_t ent, String base) {
- sfx_t sfx = null;
-
- // determine what model the client is using
- String model = "male";
- int n = CS_PLAYERSKINS + ent.number - 1;
- if (cl.configstrings[n] != null) {
- int p = cl.configstrings[n].indexOf('\\');
- if (p >= 0) {
- p++;
- model = cl.configstrings[n].substring(p);
- //strcpy(model, p);
- p = model.indexOf('/');
- if (p > 0)
- model = model.substring(0, p - 1);
- }
- }
- // if we can't figure it out, they're male
- if (model == null || model.length() == 0)
- model = "male";
-
- // see if we already know of the model specific sound
- String sexedFilename = "#players/" + model + "/" + base.substring(1);
- //Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
- sfx = FindName(sexedFilename, false);
-
- if (sfx == null) {
- // no, so see if it exists
- RandomAccessFile f = null;
- try {
- f = FS.FOpenFile(sexedFilename.substring(1));
- } catch (IOException e) {}
- if (f != null) {
- // yes, close the file and register it
- try {
- FS.FCloseFile(f);
- } catch (IOException e1) {}
- sfx = RegisterSound(sexedFilename);
- } else {
- // no, revert to the male sound in the pak0.pak
- //Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
- String maleFilename = "player/male/" + base.substring(1);
- sfx = 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
- ====================
- */
- public static void StartSound(float[] origin, int entnum, int entchannel, sfx_t sfx, float fvol, float attenuation, float timeofs) {
-
- if (!sound_started)
- return;
-
- if (sfx == null)
- return;
-
- if (sfx.name.charAt(0) == '*')
- sfx = RegisterSexedSound(cl_entities[entnum].current, sfx.name);
-
- // make sure the sound is loaded
- sfxcache_t sc = WaveLoader.LoadSound(sfx);
- if (sc == null)
- return; // couldn't load the sound's data
-
- int vol = (int) (fvol * 255);
-
- // make the playsound_t
- playsound_t ps = AllocPlaysound();
- if (ps == null)
- return;
-
- if (origin != null) {
- 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
- int start = (int) (cl.frame.servertime * 0.001f * dma.speed + s_beginofs);
- if (start < paintedtime) {
- start = paintedtime;
- s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed));
- } else if (start > paintedtime + 0.3f * dma.speed) {
- start = (int) (paintedtime + 0.1f * dma.speed);
- s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed));
- } else {
- s_beginofs -= 10;
- }
-
- if (timeofs == 0.0f)
- ps.begin = paintedtime;
- else
- ps.begin = (long) (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);
-
- ps.next = sort;
- ps.prev = sort.prev;
-
- ps.next.prev = ps;
- ps.prev.next = ps;
- }
-
- /*
- ==================
- S_StartLocalSound
- ==================
- */
- public static void StartLocalSound(String sound) {
- sfx_t sfx;
-
- if (!sound_started)
- return;
-
- sfx = RegisterSound(sound);
- if (sfx == null) {
- Com.Printf("S_StartLocalSound: can't cache " + sound + "\n");
- return;
- }
- StartSound(null, cl.playernum + 1, 0, sfx, 1, 1, 0);
- }
-
-
- /*
- ==================
- S_ClearBuffer
- ==================
- */
- static void ClearBuffer()
- {
- int clear;
-
- if (!sound_started)
- return;
-
- s_rawend = 0;
-
- if (dma.samplebits == 8)
- clear = 0x80;
- else
- clear = 0;
-
- SNDDMA_BeginPainting ();
- if (dma.buffer != null)
- //memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
- //Arrays.fill(dma.buffer, (byte)clear);
- SNDDMA_Submit ();
- }
-
- /*
- ==================
- S_StopAllSounds
- ==================
- */
- public static void StopAllSounds()
- {
- 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].clear();
- 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));
- for (i = 0; i < MAX_CHANNELS; i++)
- channels[i].clear();
-
- 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
- ==================
- */
- static void AddLoopSounds()
- {
- int i, j;
- int[] sounds = new int[Defines.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 != 0.0f)
- 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] == 0)
- continue;
-
- sfx = cl.sound_precache[sounds[i]];
- if (sfx == null)
- continue; // bad sound effect
- sc = sfx.cache;
- if (sc == null)
- continue;
-
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = cl_parse_entities[num];
-
- channel_t tch = new channel_t();
- // find the total contribution of all sounds of this type
- SpatializeOrigin(ent.origin, 255.0f, SOUND_LOOPATTENUATE, tch);
- left_total = tch.leftvol;
- right_total = tch.rightvol;
- 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];
-
- SpatializeOrigin(ent.origin, 255.0f, SOUND_LOOPATTENUATE, tch);
- left_total += tch.leftvol;
- right_total += tch.rightvol;
- }
-
- if (left_total == 0 && right_total == 0)
- continue; // not audible
-
- // allocate a channel
- ch = PickChannel(0, 0);
- if (ch == null)
- 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
- ============
- */
- static void RawSamples(int samples, int rate, int width, int channels, byte[] data)
- {
- //TODO RawSamples
- 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
- ============
- */
- public static void Update(float[] origin, float[] forward, float[] right, float[] up) {
-
- 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 != 0.0f) {
- ClearBuffer();
- return;
- }
-
- // rebuild scale tables if volume is modified
- if (s_volume.modified)
- InitScaletable();
-
- VectorCopy(origin, listener_origin);
- VectorCopy(forward, listener_forward);
- VectorCopy(right, listener_right);
- VectorCopy(up, listener_up);
-
- channel_t combine = null;
-
- // update spatialization for dynamic sounds
- channel_t ch;
- for (int i = 0; i < MAX_CHANNELS; i++) {
- ch = channels[i];
- if (ch.sfx == null)
- continue;
- if (ch.autosound) { // autosounds are regenerated fresh each frame
- //memset (ch, 0, sizeof(*ch));
- ch.clear();
- continue;
- }
- Spatialize(ch); // respatialize channel
- if (ch.leftvol == 0 && ch.rightvol == 0) {
- //memset (ch, 0, sizeof(*ch));
- ch.clear();
- continue;
- }
- }
-
- // add loopsounds
- AddLoopSounds();
-
- //
- // debugging output
- //
- if (s_show.value != 0.0f) {
- int total = 0;
-
- for (int i = 0; i < MAX_CHANNELS; i++) {
- ch = channels[i];
- if (ch.sfx != null && (ch.leftvol != 0 || ch.rightvol != 0)) {
- Com.Printf(ch.leftvol + " " + ch.rightvol + " " + ch.sfx.name + "\n");
- total++;
- }
- }
-
- //Com.Printf("----(" + total + ")---- painted: " + paintedtime + "\n");
- }
-
- // mix some sound
- Update_();
- }
-
- static int buffers = 0;
- static int oldsamplepos = 0;
- static void GetSoundtime()
- {
- 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;
- StopAllSounds();
- }
- }
- oldsamplepos = samplepos;
-
- soundtime = buffers*fullsamples + samplepos/dma.channels;
- }
-
- static void Update_()
- {
- int endtime;
- int samps;
-
- if (!sound_started)
- return;
-
- SNDDMA_BeginPainting();
-
- if (dma.buffer == null)
- 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 = (int)(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;
-
- PaintChannels(endtime);
-
- SNDDMA_Submit();
- }
-
- /*
- ===============================================================================
-
- console functions
-
- ===============================================================================
- */
-
- static void Play() {
- int i;
- String name;
- sfx_t sfx;
-
- i = 1;
- while (i < Cmd.Argc()) {
- name = new String(Cmd.Argv(i));
- if (name.indexOf('.') == -1)
- name += ".wav";
-
- sfx = RegisterSound(name);
- StartSound(null, cl.playernum + 1, 0, sfx, 1.0f, 1.0f, 0.0f);
- i++;
- }
- }
-
- static void SoundList() {
- int i;
- sfx_t sfx;
- sfxcache_t sc;
- int size, total;
-
- total = 0;
- for (i = 0; i < num_sfx; i++) {
- sfx = known_sfx[i];
- if (sfx.registration_sequence == 0)
- continue;
- sc = sfx.cache;
- if (sc != null) {
- 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", new Vargs(3).add(sc.width * 8).add(size).add(sfx.name));
- } else {
- if (sfx.name.charAt(0) == '*')
- Com.Printf(" placeholder : " + sfx.name + "\n");
- else
- Com.Printf(" not loaded : " + sfx.name + "\n");
- }
- }
- Com.Printf("Total resident: " + total + "\n");
- }
-
-}
+ ////
+ // =======================================================================
+ //// Internal sound data & structures
+ ////
+ // =======================================================================
+ //
+ //// only begin attenuating sound volumes when outside the FULLVOLUME range
+ static final int SOUND_FULLVOLUME = 80;
+
+ static final float SOUND_LOOPATTENUATE = 0.003f;
+
+ static int s_registration_sequence;
+
+ static boolean sound_started = false;
+
+ static float[] listener_origin = { 0, 0, 0 };
+
+ static float[] listener_forward = { 0, 0, 0 };
+
+ static float[] listener_right = { 0, 0, 0 };
+
+ static float[] listener_up = { 0, 0, 0 };
+
+ static boolean s_registering;
+
+ static int soundtime; // 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.
+ static final int MAX_SFX = (MAX_SOUNDS * 2);
+
+ static sfx_t[] known_sfx = new sfx_t[MAX_SFX];
+ static {
+ for (int i = 0; i < known_sfx.length; i++)
+ known_sfx[i] = new sfx_t();
+ }
+
+ static int num_sfx;
+
+ static final int MAX_PLAYSOUNDS = 128;
+
+ static playsound_t[] s_playsounds = new playsound_t[MAX_PLAYSOUNDS];
+ static {
+ for (int i = 0; i < MAX_PLAYSOUNDS; i++) {
+ s_playsounds[i] = new playsound_t();
+ }
+ }
+
+ static playsound_t s_freeplays = new playsound_t();
+
+ static int s_beginofs;
+
+ static cvar_t s_testsound;
+
+ static cvar_t s_loadas8bit;
+
+ static cvar_t s_khz;
+
+ static cvar_t s_show;
+
+ static cvar_t s_mixahead;
+
+ static cvar_t s_primary;
+
+ //
+ //
+ // int s_rawend;
+ // portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
+ //
+ //
+ // ====================================================================
+ // User-setable variables
+ // ====================================================================
+
+ static void SoundInfo_f() {
+ if (!sound_started) {
+ Com.Printf("sound system not started\n");
+ return;
+ }
+
+ Com.Printf("%5d stereo\n", new Vargs(1).add(dma.channels - 1));
+ Com.Printf("%5d samples\n", new Vargs(1).add(dma.samples));
+ //Com.Printf("%5d samplepos\n", new Vargs(1).add(dma.samplepos));
+ Com.Printf("%5d samplebits\n", new Vargs(1).add(dma.samplebits));
+ Com.Printf("%5d submission_chunk\n", new Vargs(1)
+ .add(dma.submission_chunk));
+ Com.Printf("%5d speed\n", new Vargs(1).add(dma.speed));
+ }
+
+ /*
+ * ================ S_Init ================
+ */
+ public static void Init() {
+ cvar_t cv;
+
+ Com.Printf("\n------- sound initialization -------\n");
+
+ cv = Cvar.Get("s_initsound", "0", 0);
+ if (cv.value == 0.0f)
+ 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", new xcommand_t() {
+ public void execute() {
+ Play();
+ }
+ });
+ Cmd.AddCommand("stopsound", new xcommand_t() {
+ public void execute() {
+ StopAllSounds();
+ }
+ });
+ Cmd.AddCommand("soundlist", new xcommand_t() {
+ public void execute() {
+ SoundList();
+ }
+ });
+ Cmd.AddCommand("soundinfo", new xcommand_t() {
+ public void execute() {
+ SoundInfo_f();
+ }
+ });
+
+ if (!SNDDMA_Init())
+ return;
+
+ InitScaletable();
+
+ sound_started = true;
+ num_sfx = 0;
+
+ soundtime = 0;
+ paintedtime = 0;
+
+ Com.Printf("sound sampling rate: " + dma.speed + "\n");
+
+ StopAllSounds();
+ }
+ Com.Printf("------------------------------------\n");
+ }
+
+ // =======================================================================
+ // Shutdown sound engine
+ // =======================================================================
+
+ public static void Shutdown() {
+ int i;
+ sfx_t[] sfx;
+
+ if (!sound_started)
+ return;
+
+ SNDDMA_Shutdown();
+
+ sound_started = false;
+
+ 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++) {
+ if (sfx[i].name == null)
+ continue;
+
+ //memset (sfx, 0, sizeof(*sfx));
+ sfx[i].clear();
+ }
+
+ num_sfx = 0;
+ }
+
+ // =======================================================================
+ // Load a sound
+ // =======================================================================
+
+ /*
+ * ================== S_FindName
+ *
+ * ==================
+ */
+ static sfx_t FindName(String name, boolean create) {
+ int i;
+ sfx_t sfx = null;
+
+ if (name == null)
+ Com.Error(ERR_FATAL, "S_FindName: NULL\n");
+ if (name.length() == 0)
+ Com.Error(ERR_FATAL, "S_FindName: empty name\n");
+
+ if (name.length() >= MAX_QPATH)
+ Com.Error(ERR_FATAL, "Sound name too long: " + name);
+
+ // see if already loaded
+ for (i = 0; i < num_sfx; i++)
+ if (name.equals(known_sfx[i].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 == null)
+ // 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));
+ sfx.clear();
+ sfx.name = name;
+ sfx.registration_sequence = s_registration_sequence;
+
+ return sfx;
+ }
+
+ /*
+ * ================== S_AliasName
+ *
+ * ==================
+ */
+ static sfx_t AliasName(String aliasname, String truename) {
+ sfx_t sfx = null;
+ // 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 == null)
+ 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.name = aliasname;
+ sfx.registration_sequence = s_registration_sequence;
+ sfx.truename = truename;
+
+ return sfx;
+ }
+
+ /*
+ * ===================== S_BeginRegistration
+ *
+ * =====================
+ */
+ public static void BeginRegistration() {
+ s_registration_sequence++;
+ s_registering = true;
+ }
+
+ /*
+ * ================== S_RegisterSound
+ *
+ * ==================
+ */
+ public static sfx_t RegisterSound(String name) {
+ sfx_t sfx = null;
+
+ if (!sound_started)
+ return null;
+
+ sfx = FindName(name, true);
+ sfx.registration_sequence = s_registration_sequence;
+
+ if (!s_registering)
+ WaveLoader.LoadSound(sfx);
+
+ return sfx;
+ }
+
+ /*
+ * ===================== S_EndRegistration
+ *
+ * =====================
+ */
+ public static void EndRegistration() {
+ int i;
+ sfx_t sfx;
+ int size;
+
+ // free any sounds not from this registration sequence
+ for (i = 0; i < num_sfx; i++) {
+ sfx = known_sfx[i];
+ if (sfx.name == null)
+ continue;
+ if (sfx.registration_sequence != s_registration_sequence) { // don't
+ // need
+ // this
+ // sound
+ //memset (sfx, 0, sizeof(*sfx));
+ sfx.clear();
+ } 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; i < num_sfx; i++) {
+ sfx = known_sfx[i];
+ if (sfx.name == null)
+ continue;
+ WaveLoader.LoadSound(sfx);
+ }
+
+ s_registering = false;
+ }
+
+ // =============================================================================
+
+ /*
+ * ================= S_PickChannel =================
+ */
+ static channel_t 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 != null)
+ 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));
+ ch.clear();
+
+ return ch;
+ }
+
+ /*
+ * ================= S_SpatializeOrigin
+ *
+ * Used for spatializing channels and autosounds =================
+ */
+ static void SpatializeOrigin(float[] origin, float master_vol,
+ float dist_mult, channel_t ch) {
+ float dot;
+ float dist;
+ float lscale, rscale, scale;
+ float[] source_vec = { 0, 0, 0 };
+
+ if (cls.state != ca_active) {
+ ch.leftvol = ch.rightvol = 255;
+ return;
+ }
+
+ // calculate stereo seperation and distance attenuation
+ Math3D.VectorSubtract(origin, listener_origin, source_vec);
+
+ dist = Math3D.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 = Math3D.DotProduct(listener_right, source_vec);
+
+ if (dma.channels == 1 || dist_mult == 0.0f) { // no attenuation = no
+ // spatialization
+ rscale = 1.0f;
+ lscale = 1.0f;
+ } else {
+ rscale = 0.5f * (1.0f + dot);
+ lscale = 0.5f * (1.0f - dot);
+ }
+
+ // add in distance effect
+ scale = (1.0f - dist) * rscale;
+ ch.rightvol = (int) (master_vol * scale);
+ if (ch.rightvol < 0)
+ ch.rightvol = 0;
+
+ scale = (1.0f - dist) * lscale;
+ ch.leftvol = (int) (master_vol * scale);
+ if (ch.leftvol < 0)
+ ch.leftvol = 0;
+ }
+
+ /*
+ * ================= S_Spatialize =================
+ */
+ static void Spatialize(channel_t ch) {
+ float[] origin = { 0, 0, 0 };
+
+ // 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) {
+ Math3D.VectorCopy(ch.origin, origin);
+ } else
+ CL_ents.GetEntitySoundOrigin(ch.entnum, origin);
+
+ SpatializeOrigin(origin, (float) ch.master_vol, ch.dist_mult, ch);
+ }
+
+ /*
+ * ================= S_AllocPlaysound =================
+ */
+ static playsound_t AllocPlaysound() {
+ 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 =================
+ */
+ static void 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. ===============
+ */
+ static void IssuePlaysound(playsound_t ps) {
+ channel_t ch;
+ sfxcache_t sc;
+
+ if (s_show.value != 0.0f)
+ Com.Printf("Issue " + ps.begin + "\n");
+ // pick a channel to play on
+ ch = PickChannel(ps.entnum, ps.entchannel);
+ if (ch == null) {
+ 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 = (int) ps.volume;
+ ch.entnum = ps.entnum;
+ ch.entchannel = ps.entchannel;
+ ch.sfx = ps.sfx;
+ Math3D.VectorCopy(ps.origin, ch.origin);
+ ch.fixed_origin = ps.fixed_origin;
+
+ Spatialize(ch);
+
+ ch.pos = 0;
+ sc = WaveLoader.LoadSound(ch.sfx);
+ ch.end = paintedtime + sc.length;
+
+ // free the playsound
+ FreePlaysound(ps);
+ }
+
+ static sfx_t RegisterSexedSound(entity_state_t ent, String base) {
+ sfx_t sfx = null;
+
+ // determine what model the client is using
+ String model = "male";
+ int n = CS_PLAYERSKINS + ent.number - 1;
+ if (cl.configstrings[n] != null) {
+ int p = cl.configstrings[n].indexOf('\\');
+ if (p >= 0) {
+ p++;
+ model = cl.configstrings[n].substring(p);
+ //strcpy(model, p);
+ p = model.indexOf('/');
+ if (p > 0)
+ model = model.substring(0, p - 1);
+ }
+ }
+ // if we can't figure it out, they're male
+ if (model == null || model.length() == 0)
+ model = "male";
+
+ // see if we already know of the model specific sound
+ String sexedFilename = "#players/" + model + "/" + base.substring(1);
+ //Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s",
+ // model, base+1);
+ sfx = FindName(sexedFilename, false);
+
+ if (sfx == null) {
+ // no, so see if it exists
+ RandomAccessFile f = null;
+ try {
+ f = FS.FOpenFile(sexedFilename.substring(1));
+ } catch (IOException e) {
+ }
+ if (f != null) {
+ // yes, close the file and register it
+ try {
+ FS.FCloseFile(f);
+ } catch (IOException e1) {
+ }
+ sfx = RegisterSound(sexedFilename);
+ } else {
+ // no, revert to the male sound in the pak0.pak
+ //Com_sprintf (maleFilename, sizeof(maleFilename),
+ // "player/%s/%s", "male", base+1);
+ String maleFilename = "player/male/" + base.substring(1);
+ sfx = 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 ====================
+ */
+ public static void StartSound(float[] origin, int entnum, int entchannel,
+ sfx_t sfx, float fvol, float attenuation, float timeofs) {
+
+ if (!sound_started)
+ return;
+
+ if (sfx == null)
+ return;
+
+ if (sfx.name.charAt(0) == '*')
+ sfx = RegisterSexedSound(cl_entities[entnum].current, sfx.name);
+
+ // make sure the sound is loaded
+ sfxcache_t sc = WaveLoader.LoadSound(sfx);
+ if (sc == null)
+ return; // couldn't load the sound's data
+
+ int vol = (int) (fvol * 255);
+
+ // make the playsound_t
+ playsound_t ps = AllocPlaysound();
+ if (ps == null)
+ return;
+
+ if (origin != null) {
+ Math3D.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
+ int start = (int) (cl.frame.servertime * 0.001f * dma.speed + s_beginofs);
+ if (start < paintedtime) {
+ start = paintedtime;
+ s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed));
+ } else if (start > paintedtime + 0.3f * dma.speed) {
+ start = (int) (paintedtime + 0.1f * dma.speed);
+ s_beginofs = (int) (start - (cl.frame.servertime * 0.001f * dma.speed));
+ } else {
+ s_beginofs -= 10;
+ }
+
+ if (timeofs == 0.0f)
+ ps.begin = paintedtime;
+ else
+ ps.begin = (long) (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)
+ ;
+
+ ps.next = sort;
+ ps.prev = sort.prev;
+
+ ps.next.prev = ps;
+ ps.prev.next = ps;
+ }
+
+ /*
+ * ================== S_StartLocalSound ==================
+ */
+ public static void StartLocalSound(String sound) {
+ sfx_t sfx;
+
+ if (!sound_started)
+ return;
+
+ sfx = RegisterSound(sound);
+ if (sfx == null) {
+ Com.Printf("S_StartLocalSound: can't cache " + sound + "\n");
+ return;
+ }
+ StartSound(null, cl.playernum + 1, 0, sfx, 1, 1, 0);
+ }
+
+ /*
+ * ================== S_ClearBuffer ==================
+ */
+ static void ClearBuffer() {
+ int clear;
+
+ if (!sound_started)
+ return;
+
+ s_rawend = 0;
+
+ if (dma.samplebits == 8)
+ clear = 0x80;
+ else
+ clear = 0;
+
+ SNDDMA_BeginPainting();
+ if (dma.buffer != null)
+ //memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
+ //Arrays.fill(dma.buffer, (byte)clear);
+ SNDDMA_Submit();
+ }
+
+ /*
+ * ================== S_StopAllSounds ==================
+ */
+ public static void StopAllSounds() {
+ 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].clear();
+ 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));
+ for (i = 0; i < MAX_CHANNELS; i++)
+ channels[i].clear();
+
+ 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 ==================
+ */
+ static void AddLoopSounds() {
+ int i, j;
+ int[] sounds = new int[Defines.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 != 0.0f)
+ 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] == 0)
+ continue;
+
+ sfx = cl.sound_precache[sounds[i]];
+ if (sfx == null)
+ continue; // bad sound effect
+ sc = sfx.cache;
+ if (sc == null)
+ continue;
+
+ num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
+ ent = cl_parse_entities[num];
+
+ channel_t tch = new channel_t();
+ // find the total contribution of all sounds of this type
+ SpatializeOrigin(ent.origin, 255.0f, SOUND_LOOPATTENUATE, tch);
+ left_total = tch.leftvol;
+ right_total = tch.rightvol;
+ 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];
+
+ SpatializeOrigin(ent.origin, 255.0f, SOUND_LOOPATTENUATE, tch);
+ left_total += tch.leftvol;
+ right_total += tch.rightvol;
+ }
+
+ if (left_total == 0 && right_total == 0)
+ continue; // not audible
+
+ // allocate a channel
+ ch = PickChannel(0, 0);
+ if (ch == null)
+ 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 ============
+ */
+ static void RawSamples(int samples, int rate, int width, int channels,
+ byte[] data) {
+ //TODO RawSamples
+ 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 ============
+ */
+ public static void Update(float[] origin, float[] forward, float[] right,
+ float[] up) {
+
+ 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 != 0.0f) {
+ ClearBuffer();
+ return;
+ }
+
+ // rebuild scale tables if volume is modified
+ if (s_volume.modified)
+ InitScaletable();
+
+ Math3D.VectorCopy(origin, listener_origin);
+ Math3D.VectorCopy(forward, listener_forward);
+ Math3D.VectorCopy(right, listener_right);
+ Math3D.VectorCopy(up, listener_up);
+
+ channel_t combine = null;
+
+ // update spatialization for dynamic sounds
+ channel_t ch;
+ for (int i = 0; i < MAX_CHANNELS; i++) {
+ ch = channels[i];
+ if (ch.sfx == null)
+ continue;
+ if (ch.autosound) { // autosounds are regenerated fresh each frame
+ //memset (ch, 0, sizeof(*ch));
+ ch.clear();
+ continue;
+ }
+ Spatialize(ch); // respatialize channel
+ if (ch.leftvol == 0 && ch.rightvol == 0) {
+ //memset (ch, 0, sizeof(*ch));
+ ch.clear();
+ continue;
+ }
+ }
+
+ // add loopsounds
+ AddLoopSounds();
+
+ //
+ // debugging output
+ //
+ if (s_show.value != 0.0f) {
+ int total = 0;
+
+ for (int i = 0; i < MAX_CHANNELS; i++) {
+ ch = channels[i];
+ if (ch.sfx != null && (ch.leftvol != 0 || ch.rightvol != 0)) {
+ Com.Printf(ch.leftvol + " " + ch.rightvol + " "
+ + ch.sfx.name + "\n");
+ total++;
+ }
+ }
+
+ //Com.Printf("----(" + total + ")---- painted: " + paintedtime +
+ // "\n");
+ }
+
+ // mix some sound
+ Update_();
+ }
+
+ static int buffers = 0;
+
+ static int oldsamplepos = 0;
+
+ static void GetSoundtime() {
+ 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;
+ StopAllSounds();
+ }
+ }
+ oldsamplepos = samplepos;
+
+ soundtime = buffers * fullsamples + samplepos / dma.channels;
+ }
+
+ static void Update_() {
+ int endtime;
+ int samps;
+
+ if (!sound_started)
+ return;
+
+ SNDDMA_BeginPainting();
+
+ if (dma.buffer == null)
+ 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 = (int) (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;
+
+ PaintChannels(endtime);
+
+ SNDDMA_Submit();
+ }
+
+ /*
+ * ===============================================================================
+ *
+ * console functions
+ *
+ * ===============================================================================
+ */
+
+ static void Play() {
+ int i;
+ String name;
+ sfx_t sfx;
+
+ i = 1;
+ while (i < Cmd.Argc()) {
+ name = new String(Cmd.Argv(i));
+ if (name.indexOf('.') == -1)
+ name += ".wav";
+
+ sfx = RegisterSound(name);
+ StartSound(null, cl.playernum + 1, 0, sfx, 1.0f, 1.0f, 0.0f);
+ i++;
+ }
+ }
+
+ static void SoundList() {
+ int i;
+ sfx_t sfx;
+ sfxcache_t sc;
+ int size, total;
+
+ total = 0;
+ for (i = 0; i < num_sfx; i++) {
+ sfx = known_sfx[i];
+ if (sfx.registration_sequence == 0)
+ continue;
+ sc = sfx.cache;
+ if (sc != null) {
+ 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", new Vargs(3).add(sc.width * 8)
+ .add(size).add(sfx.name));
+ } else {
+ if (sfx.name.charAt(0) == '*')
+ Com.Printf(" placeholder : " + sfx.name + "\n");
+ else
+ Com.Printf(" not loaded : " + sfx.name + "\n");
+ }
+ }
+ Com.Printf("Total resident: " + total + "\n");
+ }
+
+} \ No newline at end of file
diff --git a/src/jake2/sound/jsound/SND_MIX.java b/src/jake2/sound/jsound/SND_MIX.java
index c3aae2c..c292d5d 100644
--- a/src/jake2/sound/jsound/SND_MIX.java
+++ b/src/jake2/sound/jsound/SND_MIX.java
@@ -2,490 +2,493 @@
* SND_MIX.java
* Copyright (C) 2004
*
- * $Id: SND_MIX.java,v 1.1 2004-07-09 06:50:48 hzi Exp $
+ * $Id: SND_MIX.java,v 1.2 2004-09-22 19:22:09 salomo Exp $
*/
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ 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 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.
+ 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.
+ 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.
+ 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.
-*/
+ */
package jake2.sound.jsound;
-import java.nio.*;
-import java.nio.ByteBuffer;
-import java.nio.ShortBuffer;
-
import jake2.game.cvar_t;
-import jake2.sound.*;
+import jake2.sound.WaveLoader;
import jake2.sound.sfx_t;
import jake2.sound.sfxcache_t;
import jake2.util.Math3D;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
/**
* SND_MIX
*/
public class SND_MIX extends SND_JAVA {
- static final int MAX_CHANNELS = 32;
- static final int MAX_RAW_SAMPLES = 8192;
-
- static class playsound_t {
- playsound_t prev, next;
- sfx_t sfx;
- float volume;
- float attenuation;
- int entnum;
- int entchannel;
- boolean fixed_origin; // use origin field instead of entnum's origin
- float[] origin = { 0, 0, 0 };
- long begin; // begin on this sample
-
- public void clear() {
- prev = next = null;
- sfx = null;
- volume = attenuation = begin = entnum = entchannel = 0;
- fixed_origin = false;
- Math3D.VectorClear(origin);
- }
- };
-
- static class channel_t {
- sfx_t sfx; // sfx number
- int leftvol; // 0-255 volume
- int rightvol; // 0-255 volume
- int end; // end time in global paintsamples
- int pos; // sample position in sfx
- int looping; // where to loop, -1 = no looping OBSOLETE?
- int entnum; // to allow overriding a specific sound
- int entchannel; //
- float[] origin = { 0, 0, 0 }; // only use if fixed_origin is set
- float dist_mult; // distance multiplier (attenuation/clipK)
- int master_vol; // 0-255 master volume
- boolean fixed_origin; // use origin instead of fetching entnum's origin
- boolean autosound; // from an entity->sound, cleared each frame
-
- void clear() {
- sfx = null;
- dist_mult = leftvol = rightvol = end = pos = looping = entnum = entchannel = master_vol = 0;
- Math3D.VectorClear(origin);
- fixed_origin = autosound = false;
- }
- };
-
- static class portable_samplepair_t {
- int left;
- int right;
- };
-
- static cvar_t s_volume;
- static int s_rawend;
-//// snd_mix.c -- portable code to mix sounds for snd_dma.c
-//
-// #include "client.h"
-// #include "snd_loc.h"
-//
- static final int PAINTBUFFER_SIZE = 2048;
- //static portable_samplepair_t[] paintbuffer = new portable_samplepair_t[PAINTBUFFER_SIZE];
- static IntBuffer paintbuffer = IntBuffer.allocate(PAINTBUFFER_SIZE*2);
- static int[][] snd_scaletable = new int[32][256];
-// int *snd_p, snd_linear_count, snd_vol;
-// short *snd_out;
- static IntBuffer snd_p;
- static ShortBuffer snd_out;
- static int snd_linear_count;
- static int snd_vol;
-
- static int paintedtime; // sample PAIRS
- static playsound_t s_pendingplays = new playsound_t();
-
- //static portable_samplepair_t[] s_rawsamples = new portable_samplepair_t[MAX_RAW_SAMPLES];
- static IntBuffer s_rawsamples = IntBuffer.allocate(MAX_RAW_SAMPLES*2);
- static channel_t[] channels = new channel_t[MAX_CHANNELS];
- static {
- for(int i=0; i < MAX_CHANNELS; i++)
- channels[i] = new channel_t();
- }
-
- static void WriteLinearBlastStereo16()
- {
- int i;
- int val;
-
- for (i=0 ; i<snd_linear_count ; i+=2)
- {
- val = snd_p.get(i)>>8;
- if (val > 0x7fff)
- snd_out.put(i, (short)0x7fff);
- else if (val < (short)0x8000)
- snd_out.put(i,(short)0x8000);
- else
- snd_out.put(i, (short)val);
-
- val = snd_p.get(i+1)>>8;
- if (val > 0x7fff)
- snd_out.put(i+1, (short)0x7fff);
- else if (val < (short)0x8000)
- snd_out.put(i+1, (short)0x8000);
- else
- snd_out.put(i+1, (short)val);
- }
- }
-
- static void TransferStereo16(ByteBuffer pbuf, int endtime)
- {
- int lpos;
- int lpaintedtime;
-
- snd_p = paintbuffer;
- lpaintedtime = paintedtime;
-
- while (lpaintedtime < endtime)
- {
- // handle recirculating buffer issues
- lpos = lpaintedtime & ((dma.samples>>1)-1);
-
-// snd_out = (short *) pbuf + (lpos<<1);
- snd_out = pbuf.asShortBuffer();
- snd_out.position(lpos<<1);
- snd_out = snd_out.slice();
-
- snd_linear_count = (dma.samples>>1) - lpos;
- if (lpaintedtime + snd_linear_count > endtime)
- snd_linear_count = endtime - lpaintedtime;
-
- snd_linear_count <<= 1;
-
- // write a linear blast of samples
- WriteLinearBlastStereo16();
-
- //snd_p += snd_linear_count;
- paintbuffer.position(snd_linear_count);
- snd_p = paintbuffer.slice();
-
- lpaintedtime += (snd_linear_count>>1);
- }
- }
-
- /*
- ===================
- S_TransferPaintBuffer
-
- ===================
- */
- static void TransferPaintBuffer(int endtime)
- {
- int out_idx;
- int count;
- int out_mask;
- int p;
- int step;
- int val;
- //unsigned long *pbuf;
-
- ByteBuffer pbuf = ByteBuffer.wrap(dma.buffer);
- pbuf.order(ByteOrder.LITTLE_ENDIAN);
-
- if (SND_DMA.s_testsound.value != 0.0f)
- {
- int i;
- int count2;
-
- // write a fixed sine wave
- count2 = (endtime - paintedtime)*2;
- int v;
- for (i=0 ; i<count2 ; i+=2) {
- v = (int)(Math.sin((paintedtime+i)*0.1)*20000*256);
- paintbuffer.put(i, v);
- paintbuffer.put(i+1, v);
- }
- }
-
-
- if (dma.samplebits == 16 && dma.channels == 2)
- { // optimized case
- TransferStereo16(pbuf, endtime);
- }
- else
- { // general case
- p = 0;
- count = (endtime - paintedtime) * dma.channels;
- out_mask = dma.samples - 1;
- out_idx = paintedtime * dma.channels & out_mask;
- step = 3 - dma.channels;
-
- if (dma.samplebits == 16)
- {
-// short *out = (short *) pbuf;
- ShortBuffer out = pbuf.asShortBuffer();
- while (count-- > 0)
- {
- val = paintbuffer.get(p) >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < (short)0x8000)
- val = (short)0x8000;
- out.put(out_idx, (short)val);
-//System.out.println(out_idx + " " + val);
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- else if (dma.samplebits == 8)
- {
-// unsigned char *out = (unsigned char *) pbuf;
- ByteBuffer out = pbuf;
- while (count-- > 0)
- {
- val = paintbuffer.get(p) >> 8;
- p += step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < (short)0x8000)
- val = (short)0x8000;
- out.put(out_idx,(byte)(val>>>8));
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- }
- }
-
-
- /*
- ===============================================================================
-
- CHANNEL MIXING
-
- ===============================================================================
- */
- static void PaintChannels(int endtime)
- {
- int i;
- int end;
- channel_t ch;
- sfxcache_t sc;
- int ltime, count;
- playsound_t ps;
-
- snd_vol = (int)(s_volume.value*256);
-
-// Com_Printf ("%i to %i\n", paintedtime, endtime);
- while (paintedtime < endtime)
- {
- // if paintbuffer is smaller than DMA buffer
- end = endtime;
- if (endtime - paintedtime > PAINTBUFFER_SIZE)
- end = paintedtime + PAINTBUFFER_SIZE;
-
- // start any playsounds
- while (true)
- {
- ps = s_pendingplays.next;
- if (ps == s_pendingplays)
- break; // no more pending sounds
- if (ps.begin <= paintedtime)
- {
- SND_DMA.IssuePlaysound(ps);
- continue;
- }
-
- if (ps.begin < end)
- end = (int)ps.begin; // stop here
- break;
- }
-
- // clear the paint buffer
- if (s_rawend < paintedtime)
- {
-// Com_Printf ("clear\n");
- for (i = 0; i < (end-paintedtime)*2; i++) {
- paintbuffer.put(i, 0);
- }
- //memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
- }
- else
- { // copy from the streaming sound source
- int s;
- int stop;
-
- stop = (end < s_rawend) ? end : s_rawend;
-
- for (i=paintedtime ; i<stop ; i++)
- {
- s = i&(MAX_RAW_SAMPLES-1);
- //paintbuffer[i-paintedtime] = s_rawsamples[s];
- paintbuffer.put((i-paintedtime)*2, s_rawsamples.get(2*s));
- paintbuffer.put((i-paintedtime)*2+1, s_rawsamples.get(2*s)+1);
- }
-// if (i != end)
-// Com_Printf ("partial stream\n");
-// else
-// Com_Printf ("full stream\n");
- for ( ; i<end ; i++)
- {
- //paintbuffer[i-paintedtime].left =
- //paintbuffer[i-paintedtime].right = 0;
- paintbuffer.put((i-paintedtime)*2, 0);
- paintbuffer.put((i-paintedtime)*2+1, 0);
- }
- }
-
-
- // paint in the channels.
- //ch = channels;
- for (i=0; i<MAX_CHANNELS ; i++)
- {
- ch = channels[i];
- ltime = paintedtime;
-
- while (ltime < end)
- {
- if (ch.sfx == null || (ch.leftvol == 0 && ch.rightvol == 0))
- break;
-
- // max painting is to the end of the buffer
- count = end - ltime;
-
- // might be stopped by running out of data
- if (ch.end - ltime < count)
- count = ch.end - ltime;
-
- sc = WaveLoader.LoadSound(ch.sfx);
- if (sc == null)
- break;
-
- if (count > 0 && ch.sfx != null)
- {
- if (sc.width == 1)// FIXME; 8 bit asm is wrong now
- PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
- else
- PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
-
- ltime += count;
- }
-
- // if at end of loop, restart
- if (ltime >= ch.end)
- {
- if (ch.autosound)
- { // autolooping sounds always go back to start
- ch.pos = 0;
- ch.end = ltime + sc.length;
- }
- else if (sc.loopstart >= 0)
- {
- ch.pos = sc.loopstart;
- ch.end = ltime + sc.length - ch.pos;
- }
- else
- { // channel just stopped
- ch.sfx = null;
- }
- }
- }
-
- }
-
- // transfer out according to DMA format
- TransferPaintBuffer(end);
- paintedtime = end;
- }
- }
-
- static void InitScaletable ()
- {
- int i, j;
- int scale;
-
- s_volume.modified = false;
- for (i=0 ; i<32 ; i++)
- {
- scale = (int)(i * 8 * 256 * s_volume.value);
- for (j=0 ; j<256 ; j++)
- snd_scaletable[i][j] = ((byte)j) * scale;
- }
- }
-
- static void PaintChannelFrom8(channel_t ch, sfxcache_t sc, int count, int offset)
- {
- int data;
- int[] lscale;
- int[] rscale;
- int sfx;
- int i;
- portable_samplepair_t samp;
-
- if (ch.leftvol > 255)
- ch.leftvol = 255;
- if (ch.rightvol > 255)
- ch.rightvol = 255;
-
- //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense
- //as it would always be zero.
- lscale = snd_scaletable[ ch.leftvol >> 3];
- rscale = snd_scaletable[ ch.rightvol >> 3];
- sfx = ch.pos;
-
- //samp = paintbuffer[offset];
-
- for (i=0 ; i<count ; i++, offset++)
- {
- int left = paintbuffer.get(offset*2);
- int right = paintbuffer.get(offset*2+1);
- data = sc.data[sfx+i];
- left += lscale[data];
- right += rscale[data];
- paintbuffer.put(offset*2, left);
- paintbuffer.put(offset*2+1, right);
- }
-
- ch.pos += count;
- }
-
- private static ByteBuffer bb;
- private static ShortBuffer sb;
- static void PaintChannelFrom16(channel_t ch, sfxcache_t sc, int count, int offset)
- {
- int data;
- int left, right;
- int leftvol, rightvol;
- int sfx;
- int i;
- portable_samplepair_t samp;
-
- leftvol = ch.leftvol*snd_vol;
- rightvol = ch.rightvol*snd_vol;
- ByteBuffer bb = ByteBuffer.wrap(sc.data);
- bb.order(ByteOrder.LITTLE_ENDIAN);
- sb = bb.asShortBuffer();
- sfx = ch.pos;
-
- //samp = paintbuffer[offset];
- for (i=0 ; i<count ; i++, offset++)
- {
- left = paintbuffer.get(offset*2);
- right = paintbuffer.get(offset*2+1);
- data = sb.get(sfx+i);
- left += (data * leftvol)>>8;
- right += (data * rightvol)>>8;
- paintbuffer.put(offset*2, left);
- paintbuffer.put(offset*2+1, right);
- }
-
- ch.pos += count;
- }
+ static final int MAX_CHANNELS = 32;
+
+ static final int MAX_RAW_SAMPLES = 8192;
+
+ static class playsound_t {
+ playsound_t prev, next;
+
+ sfx_t sfx;
+
+ float volume;
+
+ float attenuation;
+
+ int entnum;
+
+ int entchannel;
+
+ boolean fixed_origin; // use origin field instead of entnum's origin
+
+ float[] origin = { 0, 0, 0 };
+
+ long begin; // begin on this sample
+
+ public void clear() {
+ prev = next = null;
+ sfx = null;
+ volume = attenuation = begin = entnum = entchannel = 0;
+ fixed_origin = false;
+ Math3D.VectorClear(origin);
+ }
+ };
+
+ static class channel_t {
+ sfx_t sfx; // sfx number
+
+ int leftvol; // 0-255 volume
+
+ int rightvol; // 0-255 volume
+
+ int end; // end time in global paintsamples
+
+ int pos; // sample position in sfx
+
+ int looping; // where to loop, -1 = no looping OBSOLETE?
+
+ int entnum; // to allow overriding a specific sound
+
+ int entchannel; //
+
+ float[] origin = { 0, 0, 0 }; // only use if fixed_origin is set
+
+ float dist_mult; // distance multiplier (attenuation/clipK)
+
+ int master_vol; // 0-255 master volume
+
+ boolean fixed_origin; // use origin instead of fetching entnum's origin
+
+ boolean autosound; // from an entity->sound, cleared each frame
+
+ void clear() {
+ sfx = null;
+ dist_mult = leftvol = rightvol = end = pos = looping = entnum = entchannel = master_vol = 0;
+ Math3D.VectorClear(origin);
+ fixed_origin = autosound = false;
+ }
+ };
+
+ static class portable_samplepair_t {
+ int left;
+
+ int right;
+ };
+
+ static cvar_t s_volume;
+
+ static int s_rawend;
+
+ //// snd_mix.c -- portable code to mix sounds for snd_dma.c
+ //
+ // #include "client.h"
+ // #include "snd_loc.h"
+ //
+ static final int PAINTBUFFER_SIZE = 2048;
+
+ //static portable_samplepair_t[] paintbuffer = new
+ // portable_samplepair_t[PAINTBUFFER_SIZE];
+ static IntBuffer paintbuffer = IntBuffer.allocate(PAINTBUFFER_SIZE * 2);
+
+ static int[][] snd_scaletable = new int[32][256];
+
+ // int *snd_p, snd_linear_count, snd_vol;
+ // short *snd_out;
+ static IntBuffer snd_p;
+
+ static ShortBuffer snd_out;
+
+ static int snd_linear_count;
+
+ static int snd_vol;
+
+ static int paintedtime; // sample PAIRS
+
+ static playsound_t s_pendingplays = new playsound_t();
+
+ //static portable_samplepair_t[] s_rawsamples = new
+ // portable_samplepair_t[MAX_RAW_SAMPLES];
+ static IntBuffer s_rawsamples = IntBuffer.allocate(MAX_RAW_SAMPLES * 2);
+
+ static channel_t[] channels = new channel_t[MAX_CHANNELS];
+ static {
+ for (int i = 0; i < MAX_CHANNELS; i++)
+ channels[i] = new channel_t();
+ }
+
+ static void WriteLinearBlastStereo16() {
+ int i;
+ int val;
+
+ for (i = 0; i < snd_linear_count; i += 2) {
+ val = snd_p.get(i) >> 8;
+ if (val > 0x7fff)
+ snd_out.put(i, (short) 0x7fff);
+ else if (val < (short) 0x8000)
+ snd_out.put(i, (short) 0x8000);
+ else
+ snd_out.put(i, (short) val);
+
+ val = snd_p.get(i + 1) >> 8;
+ if (val > 0x7fff)
+ snd_out.put(i + 1, (short) 0x7fff);
+ else if (val < (short) 0x8000)
+ snd_out.put(i + 1, (short) 0x8000);
+ else
+ snd_out.put(i + 1, (short) val);
+ }
+ }
+
+ static void TransferStereo16(ByteBuffer pbuf, int endtime) {
+ int lpos;
+ int lpaintedtime;
+
+ snd_p = paintbuffer;
+ lpaintedtime = paintedtime;
+
+ while (lpaintedtime < endtime) {
+ // handle recirculating buffer issues
+ lpos = lpaintedtime & ((dma.samples >> 1) - 1);
+
+ // snd_out = (short *) pbuf + (lpos<<1);
+ snd_out = pbuf.asShortBuffer();
+ snd_out.position(lpos << 1);
+ snd_out = snd_out.slice();
+
+ snd_linear_count = (dma.samples >> 1) - lpos;
+ if (lpaintedtime + snd_linear_count > endtime)
+ snd_linear_count = endtime - lpaintedtime;
+
+ snd_linear_count <<= 1;
+
+ // write a linear blast of samples
+ WriteLinearBlastStereo16();
+
+ //snd_p += snd_linear_count;
+ paintbuffer.position(snd_linear_count);
+ snd_p = paintbuffer.slice();
+
+ lpaintedtime += (snd_linear_count >> 1);
+ }
+ }
+
+ /*
+ * =================== S_TransferPaintBuffer
+ *
+ * ===================
+ */
+ static void TransferPaintBuffer(int endtime) {
+ int out_idx;
+ int count;
+ int out_mask;
+ int p;
+ int step;
+ int val;
+ //unsigned long *pbuf;
+
+ ByteBuffer pbuf = ByteBuffer.wrap(dma.buffer);
+ pbuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ if (SND_DMA.s_testsound.value != 0.0f) {
+ int i;
+ int count2;
+
+ // write a fixed sine wave
+ count2 = (endtime - paintedtime) * 2;
+ int v;
+ for (i = 0; i < count2; i += 2) {
+ v = (int) (Math.sin((paintedtime + i) * 0.1) * 20000 * 256);
+ paintbuffer.put(i, v);
+ paintbuffer.put(i + 1, v);
+ }
+ }
+
+ if (dma.samplebits == 16 && dma.channels == 2) { // optimized case
+ TransferStereo16(pbuf, endtime);
+ } else { // general case
+ p = 0;
+ count = (endtime - paintedtime) * dma.channels;
+ out_mask = dma.samples - 1;
+ out_idx = paintedtime * dma.channels & out_mask;
+ step = 3 - dma.channels;
+
+ if (dma.samplebits == 16) {
+ // short *out = (short *) pbuf;
+ ShortBuffer out = pbuf.asShortBuffer();
+ while (count-- > 0) {
+ val = paintbuffer.get(p) >> 8;
+ p += step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < (short) 0x8000)
+ val = (short) 0x8000;
+ out.put(out_idx, (short) val);
+ //System.out.println(out_idx + " " + val);
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ } else if (dma.samplebits == 8) {
+ // unsigned char *out = (unsigned char *) pbuf;
+ ByteBuffer out = pbuf;
+ while (count-- > 0) {
+ val = paintbuffer.get(p) >> 8;
+ p += step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < (short) 0x8000)
+ val = (short) 0x8000;
+ out.put(out_idx, (byte) (val >>> 8));
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ }
+ }
+
+ /*
+ * ===============================================================================
+ *
+ * CHANNEL MIXING
+ *
+ * ===============================================================================
+ */
+ static void PaintChannels(int endtime) {
+ int i;
+ int end;
+ channel_t ch;
+ sfxcache_t sc;
+ int ltime, count;
+ playsound_t ps;
+
+ snd_vol = (int) (s_volume.value * 256);
+
+ // Com_Printf ("%i to %i\n", paintedtime, endtime);
+ while (paintedtime < endtime) {
+ // if paintbuffer is smaller than DMA buffer
+ end = endtime;
+ if (endtime - paintedtime > PAINTBUFFER_SIZE)
+ end = paintedtime + PAINTBUFFER_SIZE;
+
+ // start any playsounds
+ while (true) {
+ ps = s_pendingplays.next;
+ if (ps == s_pendingplays)
+ break; // no more pending sounds
+ if (ps.begin <= paintedtime) {
+ SND_DMA.IssuePlaysound(ps);
+ continue;
+ }
+
+ if (ps.begin < end)
+ end = (int) ps.begin; // stop here
+ break;
+ }
+
+ // clear the paint buffer
+ if (s_rawend < paintedtime) {
+ // Com_Printf ("clear\n");
+ for (i = 0; i < (end - paintedtime) * 2; i++) {
+ paintbuffer.put(i, 0);
+ }
+ //memset(paintbuffer, 0, (end - paintedtime) *
+ // sizeof(portable_samplepair_t));
+ } else { // copy from the streaming sound source
+ int s;
+ int stop;
+
+ stop = (end < s_rawend) ? end : s_rawend;
+
+ for (i = paintedtime; i < stop; i++) {
+ s = i & (MAX_RAW_SAMPLES - 1);
+ //paintbuffer[i-paintedtime] = s_rawsamples[s];
+ paintbuffer.put((i - paintedtime) * 2, s_rawsamples
+ .get(2 * s));
+ paintbuffer.put((i - paintedtime) * 2 + 1, s_rawsamples
+ .get(2 * s) + 1);
+ }
+ // if (i != end)
+ // Com_Printf ("partial stream\n");
+ // else
+ // Com_Printf ("full stream\n");
+ for (; i < end; i++) {
+ //paintbuffer[i-paintedtime].left =
+ //paintbuffer[i-paintedtime].right = 0;
+ paintbuffer.put((i - paintedtime) * 2, 0);
+ paintbuffer.put((i - paintedtime) * 2 + 1, 0);
+ }
+ }
+
+ // paint in the channels.
+ //ch = channels;
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ ch = channels[i];
+ ltime = paintedtime;
+
+ while (ltime < end) {
+ if (ch.sfx == null || (ch.leftvol == 0 && ch.rightvol == 0))
+ break;
+
+ // max painting is to the end of the buffer
+ count = end - ltime;
+
+ // might be stopped by running out of data
+ if (ch.end - ltime < count)
+ count = ch.end - ltime;
+
+ sc = WaveLoader.LoadSound(ch.sfx);
+ if (sc == null)
+ break;
+
+ if (count > 0 && ch.sfx != null) {
+ if (sc.width == 1)// FIXME; 8 bit asm is wrong now
+ PaintChannelFrom8(ch, sc, count, ltime
+ - paintedtime);
+ else
+ PaintChannelFrom16(ch, sc, count, ltime
+ - paintedtime);
+
+ ltime += count;
+ }
+
+ // if at end of loop, restart
+ if (ltime >= ch.end) {
+ if (ch.autosound) { // autolooping sounds always go back
+ // to start
+ ch.pos = 0;
+ ch.end = ltime + sc.length;
+ } else if (sc.loopstart >= 0) {
+ ch.pos = sc.loopstart;
+ ch.end = ltime + sc.length - ch.pos;
+ } else { // channel just stopped
+ ch.sfx = null;
+ }
+ }
+ }
+
+ }
+
+ // transfer out according to DMA format
+ TransferPaintBuffer(end);
+ paintedtime = end;
+ }
+ }
+
+ static void InitScaletable() {
+ int i, j;
+ int scale;
+
+ s_volume.modified = false;
+ for (i = 0; i < 32; i++) {
+ scale = (int) (i * 8 * 256 * s_volume.value);
+ for (j = 0; j < 256; j++)
+ snd_scaletable[i][j] = ((byte) j) * scale;
+ }
+ }
+
+ static void PaintChannelFrom8(channel_t ch, sfxcache_t sc, int count,
+ int offset) {
+ int data;
+ int[] lscale;
+ int[] rscale;
+ int sfx;
+ int i;
+ portable_samplepair_t samp;
+
+ if (ch.leftvol > 255)
+ ch.leftvol = 255;
+ if (ch.rightvol > 255)
+ ch.rightvol = 255;
+
+ //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense
+ //as it would always be zero.
+ lscale = snd_scaletable[ch.leftvol >> 3];
+ rscale = snd_scaletable[ch.rightvol >> 3];
+ sfx = ch.pos;
+
+ //samp = paintbuffer[offset];
+
+ for (i = 0; i < count; i++, offset++) {
+ int left = paintbuffer.get(offset * 2);
+ int right = paintbuffer.get(offset * 2 + 1);
+ data = sc.data[sfx + i];
+ left += lscale[data];
+ right += rscale[data];
+ paintbuffer.put(offset * 2, left);
+ paintbuffer.put(offset * 2 + 1, right);
+ }
+
+ ch.pos += count;
+ }
+
+ private static ByteBuffer bb;
+
+ private static ShortBuffer sb;
+
+ static void PaintChannelFrom16(channel_t ch, sfxcache_t sc, int count,
+ int offset) {
+ int data;
+ int left, right;
+ int leftvol, rightvol;
+ int sfx;
+ int i;
+ portable_samplepair_t samp;
+
+ leftvol = ch.leftvol * snd_vol;
+ rightvol = ch.rightvol * snd_vol;
+ ByteBuffer bb = ByteBuffer.wrap(sc.data);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ sb = bb.asShortBuffer();
+ sfx = ch.pos;
+
+ //samp = paintbuffer[offset];
+ for (i = 0; i < count; i++, offset++) {
+ left = paintbuffer.get(offset * 2);
+ right = paintbuffer.get(offset * 2 + 1);
+ data = sb.get(sfx + i);
+ left += (data * leftvol) >> 8;
+ right += (data * rightvol) >> 8;
+ paintbuffer.put(offset * 2, left);
+ paintbuffer.put(offset * 2 + 1, right);
+ }
+
+ ch.pos += count;
+ }
} \ No newline at end of file