aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/jake2/sound/lwjgl/Channel.java334
-rw-r--r--src/jake2/sound/lwjgl/LWJGLSoundImpl.java351
-rw-r--r--src/jake2/sound/lwjgl/PlaySound.java169
3 files changed, 515 insertions, 339 deletions
diff --git a/src/jake2/sound/lwjgl/Channel.java b/src/jake2/sound/lwjgl/Channel.java
index c197191..c136331 100644
--- a/src/jake2/sound/lwjgl/Channel.java
+++ b/src/jake2/sound/lwjgl/Channel.java
@@ -3,7 +3,7 @@
*
* Copyright (C) 2003
*
- * $Id: Channel.java,v 1.1 2004-12-16 20:17:55 cawe Exp $
+ * $Id: Channel.java,v 1.2 2004-12-23 00:52:12 cawe Exp $
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.
@@ -26,59 +26,325 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package jake2.sound.lwjgl;
+import jake2.Defines;
+import jake2.Globals;
+import jake2.client.CL_ents;
+import jake2.game.entity_state_t;
+import jake2.sound.sfx_t;
+import jake2.sound.sfxcache_t;
+import jake2.util.Lib;
+import jake2.util.Math3D;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.*;
+
+import org.lwjgl.openal.AL10;
+
/**
* Channel
*
- * @author cwei
+ * @author dsanders/cwei
*/
public class Channel {
final static int LISTENER = 0;
final static int FIXED = 1;
final static int DYNAMIC = 2;
-
- int entnum;
- int entchannel;
- int bufferId;
- float rolloff;
- boolean autosound = false;
- int sourceId;
- boolean active = false;
- boolean modified = false;
- boolean bufferChanged = false;
+ final static int MAX_CHANNELS = 32;
+ private final static FloatBuffer NULLVECTOR = Lib.newFloatBuffer(3);
+ private static Channel[] channels = new Channel[MAX_CHANNELS];
+ private static IntBuffer sources = Lib.newIntBuffer(MAX_CHANNELS);
+ // a reference of L:WJGLSoundImpl.buffers
+ private static IntBuffer buffers;
+ private static Map looptable = new Hashtable(MAX_CHANNELS);
+
+ private static boolean isInitialized = false;
+ private static int numChannels;
+
// sound attributes
- int type;
- int entity;
- float[] origin = {0, 0, 0};
-
- Channel(int sourceId) {
+ private int type;
+ private int entnum;
+ private int entchannel;
+ private int bufferId;
+ private int sourceId;
+ // private float volume;
+ private float rolloff;
+ private float[] origin = {0, 0, 0};
+
+ // update flags
+ private boolean autosound = false;
+ private boolean active = false;
+ private boolean modified = false;
+ private boolean bufferChanged = false;
+
+ private Channel(int sourceId) {
this.sourceId = sourceId;
clear();
}
- void addListener() {
- type = LISTENER;
+ private void clear() {
+ entnum = entchannel = bufferId = -1;
+ bufferChanged = false;
+ // volume = 1.0f;
+ rolloff = 0;
+ autosound = false;
+ active = false;
+ modified = false;
+ }
+
+ private static IntBuffer tmp = Lib.newIntBuffer(1);
+
+ static int init(IntBuffer buffers, float masterVolume) {
+ Channel.buffers = buffers;
+ // create channels
+ int sourceId;
+ int error;
+ for (int i = 0; i < MAX_CHANNELS; i++) {
+
+ AL10.alGenSources(tmp);
+ sourceId = tmp.get(0);
+
+ if (sourceId <= 0) break;
+
+ sources.put(i, sourceId);
+
+ channels[i] = new Channel(sourceId);
+ numChannels++;
+
+ // set default values for AL sources
+ AL10.alSourcef (sourceId, AL10.AL_GAIN, masterVolume);
+ AL10.alSourcef (sourceId, AL10.AL_PITCH, 1.0f);
+ AL10.alSourcei (sourceId, AL10.AL_SOURCE_ABSOLUTE, AL10.AL_TRUE);
+ AL10.nalSourcefv(sourceId, AL10.AL_VELOCITY, NULLVECTOR, 0);
+ AL10.alSourcei (sourceId, AL10.AL_LOOPING, AL10.AL_FALSE);
+ AL10.alSourcef (sourceId, AL10.AL_REFERENCE_DISTANCE, 300.0f);
+ AL10.alSourcef (sourceId, AL10.AL_MIN_GAIN, 0.0005f);
+ AL10.alSourcef (sourceId, AL10.AL_MAX_GAIN, 1.0f);
+ }
+ isInitialized = true;
+ return numChannels;
+ }
+
+ static void reset() {
+ for (int i = 0; i < numChannels; i++) {
+ AL10.alSourceStop(sources.get(i));
+ AL10.alSourcei(sources.get(i), AL10.AL_BUFFER, 0);
+ channels[i].clear();
+ }
+ }
+
+ static void shutdown() {
+ AL10.alDeleteSources(sources);
+ numChannels = 0;
+ isInitialized = false;
+ }
+
+ static void addPlaySounds() {
+ while (Channel.assign(PlaySound.nextPlayableSound()));
}
+
+ private static boolean assign(PlaySound ps) {
+ if (ps == null) return false;
+ Channel ch = null;
+ int i;
+ for (i = 0; i < numChannels; i++) {
+ ch = channels[i];
+
+ if (ps.entchannel != 0 && ch.entnum == ps.entnum && ch.entchannel == ps.entchannel) {
+ // always override sound from same entity
+ if (ch.bufferId != ps.bufferId) {
+ AL10.alSourceStop(ch.sourceId);
+ }
+ break;
+ }
+
+ // don't let monster sounds override player sounds
+ if ((ch.entnum == Globals.cl.playernum+1) && (ps.entnum != Globals.cl.playernum+1) && ch.bufferId != -1)
+ continue;
+
+ // looking for a free AL source
+ if (!ch.active) {
+ break;
+ }
+ }
- void addFixed(float[] origin) {
- type = FIXED;
- this.origin = origin;
+ if (i == numChannels)
+ return false;
+
+ ch.type = ps.type;
+ if (ps.type == Channel.FIXED)
+ Math3D.VectorCopy(ps.origin, ch.origin);
+ ch.entnum = ps.entnum;
+ ch.entchannel = ps.entchannel;
+ ch.bufferChanged = (ch.bufferId != ps.bufferId);
+ ch.bufferId = ps.bufferId;
+ ch.rolloff = ps.attenuation * 2;
+ //ch.volume = ps.volume;
+ ch.active = true;
+ ch.modified = true;
+ return true;
}
+
+ private static Channel pickForLoop(int bufferId, float attenuation) {
+ Channel ch;
+ for (int i = 0; i < numChannels; i++) {
+ ch = channels[i];
+ // looking for a free AL source
+ if (!ch.active) {
+ ch.entnum = 0;
+ ch.entchannel = 0;
+ ch.bufferChanged = (ch.bufferId != bufferId);
+ ch.bufferId = bufferId;
+ ch.rolloff = attenuation * 2;
+ ch.active = true;
+ ch.modified = true;
+ return ch;
+ }
+ }
+ return null;
+ }
+
+ private static FloatBuffer sourceOriginBuffer = Lib.newFloatBuffer(3);
+
+ static void playAllSounds(FloatBuffer listenerOrigin, float masterVolume) {
+ float[] entityOrigin = {0, 0, 0};
+ FloatBuffer sourceOrigin = sourceOriginBuffer;
+ Channel ch;
+ int sourceId;
+ int state;
- void addDynamic(int entity) {
- type = DYNAMIC;
- this.entity = entity;
+ for (int i = 0; i < numChannels; i++) {
+ ch = channels[i];
+ if (ch.active) {
+ sourceId = ch.sourceId;
+ switch (ch.type) {
+ case Channel.LISTENER:
+ sourceOrigin = listenerOrigin;
+ break;
+ case Channel.DYNAMIC:
+ CL_ents.GetEntitySoundOrigin(ch.entnum, entityOrigin);
+ convertVector(entityOrigin, sourceOrigin);
+ break;
+ case Channel.FIXED:
+ convertVector(ch.origin, sourceOrigin);
+ break;
+ }
+
+ if (ch.modified) {
+ if (ch.bufferChanged) {
+ AL10.alSourcei(sourceId, AL10.AL_BUFFER, ch.bufferId);
+ }
+// AL10.alSourcef (sourceId, AL10.AL_GAIN, masterVolume * ch.volume);
+ AL10.alSourcef (sourceId, AL10.AL_GAIN, masterVolume);
+ AL10.alSourcef (sourceId, AL10.AL_ROLLOFF_FACTOR, ch.rolloff);
+ AL10.nalSourcefv(sourceId, AL10.AL_POSITION, sourceOrigin, 0);
+ AL10.alSourcePlay(sourceId);
+ ch.modified = false;
+ } else {
+ state = AL10.alGetSourcei(sourceId, AL10.AL_SOURCE_STATE);
+ if (state == AL10.AL_PLAYING) {
+ AL10.nalSourcefv(sourceId, AL10.AL_POSITION, sourceOrigin, 0);
+ } else {
+ ch.clear();
+ }
+ }
+ ch.autosound = false;
+ }
+ }
}
- void clear() {
- entnum = -1;
- entchannel = -1;
- bufferId = -1;
- bufferChanged = false;
- rolloff = 0;
- autosound = false;
- active = false;
- modified = false;
+ /*
+ * adddLoopSounds
+ * 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() {
+
+ if ((Globals.cl_paused.value != 0.0f) || (Globals.cls.state != Globals.ca_active) || !Globals.cl.sound_prepped) {
+ removeUnusedLoopSounds();
+ return;
+ }
+
+ Channel ch;
+ sfx_t sfx;
+ sfxcache_t sc;
+ int num;
+ entity_state_t ent;
+ Object key;
+ int sound = 0;
+
+ for (int i=0 ; i<Globals.cl.frame.num_entities ; i++) {
+ num = (Globals.cl.frame.parse_entities + i)&(Defines.MAX_PARSE_ENTITIES-1);
+ ent = Globals.cl_parse_entities[num];
+ sound = ent.sound;
+
+ if (sound == 0) continue;
+
+ key = new Integer(ent.number);
+ ch = (Channel)looptable.get(key);
+
+ if (ch != null) {
+ // keep on looping
+ ch.autosound = true;
+ Math3D.VectorCopy(ent.origin, ch.origin);
+ continue;
+ }
+
+ sfx = Globals.cl.sound_precache[sound];
+ if (sfx == null)
+ continue; // bad sound effect
+
+ sc = sfx.cache;
+ if (sc == null)
+ continue;
+
+ // allocate a channel
+ ch = Channel.pickForLoop(buffers.get(sfx.bufferId), 6);
+ if (ch == null)
+ break;
+
+ ch.type = FIXED;
+ Math3D.VectorCopy(ent.origin, ch.origin);
+ ch.autosound = true;
+
+ looptable.put(key, ch);
+ AL10.alSourcei(ch.sourceId, AL10.AL_LOOPING, AL10.AL_TRUE);
+ }
+
+ removeUnusedLoopSounds();
+
}
+
+ private static void removeUnusedLoopSounds() {
+ Channel ch;
+ // stop unused loopsounds
+ for (Iterator iter = looptable.values().iterator(); iter.hasNext();) {
+ ch = (Channel)iter.next();
+ if (!ch.autosound) {
+ AL10.alSourceStop(ch.sourceId);
+ AL10.alSourcei(ch.sourceId, AL10.AL_LOOPING, AL10.AL_FALSE);
+ iter.remove();
+ ch.clear();
+ }
+ }
+ }
+
+ static void convertVector(float[] from, FloatBuffer to) {
+ to.put(0, from[0]);
+ to.put(1, from[2]);
+ to.put(2, -from[1]);
+ }
+
+ static void convertOrientation(float[] forward, float[] up, FloatBuffer orientation) {
+ orientation.put(0, forward[0]);
+ orientation.put(1, forward[2]);
+ orientation.put(2, -forward[1]);
+ orientation.put(3, up[0]);
+ orientation.put(4, up[2]);
+ orientation.put(5, -up[1]);
+ }
+
}
diff --git a/src/jake2/sound/lwjgl/LWJGLSoundImpl.java b/src/jake2/sound/lwjgl/LWJGLSoundImpl.java
index ea1cdc3..eb8ed8c 100644
--- a/src/jake2/sound/lwjgl/LWJGLSoundImpl.java
+++ b/src/jake2/sound/lwjgl/LWJGLSoundImpl.java
@@ -2,33 +2,28 @@
* LWJGLSoundImpl.java
* Copyright (C) 2004
*
- * $Id: LWJGLSoundImpl.java,v 1.3 2004-12-21 00:42:31 cawe Exp $
+ * $Id: LWJGLSoundImpl.java,v 1.4 2004-12-23 00:52:12 cawe Exp $
*/
package jake2.sound.lwjgl;
import jake2.Defines;
import jake2.Globals;
-import jake2.client.CL;
-import jake2.client.CL_ents;
import jake2.game.*;
import jake2.qcommon.*;
import jake2.sound.*;
-import jake2.util.*;
+import jake2.util.Lib;
+import jake2.util.Vargs;
-import java.io.IOException;
-import java.io.RandomAccessFile;
import java.nio.*;
-import java.util.*;
-import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.openal.*;
import org.lwjgl.openal.eax.*;
-import org.lwjgl.openal.eax.EAX20;
-import org.lwjgl.openal.eax.EAXListenerProperties;
/**
* LWJGLSoundImpl
+ *
+ * @author dsanders/cwei
*/
public final class LWJGLSoundImpl implements Sound {
@@ -41,12 +36,8 @@ public final class LWJGLSoundImpl implements Sound {
private cvar_t s_volume;
private static final int MAX_SFX = Defines.MAX_SOUNDS * 2;
- private static final int MAX_CHANNELS = 32;
- private IntBuffer buffers = BufferUtils.createIntBuffer(MAX_SFX);
- private IntBuffer sources = BufferUtils.createIntBuffer(MAX_CHANNELS);
- private Channel[] channels = null;
- private int num_channels = 0;
+ private IntBuffer buffers = Lib.newIntBuffer(MAX_SFX);
// singleton
private LWJGLSoundImpl() {
@@ -71,7 +62,8 @@ public final class LWJGLSoundImpl implements Sound {
AL10.alGenBuffers(buffers);
s_volume = Cvar.Get("s_volume", "0.7", Defines.CVAR_ARCHIVE);
- initChannels();
+ int count = Channel.init(buffers, s_volume.value);
+ Com.Printf("... using " + count + " channels\n");
AL10.alDistanceModel(AL10.AL_INVERSE_DISTANCE_CLAMPED);
Cmd.AddCommand("play", new xcommand_t() {
public void execute() {
@@ -96,7 +88,6 @@ public final class LWJGLSoundImpl implements Sound {
num_sfx = 0;
-
Com.Printf("sound sampling rate: 44100Hz\n");
StopAllSounds();
@@ -158,40 +149,9 @@ public final class LWJGLSoundImpl implements Sound {
AL.destroy();
}
- private void initChannels() {
-
- // create channels
- channels = new Channel[MAX_CHANNELS];
-
- int sourceId;
- IntBuffer tmp = BufferUtils.createIntBuffer(1);
- int error;
- for (int i = 0; i < MAX_CHANNELS; i++) {
-
- AL10.alGenSources(tmp);
- sourceId = tmp.get(0);
-
- //if ((error = al.alGetError()) != AL.AL_NO_ERROR) break;
- if (sourceId <= 0) break;
-
- sources.put(i, sourceId);
-
- channels[i] = new Channel(sourceId);
- num_channels++;
-
- // set default values for AL sources
- AL10.alSourcef (sourceId, AL10.AL_GAIN, s_volume.value);
- AL10.alSourcef (sourceId, AL10.AL_PITCH, 1.0f);
- AL10.alSourcei (sourceId, AL10.AL_SOURCE_ABSOLUTE, AL10.AL_TRUE);
- AL10.nalSourcefv(sourceId, AL10.AL_VELOCITY, NULLVECTOR_BUFFER,0);
- AL10.alSourcei (sourceId, AL10.AL_LOOPING, AL10.AL_FALSE);
- AL10.alSourcef (sourceId, AL10.AL_REFERENCE_DISTANCE, 300.0f);
- AL10.alSourcef (sourceId, AL10.AL_MIN_GAIN, 0.0005f);
- AL10.alSourcef (sourceId, AL10.AL_MAX_GAIN, 1.0f);
- }
- Com.Printf("... using " + num_channels + " channels\n");
- }
-
+ // TODO check the sfx direct buffer size
+ // 2MB sfx buffer
+ ByteBuffer sfxDataBuffer = Lib.newByteBuffer(2 * 1024 * 1024);
/* (non-Javadoc)
* @see jake2.sound.SoundImpl#RegisterSound(jake2.sound.sfx_t)
@@ -203,9 +163,10 @@ public final class LWJGLSoundImpl implements Sound {
}
int format = AL10.AL_FORMAT_MONO16;
- ByteBuffer data = BufferUtils.createByteBuffer(sfx.cache.data.length);
- data.put(sfx.cache.data);
+ ByteBuffer data = sfxDataBuffer.slice();
+ data.put(sfx.cache.data, 0, sfx.cache.data.length);
data.rewind();
+ data.limit(sfx.cache.data.length);
int freq = sfx.cache.speed;
AL10.alBufferData( buffers.get(sfx.bufferId), format, data, freq);
@@ -235,8 +196,7 @@ public final class LWJGLSoundImpl implements Sound {
*/
public void Shutdown() {
StopAllSounds();
-
- AL10.alDeleteSources(sources);
+ Channel.shutdown();
AL10.alDeleteBuffers(buffers);
exitOpenAL();
@@ -252,14 +212,8 @@ public final class LWJGLSoundImpl implements Sound {
known_sfx[i].clear();
}
num_sfx = 0;
- num_channels = 0;
}
- //private final static float[] NULLVECTOR = {0, 0, 0};
- private final static FloatBuffer NULLVECTOR_BUFFER=Lib.newFloatBuffer(3);
- private float[] entityOrigin = {0, 0, 0};
- private float[] sourceOrigin = {0, 0, 0};
-
/* (non-Javadoc)
* @see jake2.sound.SoundImpl#StartSound(float[], int, int, jake2.sound.sfx_t, float, float, float)
*/
@@ -277,75 +231,22 @@ public final class LWJGLSoundImpl implements Sound {
if (attenuation != Defines.ATTN_STATIC)
attenuation *= 0.5f;
- Channel ch = pickChannel(entnum, entchannel, buffers.get(sfx.bufferId), attenuation);
-
- if (ch == null) return;
-
- if (entnum == Globals.cl.playernum + 1) {
- ch.addListener();
- } else if (origin != null) {
- ch.addFixed(origin);
- } else {
- ch.addDynamic(entnum);
- }
- }
-
- Channel pickChannel(int entnum, int entchannel, int bufferId, float rolloff) {
-
- Channel ch = null;
- int state;
- int i;
-
- for (i = 0; i < num_channels; i++) {
- ch = channels[i];
-
- if (entchannel != 0 && ch.entnum == entnum && ch.entchannel == entchannel) {
- // always override sound from same entity
- break;
- }
-
- // don't let monster sounds override player sounds
- if ((ch.entnum == Globals.cl.playernum+1) && (entnum != Globals.cl.playernum+1) && ch.bufferId != -1)
- continue;
-
- // looking for a free AL source
- if (!ch.active) {
- break;
- }
- }
-
- if (i == num_channels)
- return null;
-
- ch.entnum = entnum;
- ch.entchannel = entchannel;
- if (ch.bufferId != bufferId) {
- ch.bufferId = bufferId;
- ch.bufferChanged = true;
- }
- ch.rolloff = rolloff * 2;
- ch.active = true;
- ch.modified = true;
-
- return ch;
+ PlaySound.allocate(origin, entnum, entchannel, buffers.get(sfx.bufferId), fvol, attenuation, timeofs);
}
- private float[] listenerOrigin = {0, 0, 0};
- private FloatBuffer listenerOriginBuffer=FloatBuffer.wrap(listenerOrigin);
-
- private float[] listenerOrientation = {0, 0, 0, 0, 0, 0};
- private FloatBuffer listenerOrientationBuffer=FloatBuffer.wrap(listenerOrientation);
+ private FloatBuffer listenerOrigin = Lib.newFloatBuffer(3);
+ private FloatBuffer listenerOrientation = Lib.newFloatBuffer(6);
/* (non-Javadoc)
* @see jake2.sound.SoundImpl#Update(float[], float[], float[], float[])
*/
public void Update(float[] origin, float[] forward, float[] right, float[] up) {
- convertVector(origin, listenerOrigin);
- AL10.nalListenerfv(AL10.AL_POSITION, listenerOriginBuffer,0);
+ Channel.convertVector(origin, listenerOrigin);
+ AL10.nalListenerfv(AL10.AL_POSITION, listenerOrigin, 0);
- convertOrientation(forward, up, listenerOrientation);
- AL10.nalListenerfv(AL10.AL_ORIENTATION, listenerOrientationBuffer,0);
+ Channel.convertOrientation(forward, up, listenerOrientation);
+ AL10.nalListenerfv(AL10.AL_ORIENTATION, listenerOrientation, 0);
if (hasEAX){
if ((GameBase.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) {
@@ -355,8 +256,9 @@ public final class LWJGLSoundImpl implements Sound {
}
}
- AddLoopSounds(origin);
- playChannels(listenerOrigin);
+ Channel.addLoopSounds();
+ Channel.addPlaySounds();
+ Channel.playAllSounds(listenerOrigin, s_volume.value);
}
private IntBuffer eaxEnv = Lib.newIntBuffer(1);
@@ -368,172 +270,13 @@ public final class LWJGLSoundImpl implements Sound {
eaxEnv.put(0, currentEnv);
EAX20.eaxSet(EAX20.LISTENER_GUID, EAXListenerProperties.EAXLISTENER_ENVIRONMENT | EAXListenerProperties.EAXLISTENER_DEFERRED, 0, eaxEnv, 4);
}
-
- Map looptable = new Hashtable(MAX_CHANNELS);
-
- /*
- ==================
- 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 AddLoopSounds(float[] listener) {
-
- if (Globals.cl_paused.value != 0.0f) {
- removeUnusedLoopSounds();
- return;
- }
-
- if (Globals.cls.state != Globals.ca_active) {
- removeUnusedLoopSounds();
- return;
- }
-
- if (!Globals.cl.sound_prepped) {
- removeUnusedLoopSounds();
- return;
- }
-
- Channel ch;
- sfx_t sfx;
- sfxcache_t sc;
- int num;
- entity_state_t ent;
- Object key;
- int sound = 0;
-
- for (int i=0 ; i<Globals.cl.frame.num_entities ; i++) {
- num = (Globals.cl.frame.parse_entities + i)&(Defines.MAX_PARSE_ENTITIES-1);
- ent = Globals.cl_parse_entities[num];
- sound = ent.sound;
-
- if (sound == 0) continue;
-
- key = new Integer(ent.number);
- ch = (Channel)looptable.get(key);
-
- if (ch != null) {
- // keep on looping
- ch.autosound = true;
- ch.origin = ent.origin;
- continue;
- }
-
- sfx = Globals.cl.sound_precache[sound];
- if (sfx == null)
- continue; // bad sound effect
-
- sc = sfx.cache;
- if (sc == null)
- continue;
-
- // allocate a channel
- ch = pickChannel(0, 0, buffers.get(sfx.bufferId), 6);
- if (ch == null)
- break;
-
- ch.addFixed(ent.origin);
- ch.autosound = true;
-
- looptable.put(key, ch);
- AL10.alSourcei(ch.sourceId, AL10.AL_LOOPING, AL10.AL_TRUE);
- }
-
- removeUnusedLoopSounds();
-
- }
-
- void removeUnusedLoopSounds() {
- Channel ch;
- // stop unused loopsounds
- for (Iterator iter = looptable.values().iterator(); iter.hasNext();) {
- ch = (Channel)iter.next();
- if (!ch.autosound) {
- AL10.alSourceStop(ch.sourceId);
- AL10.alSourcei(ch.sourceId, AL10.AL_LOOPING, AL10.AL_FALSE);
- iter.remove();
- ch.clear();
- }
- }
- }
-
- void playChannels(float[] listenerOrigin)
- {
- float[] sourceOrigin = {0, 0, 0};
- FloatBuffer sourceOriginBuffer=FloatBuffer.wrap(sourceOrigin);
-
- float[] entityOrigin = {0, 0, 0};
- Channel ch;
- int sourceId;
- int state;
-
- for (int i = 0; i < num_channels; i++) {
- ch = channels[i];
- if (ch.active) {
- sourceId = ch.sourceId;
-
- switch (ch.type) {
- case Channel.LISTENER:
- Math3D.VectorCopy(listenerOrigin, sourceOrigin);
- break;
- case Channel.DYNAMIC:
- CL_ents.GetEntitySoundOrigin(ch.entity, entityOrigin);
- convertVector(entityOrigin, sourceOrigin);
- break;
- case Channel.FIXED:
- convertVector(ch.origin, sourceOrigin);
- break;
- }
-
- if (ch.modified) {
- if (ch.bufferChanged)
- AL10.alSourcei (sourceId, AL10.AL_BUFFER, ch.bufferId);
-
- AL10.alSourcef (sourceId, AL10.AL_GAIN, s_volume.value);
- AL10.alSourcef (sourceId, AL10.AL_ROLLOFF_FACTOR, ch.rolloff);
- AL10.nalSourcefv(sourceId, AL10.AL_POSITION, sourceOriginBuffer,0);
- AL10.alSourcePlay(sourceId);
- ch.modified = false;
- } else {
- state = AL10.alGetSourcei(ch.sourceId, AL10.AL_SOURCE_STATE);
- if (state == AL10.AL_PLAYING) {
- AL10.nalSourcefv(sourceId, AL10.AL_POSITION, sourceOriginBuffer,0);
- } else {
- ch.clear();
- }
- }
- ch.autosound = false;
- }
- }
- }
/* (non-Javadoc)
* @see jake2.sound.SoundImpl#StopAllSounds()
*/
public void StopAllSounds() {
- for (int i = 0; i < num_channels; i++) {
- AL10.alSourceStop(sources.get(i));
- AL10.alSourcei(sources.get(i), AL10.AL_BUFFER, 0);
- channels[i].clear();
- }
- }
-
- static void convertVector(float[] from, float[] to) {
- to[0] = from[0];
- to[1] = from[2];
- to[2] = -from[1];
- }
-
- static void convertOrientation(float[] forward, float[] up, float[] orientation) {
- orientation[0] = forward[0];
- orientation[1] = forward[2];
- orientation[2] = -forward[1];
- orientation[3] = up[0];
- orientation[4] = up[2];
- orientation[5] = -up[1];
+ PlaySound.reset();
+ Channel.reset();
}
/* (non-Javadoc)
@@ -543,7 +286,6 @@ public final class LWJGLSoundImpl implements Sound {
return "lwjgl";
}
-
int s_registration_sequence;
boolean s_registering;
@@ -603,8 +345,7 @@ public final class LWJGLSoundImpl implements Sound {
sfx_t sfx = null;
// determine what model the client is using
- // TODO configstrings for player male and female are wrong
- String model = "male";
+ String model = null;
int n = Globals.CS_PLAYERSKINS + ent.number - 1;
if (Globals.cl.configstrings[n] != null) {
int p = Globals.cl.configstrings[n].indexOf('\\');
@@ -626,25 +367,25 @@ public final class LWJGLSoundImpl implements Sound {
//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
- String maleFilename = "player/male/" + base.substring(1);
- sfx = AliasName(sexedFilename, maleFilename);
- }
+ if (sfx != null) return sfx;
+
+ //
+ // fall back strategies
+ //
+ // not found , so see if it exists
+ if (FS.FileLength(sexedFilename.substring(1)) > 0) {
+ // yes, register it
+ return RegisterSound(sexedFilename);
}
- return sfx;
+ // try it with the female sound in the pak0.pak
+ if (model.equalsIgnoreCase("female")) {
+ String femaleFilename = "player/female/" + base.substring(1);
+ if (FS.FileLength("sound/" + femaleFilename) > 0)
+ return AliasName(sexedFilename, femaleFilename);
+ }
+ // no chance, revert to the male sound in the pak0.pak
+ String maleFilename = "player/male/" + base.substring(1);
+ return AliasName(sexedFilename, maleFilename);
}
diff --git a/src/jake2/sound/lwjgl/PlaySound.java b/src/jake2/sound/lwjgl/PlaySound.java
new file mode 100644
index 0000000..703e80c
--- /dev/null
+++ b/src/jake2/sound/lwjgl/PlaySound.java
@@ -0,0 +1,169 @@
+/*
+ * Created on Dec 22, 2004
+ *
+ * Copyright (C) 2003
+ *
+ * $Id: PlaySound.java,v 1.1 2004-12-23 00:52:12 cawe Exp $
+ */
+/*
+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.
+
+*/
+package jake2.sound.lwjgl;
+
+import jake2.Globals;
+import jake2.util.Math3D;
+
+/**
+ * PlaySound
+ *
+ * @author cwei
+ */
+public class PlaySound {
+
+ final static int MAX_PLAYSOUNDS = 128;
+
+ // list with sentinel
+ private static PlaySound freeList;
+ private static PlaySound playableList;
+
+ private static PlaySound[] backbuffer = new PlaySound[MAX_PLAYSOUNDS];
+ static {
+ for (int i = 0; i < backbuffer.length; i++) {
+ backbuffer[i] = new PlaySound();
+ }
+ // init the sentinels
+ freeList = new PlaySound();
+ playableList = new PlaySound();
+ // reset the lists
+ reset();
+ }
+
+ // sound attributes
+ int type;
+ int entnum;
+ int entchannel;
+ int bufferId;
+ // float volume;
+ float attenuation;
+ float[] origin = {0,0,0};
+
+ // begin time in ms
+ private long beginTime;
+
+ // for linked list
+ private PlaySound prev, next;
+
+ private PlaySound() {
+ prev = next = null;
+ this.clear();
+ }
+
+ private void clear() {
+ type = bufferId = entnum = entchannel = -1;
+ // volume = attenuation = beginTime = 0;
+ attenuation = beginTime = 0;
+ // Math3D.VectorClear(origin);
+ }
+
+ static void reset() {
+ // init the sentinels
+ freeList.next = freeList.prev = freeList;
+ playableList.next = playableList.prev = playableList;
+
+ // concat the the freeList
+ PlaySound ps;
+ for (int i = 0; i < backbuffer.length; i++) {
+ ps = backbuffer[i];
+ ps.clear();
+ ps.prev = freeList;
+ ps.next = freeList.next;
+ ps.prev.next = ps;
+ ps.next.prev = ps;
+ }
+ }
+
+ static PlaySound nextPlayableSound() {
+ PlaySound ps = null;
+ while (true) {
+ ps = playableList.next;
+ if (ps == playableList || ps.beginTime > Globals.cl.time)
+ return null;
+ PlaySound.release(ps);
+ return ps;
+ }
+ }
+
+ private static PlaySound get() {
+ PlaySound ps = freeList.next;
+ if (ps == freeList)
+ return null;
+
+ ps.prev.next = ps.next;
+ ps.next.prev = ps.prev;
+ return ps;
+ }
+
+ private static void add(PlaySound ps) {
+
+ PlaySound sort = playableList.next;
+
+ for (; sort != playableList && sort.beginTime < ps.beginTime; sort = sort.next);
+ ps.next = sort;
+ ps.prev = sort.prev;
+ ps.next.prev = ps;
+ ps.prev.next = ps;
+ }
+
+ private static void release(PlaySound ps) {
+ ps.prev.next = ps.next;
+ ps.next.prev = ps.prev;
+ // add to free list
+ ps.next = freeList.next;
+ freeList.next.prev = ps;
+ ps.prev = freeList;
+ freeList.next = ps;
+ }
+
+ static void allocate(float[] origin, int entnum, int entchannel,
+ int bufferId, float volume, float attenuation, float timeoffset) {
+
+ PlaySound ps = PlaySound.get();
+
+ if (ps != null) {
+ // find the right sound type
+ if (entnum == Globals.cl.playernum + 1) {
+ ps.type = Channel.LISTENER;
+ } else if (origin != null) {
+ ps.type = Channel.FIXED;
+ Math3D.VectorCopy(origin, ps.origin);
+ } else {
+ ps.type = Channel.DYNAMIC;
+ }
+ ps.entnum = entnum;
+ ps.entchannel = entchannel;
+ ps.bufferId = bufferId;
+ // ps.volume = volume;
+ ps.attenuation = attenuation;
+ ps.beginTime = Globals.cl.time + (long)(timeoffset * 1000);
+ PlaySound.add(ps);
+ } else {
+ System.err.println("PlaySounds out of Limit");
+ }
+ }
+}