* Fixed issue where setReverbEnabled(false) after setPositional(false) did not actually remove reverb. Reverb is now removed automatically when setPositional(false) per contract of the method.

* Formatted the classes.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9569 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Sha..rd 13 years ago
parent 5497fcc7e6
commit 9d95528e21
  1. 6
      engine/src/core/com/jme3/audio/AudioNode.java
  2. 144
      engine/src/lwjgl/com/jme3/audio/lwjgl/LwjglAudioRenderer.java

@ -442,9 +442,10 @@ public class AudioNode extends Node {
*/ */
public void setReverbEnabled(boolean reverbEnabled) { public void setReverbEnabled(boolean reverbEnabled) {
this.reverbEnabled = reverbEnabled; this.reverbEnabled = reverbEnabled;
if (channel >= 0) if (channel >= 0) {
getRenderer().updateSourceParam(this, AudioParam.ReverbEnabled); getRenderer().updateSourceParam(this, AudioParam.ReverbEnabled);
} }
}
/** /**
* @return Filter for the reverberations of this audio node. * @return Filter for the reverberations of this audio node.
@ -642,9 +643,10 @@ public class AudioNode extends Node {
*/ */
public void setPositional(boolean positional) { public void setPositional(boolean positional) {
this.positional = positional; this.positional = positional;
if (channel >= 0) if (channel >= 0) {
getRenderer().updateSourceParam(this, AudioParam.IsPositional); getRenderer().updateSourceParam(this, AudioParam.IsPositional);
} }
}
@Override @Override
public void updateGeometricState(){ public void updateGeometricState(){

@ -29,11 +29,10 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.audio.lwjgl; package com.jme3.audio.lwjgl;
import com.jme3.audio.*;
import com.jme3.audio.AudioNode.Status; import com.jme3.audio.AudioNode.Status;
import com.jme3.audio.*;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import com.jme3.util.NativeObjectManager; import com.jme3.util.NativeObjectManager;
@ -45,42 +44,34 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
import org.lwjgl.openal.*;
import static org.lwjgl.openal.AL10.*; import static org.lwjgl.openal.AL10.*;
import org.lwjgl.openal.*;
public class LwjglAudioRenderer implements AudioRenderer, Runnable { public class LwjglAudioRenderer implements AudioRenderer, Runnable {
private static final Logger logger = Logger.getLogger(LwjglAudioRenderer.class.getName()); private static final Logger logger = Logger.getLogger(LwjglAudioRenderer.class.getName());
private final NativeObjectManager objManager = new NativeObjectManager(); private final NativeObjectManager objManager = new NativeObjectManager();
// When multiplied by STREAMING_BUFFER_COUNT, will equal 44100 * 2 * 2 // When multiplied by STREAMING_BUFFER_COUNT, will equal 44100 * 2 * 2
// which is exactly 1 second of audio. // which is exactly 1 second of audio.
private static final int BUFFER_SIZE = 35280; private static final int BUFFER_SIZE = 35280;
private static final int STREAMING_BUFFER_COUNT = 5; private static final int STREAMING_BUFFER_COUNT = 5;
private final static int MAX_NUM_CHANNELS = 64; private final static int MAX_NUM_CHANNELS = 64;
private IntBuffer ib = BufferUtils.createIntBuffer(1); private IntBuffer ib = BufferUtils.createIntBuffer(1);
private final FloatBuffer fb = BufferUtils.createVector3Buffer(2); private final FloatBuffer fb = BufferUtils.createVector3Buffer(2);
private final ByteBuffer nativeBuf = BufferUtils.createByteBuffer(BUFFER_SIZE); private final ByteBuffer nativeBuf = BufferUtils.createByteBuffer(BUFFER_SIZE);
private final byte[] arrayBuf = new byte[BUFFER_SIZE]; private final byte[] arrayBuf = new byte[BUFFER_SIZE];
private int[] channels; private int[] channels;
private AudioNode[] chanSrcs; private AudioNode[] chanSrcs;
private int nextChan = 0; private int nextChan = 0;
private ArrayList<Integer> freeChans = new ArrayList<Integer>(); private ArrayList<Integer> freeChans = new ArrayList<Integer>();
private Listener listener; private Listener listener;
private boolean audioDisabled = false; private boolean audioDisabled = false;
private boolean supportEfx = false; private boolean supportEfx = false;
private int auxSends = 0; private int auxSends = 0;
private int reverbFx = -1; private int reverbFx = -1;
private int reverbFxSlot = -1; private int reverbFxSlot = -1;
// Update audio 20 times per second // Update audio 20 times per second
private static final float UPDATE_RATE = 0.05f; private static final float UPDATE_RATE = 0.05f;
private final Thread audioThread = new Thread(this, "jME3 Audio Thread"); private final Thread audioThread = new Thread(this, "jME3 Audio Thread");
private final AtomicBoolean threadLock = new AtomicBoolean(false); private final AtomicBoolean threadLock = new AtomicBoolean(false);
@ -98,9 +89,10 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
private void checkDead() { private void checkDead() {
if (audioThread.getState() == Thread.State.TERMINATED) if (audioThread.getState() == Thread.State.TERMINATED) {
throw new IllegalStateException("Audio thread is terminated"); throw new IllegalStateException("Audio thread is terminated");
} }
}
public void run() { public void run() {
initInThread(); initInThread();
@ -110,11 +102,13 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
long updateRateNanos = (long) (UPDATE_RATE * 1000000000); long updateRateNanos = (long) (UPDATE_RATE * 1000000000);
mainloop: while (true){ mainloop:
while (true) {
long startTime = System.nanoTime(); long startTime = System.nanoTime();
if (Thread.interrupted()) if (Thread.interrupted()) {
break; break;
}
synchronized (threadLock) { synchronized (threadLock) {
updateInThread(UPDATE_RATE); updateInThread(UPDATE_RATE);
@ -281,8 +275,8 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAIN, lpf.getVolume()); EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAIN, lpf.getVolume());
EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAINHF, lpf.getHighFreqVolume()); EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAINHF, lpf.getHighFreqVolume());
} else { } else {
throw new UnsupportedOperationException("Filter type unsupported: "+ throw new UnsupportedOperationException("Filter type unsupported: "
f.getClass().getName()); + f.getClass().getName());
} }
f.clearUpdateNeeded(); f.clearUpdateNeeded();
@ -297,8 +291,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
// There is a race condition in AudioNode that can // There is a race condition in AudioNode that can
// cause this to be called for a node that has been // cause this to be called for a node that has been
@ -309,42 +304,48 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
// updateSourceParam() (because the audio stopped playing // updateSourceParam() (because the audio stopped playing
// on its own right as the volume was set). In this case, // on its own right as the volume was set). In this case,
// it should be safe to just ignore the update // it should be safe to just ignore the update
if (src.getChannel() < 0) if (src.getChannel() < 0) {
return; return;
}
assert src.getChannel() >= 0; assert src.getChannel() >= 0;
int id = channels[src.getChannel()]; int id = channels[src.getChannel()];
switch (param) { switch (param) {
case Position: case Position:
if (!src.isPositional()) if (!src.isPositional()) {
return; return;
}
Vector3f pos = src.getWorldTranslation(); Vector3f pos = src.getWorldTranslation();
alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z); alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z);
break; break;
case Velocity: case Velocity:
if (!src.isPositional()) if (!src.isPositional()) {
return; return;
}
Vector3f vel = src.getVelocity(); Vector3f vel = src.getVelocity();
alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z); alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z);
break; break;
case MaxDistance: case MaxDistance:
if (!src.isPositional()) if (!src.isPositional()) {
return; return;
}
alSourcef(id, AL_MAX_DISTANCE, src.getMaxDistance()); alSourcef(id, AL_MAX_DISTANCE, src.getMaxDistance());
break; break;
case RefDistance: case RefDistance:
if (!src.isPositional()) if (!src.isPositional()) {
return; return;
}
alSourcef(id, AL_REFERENCE_DISTANCE, src.getRefDistance()); alSourcef(id, AL_REFERENCE_DISTANCE, src.getRefDistance());
break; break;
case ReverbFilter: case ReverbFilter:
if (!supportEfx || !src.isPositional() || !src.isReverbEnabled()) if (!supportEfx || !src.isPositional() || !src.isReverbEnabled()) {
return; return;
}
int filter = EFX10.AL_FILTER_NULL; int filter = EFX10.AL_FILTER_NULL;
if (src.getReverbFilter() != null) { if (src.getReverbFilter() != null) {
@ -357,8 +358,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter); AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter);
break; break;
case ReverbEnabled: case ReverbEnabled:
if (!supportEfx || !src.isPositional()) if (!supportEfx || !src.isPositional()) {
return; return;
}
if (src.isReverbEnabled()) { if (src.isReverbEnabled()) {
updateSourceParam(src, AudioParam.ReverbFilter); updateSourceParam(src, AudioParam.ReverbFilter);
@ -368,10 +370,13 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
break; break;
case IsPositional: case IsPositional:
if (!src.isPositional()) { if (!src.isPositional()) {
// play in headspace // Play in headspace
alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);
alSource3f(id, AL_POSITION, 0, 0, 0); alSource3f(id, AL_POSITION, 0, 0, 0);
alSource3f(id, AL_VELOCITY, 0, 0, 0); alSource3f(id, AL_VELOCITY, 0, 0, 0);
// Disable reverb
AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, 0, 0, EFX10.AL_FILTER_NULL);
} else { } else {
alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE);
updateSourceParam(src, AudioParam.Position); updateSourceParam(src, AudioParam.Position);
@ -382,21 +387,24 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
break; break;
case Direction: case Direction:
if (!src.isDirectional()) if (!src.isDirectional()) {
return; return;
}
Vector3f dir = src.getDirection(); Vector3f dir = src.getDirection();
alSource3f(id, AL_DIRECTION, dir.x, dir.y, dir.z); alSource3f(id, AL_DIRECTION, dir.x, dir.y, dir.z);
break; break;
case InnerAngle: case InnerAngle:
if (!src.isDirectional()) if (!src.isDirectional()) {
return; return;
}
alSourcef(id, AL_CONE_INNER_ANGLE, src.getInnerAngle()); alSourcef(id, AL_CONE_INNER_ANGLE, src.getInnerAngle());
break; break;
case OuterAngle: case OuterAngle:
if (!src.isDirectional()) if (!src.isDirectional()) {
return; return;
}
alSourcef(id, AL_CONE_OUTER_ANGLE, src.getOuterAngle()); alSourcef(id, AL_CONE_OUTER_ANGLE, src.getOuterAngle());
break; break;
@ -413,8 +421,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
break; break;
case DryFilter: case DryFilter:
if (!supportEfx) if (!supportEfx) {
return; return;
}
if (src.getDryFilter() != null) { if (src.getDryFilter() != null) {
Filter f = src.getDryFilter(); Filter f = src.getDryFilter();
@ -516,8 +525,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
switch (param) { switch (param) {
case Position: case Position:
@ -561,9 +571,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
private int newChannel() { private int newChannel() {
if (freeChans.size() > 0) if (freeChans.size() > 0) {
return freeChans.remove(0); return freeChans.remove(0);
else if (nextChan < channels.length){ } else if (nextChan < channels.length) {
return nextChan++; return nextChan++;
} else { } else {
return -1; return -1;
@ -587,8 +597,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled || !supportEfx) if (audioDisabled || !supportEfx) {
return; return;
}
EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DENSITY, env.getDensity()); EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DENSITY, env.getDensity());
EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DIFFUSION, env.getDiffusion()); EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DIFFUSION, env.getDiffusion());
@ -622,8 +633,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
} }
if(size == 0) if (size == 0) {
return false; return false;
}
nativeBuf.clear(); nativeBuf.clear();
nativeBuf.put(arrayBuf, 0, size); nativeBuf.put(arrayBuf, 0, size);
@ -635,8 +647,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
private boolean fillStreamingSource(int sourceId, AudioStream stream) { private boolean fillStreamingSource(int sourceId, AudioStream stream) {
if (!stream.isOpen()) if (!stream.isOpen()) {
return false; return false;
}
boolean active = true; boolean active = true;
int processed = alGetSourcei(sourceId, AL_BUFFERS_PROCESSED); int processed = alGetSourcei(sourceId, AL_BUFFERS_PROCESSED);
@ -656,8 +669,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
alSourceQueueBuffers(sourceId, ib); alSourceQueueBuffers(sourceId, ib);
} }
if (!active && stream.isOpen()) if (!active && stream.isOpen()) {
stream.close(); stream.close();
}
return active; return active;
} }
@ -724,13 +738,15 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
public void updateInThread(float tpf) { public void updateInThread(float tpf) {
if (audioDisabled) if (audioDisabled) {
return; return;
}
for (int i = 0; i < channels.length; i++) { for (int i = 0; i < channels.length; i++) {
AudioNode src = chanSrcs[i]; AudioNode src = chanSrcs[i];
if (src == null) if (src == null) {
continue; continue;
}
int sourceId = channels[i]; int sourceId = channels[i];
@ -752,8 +768,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
AudioStream stream = (AudioStream) src.getAudioData(); AudioStream stream = (AudioStream) src.getAudioData();
if (stream.isOpen()) { if (stream.isOpen()) {
fillStreamingSource(sourceId, stream); fillStreamingSource(sourceId, stream);
if (stopped) if (stopped) {
alSourcePlay(sourceId); alSourcePlay(sourceId);
}
} else { } else {
if (stopped) { if (stopped) {
// became inactive // became inactive
@ -797,8 +814,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
if (this.listener != null) { if (this.listener != null) {
// previous listener no longer associated with current // previous listener no longer associated with current
@ -821,13 +839,15 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
if (src.getAudioData() instanceof AudioStream) if (src.getAudioData() instanceof AudioStream) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Cannot play instances " + "Cannot play instances "
"of audio streams. Use playSource() instead."); + "of audio streams. Use playSource() instead.");
}
if (src.getAudioData().isUpdateNeeded()) { if (src.getAudioData().isUpdateNeeded()) {
updateAudioData(src.getAudioData()); updateAudioData(src.getAudioData());
@ -835,8 +855,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
// create a new index for an audio-channel // create a new index for an audio-channel
int index = newChannel(); int index = newChannel();
if (index == -1) if (index == -1) {
return; return;
}
int sourceId = channels[index]; int sourceId = channels[index];
@ -852,7 +873,6 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
} }
public void playSource(AudioNode src) { public void playSource(AudioNode src) {
checkDead(); checkDead();
synchronized (threadLock) { synchronized (threadLock) {
@ -862,8 +882,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
//assert src.getStatus() == Status.Stopped || src.getChannel() == -1; //assert src.getStatus() == Status.Stopped || src.getChannel() == -1;
@ -881,8 +902,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
src.setChannel(index); src.setChannel(index);
AudioData data = src.getAudioData(); AudioData data = src.getAudioData();
if (data.isUpdateNeeded()) if (data.isUpdateNeeded()) {
updateAudioData(data); updateAudioData(data);
}
chanSrcs[index] = src; chanSrcs[index] = src;
setSourceParams(channels[index], src, false); setSourceParams(channels[index], src, false);
@ -894,7 +916,6 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
} }
public void pauseSource(AudioNode src) { public void pauseSource(AudioNode src) {
checkDead(); checkDead();
synchronized (threadLock) { synchronized (threadLock) {
@ -904,8 +925,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
if (src.getStatus() == Status.Playing) { if (src.getStatus() == Status.Playing) {
assert src.getChannel() != -1; assert src.getChannel() != -1;
@ -916,7 +938,6 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
} }
public void stopSource(AudioNode src) { public void stopSource(AudioNode src) {
synchronized (threadLock) { synchronized (threadLock) {
while (!threadLock.get()) { while (!threadLock.get()) {
@ -925,8 +946,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
if (src.getStatus() != Status.Stopped) { if (src.getStatus() != Status.Stopped) {
int chan = src.getChannel(); int chan = src.getChannel();
@ -954,20 +976,22 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
private int convertFormat(AudioData ad) { private int convertFormat(AudioData ad) {
switch (ad.getBitsPerSample()) { switch (ad.getBitsPerSample()) {
case 8: case 8:
if (ad.getChannels() == 1) if (ad.getChannels() == 1) {
return AL_FORMAT_MONO8; return AL_FORMAT_MONO8;
else if (ad.getChannels() == 2) } else if (ad.getChannels() == 2) {
return AL_FORMAT_STEREO8; return AL_FORMAT_STEREO8;
}
break; break;
case 16: case 16:
if (ad.getChannels() == 1) if (ad.getChannels() == 1) {
return AL_FORMAT_MONO16; return AL_FORMAT_MONO16;
else } else {
return AL_FORMAT_STEREO16; return AL_FORMAT_STEREO16;
} }
throw new UnsupportedOperationException("Unsupported channels/bits combination: "+ }
"bits="+ad.getBitsPerSample()+", channels="+ad.getChannels()); throw new UnsupportedOperationException("Unsupported channels/bits combination: "
+ "bits=" + ad.getBitsPerSample() + ", channels=" + ad.getChannels());
} }
private void updateAudioBuffer(AudioBuffer ab) { private void updateAudioBuffer(AudioBuffer ab) {
@ -1028,8 +1052,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
} }
if (audioDisabled) if (audioDisabled) {
return; return;
}
if (ad instanceof AudioBuffer) { if (ad instanceof AudioBuffer) {
AudioBuffer ab = (AudioBuffer) ad; AudioBuffer ab = (AudioBuffer) ad;
@ -1052,5 +1077,4 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
} }
} }
} }

Loading…
Cancel
Save