- add generic AudioSource to abstract audio system away from AudioNode

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10416 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
nor..67 12 years ago
parent df5afb1524
commit 22eb83fd9a
  1. 18
      engine/src/core/com/jme3/audio/AudioNode.java
  2. 12
      engine/src/core/com/jme3/audio/AudioRenderer.java
  3. 189
      engine/src/core/com/jme3/audio/AudioSource.java
  4. 54
      engine/src/jogl/com/jme3/audio/joal/JoalAudioRenderer.java
  5. 46
      engine/src/lwjgl/com/jme3/audio/lwjgl/LwjglAudioRenderer.java

@ -60,7 +60,7 @@ import java.util.logging.Logger;
* @author normenhansen
* @author Kirill Vainer
*/
public class AudioNode extends Node {
public class AudioNode extends Node implements AudioSource {
//Version #1 : AudioKey is now stored into "audio_key" instead of "key"
public static final int SAVABLE_VERSION = 1;
@ -71,7 +71,7 @@ public class AudioNode extends Node {
protected Filter dryFilter;
protected AudioKey audioKey;
protected transient AudioData data = null;
protected transient volatile Status status = Status.Stopped;
protected transient volatile AudioSource.Status status = AudioSource.Status.Stopped;
protected transient volatile int channel = -1;
protected Vector3f velocity = new Vector3f();
protected boolean reverbEnabled = true;
@ -86,7 +86,9 @@ public class AudioNode extends Node {
/**
* <code>Status</code> indicates the current status of the audio node.
* @deprecated - use AudioSource.Status instead
*/
@Deprecated
public enum Status {
/**
* The audio node is currently playing. This will be set if
@ -223,7 +225,7 @@ public class AudioNode extends Node {
* Do not use.
*/
public final void setChannel(int channel) {
if (status != Status.Stopped) {
if (status != AudioSource.Status.Stopped) {
throw new IllegalStateException("Can only set source id when stopped");
}
@ -294,14 +296,14 @@ public class AudioNode extends Node {
* The status will be changed when either the {@link AudioNode#play() }
* or {@link AudioNode#stop() } methods are called.
*/
public Status getStatus() {
public AudioSource.Status getStatus() {
return status;
}
/**
* Do not use.
*/
public final void setStatus(Status status) {
public final void setStatus(AudioSource.Status status) {
this.status = status;
}
@ -399,12 +401,16 @@ public class AudioNode extends Node {
this.timeOffset = timeOffset;
if (data instanceof AudioStream) {
((AudioStream) data).setTime(timeOffset);
}else if(status == Status.Playing){
}else if(status == AudioSource.Status.Playing){
stop();
play();
}
}
public Vector3f getPosition() {
return getWorldTranslation();
}
/**
* @return The velocity of the audio node.
*

@ -47,17 +47,17 @@ public interface AudioRenderer {
/**
* Sets the environment, used for reverb effects.
*
* @see AudioNode#setReverbEnabled(boolean)
* @see AudioSource#setReverbEnabled(boolean)
* @param env The environment to set.
*/
public void setEnvironment(Environment env);
public void playSourceInstance(AudioNode src);
public void playSource(AudioNode src);
public void pauseSource(AudioNode src);
public void stopSource(AudioNode src);
public void playSourceInstance(AudioSource src);
public void playSource(AudioSource src);
public void pauseSource(AudioSource src);
public void stopSource(AudioSource src);
public void updateSourceParam(AudioNode src, AudioParam param);
public void updateSourceParam(AudioSource src, AudioParam param);
public void updateListenerParam(Listener listener, ListenerParam param);
public void deleteFilter(Filter filter);

@ -0,0 +1,189 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.audio;
import com.jme3.math.Vector3f;
/**
*
* @author normenhansen
*/
public interface AudioSource {
/**
* <code>Status</code> indicates the current status of the audio source.
*/
public enum Status {
/**
* The audio source is currently playing. This will be set if
* {@link AudioSource#play() } is called.
*/
Playing,
/**
* The audio source is currently paused.
*/
Paused,
/**
* The audio source is currently stopped.
* This will be set if {@link AudioSource#stop() } is called
* or the audio has reached the end of the file.
*/
Stopped,
}
/**
* Do not use.
*/
public void setChannel(int channel);
/**
* Do not use.
*/
public int getChannel();
/**
* Start playing the audio.
*/
public void play();
/**
* Start playing an instance of this audio. This method can be used
* to play the same <code>AudioSource</code> multiple times. Note
* that changes to the parameters of this AudioSource will not effect the
* instances already playing.
*/
public void playInstance();
/**
* @return The {#link Filter dry filter} that is set.
* @see AudioSource#setDryFilter(com.jme3.audio.Filter)
*/
public Filter getDryFilter();
/**
* @return The {@link AudioData} set previously with
* {@link AudioSource#setAudioData(com.jme3.audio.AudioData, com.jme3.audio.AudioKey) }
* or any of the constructors that initialize the audio data.
*/
public AudioData getAudioData();
/**
* Do not use.
*/
public void setStatus(Status status);
/**
* @return The {@link Status} of the audio source.
* The status will be changed when either the {@link AudioSource#play() }
* or {@link AudioSource#stop() } methods are called.
*/
public Status getStatus();
/**
* @return True if the audio will keep looping after it is done playing,
* otherwise, false.
* @see AudioSource#setLooping(boolean)
*/
public boolean isLooping();
/**
* @return The pitch of the audio, also the speed of playback.
*
* @see AudioSource#setPitch(float)
*/
public float getPitch();
/**
* @return The volume of this audio source.
*
* @see AudioSource#setVolume(float)
*/
public float getVolume();
/**
* @return the time offset in the sound sample when to start playing.
*/
public float getTimeOffset();
/**
* @return The velocity of the audio source.
*
* @see AudioSource#setVelocity(com.jme3.math.Vector3f)
*/
public Vector3f getPosition();
/**
* @return The velocity of the audio source.
*
* @see AudioSource#setVelocity(com.jme3.math.Vector3f)
*/
public Vector3f getVelocity();
/**
* @return True if reverb is enabled, otherwise false.
*
* @see AudioSource#setReverbEnabled(boolean)
*/
public boolean isReverbEnabled();
/**
* @return Filter for the reverberations of this audio source.
*
* @see AudioSource#setReverbFilter(com.jme3.audio.Filter)
*/
public Filter getReverbFilter();
/**
* @return Max distance for this audio source.
*
* @see AudioSource#setMaxDistance(float)
*/
public float getMaxDistance();
/**
* @return The reference playing distance for the audio source.
*
* @see AudioSource#setRefDistance(float)
*/
public float getRefDistance();
/**
* @return True if the audio source is directional
*
* @see AudioSource#setDirectional(boolean)
*/
public boolean isDirectional();
/**
* @return The direction of this audio source.
*
* @see AudioSource#setDirection(com.jme3.math.Vector3f)
*/
public Vector3f getDirection();
/**
* @return The directional audio source, cone inner angle.
*
* @see AudioSource#setInnerAngle(float)
*/
public float getInnerAngle();
/**
* @return The directional audio source, cone outer angle.
*
* @see AudioSource#setOuterAngle(float)
*/
public float getOuterAngle();
/**
* @return True if the audio source is positional.
*
* @see AudioSource#setPositional(boolean)
*/
public boolean isPositional();
}

@ -31,7 +31,7 @@
*/
package com.jme3.audio.joal;
import com.jme3.audio.AudioNode.Status;
import com.jme3.audio.AudioSource.Status;
import com.jme3.audio.*;
import com.jme3.math.Vector3f;
import com.jme3.util.BufferUtils;
@ -61,7 +61,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
private final ByteBuffer nativeBuf = BufferUtils.createByteBuffer(BUFFER_SIZE);
private final byte[] arrayBuf = new byte[BUFFER_SIZE];
private int[] channels;
private AudioNode[] chanSrcs;
private AudioSource[] chanSrcs;
private int nextChan = 0;
private ArrayList<Integer> freeChans = new ArrayList<Integer>();
private Listener listener;
@ -194,7 +194,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
}
ib = BufferUtils.createIntBuffer(channels.length);
chanSrcs = new AudioNode[channels.length];
chanSrcs = new AudioSource[channels.length];
logger.log(Level.FINE, "AudioRenderer supports {0} channels", channels.length);
@ -308,7 +308,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
f.clearUpdateNeeded();
}
public void updateSourceParam(AudioNode src, AudioParam param) {
public void updateSourceParam(AudioSource src, AudioParam param) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -321,10 +321,10 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
return;
}
// There is a race condition in AudioNode that can
// There is a race condition in AudioSource that can
// cause this to be called for a node that has been
// detached from its channel. For example, setVolume()
// called from the render thread may see that that AudioNode
// called from the render thread may see that that AudioSource
// still has a channel value but the audio thread may
// clear that channel before setVolume() gets to call
// updateSourceParam() (because the audio stopped playing
@ -343,7 +343,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
return;
}
Vector3f pos = src.getWorldTranslation();
Vector3f pos = src.getPosition();
al.alSource3f(id, ALConstants.AL_POSITION, pos.x, pos.y, pos.z);
break;
case Velocity:
@ -482,9 +482,9 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
}
}
private void setSourceParams(int id, AudioNode src, boolean forceNonLoop) {
private void setSourceParams(int id, AudioSource src, boolean forceNonLoop) {
if (src.isPositional()) {
Vector3f pos = src.getWorldTranslation();
Vector3f pos = src.getPosition();
Vector3f vel = src.getVelocity();
al.alSource3f(id, ALConstants.AL_POSITION, pos.x, pos.y, pos.z);
al.alSource3f(id, ALConstants.AL_VELOCITY, vel.x, vel.y, vel.z);
@ -731,7 +731,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
private void clearChannel(int index) {
// make room at this channel
if (chanSrcs[index] != null) {
AudioNode src = chanSrcs[index];
AudioSource src = chanSrcs[index];
int sourceId = channels[index];
al.alSourceStop(sourceId);
@ -750,7 +750,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
al.alSourcei(sourceId, AL.AL_DIRECT_FILTER, AL.AL_FILTER_NULL);
}
if (src.isPositional()) {
AudioNode pas = (AudioNode) src;
AudioSource pas = (AudioSource) src;
if (pas.isReverbEnabled() && supportEfx) {
al.alSource3i(sourceId, AL.AL_AUXILIARY_SEND_FILTER, 0, 0, AL.AL_FILTER_NULL);
}
@ -770,7 +770,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
}
for (int i = 0; i < channels.length; i++) {
AudioNode src = chanSrcs[i];
AudioSource src = chanSrcs[i];
if (src == null) {
continue;
}
@ -790,7 +790,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
ib.position(0).limit(1);
al.alGetSourcei(sourceId, AL.AL_SOURCE_STATE, ib);
int state = ib.get(0);
boolean wantPlaying = src.getStatus() == AudioNode.Status.Playing;
boolean wantPlaying = src.getStatus() == AudioSource.Status.Playing;
boolean stopped = state == ALConstants.AL_STOPPED;
if (streaming && wantPlaying) {
@ -803,7 +803,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
} else {
if (stopped) {
// became inactive
src.setStatus(AudioNode.Status.Stopped);
src.setStatus(AudioSource.Status.Stopped);
src.setChannel(-1);
clearChannel(i);
freeChannel(i);
@ -817,11 +817,11 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
boolean paused = state == ALConstants.AL_PAUSED;
// make sure OAL pause state & source state coincide
assert (src.getStatus() == AudioNode.Status.Paused && paused) || (!paused);
assert (src.getStatus() == AudioSource.Status.Paused && paused) || (!paused);
if (stopped) {
if (boundSource) {
src.setStatus(AudioNode.Status.Stopped);
src.setStatus(AudioSource.Status.Stopped);
src.setChannel(-1);
}
clearChannel(i);
@ -859,7 +859,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
}
}
public void playSourceInstance(AudioNode src) {
public void playSourceInstance(AudioSource src) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -902,7 +902,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
}
}
public void playSource(AudioNode src) {
public void playSource(AudioSource src) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -917,9 +917,9 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
//assert src.getStatus() == Status.Stopped || src.getChannel() == -1;
if (src.getStatus() == AudioNode.Status.Playing) {
if (src.getStatus() == AudioSource.Status.Playing) {
return;
} else if (src.getStatus() == AudioNode.Status.Stopped) {
} else if (src.getStatus() == AudioSource.Status.Stopped) {
// allocate channel to this source
int index = newChannel();
@ -941,11 +941,11 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
}
al.alSourcePlay(channels[src.getChannel()]);
src.setStatus(AudioNode.Status.Playing);
src.setStatus(AudioSource.Status.Playing);
}
}
public void pauseSource(AudioNode src) {
public void pauseSource(AudioSource src) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -958,16 +958,16 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
return;
}
if (src.getStatus() == AudioNode.Status.Playing) {
if (src.getStatus() == AudioSource.Status.Playing) {
assert src.getChannel() != -1;
al.alSourcePause(channels[src.getChannel()]);
src.setStatus(AudioNode.Status.Paused);
src.setStatus(AudioSource.Status.Paused);
}
}
}
public void stopSource(AudioNode src) {
public void stopSource(AudioSource src) {
synchronized (threadLock) {
while (!threadLock.get()) {
try {
@ -979,11 +979,11 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
return;
}
if (src.getStatus() != AudioNode.Status.Stopped) {
if (src.getStatus() != AudioSource.Status.Stopped) {
int chan = src.getChannel();
assert chan != -1; // if it's not stopped, must have id
src.setStatus(AudioNode.Status.Stopped);
src.setStatus(AudioSource.Status.Stopped);
src.setChannel(-1);
clearChannel(chan);
freeChannel(chan);

@ -31,7 +31,7 @@
*/
package com.jme3.audio.lwjgl;
import com.jme3.audio.AudioNode.Status;
import com.jme3.audio.AudioSource.Status;
import com.jme3.audio.*;
import com.jme3.math.Vector3f;
import com.jme3.util.BufferUtils;
@ -61,7 +61,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
private final ByteBuffer nativeBuf = BufferUtils.createByteBuffer(BUFFER_SIZE);
private final byte[] arrayBuf = new byte[BUFFER_SIZE];
private int[] channels;
private AudioNode[] chanSrcs;
private AudioSource[] chanSrcs;
private int nextChan = 0;
private ArrayList<Integer> freeChans = new ArrayList<Integer>();
private Listener listener;
@ -156,10 +156,10 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
ALCdevice device = AL.getDevice();
String deviceName = ALC10.alcGetString(device, ALC10.ALC_DEVICE_SPECIFIER);
logger.log(Level.FINER, "Audio Device: {0}", deviceName);
logger.log(Level.FINER, "Audio Vendor: {0}", alGetString(AL_VENDOR));
logger.log(Level.FINER, "Audio Renderer: {0}", alGetString(AL_RENDERER));
logger.log(Level.FINER, "Audio Version: {0}", alGetString(AL_VERSION));
logger.log(Level.INFO, "Audio Device: {0}", deviceName);
logger.log(Level.INFO, "Audio Vendor: {0}", alGetString(AL_VENDOR));
logger.log(Level.INFO, "Audio Renderer: {0}", alGetString(AL_RENDERER));
logger.log(Level.INFO, "Audio Version: {0}", alGetString(AL_VERSION));
// Find maximum # of sources supported by this implementation
ArrayList<Integer> channelList = new ArrayList<Integer>();
@ -178,9 +178,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
ib = BufferUtils.createIntBuffer(channels.length);
chanSrcs = new AudioNode[channels.length];
chanSrcs = new AudioSource[channels.length];
logger.log(Level.FINE, "AudioRenderer supports {0} channels", channels.length);
logger.log(Level.INFO, "AudioRenderer supports {0} channels", channels.length);
supportEfx = ALC10.alcIsExtensionPresent(device, "ALC_EXT_EFX");
if (supportEfx) {
@ -190,11 +190,11 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
ib.position(0).limit(1);
ALC10.alcGetInteger(device, EFX10.ALC_EFX_MINOR_VERSION, ib);
int minor = ib.get(0);
logger.log(Level.FINE, "Audio effect extension version: {0}.{1}", new Object[]{major, minor});
logger.log(Level.INFO, "Audio effect extension version: {0}.{1}", new Object[]{major, minor});
ALC10.alcGetInteger(device, EFX10.ALC_MAX_AUXILIARY_SENDS, ib);
auxSends = ib.get(0);
logger.log(Level.FINE, "Audio max auxilary sends: {0}", auxSends);
logger.log(Level.INFO, "Audio max auxilary sends: {0}", auxSends);
// create slot
ib.position(0).limit(1);
@ -282,7 +282,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
f.clearUpdateNeeded();
}
public void updateSourceParam(AudioNode src, AudioParam param) {
public void updateSourceParam(AudioSource src, AudioParam param) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -295,10 +295,10 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
return;
}
// There is a race condition in AudioNode that can
// There is a race condition in AudioSource that can
// cause this to be called for a node that has been
// detached from its channel. For example, setVolume()
// called from the render thread may see that that AudioNode
// called from the render thread may see that that AudioSource
// still has a channel value but the audio thread may
// clear that channel before setVolume() gets to call
// updateSourceParam() (because the audio stopped playing
@ -317,7 +317,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
return;
}
Vector3f pos = src.getWorldTranslation();
Vector3f pos = src.getPosition();
alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z);
break;
case Velocity:
@ -456,9 +456,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
}
private void setSourceParams(int id, AudioNode src, boolean forceNonLoop) {
private void setSourceParams(int id, AudioSource src, boolean forceNonLoop) {
if (src.isPositional()) {
Vector3f pos = src.getWorldTranslation();
Vector3f pos = src.getPosition();
Vector3f vel = src.getVelocity();
alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z);
alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z);
@ -704,7 +704,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
private void clearChannel(int index) {
// make room at this channel
if (chanSrcs[index] != null) {
AudioNode src = chanSrcs[index];
AudioSource src = chanSrcs[index];
int sourceId = channels[index];
alSourceStop(sourceId);
@ -723,7 +723,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
alSourcei(sourceId, EFX10.AL_DIRECT_FILTER, EFX10.AL_FILTER_NULL);
}
if (src.isPositional()) {
AudioNode pas = (AudioNode) src;
AudioSource pas = (AudioSource) src;
if (pas.isReverbEnabled() && supportEfx) {
AL11.alSource3i(sourceId, EFX10.AL_AUXILIARY_SEND_FILTER, 0, 0, EFX10.AL_FILTER_NULL);
}
@ -743,7 +743,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
for (int i = 0; i < channels.length; i++) {
AudioNode src = chanSrcs[i];
AudioSource src = chanSrcs[i];
if (src == null) {
continue;
}
@ -830,7 +830,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
}
public void playSourceInstance(AudioNode src) {
public void playSourceInstance(AudioSource src) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -873,7 +873,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
}
public void playSource(AudioNode src) {
public void playSource(AudioSource src) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -916,7 +916,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
}
public void pauseSource(AudioNode src) {
public void pauseSource(AudioSource src) {
checkDead();
synchronized (threadLock) {
while (!threadLock.get()) {
@ -938,7 +938,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
}
}
public void stopSource(AudioNode src) {
public void stopSource(AudioSource src) {
synchronized (threadLock) {
while (!threadLock.get()) {
try {

Loading…
Cancel
Save