Some changes to bring OpenAL code in line with OpenGL code: use a
Java object to represent each OpenAL object (listener, sources, and buffers) and delete the OpenAL object if the Java object is garbage-collected. Added the full range of listener and source settings. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@653 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -0,0 +1,113 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.openal;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.openal.AL10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an OpenAL buffer object.
|
||||||
|
*/
|
||||||
|
public class Buffer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a new buffer for the specified sound manager.
|
||||||
|
*/
|
||||||
|
public Buffer (SoundManager soundmgr)
|
||||||
|
{
|
||||||
|
_soundmgr = soundmgr;
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(1);
|
||||||
|
AL10.alGenBuffers(idbuf);
|
||||||
|
_id = idbuf.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this buffer's OpenAL identifier.
|
||||||
|
*/
|
||||||
|
public final int getId ()
|
||||||
|
{
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data in this buffer.
|
||||||
|
*/
|
||||||
|
public void setData (int format, ByteBuffer data, int frequency)
|
||||||
|
{
|
||||||
|
AL10.alBufferData(_id, format, data, frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data in this buffer.
|
||||||
|
*/
|
||||||
|
public void setData (int format, IntBuffer data, int frequency)
|
||||||
|
{
|
||||||
|
AL10.alBufferData(_id, format, data, frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data in this buffer.
|
||||||
|
*/
|
||||||
|
public void setData (int format, ShortBuffer data, int frequency)
|
||||||
|
{
|
||||||
|
AL10.alBufferData(_id, format, data, frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of this buffer.
|
||||||
|
*/
|
||||||
|
public int getSize ()
|
||||||
|
{
|
||||||
|
return AL10.alGetBufferi(_id, AL10.AL_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this buffer, rendering it unusable.
|
||||||
|
*/
|
||||||
|
public void delete ()
|
||||||
|
{
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(1);
|
||||||
|
idbuf.put(_id).rewind();
|
||||||
|
AL10.alDeleteBuffers(idbuf);
|
||||||
|
_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
protected void finalize ()
|
||||||
|
throws Throwable
|
||||||
|
{
|
||||||
|
super.finalize();
|
||||||
|
if (_id > 0) {
|
||||||
|
_soundmgr.bufferFinalized(_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The sound manager responsible for this buffer. */
|
||||||
|
protected SoundManager _soundmgr;
|
||||||
|
|
||||||
|
/** The OpenAL identifier for this buffer. */
|
||||||
|
protected int _id;
|
||||||
|
}
|
||||||
@@ -101,12 +101,11 @@ public class ClipBuffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the identifier for this clip's buffer or -1 if it is not
|
* Returns a reference to this clip's buffer or <code>null</code> if it is not loaded.
|
||||||
* loaded.
|
|
||||||
*/
|
*/
|
||||||
public int getBufferId ()
|
public Buffer getBuffer ()
|
||||||
{
|
{
|
||||||
return (_bufferId == null) ? -1 : _bufferId.get(0);
|
return _buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,13 +149,12 @@ public class ClipBuffer
|
|||||||
|
|
||||||
// create our OpenAL buffer and then queue ourselves up to have
|
// create our OpenAL buffer and then queue ourselves up to have
|
||||||
// our clip data loaded
|
// our clip data loaded
|
||||||
_bufferId = BufferUtils.createIntBuffer(1);
|
_buffer = new Buffer(_manager);
|
||||||
AL10.alGenBuffers(_bufferId);
|
|
||||||
int errno = AL10.alGetError();
|
int errno = AL10.alGetError();
|
||||||
if (errno != AL10.AL_NO_ERROR) {
|
if (errno != AL10.AL_NO_ERROR) {
|
||||||
log.warning("Failed to create buffer [key=" + getKey() +
|
log.warning("Failed to create buffer [key=" + getKey() +
|
||||||
", errno=" + errno + "].");
|
", errno=" + errno + "].");
|
||||||
_bufferId = null;
|
_buffer = null;
|
||||||
// queue up a failure notification so that we properly return
|
// queue up a failure notification so that we properly return
|
||||||
// from this method and our sound has a chance to register
|
// from this method and our sound has a chance to register
|
||||||
// itself as an observer before we jump up and declare failure
|
// itself as an observer before we jump up and declare failure
|
||||||
@@ -173,7 +171,7 @@ public class ClipBuffer
|
|||||||
*/
|
*/
|
||||||
public void dispose ()
|
public void dispose ()
|
||||||
{
|
{
|
||||||
if (_bufferId != null) {
|
if (_buffer != null) {
|
||||||
// if there are sources bound to this buffer, we must wait
|
// if there are sources bound to this buffer, we must wait
|
||||||
// for them to be unbound
|
// for them to be unbound
|
||||||
if (_bound > 0) {
|
if (_bound > 0) {
|
||||||
@@ -182,8 +180,8 @@ public class ClipBuffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free up our buffer
|
// free up our buffer
|
||||||
AL10.alDeleteBuffers(_bufferId);
|
_buffer.delete();
|
||||||
_bufferId = null;
|
_buffer = null;
|
||||||
_state = UNLOADED;
|
_state = UNLOADED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +205,7 @@ public class ClipBuffer
|
|||||||
*/
|
*/
|
||||||
protected boolean bind (Clip clip)
|
protected boolean bind (Clip clip)
|
||||||
{
|
{
|
||||||
AL10.alBufferData(_bufferId.get(0), clip.format, clip.data, clip.frequency);
|
_buffer.setData(clip.format, clip.data, clip.frequency);
|
||||||
int errno = AL10.alGetError();
|
int errno = AL10.alGetError();
|
||||||
if (errno != AL10.AL_NO_ERROR) {
|
if (errno != AL10.AL_NO_ERROR) {
|
||||||
log.warning("Failed to bind clip", "key", getKey(), "errno", errno);
|
log.warning("Failed to bind clip", "key", getKey(), "errno", errno);
|
||||||
@@ -216,7 +214,7 @@ public class ClipBuffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
_state = LOADED;
|
_state = LOADED;
|
||||||
_size = AL10.alGetBufferi(_bufferId.get(0), AL10.AL_SIZE);
|
_size = _buffer.getSize();
|
||||||
_observers.apply(new ObserverList.ObserverOp<Observer>() {
|
_observers.apply(new ObserverList.ObserverOp<Observer>() {
|
||||||
public boolean apply (Observer observer) {
|
public boolean apply (Observer observer) {
|
||||||
observer.clipLoaded(ClipBuffer.this);
|
observer.clipLoaded(ClipBuffer.this);
|
||||||
@@ -234,9 +232,9 @@ public class ClipBuffer
|
|||||||
*/
|
*/
|
||||||
protected void failed ()
|
protected void failed ()
|
||||||
{
|
{
|
||||||
if (_bufferId != null) {
|
if (_buffer != null) {
|
||||||
AL10.alDeleteBuffers(_bufferId);
|
_buffer.delete();
|
||||||
_bufferId = null;
|
_buffer = null;
|
||||||
}
|
}
|
||||||
_state = UNLOADED;
|
_state = UNLOADED;
|
||||||
|
|
||||||
@@ -272,7 +270,7 @@ public class ClipBuffer
|
|||||||
protected ClipProvider _provider;
|
protected ClipProvider _provider;
|
||||||
protected String _path;
|
protected String _path;
|
||||||
protected int _state;
|
protected int _state;
|
||||||
protected IntBuffer _bufferId;
|
protected Buffer _buffer;
|
||||||
protected int _size;
|
protected int _size;
|
||||||
protected ObserverList<Observer> _observers =
|
protected ObserverList<Observer> _observers =
|
||||||
new ObserverList<Observer>(ObserverList.FAST_UNSAFE_NOTIFY);
|
new ObserverList<Observer>(ObserverList.FAST_UNSAFE_NOTIFY);
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.openal;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.openal.AL10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the OpenAL listener object.
|
||||||
|
*/
|
||||||
|
public class Listener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sets the position of the listener.
|
||||||
|
*/
|
||||||
|
public void setPosition (float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (_px != x || _py != y || _pz != z) {
|
||||||
|
AL10.alListener3f(AL10.AL_POSITION, _px = x, _py = y, _pz = z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the velocity of the listener.
|
||||||
|
*/
|
||||||
|
public void setVelocity (float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (_vx != x || _vy != y || _vz != z) {
|
||||||
|
AL10.alListener3f(AL10.AL_VELOCITY, _vx = x, _vy = y, _vz = z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gain of the listener.
|
||||||
|
*/
|
||||||
|
public void setGain (float gain)
|
||||||
|
{
|
||||||
|
if (_gain != gain) {
|
||||||
|
AL10.alListenerf(AL10.AL_GAIN, _gain = gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the orientation of the listener in terms of an "at" (direction) and "up" vector.
|
||||||
|
*/
|
||||||
|
public void setOrientation (float ax, float ay, float az, float ux, float uy, float uz)
|
||||||
|
{
|
||||||
|
if (_ax != ax || _ay != ay || _az != az || _ux != ux || _uy != uy || _uz != uz) {
|
||||||
|
_vbuf.put(_ax = ax).put(_ay = ay).put(_az = az);
|
||||||
|
_vbuf.put(_ux = ux).put(_uy = uy).put(_uz = uz).rewind();
|
||||||
|
AL10.alListener(AL10.AL_ORIENTATION, _vbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The listener is only to be created by the {@link SoundManager}.
|
||||||
|
*/
|
||||||
|
protected Listener ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The position of the listener. */
|
||||||
|
protected float _px, _py, _pz;
|
||||||
|
|
||||||
|
/** The velocity of the listener. */
|
||||||
|
protected float _vx, _vy, _vz;
|
||||||
|
|
||||||
|
/** The gain of the listener. */
|
||||||
|
protected float _gain = 1f;
|
||||||
|
|
||||||
|
/** The orientation of the listener (initialized to the OpenAL defaults). */
|
||||||
|
protected float _ax, _ay, _az = -1f, _ux, _uy = 1f, _uz;
|
||||||
|
|
||||||
|
/** A buffer for floating point values. */
|
||||||
|
protected FloatBuffer _vbuf = BufferUtils.createFloatBuffer(6);
|
||||||
|
}
|
||||||
@@ -54,53 +54,164 @@ public class Sound
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the location of this sound in 3D space. This will not affect an already playing
|
* Sets the position of the sound.
|
||||||
* sound but will take effect the next time it is played.
|
|
||||||
*/
|
*/
|
||||||
public void setLocation (float x, float y, float z)
|
public void setPosition (float x, float y, float z)
|
||||||
{
|
{
|
||||||
if (_position == null) {
|
if (_source != null) {
|
||||||
_position = BufferUtils.createFloatBuffer(3);
|
_source.setPosition(x, y, z);
|
||||||
}
|
}
|
||||||
_position.put(x).put(y).put(z);
|
_px = x;
|
||||||
_position.flip();
|
_py = y;
|
||||||
|
_pz = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the velocity of this sound in 3D space, in delta location per second (see
|
* Sets the velocity of the sound.
|
||||||
* {@link #setLocation}). This will not affect an already playing sound but will take effect
|
|
||||||
* the next time it is played.
|
|
||||||
*/
|
*/
|
||||||
public void setVelocity (float dx, float dy, float dz)
|
public void setVelocity (float x, float y, float z)
|
||||||
{
|
{
|
||||||
if (_velocity == null) {
|
if (_source != null) {
|
||||||
_velocity = BufferUtils.createFloatBuffer(3);
|
_source.setVelocity(x, y, z);
|
||||||
}
|
}
|
||||||
_velocity.put(dx).put(dy).put(dz);
|
_vx = x;
|
||||||
_velocity.flip();
|
_vy = y;
|
||||||
|
_vz = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the sounds's pitch. This value can range from 0.5 to 2.0. This will not affect
|
* Sets the gain of the sound.
|
||||||
* an already playing sound but will take effect the next time it is played.
|
*/
|
||||||
|
public void setGain (float gain)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setGain(gain);
|
||||||
|
}
|
||||||
|
_gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not the position, velocity, etc., of the sound are relative to the
|
||||||
|
* listener.
|
||||||
|
*/
|
||||||
|
public void setSourceRelative (boolean relative)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setSourceRelative(relative);
|
||||||
|
}
|
||||||
|
_sourceRelative = relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum gain.
|
||||||
|
*/
|
||||||
|
public void setMinGain (float gain)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setMinGain(gain);
|
||||||
|
}
|
||||||
|
_minGain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum gain.
|
||||||
|
*/
|
||||||
|
public void setMaxGain (float gain)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setMaxGain(gain);
|
||||||
|
}
|
||||||
|
_maxGain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reference distance for attenuation.
|
||||||
|
*/
|
||||||
|
public void setReferenceDistance (float distance)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setReferenceDistance(distance);
|
||||||
|
}
|
||||||
|
_referenceDistance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rolloff factor for attenuation.
|
||||||
|
*/
|
||||||
|
public void setRolloffFactor (float rolloff)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setRolloffFactor(rolloff);
|
||||||
|
}
|
||||||
|
_rolloffFactor = rolloff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum distance for attenuation.
|
||||||
|
*/
|
||||||
|
public void setMaxDistance (float distance)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setMaxDistance(distance);
|
||||||
|
}
|
||||||
|
_maxDistance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the pitch multiplier.
|
||||||
*/
|
*/
|
||||||
public void setPitch (float pitch)
|
public void setPitch (float pitch)
|
||||||
{
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setPitch(pitch);
|
||||||
|
}
|
||||||
_pitch = pitch;
|
_pitch = pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the sound's gain (volume). This value can range from 0.0 to 1.0 with 1.0 meaning
|
* Sets the direction of the sound.
|
||||||
* no attenuation, each division by two corresponding to a -6db attentuation and each
|
|
||||||
* multiplication by two corresponding to +6db amplification. This will not affect an already
|
|
||||||
* playing sound but will take effect the next time it is played.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <em>Note:</em> this value is multiplied by the base gain configured in the sound manager.
|
|
||||||
*/
|
*/
|
||||||
public void setGain (float gain)
|
public void setDirection (float x, float y, float z)
|
||||||
{
|
{
|
||||||
_gain = gain;
|
if (_source != null) {
|
||||||
|
_source.setDirection(x, y, z);
|
||||||
|
}
|
||||||
|
_dx = x;
|
||||||
|
_dy = y;
|
||||||
|
_dz = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the inside angle of the sound cone.
|
||||||
|
*/
|
||||||
|
public void setConeInnerAngle (float angle)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setConeInnerAngle(angle);
|
||||||
|
}
|
||||||
|
_coneInnerAngle = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the outside angle of the sound cone.
|
||||||
|
*/
|
||||||
|
public void setConeOuterAngle (float angle)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setConeOuterAngle(angle);
|
||||||
|
}
|
||||||
|
_coneOuterAngle = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gain outside of the sound cone.
|
||||||
|
*/
|
||||||
|
public void setConeOuterGain (float gain)
|
||||||
|
{
|
||||||
|
if (_source != null) {
|
||||||
|
_source.setConeOuterGain(gain);
|
||||||
|
}
|
||||||
|
_coneOuterGain = gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,8 +262,8 @@ public class Sound
|
|||||||
*/
|
*/
|
||||||
public void pause ()
|
public void pause ()
|
||||||
{
|
{
|
||||||
if (_sourceId != -1) {
|
if (_source != null) {
|
||||||
AL10.alSourcePause(_sourceId);
|
_source.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,8 +273,8 @@ public class Sound
|
|||||||
*/
|
*/
|
||||||
public void stop ()
|
public void stop ()
|
||||||
{
|
{
|
||||||
if (_sourceId != -1) {
|
if (_source != null) {
|
||||||
AL10.alSourceStop(_sourceId);
|
_source.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,8 +283,7 @@ public class Sound
|
|||||||
*/
|
*/
|
||||||
public boolean isPlaying ()
|
public boolean isPlaying ()
|
||||||
{
|
{
|
||||||
return (_sourceId != -1 && AL10.AL_PLAYING ==
|
return _source != null && _source.isPlaying();
|
||||||
AL10.alGetSourcei(_sourceId, AL10.AL_SOURCE_STATE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Sound (SoundGroup group, ClipBuffer buffer)
|
protected Sound (SoundGroup group, ClipBuffer buffer)
|
||||||
@@ -224,32 +334,38 @@ public class Sound
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if we do not already have a source, obtain one
|
// if we do not already have a source, obtain one
|
||||||
if (_sourceId == -1) {
|
if (_source == null) {
|
||||||
_sourceId = _group.acquireSource(this);
|
_source = _group.acquireSource(this);
|
||||||
if (_sourceId == -1) {
|
if (_source == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind our clip buffer to the source and notify it
|
// bind our clip buffer to the source and notify it
|
||||||
AL10.alSourcei(_sourceId, AL10.AL_BUFFER, _buffer.getBufferId());
|
_source.setBuffer(_buffer.getBuffer());
|
||||||
_buffer.sourceBound();
|
_buffer.sourceBound();
|
||||||
}
|
|
||||||
|
|
||||||
// configure the source with our ephemera
|
// configure the source with our ephemera
|
||||||
AL10.alSourcef(_sourceId, AL10.AL_PITCH, _pitch);
|
_source.setPosition(_px, _py, _pz);
|
||||||
AL10.alSourcef(_sourceId, AL10.AL_GAIN, _gain * _group.getBaseGain());
|
_source.setVelocity(_vx, _vy, _vz);
|
||||||
if (_position != null) {
|
_source.setGain(_gain * _group.getBaseGain());
|
||||||
AL10.alSource(_sourceId, AL10.AL_POSITION, _position);
|
_source.setSourceRelative(_sourceRelative);
|
||||||
}
|
_source.setMinGain(_minGain);
|
||||||
if (_velocity != null) {
|
_source.setMaxGain(_maxGain);
|
||||||
AL10.alSource(_sourceId, AL10.AL_VELOCITY, _velocity);
|
_source.setReferenceDistance(_referenceDistance);
|
||||||
|
_source.setRolloffFactor(_rolloffFactor);
|
||||||
|
_source.setMaxDistance(_maxDistance);
|
||||||
|
_source.setPitch(_pitch);
|
||||||
|
_source.setDirection(_dx, _dy, _dz);
|
||||||
|
_source.setConeInnerAngle(_coneInnerAngle);
|
||||||
|
_source.setConeOuterAngle(_coneOuterAngle);
|
||||||
|
_source.setConeOuterGain(_coneOuterGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure whether or not we should loop
|
// configure whether or not we should loop
|
||||||
AL10.alSourcei(_sourceId, AL10.AL_LOOPING, loop ? AL10.AL_TRUE : AL10.AL_FALSE);
|
_source.setLooping(loop);
|
||||||
|
|
||||||
// and start that damned thing up!
|
// and start that damned thing up!
|
||||||
AL10.alSourcePlay(_sourceId);
|
_source.play();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -262,11 +378,10 @@ public class Sound
|
|||||||
*/
|
*/
|
||||||
protected boolean reclaim ()
|
protected boolean reclaim ()
|
||||||
{
|
{
|
||||||
if (_sourceId != -1 &&
|
if (_source != null && _source.isStopped()) {
|
||||||
AL10.alGetSourcei(_sourceId, AL10.AL_SOURCE_STATE) == AL10.AL_STOPPED) {
|
_source.setBuffer(null);
|
||||||
AL10.alSourcei(_sourceId, AL10.AL_BUFFER, 0);
|
|
||||||
_buffer.sourceUnbound();
|
_buffer.sourceUnbound();
|
||||||
_sourceId = -1;
|
_source = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -279,17 +394,47 @@ public class Sound
|
|||||||
protected ClipBuffer _buffer;
|
protected ClipBuffer _buffer;
|
||||||
|
|
||||||
/** The source via which we are playing our sound currently. */
|
/** The source via which we are playing our sound currently. */
|
||||||
protected int _sourceId = -1;
|
protected Source _source;
|
||||||
|
|
||||||
/** The pitch adjustment. */
|
/** The position of the sound. */
|
||||||
protected float _pitch = 1;
|
protected float _px, _py, _pz;
|
||||||
|
|
||||||
/** The gain adjustment. */
|
/** The velocity of the sound. */
|
||||||
protected float _gain = 1;
|
protected float _vx, _vy, _vz;
|
||||||
|
|
||||||
/** The starting position in 3D space. */
|
/** The gain of the sound. */
|
||||||
protected FloatBuffer _position;
|
protected float _gain = 1f;
|
||||||
|
|
||||||
/** The velocity vector. */
|
/** Whether or not the sound's position, velocity, etc. are relative to the listener. */
|
||||||
protected FloatBuffer _velocity;
|
protected boolean _sourceRelative;
|
||||||
|
|
||||||
|
/** The minimum gain. */
|
||||||
|
protected float _minGain;
|
||||||
|
|
||||||
|
/** The maximum gain. */
|
||||||
|
protected float _maxGain = 1f;
|
||||||
|
|
||||||
|
/** The reference distance for attenuation. */
|
||||||
|
protected float _referenceDistance = 1f;
|
||||||
|
|
||||||
|
/** The attenuation rolloff factor. */
|
||||||
|
protected float _rolloffFactor = 1f;
|
||||||
|
|
||||||
|
/** The maximum distance for attenuation. */
|
||||||
|
protected float _maxDistance = Float.MAX_VALUE;
|
||||||
|
|
||||||
|
/** The pitch multiplier. */
|
||||||
|
protected float _pitch = 1f;
|
||||||
|
|
||||||
|
/** The direction of the sound. */
|
||||||
|
protected float _dx, _dy, _dz;
|
||||||
|
|
||||||
|
/** The inside angle of the sound cone. */
|
||||||
|
protected float _coneInnerAngle = 360f;
|
||||||
|
|
||||||
|
/** The outside angle of the sound cone. */
|
||||||
|
protected float _coneOuterAngle = 360f;
|
||||||
|
|
||||||
|
/** The gain outside the sound cone. */
|
||||||
|
protected float _coneOuterGain;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,11 +65,10 @@ public class SoundGroup
|
|||||||
public void dispose ()
|
public void dispose ()
|
||||||
{
|
{
|
||||||
reclaimAll();
|
reclaimAll();
|
||||||
if (_sourceIds != null) {
|
for (PooledSource pooled : _sources) {
|
||||||
_sources.clear();
|
pooled.source.delete();
|
||||||
AL10.alDeleteSources(_sourceIds);
|
|
||||||
_sourceIds = null;
|
|
||||||
}
|
}
|
||||||
|
_sources.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,14 +76,12 @@ public class SoundGroup
|
|||||||
*/
|
*/
|
||||||
public void reclaimAll ()
|
public void reclaimAll ()
|
||||||
{
|
{
|
||||||
if (_sourceIds != null) {
|
// make sure any bound sources are released
|
||||||
// make sure any bound sources are released
|
for (PooledSource pooled : _sources) {
|
||||||
for (Source source : _sources) {
|
if (pooled.holder != null) {
|
||||||
if (source.holder != null) {
|
pooled.holder.stop();
|
||||||
source.holder.stop();
|
pooled.holder.reclaim();
|
||||||
source.holder.reclaim();
|
pooled.holder = null;
|
||||||
source.holder = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,45 +97,38 @@ public class SoundGroup
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create our sources
|
// create our sources (or as many of them as we can)
|
||||||
_sourceIds = BufferUtils.createIntBuffer(sources);
|
for (int ii = 0; ii < sources; ii++) {
|
||||||
AL10.alGenSources(_sourceIds);
|
PooledSource pooled = new PooledSource();
|
||||||
int errno = AL10.alGetError();
|
pooled.source = new Source(manager);
|
||||||
if (errno != AL10.AL_NO_ERROR) {
|
int errno = AL10.alGetError();
|
||||||
log.warning("Failed to create sources [cprov=" + provider +
|
if (errno != AL10.AL_NO_ERROR) {
|
||||||
", sources=" + sources + ", errno=" + errno + "].");
|
log.warning("Failed to create sources [cprov=" + provider +
|
||||||
_sourceIds = null;
|
", sources=" + sources + ", errno=" + errno + "].");
|
||||||
// we'll have no sources which means all requests to play
|
return;
|
||||||
// sounds will silently fail as if all sources were in use
|
|
||||||
|
|
||||||
} else {
|
|
||||||
for (int ii = 0; ii < sources; ii++) {
|
|
||||||
Source source = new Source();
|
|
||||||
source.sourceId = _sourceIds.get(ii);
|
|
||||||
_sources.add(source);
|
|
||||||
}
|
}
|
||||||
|
_sources.add(pooled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by a {@link Sound} when it wants to obtain a source on which to play its clip.
|
* Called by a {@link Sound} when it wants to obtain a source on which to play its clip.
|
||||||
*/
|
*/
|
||||||
protected int acquireSource (Sound acquirer)
|
protected Source acquireSource (Sound acquirer)
|
||||||
{
|
{
|
||||||
// start at the beginning of the list looking for an available
|
// start at the beginning of the list looking for an available source
|
||||||
// source
|
|
||||||
for (int ii = 0, ll = _sources.size(); ii < ll; ii++) {
|
for (int ii = 0, ll = _sources.size(); ii < ll; ii++) {
|
||||||
Source source = _sources.get(ii);
|
PooledSource pooled = _sources.get(ii);
|
||||||
if (source.holder == null || source.holder.reclaim()) {
|
if (pooled.holder == null || pooled.holder.reclaim()) {
|
||||||
// note this source's new holder
|
// note this source's new holder
|
||||||
source.holder = acquirer;
|
pooled.holder = acquirer;
|
||||||
// move this source to the end of the list
|
// move this source to the end of the list
|
||||||
_sources.remove(ii);
|
_sources.remove(ii);
|
||||||
_sources.add(source);
|
_sources.add(pooled);
|
||||||
return source.sourceId;
|
return pooled.source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,15 +140,14 @@ public class SoundGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Used to track which sources are in use. */
|
/** Used to track which sources are in use. */
|
||||||
protected static class Source
|
protected static class PooledSource
|
||||||
{
|
{
|
||||||
public int sourceId;
|
public Source source;
|
||||||
public Sound holder;
|
public Sound holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SoundManager _manager;
|
protected SoundManager _manager;
|
||||||
protected ClipProvider _provider;
|
protected ClipProvider _provider;
|
||||||
|
|
||||||
protected IntBuffer _sourceIds;
|
protected ArrayList<PooledSource> _sources = new ArrayList<PooledSource>();
|
||||||
protected ArrayList<Source> _sources = new ArrayList<Source>();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,14 +23,18 @@ package com.threerings.openal;
|
|||||||
|
|
||||||
import static com.threerings.openal.Log.log;
|
import static com.threerings.openal.Log.log;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
import org.lwjgl.openal.AL;
|
import org.lwjgl.openal.AL;
|
||||||
import org.lwjgl.openal.AL10;
|
import org.lwjgl.openal.AL10;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import com.samskivert.util.IntListUtil;
|
||||||
import com.samskivert.util.LRUHashMap;
|
import com.samskivert.util.LRUHashMap;
|
||||||
import com.samskivert.util.Queue;
|
import com.samskivert.util.Queue;
|
||||||
import com.samskivert.util.RunQueue;
|
import com.samskivert.util.RunQueue;
|
||||||
@@ -85,6 +89,14 @@ public class SoundManager
|
|||||||
_clips.setMaxSize(bytes);
|
_clips.setMaxSize(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the listener object.
|
||||||
|
*/
|
||||||
|
public Listener getListener ()
|
||||||
|
{
|
||||||
|
return _listener;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the base gain (which must be a value between 0 and 1.0) which is multiplied to
|
* Configures the base gain (which must be a value between 0 and 1.0) which is multiplied to
|
||||||
* the individual gain assigned to sound effects (but not music).
|
* the individual gain assigned to sound effects (but not music).
|
||||||
@@ -137,6 +149,9 @@ public class SoundManager
|
|||||||
for (int ii = _streams.size() - 1; ii >= 0; ii--) {
|
for (int ii = _streams.size() - 1; ii >= 0; ii--) {
|
||||||
_streams.get(ii).update(time);
|
_streams.get(ii).update(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete any finalized objects
|
||||||
|
deleteFinalizedObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -290,6 +305,41 @@ public class SoundManager
|
|||||||
_streams.remove(stream);
|
_streams.remove(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a source has been finalized.
|
||||||
|
*/
|
||||||
|
protected synchronized void sourceFinalized (int id)
|
||||||
|
{
|
||||||
|
_finalizedSources = IntListUtil.add(_finalizedSources, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a buffer has been finalized.
|
||||||
|
*/
|
||||||
|
protected synchronized void bufferFinalized (int id)
|
||||||
|
{
|
||||||
|
_finalizedBuffers = IntListUtil.add(_finalizedBuffers, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all finalized objects.
|
||||||
|
*/
|
||||||
|
protected synchronized void deleteFinalizedObjects ()
|
||||||
|
{
|
||||||
|
if (_finalizedSources != null) {
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(_finalizedSources.length);
|
||||||
|
idbuf.put(_finalizedSources).rewind();
|
||||||
|
AL10.alDeleteSources(idbuf);
|
||||||
|
_finalizedSources = null;
|
||||||
|
}
|
||||||
|
if (_finalizedBuffers != null) {
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(_finalizedBuffers.length);
|
||||||
|
idbuf.put(_finalizedBuffers).rewind();
|
||||||
|
AL10.alDeleteBuffers(idbuf);
|
||||||
|
_finalizedBuffers = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** The thread that loads up sound clips in the background. */
|
/** The thread that loads up sound clips in the background. */
|
||||||
protected Thread _loader = new Thread("SoundManager.Loader") {
|
protected Thread _loader = new Thread("SoundManager.Loader") {
|
||||||
@Override
|
@Override
|
||||||
@@ -326,6 +376,9 @@ public class SoundManager
|
|||||||
/** Used to get back from the background thread to our "main" thread. */
|
/** Used to get back from the background thread to our "main" thread. */
|
||||||
protected RunQueue _rqueue;
|
protected RunQueue _rqueue;
|
||||||
|
|
||||||
|
/** The listener object. */
|
||||||
|
protected Listener _listener = new Listener();
|
||||||
|
|
||||||
/** A base gain that is multiplied by the individual gain assigned to sounds. */
|
/** A base gain that is multiplied by the individual gain assigned to sounds. */
|
||||||
protected float _baseGain = 1;
|
protected float _baseGain = 1;
|
||||||
|
|
||||||
@@ -342,6 +395,12 @@ public class SoundManager
|
|||||||
/** The list of active streams. */
|
/** The list of active streams. */
|
||||||
protected ArrayList<Stream> _streams = new ArrayList<Stream>();
|
protected ArrayList<Stream> _streams = new ArrayList<Stream>();
|
||||||
|
|
||||||
|
/** The list of sources to be deleted. */
|
||||||
|
protected int[] _finalizedSources;
|
||||||
|
|
||||||
|
/** The list of buffers to be deleted. */
|
||||||
|
protected int[] _finalizedBuffers;
|
||||||
|
|
||||||
/** The one and only sound manager, here for an exclusive performance by special request.
|
/** The one and only sound manager, here for an exclusive performance by special request.
|
||||||
* Available for all your sound playing needs. */
|
* Available for all your sound playing needs. */
|
||||||
protected static SoundManager _soundmgr;
|
protected static SoundManager _soundmgr;
|
||||||
|
|||||||
@@ -0,0 +1,399 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// Nenya library - tools for developing networked games
|
||||||
|
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||||
|
// http://www.threerings.net/code/nenya/
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.threerings.openal;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.openal.AL10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an OpenAL source object.
|
||||||
|
*/
|
||||||
|
public class Source
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a new source for the specified sound manager.
|
||||||
|
*/
|
||||||
|
public Source (SoundManager soundmgr)
|
||||||
|
{
|
||||||
|
_soundmgr = soundmgr;
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(1);
|
||||||
|
AL10.alGenSources(idbuf);
|
||||||
|
_id = idbuf.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this source's OpenAL identifier.
|
||||||
|
*/
|
||||||
|
public final int getId ()
|
||||||
|
{
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the position of the source.
|
||||||
|
*/
|
||||||
|
public void setPosition (float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (_px != x || _py != y || _pz != z) {
|
||||||
|
AL10.alSource3f(_id, AL10.AL_POSITION, _px = x, _py = y, _pz = z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the velocity of the source.
|
||||||
|
*/
|
||||||
|
public void setVelocity (float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (_vx != x || _vy != y || _vz != z) {
|
||||||
|
AL10.alSource3f(_id, AL10.AL_VELOCITY, _vx = x, _vy = y, _vz = z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gain of the source.
|
||||||
|
*/
|
||||||
|
public void setGain (float gain)
|
||||||
|
{
|
||||||
|
if (_gain != gain) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_GAIN, _gain = gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not the position, velocity, etc., of the source are relative to the
|
||||||
|
* listener.
|
||||||
|
*/
|
||||||
|
public void setSourceRelative (boolean relative)
|
||||||
|
{
|
||||||
|
if (_sourceRelative != relative) {
|
||||||
|
AL10.alSourcei(_id, AL10.AL_SOURCE_RELATIVE,
|
||||||
|
(_sourceRelative = relative) ? AL10.AL_TRUE : AL10.AL_FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not the source is looping.
|
||||||
|
*/
|
||||||
|
public void setLooping (boolean looping)
|
||||||
|
{
|
||||||
|
if (_looping != looping) {
|
||||||
|
AL10.alSourcei(_id, AL10.AL_LOOPING,
|
||||||
|
(_looping = looping) ? AL10.AL_TRUE : AL10.AL_FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum gain.
|
||||||
|
*/
|
||||||
|
public void setMinGain (float gain)
|
||||||
|
{
|
||||||
|
if (_minGain != gain) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_MIN_GAIN, _minGain = gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum gain.
|
||||||
|
*/
|
||||||
|
public void setMaxGain (float gain)
|
||||||
|
{
|
||||||
|
if (_maxGain != gain) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_MAX_GAIN, _maxGain = gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reference distance for attenuation.
|
||||||
|
*/
|
||||||
|
public void setReferenceDistance (float distance)
|
||||||
|
{
|
||||||
|
if (_referenceDistance != distance) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_REFERENCE_DISTANCE, _referenceDistance = distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rolloff factor for attenuation.
|
||||||
|
*/
|
||||||
|
public void setRolloffFactor (float rolloff)
|
||||||
|
{
|
||||||
|
if (_rolloffFactor != rolloff) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_ROLLOFF_FACTOR, _rolloffFactor = rolloff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum distance for attenuation.
|
||||||
|
*/
|
||||||
|
public void setMaxDistance (float distance)
|
||||||
|
{
|
||||||
|
if (_maxDistance != distance) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_MAX_DISTANCE, _maxDistance = distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the pitch multiplier.
|
||||||
|
*/
|
||||||
|
public void setPitch (float pitch)
|
||||||
|
{
|
||||||
|
if (_pitch != pitch) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_PITCH, _pitch = pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the direction of the source.
|
||||||
|
*/
|
||||||
|
public void setDirection (float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (_dx != x || _dy != y || _dz != z) {
|
||||||
|
AL10.alSource3f(_id, AL10.AL_DIRECTION, _dx = x, _dy = y, _dz = z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the inside angle of the sound cone.
|
||||||
|
*/
|
||||||
|
public void setConeInnerAngle (float angle)
|
||||||
|
{
|
||||||
|
if (_coneInnerAngle != angle) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_CONE_INNER_ANGLE, _coneInnerAngle = angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the outside angle of the sound cone.
|
||||||
|
*/
|
||||||
|
public void setConeOuterAngle (float angle)
|
||||||
|
{
|
||||||
|
if (_coneOuterAngle != angle) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_CONE_OUTER_ANGLE, _coneOuterAngle = angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gain outside of the sound cone.
|
||||||
|
*/
|
||||||
|
public void setConeOuterGain (float gain)
|
||||||
|
{
|
||||||
|
if (_coneOuterGain != gain) {
|
||||||
|
AL10.alSourcef(_id, AL10.AL_CONE_OUTER_GAIN, _coneOuterGain = gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the source buffer. Equivalent to unqueueing all buffers, then queuing the provided
|
||||||
|
* buffer. Cannot be called when the source is playing or paused.
|
||||||
|
*
|
||||||
|
* @param buffer the buffer to set, or <code>null</code> to clear.
|
||||||
|
*/
|
||||||
|
public void setBuffer (Buffer buffer)
|
||||||
|
{
|
||||||
|
_queue.clear();
|
||||||
|
if (buffer != null) {
|
||||||
|
_queue.add(buffer);
|
||||||
|
}
|
||||||
|
AL10.alSourcei(_id, AL10.AL_BUFFER, buffer == null ? AL10.AL_NONE : buffer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues the specified buffers.
|
||||||
|
*/
|
||||||
|
public void queueBuffers (Buffer... buffers)
|
||||||
|
{
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(buffers.length);
|
||||||
|
for (int ii = 0; ii < buffers.length; ii++) {
|
||||||
|
Buffer buffer = buffers[ii];
|
||||||
|
_queue.add(buffer);
|
||||||
|
idbuf.put(ii, buffer.getId());
|
||||||
|
}
|
||||||
|
AL10.alSourceQueueBuffers(_id, idbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified buffers from the queue.
|
||||||
|
*/
|
||||||
|
public void unqueueBuffers (Buffer... buffers)
|
||||||
|
{
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(buffers.length);
|
||||||
|
for (int ii = 0; ii < buffers.length; ii++) {
|
||||||
|
Buffer buffer = buffers[ii];
|
||||||
|
_queue.remove(buffer);
|
||||||
|
idbuf.put(ii, buffer.getId());
|
||||||
|
}
|
||||||
|
AL10.alSourceUnqueueBuffers(_id, idbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the source is playing.
|
||||||
|
*/
|
||||||
|
public boolean isPlaying ()
|
||||||
|
{
|
||||||
|
return getSourceState() == AL10.AL_PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the source is paused.
|
||||||
|
*/
|
||||||
|
public boolean isPaused ()
|
||||||
|
{
|
||||||
|
return getSourceState() == AL10.AL_PAUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the source is stopped.
|
||||||
|
*/
|
||||||
|
public boolean isStopped ()
|
||||||
|
{
|
||||||
|
return getSourceState() == AL10.AL_STOPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the state of the source: {@link AL10#AL_INITIAL}, {@link AL10#AL_PLAYING},
|
||||||
|
* {@link AL10#AL_PAUSED}, or {@link AL10#AL_STOPPED}.
|
||||||
|
*/
|
||||||
|
public int getSourceState ()
|
||||||
|
{
|
||||||
|
return AL10.alGetSourcei(_id, AL10.AL_SOURCE_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of buffers that have been processed.
|
||||||
|
*/
|
||||||
|
public int getBuffersProcessed ()
|
||||||
|
{
|
||||||
|
return AL10.alGetSourcei(_id, AL10.AL_BUFFERS_PROCESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts playing the source.
|
||||||
|
*/
|
||||||
|
public void play ()
|
||||||
|
{
|
||||||
|
AL10.alSourcePlay(_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses the source.
|
||||||
|
*/
|
||||||
|
public void pause ()
|
||||||
|
{
|
||||||
|
AL10.alSourcePause(_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the source.
|
||||||
|
*/
|
||||||
|
public void stop ()
|
||||||
|
{
|
||||||
|
AL10.alSourceStop(_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewinds the source.
|
||||||
|
*/
|
||||||
|
public void rewind ()
|
||||||
|
{
|
||||||
|
AL10.alSourceRewind(_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this source, rendering it unusable.
|
||||||
|
*/
|
||||||
|
public void delete ()
|
||||||
|
{
|
||||||
|
IntBuffer idbuf = BufferUtils.createIntBuffer(1);
|
||||||
|
idbuf.put(_id).rewind();
|
||||||
|
AL10.alDeleteSources(idbuf);
|
||||||
|
_id = 0;
|
||||||
|
_queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
protected void finalize ()
|
||||||
|
throws Throwable
|
||||||
|
{
|
||||||
|
super.finalize();
|
||||||
|
if (_id > 0) {
|
||||||
|
_soundmgr.sourceFinalized(_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The sound manager responsible for this source. */
|
||||||
|
protected SoundManager _soundmgr;
|
||||||
|
|
||||||
|
/** The OpenAL identifier for this source. */
|
||||||
|
protected int _id;
|
||||||
|
|
||||||
|
/** The position of the source. */
|
||||||
|
protected float _px, _py, _pz;
|
||||||
|
|
||||||
|
/** The velocity of the source. */
|
||||||
|
protected float _vx, _vy, _vz;
|
||||||
|
|
||||||
|
/** The gain of the source. */
|
||||||
|
protected float _gain = 1f;
|
||||||
|
|
||||||
|
/** Whether or not the source's position, velocity, etc. are relative to the listener. */
|
||||||
|
protected boolean _sourceRelative;
|
||||||
|
|
||||||
|
/** Whether or not the source is looping. */
|
||||||
|
protected boolean _looping;
|
||||||
|
|
||||||
|
/** The minimum gain. */
|
||||||
|
protected float _minGain;
|
||||||
|
|
||||||
|
/** The maximum gain. */
|
||||||
|
protected float _maxGain = 1f;
|
||||||
|
|
||||||
|
/** The reference distance for attenuation. */
|
||||||
|
protected float _referenceDistance = 1f;
|
||||||
|
|
||||||
|
/** The attenuation rolloff factor. */
|
||||||
|
protected float _rolloffFactor = 1f;
|
||||||
|
|
||||||
|
/** The maximum distance for attenuation. */
|
||||||
|
protected float _maxDistance = Float.MAX_VALUE;
|
||||||
|
|
||||||
|
/** The pitch multiplier. */
|
||||||
|
protected float _pitch = 1f;
|
||||||
|
|
||||||
|
/** The direction of the source. */
|
||||||
|
protected float _dx, _dy, _dz;
|
||||||
|
|
||||||
|
/** The inside angle of the sound cone. */
|
||||||
|
protected float _coneInnerAngle = 360f;
|
||||||
|
|
||||||
|
/** The outside angle of the sound cone. */
|
||||||
|
protected float _coneOuterAngle = 360f;
|
||||||
|
|
||||||
|
/** The gain outside the sound cone. */
|
||||||
|
protected float _coneOuterGain;
|
||||||
|
|
||||||
|
/** The source's queue of buffers (storing them keeps them from being garbage-collected). */
|
||||||
|
protected ArrayList<Buffer> _queue = new ArrayList<Buffer>();
|
||||||
|
}
|
||||||
@@ -47,13 +47,10 @@ public abstract class Stream
|
|||||||
_soundmgr = soundmgr;
|
_soundmgr = soundmgr;
|
||||||
|
|
||||||
// create the source and buffers
|
// create the source and buffers
|
||||||
_nbuf = BufferUtils.createIntBuffer(NUM_BUFFERS);
|
_source = new Source(soundmgr);
|
||||||
_nbuf.limit(1);
|
for (int ii = 0; ii < _buffers.length; ii++) {
|
||||||
AL10.alGenSources(_nbuf);
|
_buffers[ii] = new Buffer(soundmgr);
|
||||||
_sourceId = _nbuf.get();
|
}
|
||||||
_nbuf.clear();
|
|
||||||
AL10.alGenBuffers(_nbuf);
|
|
||||||
_nbuf.get(_bufferIds);
|
|
||||||
|
|
||||||
// register with sound manager
|
// register with sound manager
|
||||||
_soundmgr.addStream(this);
|
_soundmgr.addStream(this);
|
||||||
@@ -66,17 +63,16 @@ public abstract class Stream
|
|||||||
{
|
{
|
||||||
_gain = gain;
|
_gain = gain;
|
||||||
if (_fadeMode == FadeMode.NONE) {
|
if (_fadeMode == FadeMode.NONE) {
|
||||||
AL10.alSourcef(_sourceId, AL10.AL_GAIN, _gain);
|
_source.setGain(_gain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the pitch of the stream.
|
* Returns a reference to the stream source.
|
||||||
*/
|
*/
|
||||||
public void setPitch (float pitch)
|
public Source getSource ()
|
||||||
{
|
{
|
||||||
_pitch = pitch;
|
return _source;
|
||||||
AL10.alSourcef(_sourceId, AL10.AL_PITCH, _pitch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,7 +96,7 @@ public abstract class Stream
|
|||||||
_qidx = _qlen = 0;
|
_qidx = _qlen = 0;
|
||||||
queueBuffers(NUM_BUFFERS);
|
queueBuffers(NUM_BUFFERS);
|
||||||
}
|
}
|
||||||
AL10.alSourcePlay(_sourceId);
|
_source.play();
|
||||||
_state = AL10.AL_PLAYING;
|
_state = AL10.AL_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +109,7 @@ public abstract class Stream
|
|||||||
log.warning("Tried to pause stream that wasn't playing.");
|
log.warning("Tried to pause stream that wasn't playing.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AL10.alSourcePause(_sourceId);
|
_source.pause();
|
||||||
_state = AL10.AL_PAUSED;
|
_state = AL10.AL_PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +122,7 @@ public abstract class Stream
|
|||||||
log.warning("Tried to stop stream that was already stopped.");
|
log.warning("Tried to stop stream that was already stopped.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AL10.alSourceStop(_sourceId);
|
_source.stop();
|
||||||
_state = AL10.AL_STOPPED;
|
_state = AL10.AL_STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +135,7 @@ public abstract class Stream
|
|||||||
if (_state != AL10.AL_PLAYING) {
|
if (_state != AL10.AL_PLAYING) {
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
AL10.alSourcef(_sourceId, AL10.AL_GAIN, 0f);
|
_source.setGain(0f);
|
||||||
_fadeMode = FadeMode.IN;
|
_fadeMode = FadeMode.IN;
|
||||||
_fadeInterval = interval;
|
_fadeInterval = interval;
|
||||||
_fadeElapsed = 0f;
|
_fadeElapsed = 0f;
|
||||||
@@ -168,12 +164,10 @@ public abstract class Stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete the source and buffers
|
// delete the source and buffers
|
||||||
_nbuf.clear();
|
_source.delete();
|
||||||
_nbuf.put(_sourceId).flip();
|
for (Buffer buffer : _buffers) {
|
||||||
AL10.alDeleteSources(_nbuf);
|
buffer.delete();
|
||||||
_nbuf.clear();
|
}
|
||||||
_nbuf.put(_bufferIds).flip();
|
|
||||||
AL10.alDeleteBuffers(_nbuf);
|
|
||||||
|
|
||||||
// remove from manager
|
// remove from manager
|
||||||
_soundmgr.removeStream(this);
|
_soundmgr.removeStream(this);
|
||||||
@@ -194,24 +188,21 @@ public abstract class Stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find out how many buffers have been played and unqueue them
|
// find out how many buffers have been played and unqueue them
|
||||||
int played = AL10.alGetSourcei(_sourceId, AL10.AL_BUFFERS_PROCESSED);
|
int played = _source.getBuffersProcessed();
|
||||||
if (played == 0) {
|
if (played == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_nbuf.clear();
|
|
||||||
for (int ii = 0; ii < played; ii++) {
|
for (int ii = 0; ii < played; ii++) {
|
||||||
_nbuf.put(_bufferIds[_qidx]);
|
_source.unqueueBuffers(_buffers[_qidx]);
|
||||||
_qidx = (_qidx + 1) % NUM_BUFFERS;
|
_qidx = (_qidx + 1) % NUM_BUFFERS;
|
||||||
_qlen--;
|
_qlen--;
|
||||||
}
|
}
|
||||||
_nbuf.flip();
|
|
||||||
AL10.alSourceUnqueueBuffers(_sourceId, _nbuf);
|
|
||||||
|
|
||||||
// enqueue up to the number of buffers played
|
// enqueue up to the number of buffers played
|
||||||
queueBuffers(played);
|
queueBuffers(played);
|
||||||
|
|
||||||
// find out if we're still playing; if not and we have buffers queued, we must restart
|
// find out if we're still playing; if not and we have buffers queued, we must restart
|
||||||
_state = AL10.alGetSourcei(_sourceId, AL10.AL_SOURCE_STATE);
|
_state = _source.getSourceState();
|
||||||
if (_qlen > 0 && _state != AL10.AL_PLAYING) {
|
if (_qlen > 0 && _state != AL10.AL_PLAYING) {
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
@@ -226,8 +217,7 @@ public abstract class Stream
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float alpha = Math.min((_fadeElapsed += time) / _fadeInterval, 1f);
|
float alpha = Math.min((_fadeElapsed += time) / _fadeInterval, 1f);
|
||||||
AL10.alSourcef(_sourceId, AL10.AL_GAIN, _gain *
|
_source.setGain(_gain * (_fadeMode == FadeMode.IN ? alpha : (1f - alpha)));
|
||||||
(_fadeMode == FadeMode.IN ? alpha : (1f - alpha)));
|
|
||||||
if (alpha == 1f) {
|
if (alpha == 1f) {
|
||||||
if (_fadeMode == FadeMode.OUT) {
|
if (_fadeMode == FadeMode.OUT) {
|
||||||
stop();
|
stop();
|
||||||
@@ -243,18 +233,15 @@ public abstract class Stream
|
|||||||
*/
|
*/
|
||||||
protected void queueBuffers (int buffers)
|
protected void queueBuffers (int buffers)
|
||||||
{
|
{
|
||||||
_nbuf.clear();
|
|
||||||
for (int ii = 0; ii < buffers; ii++) {
|
for (int ii = 0; ii < buffers; ii++) {
|
||||||
int bufferId = _bufferIds[(_qidx + _qlen) % NUM_BUFFERS];
|
Buffer buffer = _buffers[(_qidx + _qlen) % NUM_BUFFERS];
|
||||||
if (populateBuffer(bufferId)) {
|
if (populateBuffer(buffer)) {
|
||||||
_nbuf.put(bufferId);
|
_source.queueBuffers(buffer);
|
||||||
_qlen++;
|
_qlen++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_nbuf.flip();
|
|
||||||
AL10.alSourceQueueBuffers(_sourceId, _nbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,7 +250,7 @@ public abstract class Stream
|
|||||||
* @return true if data was read into the buffer and it should be enqueued, false if the end of
|
* @return true if data was read into the buffer and it should be enqueued, false if the end of
|
||||||
* the stream has been reached and no data was read into the buffer
|
* the stream has been reached and no data was read into the buffer
|
||||||
*/
|
*/
|
||||||
protected boolean populateBuffer (int bufferId)
|
protected boolean populateBuffer (Buffer buffer)
|
||||||
{
|
{
|
||||||
if (_abuf == null) {
|
if (_abuf == null) {
|
||||||
_abuf = ByteBuffer.allocateDirect(BUFFER_SIZE).order(ByteOrder.nativeOrder());
|
_abuf = ByteBuffer.allocateDirect(BUFFER_SIZE).order(ByteOrder.nativeOrder());
|
||||||
@@ -279,7 +266,7 @@ public abstract class Stream
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_abuf.rewind().limit(read);
|
_abuf.rewind().limit(read);
|
||||||
AL10.alBufferData(bufferId, getFormat(), _abuf, getFrequency());
|
buffer.setData(getFormat(), _abuf, getFrequency());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,17 +293,14 @@ public abstract class Stream
|
|||||||
protected SoundManager _soundmgr;
|
protected SoundManager _soundmgr;
|
||||||
|
|
||||||
/** The source through which the stream plays. */
|
/** The source through which the stream plays. */
|
||||||
protected int _sourceId;
|
protected Source _source;
|
||||||
|
|
||||||
/** The buffers through which we cycle. */
|
/** The buffers through which we cycle. */
|
||||||
protected int[] _bufferIds = new int[NUM_BUFFERS];
|
protected Buffer[] _buffers = new Buffer[NUM_BUFFERS];
|
||||||
|
|
||||||
/** The starting index and length of the current queue in {@link #_bufferIds}. */
|
/** The starting index and length of the current queue in {@link #_bufferIds}. */
|
||||||
protected int _qidx, _qlen;
|
protected int _qidx, _qlen;
|
||||||
|
|
||||||
/** The pitch of the stream. */
|
|
||||||
protected float _pitch = 1f;
|
|
||||||
|
|
||||||
/** The gain of the stream. */
|
/** The gain of the stream. */
|
||||||
protected float _gain = 1f;
|
protected float _gain = 1f;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user