From d90eac4f635b2eee76167651f7c470e37f068748 Mon Sep 17 00:00:00 2001 From: Carsten Weisse Date: Thu, 16 Dec 2004 20:33:08 +0000 Subject: renamed to lwjgl --- src/jake2/sound/lwjgl/LWJGLSoundImpl.java | 1672 ++++++++++++++--------------- 1 file changed, 836 insertions(+), 836 deletions(-) (limited to 'src/jake2/sound/lwjgl') diff --git a/src/jake2/sound/lwjgl/LWJGLSoundImpl.java b/src/jake2/sound/lwjgl/LWJGLSoundImpl.java index e82e32a..8016423 100644 --- a/src/jake2/sound/lwjgl/LWJGLSoundImpl.java +++ b/src/jake2/sound/lwjgl/LWJGLSoundImpl.java @@ -1,836 +1,836 @@ -/* - * LWJGLSoundImpl.java - * Copyright (C) 2004 - * - * $Id: LWJGLSoundImpl.java,v 1.1 2004-12-16 20:17:55 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 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.EAX20; -import org.lwjgl.openal.eax.EAXListenerProperties; - -/** - * LWJGLSoundImpl - */ -public final class LWJGLSoundImpl implements Sound { - - static { - S.register(new LWJGLSoundImpl()); - }; - - private boolean hasEAX; - - 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; - - // singleton - private LWJGLSoundImpl() { - } - - /* (non-Javadoc) - * @see jake2.sound.SoundImpl#Init() - */ - public boolean Init() { - - try { - initOpenAL(); - checkError(); - initOpenALExtensions(); - } catch (OpenALException e) { - Com.Printf(e.getMessage() + '\n'); - return false; - } catch (Exception e) { - Com.DPrintf(e.getMessage() + '\n'); - return false; - } - - AL10.alGenBuffers(buffers); - s_volume = Cvar.Get("s_volume", "0.7", Defines.CVAR_ARCHIVE); - initChannels(); - AL10.alDistanceModel(AL10.AL_INVERSE_DISTANCE_CLAMPED); - 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(); - } - }); - - num_sfx = 0; - - - Com.Printf("sound sampling rate: 44100Hz\n"); - - StopAllSounds(); - Com.Printf("------------------------------------\n"); - return true; - } - - - private void initOpenAL() throws OpenALException - { - try { AL.create(); } catch (LWJGLException e) { throw new OpenALException(e); } - String deviceName = null; - - String os = System.getProperty("os.name"); - if (os.startsWith("Windows")) { - deviceName = "DirectSound3D"; - } - - String deviceSpecifier = ALC.alcGetString(ALC.ALC_DEVICE_SPECIFIER); - String defaultSpecifier = ALC.alcGetString(ALC.ALC_DEFAULT_DEVICE_SPECIFIER); - - Com.Printf(os + " using " + ((deviceName == null) ? defaultSpecifier : deviceName) + '\n'); - - // Check for an error. - if (ALC.alcGetError() != ALC.ALC_NO_ERROR) - { - Com.DPrintf("Error with SoundDevice"); - } - } - - private void initOpenALExtensions() throws OpenALException - { - if (AL10.alIsExtensionPresent("EAX2.0")) - { - Com.Printf("... using EAX2.0\n"); - hasEAX=true; - } - else - { - Com.Printf("... EAX2.0 not found\n"); - hasEAX=false; - } - } - - - void exitOpenAL() - { - // Release the context and the device. - 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"); - } - - - /* (non-Javadoc) - * @see jake2.sound.SoundImpl#RegisterSound(jake2.sound.sfx_t) - */ - private void initBuffer(sfx_t sfx) { - if (sfx.cache == null ) { - //System.out.println(sfx.name + " " + sfx.cache.length+ " " + sfx.cache.loopstart + " " + sfx.cache.speed + " " + sfx.cache.stereo + " " + sfx.cache.width); - return; - } - - int format = AL10.AL_FORMAT_MONO16; - ByteBuffer data = BufferUtils.createByteBuffer(sfx.cache.data.length); - data.put(sfx.cache.data); - data.rewind(); - int freq = sfx.cache.speed; - - AL10.alBufferData( buffers.get(sfx.bufferId), format, data, freq); - } - - private void checkError() { - Com.DPrintf("AL Error: " + alErrorString() +'\n'); - } - - private String alErrorString(){ - int error; - String message = ""; - if ((error = AL10.alGetError()) != AL10.AL_NO_ERROR) { - switch(error) { - case AL10.AL_INVALID_OPERATION: message = "invalid operation"; break; - case AL10.AL_INVALID_VALUE: message = "invalid value"; break; - case AL10.AL_INVALID_ENUM: message = "invalid enum"; break; - case AL10.AL_INVALID_NAME: message = "invalid name"; break; - default: message = "" + error; - } - } - return message; - } - - /* (non-Javadoc) - * @see jake2.sound.SoundImpl#Shutdown() - */ - public void Shutdown() { - StopAllSounds(); - - AL10.alDeleteSources(sources); - AL10.alDeleteBuffers(buffers); - exitOpenAL(); - - Cmd.RemoveCommand("play"); - Cmd.RemoveCommand("stopsound"); - Cmd.RemoveCommand("soundlist"); - Cmd.RemoveCommand("soundinfo"); - - // free all sounds - for (int i = 0; i < num_sfx; i++) { - if (known_sfx[i].name == null) - continue; - 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) - */ - public void StartSound(float[] origin, int entnum, int entchannel, sfx_t sfx, float fvol, float attenuation, float timeofs) { - - if (sfx == null) - return; - - if (sfx.name.charAt(0) == '*') - sfx = RegisterSexedSound(Globals.cl_entities[entnum].current, sfx.name); - - if (LoadSound(sfx) == null) - return; // can't load 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; - } - - 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 IntBuffer eaxEnv = Lib.newIntBuffer(1); - private int currentEnv = -1; - private boolean changeEnv = true; - - // TODO workaround for JOAL-bug - // should be EAX.LISTENER - private final static int EAX_LISTENER = 0; - // should be EAX.SOURCE - private final static int EAX_SOURCE = 1; - - /* (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); - - convertOrientation(forward, up, listenerOrientation); - AL10.nalListenerfv(AL10.AL_ORIENTATION, listenerOrientationBuffer,0); - - if (hasEAX) - { - // workaround for environment initialisation - if (currentEnv == -1) - { - eaxEnv.put(0, EAX20.EAX_ENVIRONMENT_UNDERWATER); - EAX20.eaxSet(EAX_LISTENER, EAXListenerProperties.EAXLISTENER_ENVIRONMENT | EAXListenerProperties.EAXLISTENER_DEFERRED, 0, eaxEnv, 4); - changeEnv = true; - } - - if ((GameBase.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) { - changeEnv = currentEnv != EAX20.EAX_ENVIRONMENT_UNDERWATER; - currentEnv = EAX20.EAX_ENVIRONMENT_UNDERWATER; - } else { - changeEnv = currentEnv != EAX20.EAX_ENVIRONMENT_GENERIC; - currentEnv = EAX20.EAX_ENVIRONMENT_GENERIC; - } - if (changeEnv) { - eaxEnv.put(0, currentEnv); - EAX20.eaxSet(EAX_LISTENER, EAXListenerProperties.EAXLISTENER_ENVIRONMENT | EAXListenerProperties.EAXLISTENER_DEFERRED, 0, eaxEnv, 4); - } - } - - AddLoopSounds(origin); - playChannels(listenerOrigin); - } - - 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= 0) { - p++; - model = Globals.cl.configstrings[n].substring(p); - //strcpy(model, p); - p = model.indexOf('/'); - if (p > 0) - model = model.substring(0, p); - } - } - // 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 - String maleFilename = "player/male/" + base.substring(1); - sfx = AliasName(sexedFilename, maleFilename); - } - } - return sfx; - } - - - 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; - - sfx_t FindName(String name, boolean create) { - int i; - sfx_t sfx = null; - - if (name == null) - Com.Error(Defines.ERR_FATAL, "S_FindName: NULL\n"); - if (name.length() == 0) - Com.Error(Defines.ERR_FATAL, "S_FindName: empty name\n"); - - if (name.length() >= Defines.MAX_QPATH) - Com.Error(Defines.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(Defines.ERR_FATAL, "S_FindName: out of sfx_t"); - num_sfx++; - } - - sfx = known_sfx[i]; - sfx.clear(); - sfx.name = name; - sfx.registration_sequence = s_registration_sequence; - sfx.bufferId = i; - - return sfx; - } - - /* - ================== - S_AliasName - - ================== - */ - sfx_t AliasName(String aliasname, String truename) - { - sfx_t sfx = null; - String s; - int i; - - s = new String(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(Defines.ERR_FATAL, "S_FindName: out of sfx_t"); - num_sfx++; - } - - sfx = known_sfx[i]; - sfx.clear(); - sfx.name = new String(aliasname); - sfx.registration_sequence = s_registration_sequence; - sfx.truename = s; - // set the AL bufferId - sfx.bufferId = i; - - return sfx; - } - - /* - ============== - S_LoadSound - ============== - */ - public sfxcache_t LoadSound(sfx_t s) { - sfxcache_t sc = WaveLoader.LoadSound(s); - initBuffer(s); - return sc; - } - - /* (non-Javadoc) - * @see jake2.sound.Sound#StartLocalSound(java.lang.String) - */ - public void StartLocalSound(String sound) { - sfx_t sfx; - - sfx = RegisterSound(sound); - if (sfx == null) { - Com.Printf("S_StartLocalSound: can't cache " + sound + "\n"); - return; - } - StartSound(null, Globals.cl.playernum + 1, 0, sfx, 1, 1, 0); - } - - /* (non-Javadoc) - * @see jake2.sound.Sound#RawSamples(int, int, int, int, byte[]) - */ - public void RawSamples(int samples, int rate, int width, int channels, byte[] data) { - // TODO implement RawSamples - } - - /* - =============================================================================== - - console functions - - =============================================================================== - */ - - 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, Globals.cl.playernum + 1, 0, sfx, 1.0f, 1.0f, 0.0f); - i++; - } - } - - 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"); - } - - void SoundInfo_f() { - - Com.Printf("%5d stereo\n", new Vargs(1).add(1)); - Com.Printf("%5d samples\n", new Vargs(1).add(22050)); - Com.Printf("%5d samplebits\n", new Vargs(1).add(16)); - Com.Printf("%5d speed\n", new Vargs(1).add(44100)); - } - -} +/* + * LWJGLSoundImpl.java + * Copyright (C) 2004 + * + * $Id: LWJGLSoundImpl.java,v 1.2 2004-12-16 20:33:08 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 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.EAX20; +import org.lwjgl.openal.eax.EAXListenerProperties; + +/** + * LWJGLSoundImpl + */ +public final class LWJGLSoundImpl implements Sound { + + static { + S.register(new LWJGLSoundImpl()); + }; + + private boolean hasEAX; + + 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; + + // singleton + private LWJGLSoundImpl() { + } + + /* (non-Javadoc) + * @see jake2.sound.SoundImpl#Init() + */ + public boolean Init() { + + try { + initOpenAL(); + checkError(); + initOpenALExtensions(); + } catch (OpenALException e) { + Com.Printf(e.getMessage() + '\n'); + return false; + } catch (Exception e) { + Com.DPrintf(e.getMessage() + '\n'); + return false; + } + + AL10.alGenBuffers(buffers); + s_volume = Cvar.Get("s_volume", "0.7", Defines.CVAR_ARCHIVE); + initChannels(); + AL10.alDistanceModel(AL10.AL_INVERSE_DISTANCE_CLAMPED); + 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(); + } + }); + + num_sfx = 0; + + + Com.Printf("sound sampling rate: 44100Hz\n"); + + StopAllSounds(); + Com.Printf("------------------------------------\n"); + return true; + } + + + private void initOpenAL() throws OpenALException + { + try { AL.create(); } catch (LWJGLException e) { throw new OpenALException(e); } + String deviceName = null; + + String os = System.getProperty("os.name"); + if (os.startsWith("Windows")) { + deviceName = "DirectSound3D"; + } + + String deviceSpecifier = ALC.alcGetString(ALC.ALC_DEVICE_SPECIFIER); + String defaultSpecifier = ALC.alcGetString(ALC.ALC_DEFAULT_DEVICE_SPECIFIER); + + Com.Printf(os + " using " + ((deviceName == null) ? defaultSpecifier : deviceName) + '\n'); + + // Check for an error. + if (ALC.alcGetError() != ALC.ALC_NO_ERROR) + { + Com.DPrintf("Error with SoundDevice"); + } + } + + private void initOpenALExtensions() throws OpenALException + { + if (AL10.alIsExtensionPresent("EAX2.0")) + { + Com.Printf("... using EAX2.0\n"); + hasEAX=true; + } + else + { + Com.Printf("... EAX2.0 not found\n"); + hasEAX=false; + } + } + + + void exitOpenAL() + { + // Release the context and the device. + 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"); + } + + + /* (non-Javadoc) + * @see jake2.sound.SoundImpl#RegisterSound(jake2.sound.sfx_t) + */ + private void initBuffer(sfx_t sfx) { + if (sfx.cache == null ) { + //System.out.println(sfx.name + " " + sfx.cache.length+ " " + sfx.cache.loopstart + " " + sfx.cache.speed + " " + sfx.cache.stereo + " " + sfx.cache.width); + return; + } + + int format = AL10.AL_FORMAT_MONO16; + ByteBuffer data = BufferUtils.createByteBuffer(sfx.cache.data.length); + data.put(sfx.cache.data); + data.rewind(); + int freq = sfx.cache.speed; + + AL10.alBufferData( buffers.get(sfx.bufferId), format, data, freq); + } + + private void checkError() { + Com.DPrintf("AL Error: " + alErrorString() +'\n'); + } + + private String alErrorString(){ + int error; + String message = ""; + if ((error = AL10.alGetError()) != AL10.AL_NO_ERROR) { + switch(error) { + case AL10.AL_INVALID_OPERATION: message = "invalid operation"; break; + case AL10.AL_INVALID_VALUE: message = "invalid value"; break; + case AL10.AL_INVALID_ENUM: message = "invalid enum"; break; + case AL10.AL_INVALID_NAME: message = "invalid name"; break; + default: message = "" + error; + } + } + return message; + } + + /* (non-Javadoc) + * @see jake2.sound.SoundImpl#Shutdown() + */ + public void Shutdown() { + StopAllSounds(); + + AL10.alDeleteSources(sources); + AL10.alDeleteBuffers(buffers); + exitOpenAL(); + + Cmd.RemoveCommand("play"); + Cmd.RemoveCommand("stopsound"); + Cmd.RemoveCommand("soundlist"); + Cmd.RemoveCommand("soundinfo"); + + // free all sounds + for (int i = 0; i < num_sfx; i++) { + if (known_sfx[i].name == null) + continue; + 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) + */ + public void StartSound(float[] origin, int entnum, int entchannel, sfx_t sfx, float fvol, float attenuation, float timeofs) { + + if (sfx == null) + return; + + if (sfx.name.charAt(0) == '*') + sfx = RegisterSexedSound(Globals.cl_entities[entnum].current, sfx.name); + + if (LoadSound(sfx) == null) + return; // can't load 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; + } + + 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 IntBuffer eaxEnv = Lib.newIntBuffer(1); + private int currentEnv = -1; + private boolean changeEnv = true; + + // TODO workaround for JOAL-bug + // should be EAX.LISTENER + private final static int EAX_LISTENER = 0; + // should be EAX.SOURCE + private final static int EAX_SOURCE = 1; + + /* (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); + + convertOrientation(forward, up, listenerOrientation); + AL10.nalListenerfv(AL10.AL_ORIENTATION, listenerOrientationBuffer,0); + + if (hasEAX) + { + // workaround for environment initialisation + if (currentEnv == -1) + { + eaxEnv.put(0, EAX20.EAX_ENVIRONMENT_UNDERWATER); + EAX20.eaxSet(EAX_LISTENER, EAXListenerProperties.EAXLISTENER_ENVIRONMENT | EAXListenerProperties.EAXLISTENER_DEFERRED, 0, eaxEnv, 4); + changeEnv = true; + } + + if ((GameBase.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) { + changeEnv = currentEnv != EAX20.EAX_ENVIRONMENT_UNDERWATER; + currentEnv = EAX20.EAX_ENVIRONMENT_UNDERWATER; + } else { + changeEnv = currentEnv != EAX20.EAX_ENVIRONMENT_GENERIC; + currentEnv = EAX20.EAX_ENVIRONMENT_GENERIC; + } + if (changeEnv) { + eaxEnv.put(0, currentEnv); + EAX20.eaxSet(EAX_LISTENER, EAXListenerProperties.EAXLISTENER_ENVIRONMENT | EAXListenerProperties.EAXLISTENER_DEFERRED, 0, eaxEnv, 4); + } + } + + AddLoopSounds(origin); + playChannels(listenerOrigin); + } + + 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= 0) { + p++; + model = Globals.cl.configstrings[n].substring(p); + //strcpy(model, p); + p = model.indexOf('/'); + if (p > 0) + model = model.substring(0, p); + } + } + // 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 + String maleFilename = "player/male/" + base.substring(1); + sfx = AliasName(sexedFilename, maleFilename); + } + } + return sfx; + } + + + 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; + + sfx_t FindName(String name, boolean create) { + int i; + sfx_t sfx = null; + + if (name == null) + Com.Error(Defines.ERR_FATAL, "S_FindName: NULL\n"); + if (name.length() == 0) + Com.Error(Defines.ERR_FATAL, "S_FindName: empty name\n"); + + if (name.length() >= Defines.MAX_QPATH) + Com.Error(Defines.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(Defines.ERR_FATAL, "S_FindName: out of sfx_t"); + num_sfx++; + } + + sfx = known_sfx[i]; + sfx.clear(); + sfx.name = name; + sfx.registration_sequence = s_registration_sequence; + sfx.bufferId = i; + + return sfx; + } + + /* + ================== + S_AliasName + + ================== + */ + sfx_t AliasName(String aliasname, String truename) + { + sfx_t sfx = null; + String s; + int i; + + s = new String(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(Defines.ERR_FATAL, "S_FindName: out of sfx_t"); + num_sfx++; + } + + sfx = known_sfx[i]; + sfx.clear(); + sfx.name = new String(aliasname); + sfx.registration_sequence = s_registration_sequence; + sfx.truename = s; + // set the AL bufferId + sfx.bufferId = i; + + return sfx; + } + + /* + ============== + S_LoadSound + ============== + */ + public sfxcache_t LoadSound(sfx_t s) { + sfxcache_t sc = WaveLoader.LoadSound(s); + initBuffer(s); + return sc; + } + + /* (non-Javadoc) + * @see jake2.sound.Sound#StartLocalSound(java.lang.String) + */ + public void StartLocalSound(String sound) { + sfx_t sfx; + + sfx = RegisterSound(sound); + if (sfx == null) { + Com.Printf("S_StartLocalSound: can't cache " + sound + "\n"); + return; + } + StartSound(null, Globals.cl.playernum + 1, 0, sfx, 1, 1, 0); + } + + /* (non-Javadoc) + * @see jake2.sound.Sound#RawSamples(int, int, int, int, byte[]) + */ + public void RawSamples(int samples, int rate, int width, int channels, byte[] data) { + // TODO implement RawSamples + } + + /* + =============================================================================== + + console functions + + =============================================================================== + */ + + 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, Globals.cl.playernum + 1, 0, sfx, 1.0f, 1.0f, 0.0f); + i++; + } + } + + 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"); + } + + void SoundInfo_f() { + + Com.Printf("%5d stereo\n", new Vargs(1).add(1)); + Com.Printf("%5d samples\n", new Vargs(1).add(22050)); + Com.Printf("%5d samplebits\n", new Vargs(1).add(16)); + Com.Printf("%5d speed\n", new Vargs(1).add(44100)); + } + +} -- cgit v1.2.3