* Update to LWJGL 2.8.1

* Audio system to use new NativeObject class for managing audio buffers and filters
 * Formatting for AndroidAudioRenderer
 * Changed AndroidAudioData to match new NativeObject class
 * AudioNode now serializes the audio key as "audio_key" instead "key"
 

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8423 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
sha..rd 13 years ago
parent 107380afc1
commit 55bfc5f0cf
  1. 6
      engine/lib/lwjgl/CREDITS
  2. 2
      engine/lib/lwjgl/README
  3. BIN
      engine/lib/lwjgl/jME3-lwjgl-natives.jar
  4. BIN
      engine/lib/lwjgl/lwjgl-debug.jar
  5. BIN
      engine/lib/lwjgl/lwjgl.jar
  6. 42
      engine/src/android/com/jme3/audio/android/AndroidAudioData.java
  7. 792
      engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java
  8. 78
      engine/src/core/com/jme3/audio/ALObject.java
  9. 18
      engine/src/core/com/jme3/audio/AudioBuffer.java
  10. 12
      engine/src/core/com/jme3/audio/AudioData.java
  11. 46
      engine/src/core/com/jme3/audio/AudioNode.java
  12. 1
      engine/src/core/com/jme3/audio/AudioRenderer.java
  13. 22
      engine/src/core/com/jme3/audio/AudioStream.java
  14. 40
      engine/src/core/com/jme3/audio/Filter.java
  15. 11
      engine/src/core/com/jme3/audio/LowPassFilter.java
  16. 32
      engine/src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java

@ -3,7 +3,7 @@ The following people have helped to make this project what it is today:
- Brian Matzon <brian@matzon.dk> - Brian Matzon <brian@matzon.dk>
- Elias Naur <elias.naur@gmail.com> - Elias Naur <elias.naur@gmail.com>
- Ioannis Tsakpinis <spasi@users.sourceforge.net> - Ioannis Tsakpinis <spasi@users.sourceforge.net>
- Niels Jørgensen <nj@niemo.com> - Niels J<EFBFBD>rgensen <nj@niemo.com>
- Tristan Campbell <tristan@happypedestrian.com> - Tristan Campbell <tristan@happypedestrian.com>
- Gregory Pierce <gregorypierce@yahoo.com> - Gregory Pierce <gregorypierce@yahoo.com>
- Luke Holden <lholden@users.sf.net> - Luke Holden <lholden@users.sf.net>
@ -12,12 +12,14 @@ The following people have helped to make this project what it is today:
- Jos Hirth <jhirth@kaioa.com> - Jos Hirth <jhirth@kaioa.com>
- Kevin Glass <kevin@cokeandcode.com> - Kevin Glass <kevin@cokeandcode.com>
- Atsuya Takagi - Atsuya Takagi
- kappaOne - kappaOne <one.kappa@gmail.com>
- Simon Felix - Simon Felix
- Ryan McNally - Ryan McNally
- Ciardhubh <ciardhubh[at]ciardhubh.de> - Ciardhubh <ciardhubh[at]ciardhubh.de>
- Jens von Pilgrim - Jens von Pilgrim
- Ruben Garat - Ruben Garat
- Pelle Johnsen <pelle.johnsen@gmail.com>
- Jae Kwon
additional credits goes to: additional credits goes to:
- Joseph I. Valenzuela [OpenAL stuff] - Joseph I. Valenzuela [OpenAL stuff]

@ -1,4 +1,4 @@
This is the official readme file for lwjgl! This is the official readme file for lwjgl.
Unless otherwise stated, all files distributed or in SVN are covered by Unless otherwise stated, all files distributed or in SVN are covered by
the license as stated in the LICENSE file. If you have not received this the license as stated in the LICENSE file. If you have not received this

Binary file not shown.

Binary file not shown.

@ -3,12 +3,20 @@ package com.jme3.audio.android;
import com.jme3.asset.AssetKey; import com.jme3.asset.AssetKey;
import com.jme3.audio.AudioData; import com.jme3.audio.AudioData;
import com.jme3.audio.AudioRenderer; import com.jme3.audio.AudioRenderer;
import com.jme3.util.NativeObject;
public class AndroidAudioData extends AudioData {
public class AndroidAudioData extends AudioData
{
protected AssetKey assetKey; protected AssetKey assetKey;
protected int soundId = 0;
protected float currentVolume = 0f; protected float currentVolume = 0f;
public AndroidAudioData(){
super();
}
protected AndroidAudioData(int id){
super(id);
}
public AssetKey getAssetKey() { public AssetKey getAssetKey() {
return assetKey; return assetKey;
@ -18,35 +26,25 @@ public class AndroidAudioData extends AudioData
this.assetKey = assetKey; this.assetKey = assetKey;
} }
public int getSoundId() {
return soundId;
}
public void setSoundId(int soundId) {
this.soundId = soundId;
}
@Override @Override
public DataType getDataType() { public DataType getDataType() {
// TODO Auto-generated method stub return DataType.Buffer;
return null;
} }
@Override @Override
public float getDuration() { public float getDuration() {
// TODO Auto-generated method stub return 0; // TODO: ???
return 0;
} }
@Override @Override
public void resetObject() { public void resetObject() {
// TODO Auto-generated method stub this.id = -1;
setUpdateNeeded();
} }
@Override @Override
public void deleteObject(AudioRenderer r) { public void deleteObject(Object rendererObject) {
r.deleteAudioData(this); ((AudioRenderer)rendererObject).deleteAudioData(this);
} }
public float getCurrentVolume() { public float getCurrentVolume() {
@ -56,7 +54,9 @@ public class AndroidAudioData extends AudioData
public void setCurrentVolume(float currentVolume) { public void setCurrentVolume(float currentVolume) {
this.currentVolume = currentVolume; this.currentVolume = currentVolume;
} }
@Override
public NativeObject createDestructableClone() {
return new AndroidAudioData(id);
}
} }

@ -64,165 +64,161 @@ 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;
/** /**
* This class is the android implementation for {@link AudioRenderer} * This class is the android implementation for {@link AudioRenderer}
* @author larynx * @author larynx
* *
*/ */
public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadCompleteListener, MediaPlayer.OnCompletionListener public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadCompleteListener, MediaPlayer.OnCompletionListener {
{
private static final Logger logger = Logger.getLogger(AndroidAudioRenderer.class.getName()); private static final Logger logger = Logger.getLogger(AndroidAudioRenderer.class.getName());
private final static int MAX_NUM_CHANNELS = 16; private final static int MAX_NUM_CHANNELS = 16;
private SoundPool soundPool = null; private SoundPool soundPool = null;
private HashMap<AudioNode, MediaPlayer> musicPlaying = new HashMap<AudioNode, MediaPlayer>(); private HashMap<AudioNode, MediaPlayer> musicPlaying = new HashMap<AudioNode, MediaPlayer>();
private final Vector3f listenerPosition = new Vector3f(); private final Vector3f listenerPosition = new Vector3f();
// For temp use // For temp use
private final Vector3f distanceVector = new Vector3f(); private final Vector3f distanceVector = new Vector3f();
private final AudioManager manager; private final AudioManager manager;
private final Context context; private final Context context;
private final AssetManager am; private final AssetManager am;
private HashMap<Integer, AudioNode> mapLoadingAudioNodes = new HashMap<Integer, AudioNode>(); private HashMap<Integer, AudioNode> mapLoadingAudioNodes = new HashMap<Integer, AudioNode>();
private final AtomicBoolean lastLoadCompleted = new AtomicBoolean(); private final AtomicBoolean lastLoadCompleted = new AtomicBoolean();
private Listener listener; private Listener listener;
private boolean audioDisabled = false; private boolean audioDisabled = false;
public AndroidAudioRenderer(Activity context) {
public AndroidAudioRenderer(Activity context)
{
this.context = context; this.context = context;
manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); manager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
context.setVolumeControlStream(AudioManager.STREAM_MUSIC); context.setVolumeControlStream(AudioManager.STREAM_MUSIC);
am = context.getAssets(); am = context.getAssets();
} }
@Override @Override
public void initialize() public void initialize() {
{ soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC, 0);
soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(this); soundPool.setOnLoadCompleteListener(this);
} }
@Override @Override
public void updateSourceParam(AudioNode src, AudioParam param) public void updateSourceParam(AudioNode src, AudioParam param) {
{
//logger.log(Level.INFO, "updateSourceParam " + param); //logger.log(Level.INFO, "updateSourceParam " + param);
if (audioDisabled)
return;
if (src.getChannel() < 0)
return;
assert src.getChannel() >= 0;
switch (param){
case Position:
if (!src.isPositional())
return;
Vector3f pos = src.getWorldTranslation();
break;
case Velocity:
if (!src.isPositional())
return;
Vector3f vel = src.getVelocity();
break;
case MaxDistance:
if (!src.isPositional())
return;
break;
case RefDistance:
if (!src.isPositional())
return;
break;
case ReverbFilter:
if (!src.isPositional() || !src.isReverbEnabled())
return;
break;
case ReverbEnabled:
if (!src.isPositional())
return;
if (src.isReverbEnabled()){
updateSourceParam(src, AudioParam.ReverbFilter);
}
break;
case IsPositional:
break;
case Direction:
if (!src.isDirectional())
return;
Vector3f dir = src.getDirection();
break;
case InnerAngle:
if (!src.isDirectional())
return;
break;
case OuterAngle:
if (!src.isDirectional())
return;
break;
case IsDirectional:
if (src.isDirectional()){
updateSourceParam(src, AudioParam.Direction);
updateSourceParam(src, AudioParam.InnerAngle);
updateSourceParam(src, AudioParam.OuterAngle);
}else{
}
break;
case DryFilter:
if (src.getDryFilter() != null){
Filter f = src.getDryFilter();
if (f.isUpdateNeeded()){
//updateFilter(f);
} if (audioDisabled) {
} return;
break; }
case Looping:
if (src.isLooping()){ if (src.getChannel() < 0) {
return;
}
assert src.getChannel() >= 0;
switch (param) {
case Position:
if (!src.isPositional()) {
return;
}
Vector3f pos = src.getWorldTranslation();
break;
case Velocity:
if (!src.isPositional()) {
return;
}
Vector3f vel = src.getVelocity();
break;
case MaxDistance:
if (!src.isPositional()) {
return;
}
break;
case RefDistance:
if (!src.isPositional()) {
return;
}
break;
case ReverbFilter:
if (!src.isPositional() || !src.isReverbEnabled()) {
return;
}
break;
case ReverbEnabled:
if (!src.isPositional()) {
return;
}
if (src.isReverbEnabled()) {
updateSourceParam(src, AudioParam.ReverbFilter);
}
break;
case IsPositional:
break;
case Direction:
if (!src.isDirectional()) {
return;
}
Vector3f dir = src.getDirection();
break;
case InnerAngle:
if (!src.isDirectional()) {
return;
}
break;
case OuterAngle:
if (!src.isDirectional()) {
return;
}
break;
case IsDirectional:
if (src.isDirectional()) {
updateSourceParam(src, AudioParam.Direction);
updateSourceParam(src, AudioParam.InnerAngle);
updateSourceParam(src, AudioParam.OuterAngle);
} else {
}
break;
case DryFilter:
if (src.getDryFilter() != null) {
Filter f = src.getDryFilter();
if (f.isUpdateNeeded()) {
//updateFilter(f);
} }
break; }
case Volume: break;
case Looping:
soundPool.setVolume(src.getChannel(), src.getVolume(), src.getVolume()); if (src.isLooping()) {
}
break;
case Volume:
break; soundPool.setVolume(src.getChannel(), src.getVolume(), src.getVolume());
case Pitch:
break;
case Pitch:
break;
}
break;
}
} }
@Override @Override
public void updateListenerParam(Listener listener, ListenerParam param) public void updateListenerParam(Listener listener, ListenerParam param) {
{
//logger.log(Level.INFO, "updateListenerParam " + param); //logger.log(Level.INFO, "updateListenerParam " + param);
if (audioDisabled) if (audioDisabled) {
return; return;
}
switch (param){
switch (param) {
case Position: case Position:
listenerPosition.set(listener.getLocation()); listenerPosition.set(listener.getLocation());
break; break;
case Rotation: case Rotation:
Vector3f dir = listener.getDirection(); Vector3f dir = listener.getDirection();
Vector3f up = listener.getUp(); Vector3f up = listener.getUp();
break; break;
case Velocity: case Velocity:
@ -237,436 +233,358 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
} }
@Override @Override
public void update(float tpf) public void update(float tpf) {
{
float distance; float distance;
float volume; float volume;
// Loop over all mediaplayers // Loop over all mediaplayers
for (AudioNode src : musicPlaying.keySet()) for (AudioNode src : musicPlaying.keySet()) {
{
MediaPlayer mp = musicPlaying.get(src); MediaPlayer mp = musicPlaying.get(src);
{ {
// Calc the distance to the listener // Calc the distance to the listener
distanceVector.set(listenerPosition); distanceVector.set(listenerPosition);
distanceVector.subtractLocal(src.getLocalTranslation()); distanceVector.subtractLocal(src.getLocalTranslation());
distance = FastMath.abs(distanceVector.length()); distance = FastMath.abs(distanceVector.length());
if (distance < src.getRefDistance()) if (distance < src.getRefDistance()) {
distance = src.getRefDistance(); distance = src.getRefDistance();
if (distance > src.getMaxDistance()) }
distance = src.getMaxDistance(); if (distance > src.getMaxDistance()) {
distance = src.getMaxDistance();
}
volume = src.getRefDistance() / distance; volume = src.getRefDistance() / distance;
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData(); AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
if (FastMath.abs(audioData.getCurrentVolume() - volume) > FastMath.FLT_EPSILON) if (FastMath.abs(audioData.getCurrentVolume() - volume) > FastMath.FLT_EPSILON) {
{
// Left / Right channel get the same volume by now, only positional // Left / Right channel get the same volume by now, only positional
mp.setVolume(volume, volume); mp.setVolume(volume, volume);
audioData.setCurrentVolume(volume); audioData.setCurrentVolume(volume);
} }
} }
} }
} }
public void setListener(Listener listener) {
public void setListener(Listener listener) if (audioDisabled) {
{ return;
if (audioDisabled) }
return;
if (this.listener != null){ if (this.listener != null) {
// previous listener no longer associated with current // previous listener no longer associated with current
// renderer // renderer
this.listener.setRenderer(null); this.listener.setRenderer(null);
} }
this.listener = listener; this.listener = listener;
this.listener.setRenderer(this); this.listener.setRenderer(this);
} }
@Override @Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
{
AudioNode src = mapLoadingAudioNodes.get(sampleId); AudioNode src = mapLoadingAudioNodes.get(sampleId);
if (src.getAudioData() instanceof AndroidAudioData) if (src.getAudioData() instanceof AndroidAudioData) {
{ AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();
if (status == 0) // load was successfull
if (status == 0) // load was successfull
{ {
int channelIndex; int channelIndex;
channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f); channelIndex = soundPool.play(audioData.getId(), 1f, 1f, 1, -1, 1f);
src.setChannel(channelIndex); src.setChannel(channelIndex);
// Playing started ? // Playing started ?
if (src.getChannel() > 0) if (src.getChannel() > 0) {
{
src.setStatus(Status.Playing); src.setStatus(Status.Playing);
} }
} else {
src.setChannel(-1);
} }
else } else {
{
src.setChannel(-1);
}
}
else
{
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString()); throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
} }
} }
@Override @Override
public void cleanup() public void cleanup() {
{
// Cleanup sound pool // Cleanup sound pool
if (soundPool != null) if (soundPool != null) {
{ for (AudioNode src : mapLoadingAudioNodes.values()) {
for (AudioNode src: mapLoadingAudioNodes.values()) if ((src.getStatus() == Status.Playing) && (src.getChannel() > 0)) {
{
if ((src.getStatus() == Status.Playing) && (src.getChannel() > 0))
{
soundPool.stop(src.getChannel()); soundPool.stop(src.getChannel());
} }
if (src.getAudioData() instanceof AndroidAudioData) if (src.getAudioData() instanceof AndroidAudioData) {
{ AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData(); if (audioData.getId() > 0) {
if (audioData.getSoundId() > 0) soundPool.unload(audioData.getId());
{ }
soundPool.unload(audioData.getSoundId()); }
}
}
} }
soundPool.release(); soundPool.release();
soundPool = null; soundPool = null;
} }
// Cleanup media player // Cleanup media player
for (AudioNode src : musicPlaying.keySet()) for (AudioNode src : musicPlaying.keySet()) {
{
MediaPlayer mp = musicPlaying.get(src); MediaPlayer mp = musicPlaying.get(src);
{ {
mp.stop(); mp.stop();
mp.release(); mp.release();
src.setStatus(Status.Stopped); src.setStatus(Status.Stopped);
} }
} }
musicPlaying.clear(); musicPlaying.clear();
} }
@Override @Override
public void onCompletion(MediaPlayer mp) public void onCompletion(MediaPlayer mp) {
{ for (AudioNode src : musicPlaying.keySet()) {
for (AudioNode src : musicPlaying.keySet()) if (musicPlaying.get(src) == mp) {
{ mp.seekTo(0);
if (musicPlaying.get(src) == mp)
{
mp.seekTo(0);
mp.stop(); mp.stop();
src.setStatus(Status.Stopped); src.setStatus(Status.Stopped);
break; break;
} }
} }
} }
public void playSourceInstance(AudioNode src) public void playSourceInstance(AudioNode src) {
{ if (audioDisabled) {
if (audioDisabled) return;
return; }
AndroidAudioData audioData; AndroidAudioData audioData;
int soundId = 0; int soundId = 0;
if (src.getAudioData() instanceof AndroidAudioData) if (src.getAudioData() instanceof AndroidAudioData) {
{ audioData = (AndroidAudioData) src.getAudioData();
audioData = (AndroidAudioData)src.getAudioData();
if (audioData.getAssetKey() instanceof AudioKey) {
if (audioData.getAssetKey() instanceof AudioKey) AudioKey assetKey = (AudioKey) audioData.getAssetKey();
{
AudioKey assetKey = (AudioKey) audioData.getAssetKey(); // streaming audionodes get played using android mediaplayer, non streaming uses SoundPool
if (assetKey.isStream()) {
// streaming audionodes get played using android mediaplayer, non streaming uses SoundPool MediaPlayer mp;
if (assetKey.isStream()) if (musicPlaying.containsKey(src)) {
{ mp = musicPlaying.get(src);
MediaPlayer mp; } else {
if (musicPlaying.containsKey(src)) mp = new MediaPlayer();
{ mp.setOnCompletionListener(this);
mp = musicPlaying.get(src); //mp = MediaPlayer.create(context, new Ur );
} musicPlaying.put(src, mp);
else }
{ if (!mp.isPlaying()) {
mp = new MediaPlayer(); try {
mp.setOnCompletionListener(this); AssetFileDescriptor afd = am.openFd(assetKey.getName());
//mp = MediaPlayer.create(context, new Ur ); mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
musicPlaying.put(src, mp);
} mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
if (!mp.isPlaying()) mp.prepare();
{ mp.setLooping(src.isLooping());
try { mp.start();
AssetFileDescriptor afd = am.openFd(assetKey.getName()); src.setChannel(1);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); src.setStatus(Status.Playing);
} catch (IllegalArgumentException e) {
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); logger.log(Level.SEVERE, "Failed to play " + assetKey.getName(), e);
mp.prepare(); } catch (IllegalStateException e) {
mp.setLooping(src.isLooping()); // TODO Auto-generated catch block
mp.start(); logger.log(Level.SEVERE, "Failed to play " + assetKey.getName(), e);
src.setChannel(1); } catch (IOException e) {
src.setStatus(Status.Playing); // TODO Auto-generated catch block
} catch (IllegalArgumentException e) logger.log(Level.SEVERE, "Failed to play " + assetKey.getName(), e);
{
logger.log(Level.SEVERE, "Failed to play " + assetKey.getName(), e);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
logger.log(Level.SEVERE, "Failed to play " + assetKey.getName(), e);
} catch (IOException e) {
// TODO Auto-generated catch block
logger.log(Level.SEVERE, "Failed to play " + assetKey.getName(), e);
}
} }
} }
else
{ } else {
// Low latency Sound effect using SoundPool // Low latency Sound effect using SoundPool
if (audioData.isUpdateNeeded() || (audioData.getSoundId() <= 0)) if (audioData.isUpdateNeeded() || (audioData.getId() <= 0)) {
{ if (audioData.getId() > 0) {
if (audioData.getSoundId() > 0) if (src.getChannel() > 0) {
{ soundPool.stop(src.getChannel());
if (src.getChannel() > 0) src.setChannel(-1);
{
soundPool.stop(src.getChannel());
src.setChannel(-1);
}
soundPool.unload(audioData.getSoundId());
}
try
{
soundId = soundPool.load(am.openFd(assetKey.getName()), 1);
}
catch (IOException e)
{
logger.log(Level.SEVERE, "Failed to load sound " + assetKey.getName(), e);
soundId = -1;
} }
audioData.setSoundId(soundId); soundPool.unload(audioData.getId());
}
// Sound failed to load ?
if (audioData.getSoundId() <= 0)
{
throw new IllegalArgumentException("Failed to load: " + assetKey.getName());
} }
else
{ try {
int channelIndex; soundId = soundPool.load(am.openFd(assetKey.getName()), 1);
channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f); } catch (IOException e) {
if (channelIndex == 0) logger.log(Level.SEVERE, "Failed to load sound " + assetKey.getName(), e);
{ soundId = -1;
// Loading is not finished
// Store the soundId and the AudioNode for async loading and later play start
mapLoadingAudioNodes.put(audioData.getSoundId(), src);
}
src.setChannel(channelIndex);
} }
audioData.setId(soundId);
// Playing started ? }
if (src.getChannel() > 0)
{ // Sound failed to load ?
src.setStatus(Status.Playing); if (audioData.getId() <= 0) {
throw new IllegalArgumentException("Failed to load: " + assetKey.getName());
} else {
int channelIndex;
channelIndex = soundPool.play(audioData.getId(), 1f, 1f, 1, -1, 1f);
if (channelIndex == 0) {
// Loading is not finished
// Store the soundId and the AudioNode for async loading and later play start
mapLoadingAudioNodes.put(audioData.getId(), src);
} }
src.setChannel(channelIndex);
}
// Playing started ?
if (src.getChannel() > 0) {
src.setStatus(Status.Playing);
} }
} }
} }
else } else {
{ throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString()); }
}
} }
public void playSource(AudioNode src) {
public void playSource(AudioNode src) if (audioDisabled) {
{ return;
if (audioDisabled) }
return;
//assert src.getStatus() == Status.Stopped || src.getChannel() == -1;
if (src.getStatus() == Status.Playing) {
return;
} else if (src.getStatus() == Status.Stopped) {
playSourceInstance(src);
}
//assert src.getStatus() == Status.Stopped || src.getChannel() == -1;
if (src.getStatus() == Status.Playing)
{
return;
}
else if (src.getStatus() == Status.Stopped)
{
playSourceInstance(src);
}
} }
public void pauseSource(AudioNode src) {
public void pauseSource(AudioNode src) if (audioDisabled) {
{ return;
if (audioDisabled) }
return;
if (src.getStatus() == Status.Playing) {
if (src.getStatus() == Status.Playing) if (src.getAudioData() instanceof AndroidAudioData) {
{ AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
if (src.getAudioData() instanceof AndroidAudioData) if (audioData.getAssetKey() instanceof AudioKey) {
{ AudioKey assetKey = (AudioKey) audioData.getAssetKey();
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();
if (audioData.getAssetKey() instanceof AudioKey) if (assetKey.isStream()) {
{ MediaPlayer mp;
AudioKey assetKey = (AudioKey) audioData.getAssetKey(); if (musicPlaying.containsKey(src)) {
mp = musicPlaying.get(src);
if (assetKey.isStream()) mp.pause();
{ src.setStatus(Status.Paused);
MediaPlayer mp;
if (musicPlaying.containsKey(src))
{
mp = musicPlaying.get(src);
mp.pause();
src.setStatus(Status.Paused);
}
} }
else } else {
{ assert src.getChannel() != -1;
assert src.getChannel() != -1;
if (src.getChannel() > 0) {
if (src.getChannel() > 0) soundPool.pause(src.getChannel());
{ src.setStatus(Status.Paused);
soundPool.pause(src.getChannel());
src.setStatus(Status.Paused);
}
} }
} }
} }
} }
}
} }
public void stopSource(AudioNode src) {
public void stopSource(AudioNode src) if (audioDisabled) {
{ return;
if (audioDisabled) }
return;
if (src.getStatus() != Status.Stopped) {
if (src.getStatus() != Status.Stopped) if (src.getAudioData() instanceof AndroidAudioData) {
{ AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
if (src.getAudioData() instanceof AndroidAudioData) if (audioData.getAssetKey() instanceof AudioKey) {
{ AudioKey assetKey = (AudioKey) audioData.getAssetKey();
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData(); if (assetKey.isStream()) {
if (audioData.getAssetKey() instanceof AudioKey) MediaPlayer mp;
{ if (musicPlaying.containsKey(src)) {
AudioKey assetKey = (AudioKey) audioData.getAssetKey(); mp = musicPlaying.get(src);
if (assetKey.isStream()) mp.stop();
{
MediaPlayer mp;
if (musicPlaying.containsKey(src))
{
mp = musicPlaying.get(src);
mp.stop();
src.setStatus(Status.Stopped);
src.setChannel(-1);
}
}
else
{
int chan = src.getChannel();
assert chan != -1; // if it's not stopped, must have id
if (src.getChannel() > 0)
{
soundPool.stop(src.getChannel());
src.setChannel(-1);
}
src.setStatus(Status.Stopped); src.setStatus(Status.Stopped);
src.setChannel(-1);
if (audioData.getSoundId() > 0) }
{ } else {
soundPool.unload(audioData.getSoundId()); int chan = src.getChannel();
} assert chan != -1; // if it's not stopped, must have id
audioData.setSoundId(-1);
if (src.getChannel() > 0) {
soundPool.stop(src.getChannel());
src.setChannel(-1);
}
src.setStatus(Status.Stopped);
if (audioData.getId() > 0) {
soundPool.unload(audioData.getId());
} }
audioData.setId(-1);
} }
} }
}
}
}
}
}
public void updateAudioData(AndroidAudioData data) public void updateAudioData(AndroidAudioData data) {
{
throw new UnsupportedOperationException("updateAudioData"); throw new UnsupportedOperationException("updateAudioData");
} }
public void deleteFilter(Filter filter) {
}
@Override @Override
public void deleteAudioData(AudioData ad) public void deleteAudioData(AudioData ad) {
{ if (ad instanceof AndroidAudioData) {
if (ad instanceof AndroidAudioData) AndroidAudioData audioData = (AndroidAudioData) ad;
{ if (audioData.getAssetKey() instanceof AudioKey) {
AndroidAudioData audioData = (AndroidAudioData)ad; AudioKey assetKey = (AudioKey) audioData.getAssetKey();
if (audioData.getAssetKey() instanceof AudioKey) if (assetKey.isStream()) {
{ for (AudioNode src : musicPlaying.keySet()) {
AudioKey assetKey = (AudioKey) audioData.getAssetKey(); if (src.getAudioData() == ad) {
if (assetKey.isStream())
{
for (AudioNode src : musicPlaying.keySet())
{
if (src.getAudioData() == ad)
{
MediaPlayer mp = musicPlaying.get(src); MediaPlayer mp = musicPlaying.get(src);
mp.stop(); mp.stop();
mp.release(); mp.release();
musicPlaying.remove(src); musicPlaying.remove(src);
src.setStatus(Status.Stopped); src.setStatus(Status.Stopped);
src.setChannel(-1); src.setChannel(-1);
break; break;
} }
} }
} } else {
else if (audioData.getId() > 0) {
{ soundPool.unload(audioData.getId());
if (audioData.getSoundId() > 0)
{
soundPool.unload(audioData.getSoundId());
} }
audioData.setSoundId(0); audioData.setId(0);
} }
} }
} } else {
else
{
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData in deleteAudioData"); throw new IllegalArgumentException("AudioData is not of type AndroidAudioData in deleteAudioData");
} }
} }
@Override @Override
public void setEnvironment(Environment env) { public void setEnvironment(Environment env) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
} }

@ -1,78 +0,0 @@
/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.audio;
/**
* Used for managing AL (Audio Library) objects.
*
* @author Kirill Vainer
*/
public abstract class ALObject {
protected int id = -1;
protected Object handleRef = null;
protected boolean updateNeeded = true;
public void setId(int id){
if (this.id != -1)
throw new IllegalStateException("ID has already been set for this AL object.");
this.id = id;
}
public int getId(){
return id;
}
public void setUpdateNeeded(){
updateNeeded = true;
}
public void clearUpdateNeeded(){
updateNeeded = false;
}
public boolean isUpdateNeeded(){
return updateNeeded;
}
@Override
public String toString(){
return getClass().getSimpleName() + " " + Integer.toHexString(hashCode());
}
public abstract void resetObject();
public abstract void deleteObject(AudioRenderer r);
}

@ -33,6 +33,7 @@
package com.jme3.audio; package com.jme3.audio;
import com.jme3.audio.AudioData.DataType; import com.jme3.audio.AudioData.DataType;
import com.jme3.util.NativeObject;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
@ -51,6 +52,11 @@ public class AudioBuffer extends AudioData {
protected ByteBuffer audioData; protected ByteBuffer audioData;
public AudioBuffer(){ public AudioBuffer(){
super();
}
protected AudioBuffer(int id){
super(id);
} }
public DataType getDataType() { public DataType getDataType() {
@ -98,7 +104,17 @@ public class AudioBuffer extends AudioData {
} }
public void deleteObject(AudioRenderer ar) { public void deleteObject(AudioRenderer ar) {
ar.deleteAudioData(this);
}
@Override
public void deleteObject(Object rendererObject) {
((AudioRenderer)rendererObject).deleteAudioData(this);
}
@Override
public NativeObject createDestructableClone() {
return new AudioBuffer(id);
} }
} }

@ -32,6 +32,8 @@
package com.jme3.audio; package com.jme3.audio;
import com.jme3.util.NativeObject;
/** /**
* <code>AudioData</code> is an abstract representation * <code>AudioData</code> is an abstract representation
* of audio data. There are two ways to handle audio data, short audio files * of audio data. There are two ways to handle audio data, short audio files
@ -40,7 +42,7 @@ package com.jme3.audio;
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public abstract class AudioData extends ALObject { public abstract class AudioData extends NativeObject {
protected int sampleRate; protected int sampleRate;
protected int channels; protected int channels;
@ -50,7 +52,15 @@ public abstract class AudioData extends ALObject {
Buffer, Buffer,
Stream Stream
} }
public AudioData(){
super(AudioData.class);
}
protected AudioData(int id){
super(AudioData.class, id);
}
/** /**
* @return The data type, either <code>Buffer</code> or <code>Stream</code>. * @return The data type, either <code>Buffer</code> or <code>Stream</code>.
*/ */

@ -64,7 +64,7 @@ public class AudioNode extends Node {
protected float pitch = 1; protected float pitch = 1;
protected float timeOffset = 0; protected float timeOffset = 0;
protected Filter dryFilter; protected Filter dryFilter;
protected AudioKey key; protected AudioKey audioKey;
protected transient AudioData data = null; protected transient AudioData data = null;
protected transient volatile Status status = Status.Stopped; protected transient volatile Status status = Status.Stopped;
protected transient volatile int channel = -1; protected transient volatile int channel = -1;
@ -123,22 +123,22 @@ public class AudioNode extends Node {
* *
* @param audioRenderer The audio renderer to use for playing. Cannot be null. * @param audioRenderer The audio renderer to use for playing. Cannot be null.
* @param audioData The audio data contains the audio track to play. * @param audioData The audio data contains the audio track to play.
* @param key The audio key that was used to load the AudioData * @param audioKey The audio key that was used to load the AudioData
* *
* @deprecated AudioRenderer parameter is ignored. * @deprecated AudioRenderer parameter is ignored.
*/ */
public AudioNode(AudioRenderer audioRenderer, AudioData audioData, AudioKey key) { public AudioNode(AudioRenderer audioRenderer, AudioData audioData, AudioKey audioKey) {
setAudioData(audioData, key); setAudioData(audioData, audioKey);
} }
/** /**
* Creates a new <code>AudioNode</code> with the given data and key. * Creates a new <code>AudioNode</code> with the given data and key.
* *
* @param audioData The audio data contains the audio track to play. * @param audioData The audio data contains the audio track to play.
* @param key The audio key that was used to load the AudioData * @param audioKey The audio key that was used to load the AudioData
*/ */
public AudioNode(AudioData audioData, AudioKey key) { public AudioNode(AudioData audioData, AudioKey audioKey) {
setAudioData(audioData, key); setAudioData(audioData, audioKey);
} }
/** /**
@ -157,8 +157,8 @@ public class AudioNode extends Node {
* @deprecated AudioRenderer parameter is ignored. * @deprecated AudioRenderer parameter is ignored.
*/ */
public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name, boolean stream, boolean streamCache) { public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name, boolean stream, boolean streamCache) {
this.key = new AudioKey(name, stream, streamCache); this.audioKey = new AudioKey(name, stream, streamCache);
this.data = (AudioData) assetManager.loadAsset(key); this.data = (AudioData) assetManager.loadAsset(audioKey);
} }
/** /**
@ -174,8 +174,8 @@ public class AudioNode extends Node {
* seeking, looping and determining duration. * seeking, looping and determining duration.
*/ */
public AudioNode(AssetManager assetManager, String name, boolean stream, boolean streamCache) { public AudioNode(AssetManager assetManager, String name, boolean stream, boolean streamCache) {
this.key = new AudioKey(name, stream, streamCache); this.audioKey = new AudioKey(name, stream, streamCache);
this.data = (AudioData) assetManager.loadAsset(key); this.data = (AudioData) assetManager.loadAsset(audioKey);
} }
/** /**
@ -309,15 +309,15 @@ public class AudioNode extends Node {
* without an {@link AudioData}. * without an {@link AudioData}.
* *
* @param audioData The audio data contains the audio track to play. * @param audioData The audio data contains the audio track to play.
* @param key The audio key that was used to load the AudioData * @param audioKey The audio key that was used to load the AudioData
*/ */
public void setAudioData(AudioData audioData, AudioKey key) { public void setAudioData(AudioData audioData, AudioKey audioKey) {
if (data != null) { if (data != null) {
throw new IllegalStateException("Cannot change data once its set"); throw new IllegalStateException("Cannot change data once its set");
} }
data = audioData; data = audioData;
this.key = key; this.audioKey = audioKey;
} }
/** /**
@ -713,7 +713,7 @@ public class AudioNode extends Node {
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
super.write(ex); super.write(ex);
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
oc.write(key, "key", null); oc.write(audioKey, "audio_key", null);
oc.write(loop, "looping", false); oc.write(loop, "looping", false);
oc.write(volume, "volume", 1); oc.write(volume, "volume", 1);
oc.write(pitch, "pitch", 1); oc.write(pitch, "pitch", 1);
@ -738,7 +738,16 @@ public class AudioNode extends Node {
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
super.read(im); super.read(im);
InputCapsule ic = im.getCapsule(this); InputCapsule ic = im.getCapsule(this);
key = (AudioKey) ic.readSavable("key", null);
// NOTE: In previous versions of jME3, audioKey was actually
// written with the name "key". This has been changed
// to "audio_key" in case Spatial's key will be written as "key".
if (ic.getSavableVersion(AudioNode.class) == 0){
audioKey = (AudioKey) ic.readSavable("key", null);
}else{
audioKey = (AudioKey) ic.readSavable("audio_key", null);
}
loop = ic.readBoolean("looping", false); loop = ic.readBoolean("looping", false);
volume = ic.readFloat("volume", 1); volume = ic.readFloat("volume", 1);
pitch = ic.readFloat("pitch", 1); pitch = ic.readFloat("pitch", 1);
@ -758,8 +767,9 @@ public class AudioNode extends Node {
positional = ic.readBoolean("positional", false); positional = ic.readBoolean("positional", false);
if (key != null) if (audioKey != null) {
data = im.getAssetManager().loadAudio(key); data = im.getAssetManager().loadAudio(audioKey);
}
} }
@Override @Override

@ -61,6 +61,7 @@ public interface AudioRenderer {
public void updateSourceParam(AudioNode src, AudioParam param); public void updateSourceParam(AudioNode src, AudioParam param);
public void updateListenerParam(Listener listener, ListenerParam param); public void updateListenerParam(Listener listener, ListenerParam param);
public void deleteFilter(Filter filter);
public void deleteAudioData(AudioData ad); public void deleteAudioData(AudioData ad);
/** /**

@ -32,6 +32,7 @@
package com.jme3.audio; package com.jme3.audio;
import com.jme3.util.NativeObject;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -52,6 +53,16 @@ public class AudioStream extends AudioData implements Closeable{
protected int[] ids; protected int[] ids;
public AudioStream(){ public AudioStream(){
super();
}
protected AudioStream(int[] ids){
// Pass some dummy ID so handle
// doesn't get created.
super(-1);
// This is what gets destroyed in reality
this.ids = ids;
} }
public void updateData(InputStream in, float duration){ public void updateData(InputStream in, float duration){
@ -142,10 +153,17 @@ public class AudioStream extends AudioData implements Closeable{
} }
@Override @Override
public void deleteObject(AudioRenderer r) { public void deleteObject(Object rendererObject) {
r.deleteAudioData(this); // It seems that the audio renderer is already doing a good
// job at deleting audio streams when they finish playing.
// ((AudioRenderer)rendererObject).deleteAudioData(this);
} }
@Override
public NativeObject createDestructableClone() {
return new AudioStream(ids);
}
/** /**
* @return Whether the stream is open or not. Reading from a closed * @return Whether the stream is open or not. Reading from a closed
* stream will always return eof. * stream will always return eof.

@ -35,29 +35,19 @@ package com.jme3.audio;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.Savable; import com.jme3.export.Savable;
import com.jme3.util.NativeObject;
import java.io.IOException; import java.io.IOException;
public class Filter implements Savable { public abstract class Filter extends NativeObject implements Savable {
protected int id = -1; public Filter(){
protected boolean updateNeeded = true; super(Filter.class);
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
} }
public void clearUpdateNeeded(){ protected Filter(int id){
this.updateNeeded = false; super(Filter.class, id);
}
public boolean isUpdateNeeded() {
return updateNeeded;
} }
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
// nothing to save // nothing to save
} }
@ -66,4 +56,18 @@ public class Filter implements Savable {
// nothing to read // nothing to read
} }
@Override
public void resetObject() {
this.id = -1;
setUpdateNeeded();
}
@Override
public void deleteObject(Object rendererObject) {
((AudioRenderer)rendererObject).deleteFilter(this);
}
@Override
public abstract NativeObject createDestructableClone();
} }

@ -36,6 +36,7 @@ import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.InputCapsule; import com.jme3.export.InputCapsule;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.util.NativeObject;
import java.io.IOException; import java.io.IOException;
public class LowPassFilter extends Filter { public class LowPassFilter extends Filter {
@ -43,9 +44,14 @@ public class LowPassFilter extends Filter {
protected float volume, highFreqVolume; protected float volume, highFreqVolume;
public LowPassFilter(float volume, float highFreqVolume) { public LowPassFilter(float volume, float highFreqVolume) {
super();
setVolume(volume); setVolume(volume);
setHighFreqVolume(highFreqVolume); setHighFreqVolume(highFreqVolume);
} }
protected LowPassFilter(int id){
super(id);
}
public float getHighFreqVolume() { public float getHighFreqVolume() {
return highFreqVolume; return highFreqVolume;
@ -86,4 +92,9 @@ public class LowPassFilter extends Filter {
highFreqVolume = ic.readFloat("hf_volume", 0); highFreqVolume = ic.readFloat("hf_volume", 0);
} }
@Override
public NativeObject createDestructableClone() {
return new LowPassFilter(id);
}
} }

@ -46,6 +46,7 @@ import com.jme3.audio.Listener;
import com.jme3.audio.LowPassFilter; import com.jme3.audio.LowPassFilter;
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 java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
@ -68,6 +69,8 @@ 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();
// 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;
@ -228,7 +231,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
EFX10.alEffecti(reverbFx, EFX10.AL_EFFECT_TYPE, EFX10.AL_EFFECT_REVERB); EFX10.alEffecti(reverbFx, EFX10.AL_EFFECT_TYPE, EFX10.AL_EFFECT_REVERB);
// attach reverb effect to effect slot // attach reverb effect to effect slot
// EFX10.alAuxiliaryEffectSloti(reverbFxSlot, EFX10.AL_EFFECTSLOT_EFFECT, reverbFx); EFX10.alAuxiliaryEffectSloti(reverbFxSlot, EFX10.AL_EFFECTSLOT_EFFECT, reverbFx);
}else{ }else{
logger.log(Level.WARNING, "OpenAL EFX not available! Audio effects won't work."); logger.log(Level.WARNING, "OpenAL EFX not available! Audio effects won't work.");
} }
@ -252,19 +255,22 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
ib.put(channels); ib.put(channels);
ib.flip(); ib.flip();
alDeleteSources(ib); alDeleteSources(ib);
// delete audio buffers and filters
objManager.deleteAllObjects(this);
if (supportEfx){ if (supportEfx){
ib.position(0).limit(1); ib.position(0).limit(1);
ib.put(0, reverbFx); ib.put(0, reverbFx);
EFX10.alDeleteEffects(ib); EFX10.alDeleteEffects(ib);
// If this is not allocated, why is it deleted?
// Commented out to fix native crash in OpenAL.
ib.position(0).limit(1); ib.position(0).limit(1);
ib.put(0, reverbFxSlot); ib.put(0, reverbFxSlot);
EFX10.alDeleteAuxiliaryEffectSlots(ib); EFX10.alDeleteAuxiliaryEffectSlots(ib);
} }
// TODO: Cleanup buffers allocated for audio buffers and streams
AL.destroy(); AL.destroy();
} }
@ -282,6 +288,8 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
EFX10.alGenFilters(ib); EFX10.alGenFilters(ib);
id = ib.get(0); id = ib.get(0);
f.setId(id); f.setId(id);
objManager.registerForCleanup(f);
} }
if (f instanceof LowPassFilter){ if (f instanceof LowPassFilter){
@ -296,7 +304,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
f.clearUpdateNeeded(); f.clearUpdateNeeded();
} }
public void updateSourceParam(AudioNode src, AudioParam param){ public void updateSourceParam(AudioNode src, AudioParam param){
checkDead(); checkDead();
synchronized (threadLock){ synchronized (threadLock){
@ -792,6 +800,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
} }
} }
} }
// Delete any unused objects.
objManager.deleteUnused(this);
} }
public void setListener(Listener listener) { public void setListener(Listener listener) {
@ -983,6 +994,8 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
alGenBuffers(ib); alGenBuffers(ib);
id = ib.get(0); id = ib.get(0);
ab.setId(id); ab.setId(id);
objManager.registerForCleanup(ab);
} }
ab.getData().clear(); ab.getData().clear();
@ -1001,6 +1014,10 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
ib.position(0).limit(STREAMING_BUFFER_COUNT); ib.position(0).limit(STREAMING_BUFFER_COUNT);
ib.get(ids); ib.get(ids);
// Not registered with object manager.
// AudioStreams can be handled without object manager
// since their lifecycle is known to the audio renderer.
as.setIds(ids); as.setIds(ids);
as.clearUpdateNeeded(); as.clearUpdateNeeded();
} }
@ -1012,6 +1029,13 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
updateAudioStream((AudioStream) ad); updateAudioStream((AudioStream) ad);
} }
} }
public void deleteFilter(Filter filter) {
int id = filter.getId();
if (id != -1){
EFX10.alDeleteFilters(id);
}
}
public void deleteAudioData(AudioData ad){ public void deleteAudioData(AudioData ad){
synchronized (threadLock){ synchronized (threadLock){

Loading…
Cancel
Save