📄 joalsoundimpl.java
字号:
/* * JOALSoundImpl.java * Copyright (C) 2004 * * $Id: JOALSoundImpl.java,v 1.15 2005/12/04 19:21:04 cawe Exp $ */package jake2.sound.joal;import jake2.Defines;import jake2.Globals;import jake2.game.*;import jake2.qcommon.*;import jake2.sound.*;import jake2.util.Lib;import jake2.util.Vargs;import java.io.*;import java.nio.*;import net.java.games.joal.*;import net.java.games.joal.eax.EAX;import net.java.games.joal.eax.EAXFactory;/** * JOALSoundImpl */public final class JOALSoundImpl implements Sound { static { S.register(new JOALSoundImpl()); }; static AL al; static ALC alc; static EAX eax; cvar_t s_volume; private int[] buffers = new int[MAX_SFX + STREAM_QUEUE]; // singleton private JOALSoundImpl() { } /** * unpack OpenAL shared library on Linux */ private void unpack() { String path = System.getProperty("user.home") + "/.jake2/libopenal.so"; File f = new File(path); if (!f.exists()) { try { f.createNewFile(); InputStream in = getClass().getResourceAsStream("/libopenal.so"); OutputStream out = new FileOutputStream(f); byte[] buf = new byte[8192]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } catch (Exception e) { f.delete(); } } } /* (non-Javadoc) * @see jake2.sound.SoundImpl#Init() */ public boolean Init() { // preload OpenAL native library String os = System.getProperty("os.name"); if (os.startsWith("Linux")) { unpack(); } else if (os.startsWith("Windows")) { try { System.loadLibrary("OpenAL32"); } catch (Throwable e) {} } try { initOpenAL(); al = ALFactory.getAL(); checkError(); initOpenALExtensions(); } catch (OpenALException e) { Com.Printf(e.getMessage() + '\n'); return false; } catch (Throwable e) { Com.DPrintf(e.getMessage() + '\n'); return false; } // set the master volume s_volume = Cvar.Get("s_volume", "0.7", Defines.CVAR_ARCHIVE); al.alGenBuffers(buffers.length, buffers); int count = Channel.init(al, buffers); Com.Printf("... using " + count + " channels\n"); al.alDistanceModel(AL.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 { ALFactory.initialize(); alc = ALFactory.getALC(); String deviceName = null; String os = System.getProperty("os.name"); if (os.startsWith("Windows")) { deviceName = "DirectSound3D"; } ALC.Device device = alc.alcOpenDevice(deviceName); String deviceSpecifier = alc.alcGetString(device, ALC.ALC_DEVICE_SPECIFIER); String defaultSpecifier = alc.alcGetString(device, ALC.ALC_DEFAULT_DEVICE_SPECIFIER); Com.Printf(os + " using " + ((deviceName == null) ? defaultSpecifier : deviceName) + '\n'); ALC.Context context = alc.alcCreateContext(device, new int[] {0}); alc.alcMakeContextCurrent(context); // Check for an error. if (alc.alcGetError(device) != ALC.ALC_NO_ERROR) { Com.DPrintf("Error with SoundDevice"); } } private void initOpenALExtensions() { if (al.alIsExtensionPresent("EAX2.0")) { Com.Printf("... using EAX2.0\n"); eax = EAXFactory.getEAX(); } else { Com.Printf("... EAX2.0 not found\n"); eax = null; } } void exitOpenAL() { // Get the current context. ALC.Context curContext = alc.alcGetCurrentContext(); // Get the device used by that context. ALC.Device curDevice = alc.alcGetContextsDevice(curContext); // Reset the current context to NULL. alc.alcMakeContextCurrent(null); // Release the context and the device. alc.alcDestroyContext(curContext); alc.alcCloseDevice(curDevice); } // TODO check the sfx direct buffer size // 2MB sfx buffer private ByteBuffer sfxDataBuffer = Lib.newByteBuffer(2 * 1024 * 1024); /* (non-Javadoc) * @see jake2.sound.SoundImpl#RegisterSound(jake2.sound.sfx_t) */ private void initBuffer(byte[] samples, int bufferId, int freq) { ByteBuffer data = sfxDataBuffer.slice(); data.put(samples).flip(); al.alBufferData(buffers[bufferId], AL.AL_FORMAT_MONO16, data, data.limit(), freq); } private void checkError() { Com.DPrintf("AL Error: " + alErrorString() +'\n'); } private String alErrorString(){ int error; String message = ""; if ((error = al.alGetError()) != AL.AL_NO_ERROR) { switch(error) { case AL.AL_INVALID_OPERATION: message = "invalid operation"; break; case AL.AL_INVALID_VALUE: message = "invalid value"; break; case AL.AL_INVALID_ENUM: message = "invalid enum"; break; case AL.AL_INVALID_NAME: message = "invalid name"; break; default: message = "" + error; } } return message; } /* (non-Javadoc) * @see jake2.sound.SoundImpl#Shutdown() */ public void Shutdown() { StopAllSounds(); Channel.shutdown(); al.alDeleteBuffers(buffers.length, 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; } /* (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; PlaySound.allocate(origin, entnum, entchannel, buffers[sfx.bufferId], fvol, attenuation, timeofs); } private float[] listenerOrigin = {0, 0, 0}; private float[] listenerOrientation = {0, 0, 0, 0, 0, 0}; 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) { Channel.convertVector(origin, listenerOrigin); al.alListenerfv(AL.AL_POSITION, listenerOrigin); Channel.convertOrientation(forward, up, listenerOrientation); al.alListenerfv(AL.AL_ORIENTATION, listenerOrientation); // set the listener (master) volume al.alListenerf(AL.AL_GAIN, s_volume.value); if (eax != null) { // workaround for environment initialisation if (currentEnv == -1) { eaxEnv.put(0, EAX.EAX_ENVIRONMENT_UNDERWATER); eax.EAXSet(EAX_LISTENER, EAX.DSPROPERTY_EAXLISTENER_ENVIRONMENT | EAX.DSPROPERTY_EAXLISTENER_DEFERRED, 0, eaxEnv, 4); changeEnv = true; } if ((GameBase.gi.pointcontents.pointcontents(origin)& Defines.MASK_WATER)!= 0) { changeEnv = currentEnv != EAX.EAX_ENVIRONMENT_UNDERWATER; currentEnv = EAX.EAX_ENVIRONMENT_UNDERWATER; } else { changeEnv = currentEnv != EAX.EAX_ENVIRONMENT_GENERIC; currentEnv = EAX.EAX_ENVIRONMENT_GENERIC; } if (changeEnv) { eaxEnv.put(0, currentEnv); eax.EAXSet(EAX_LISTENER, EAX.DSPROPERTY_EAXLISTENER_ENVIRONMENT | EAX.DSPROPERTY_EAXLISTENER_DEFERRED, 0, eaxEnv, 4); } } Channel.addLoopSounds(); Channel.addPlaySounds(); Channel.playAllSounds(listenerOrigin); } /* (non-Javadoc) * @see jake2.sound.SoundImpl#StopAllSounds() */ public void StopAllSounds() { // mute the listener (master) al.alListenerf(AL.AL_GAIN, 0); PlaySound.reset(); Channel.reset(); } /* (non-Javadoc) * @see jake2.sound.Sound#getName() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -