diff options
-rw-r--r-- | src/jake2/sound/lwjgl/Channel.java | 334 | ||||
-rw-r--r-- | src/jake2/sound/lwjgl/LWJGLSoundImpl.java | 351 | ||||
-rw-r--r-- | src/jake2/sound/lwjgl/PlaySound.java | 169 |
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"); + } + } +} |