* Added javadoc to AudioNode
* Added methods play(), playInstance() and stop() to AudioNode git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7334 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
6196de22f7
commit
f640e5de21
@ -42,8 +42,20 @@ import com.jme3.scene.Node;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* An <code>AudioNode</code> is used in jME3 for playing audio files.
|
||||
* <br/>
|
||||
* First, an {@link AudioNode} is loaded from file, and then assigned
|
||||
* to an audio node for playback. Once the audio node is attached to the
|
||||
* scene, its location will influence the position it is playing from relative
|
||||
* to the {@link Listener}.
|
||||
* <br/>
|
||||
* An audio node can also play in "headspace", meaning its location
|
||||
* or velocity does not influence how it is played.
|
||||
* The "positional" property of an AudioNode can be set via
|
||||
* {@link AudioNode#setPositional(boolean) }.
|
||||
*
|
||||
* @author normenhansen
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class AudioNode extends Node {
|
||||
|
||||
@ -67,35 +79,108 @@ public class AudioNode extends Node {
|
||||
protected Vector3f direction = new Vector3f(0, 0, 1);
|
||||
protected float innerAngle = 360;
|
||||
protected float outerAngle = 360;
|
||||
private boolean positional = true;
|
||||
protected boolean positional = true;
|
||||
|
||||
/**
|
||||
* <code>Status</code> indicates the current status of the audio node.
|
||||
*/
|
||||
public enum Status {
|
||||
/**
|
||||
* The audio node is currently playing. This will be set if
|
||||
* {@link AudioNode#play() } is called.
|
||||
*/
|
||||
Playing,
|
||||
|
||||
/**
|
||||
* The audio node is currently paused.
|
||||
*/
|
||||
Paused,
|
||||
|
||||
/**
|
||||
* The audio node is currently stopped.
|
||||
* This will be set if {@link AudioNode#stop() } is called
|
||||
* or the audio has reached the end of the file.
|
||||
*/
|
||||
Stopped,
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AudioNode</code> without any audio data set.
|
||||
*
|
||||
* @param audioRenderer The audio renderer to use for playing. Cannot be null.
|
||||
*/
|
||||
public AudioNode(AudioRenderer audioRenderer) {
|
||||
if (audioRenderer == null)
|
||||
throw new IllegalArgumentException("audioRenderer cannot be null");
|
||||
|
||||
this.renderer = audioRenderer;
|
||||
}
|
||||
|
||||
public AudioNode(AudioRenderer audioRenderer, AudioData ad, AudioKey key) {
|
||||
/**
|
||||
* Creates a new <code>AudioNode</code> with the given data and key.
|
||||
*
|
||||
* @param audioRenderer The audio renderer to use for playing. Cannot be null.
|
||||
* @param audioData The audio data contains the audio track to play.
|
||||
* @param key The audio key that was used to load the AudioData
|
||||
*/
|
||||
public AudioNode(AudioRenderer audioRenderer, AudioData audioData, AudioKey key) {
|
||||
this(audioRenderer);
|
||||
setAudioData(ad, key);
|
||||
setAudioData(audioData, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AudioNode</code> with the given audio file.
|
||||
*
|
||||
* @param audioRenderer The audio renderer to use for playing. Cannot be null.
|
||||
* @param assetManager The asset manager to use to load the audio file
|
||||
* @param name The filename of the audio file
|
||||
* @param stream If true, the audio will be streamed gradually from disk,
|
||||
* otherwise, it will be buffered.
|
||||
*/
|
||||
public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name, boolean stream) {
|
||||
this(audioRenderer);
|
||||
this.key = new AudioKey(name, stream);
|
||||
this.data = (AudioData) assetManager.loadAsset(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AudioNode</code> with the given audio file.
|
||||
*
|
||||
* @param audioRenderer The audio renderer to use for playing. Cannot be null.
|
||||
* @param assetManager The asset manager to use to load the audio file
|
||||
* @param name The filename of the audio file
|
||||
*/
|
||||
public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name) {
|
||||
this(audioRenderer, assetManager, name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start playing the audio.
|
||||
*/
|
||||
public void play(){
|
||||
renderer.playSource(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Start playing an instance of this audio. This method can be used
|
||||
* to play the same <code>AudioNode</code> multiple times. Note
|
||||
* that changes to the parameters of this AudioNode will not effect the
|
||||
* instances already playing.
|
||||
*/
|
||||
public void playInstance(){
|
||||
renderer.playSourceInstance(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop playing the audio that was started with {@link AudioNode#play() }.
|
||||
*/
|
||||
public void stop(){
|
||||
renderer.stopSource(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not use.
|
||||
*/
|
||||
public void setChannel(int channel) {
|
||||
if (status != Status.Stopped) {
|
||||
throw new IllegalStateException("Can only set source id when stopped");
|
||||
@ -104,59 +189,117 @@ public class AudioNode extends Node {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not use.
|
||||
*/
|
||||
public int getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {#link Filter dry filter} that is set.
|
||||
* @see AudioNode#setDryFilter(com.jme3.audio.Filter)
|
||||
*/
|
||||
public Filter getDryFilter() {
|
||||
return dryFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dry filter to use for this audio node.
|
||||
*
|
||||
* When {@link AudioNode#setReverbEnabled(boolean) reverb} is used,
|
||||
* the dry filter will only influence the "dry" portion of the audio,
|
||||
* e.g. not the reverberated parts of the AudioNode playing.
|
||||
*
|
||||
* See the relevent documentation for the {@link Filter} to determine
|
||||
* the effect.
|
||||
*
|
||||
* @param dryFilter The filter to set, or null to disable dry filter.
|
||||
*/
|
||||
public void setDryFilter(Filter dryFilter) {
|
||||
if (this.dryFilter != null) {
|
||||
throw new IllegalStateException("Filter already set");
|
||||
}
|
||||
|
||||
this.dryFilter = dryFilter;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.DryFilter);
|
||||
}
|
||||
|
||||
public void setAudioData(AudioData ad, AudioKey key) {
|
||||
/**
|
||||
* Set the audio data to use for the audio. Note that this method
|
||||
* can only be called once, if for example the audio node was initialized
|
||||
* without an {@link AudioData}.
|
||||
*
|
||||
* @param audioData The audio data contains the audio track to play.
|
||||
* @param key The audio key that was used to load the AudioData
|
||||
*/
|
||||
public void setAudioData(AudioData audioData, AudioKey key) {
|
||||
if (data != null) {
|
||||
throw new IllegalStateException("Cannot change data once its set");
|
||||
}
|
||||
|
||||
data = ad;
|
||||
data = audioData;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link AudioData} set previously with
|
||||
* {@link AudioNode#setAudioData(com.jme3.audio.AudioData, com.jme3.audio.AudioKey) }
|
||||
* or any of the constructors that initialize the audio data.
|
||||
*/
|
||||
public AudioData getAudioData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link Status} of the audio node.
|
||||
* The status will be changed when either the {@link AudioNode#play() }
|
||||
* or {@link AudioNode#stop() } methods are called.
|
||||
*/
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not use.
|
||||
*/
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the audio will keep looping after it is done playing,
|
||||
* otherwise, false.
|
||||
* @see AudioNode#setLooping(boolean)
|
||||
*/
|
||||
public boolean isLooping() {
|
||||
return loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the looping mode for the audio node. The default is false.
|
||||
*
|
||||
* @param loop True if the audio should keep looping after it is done playing.
|
||||
*/
|
||||
public void setLooping(boolean loop) {
|
||||
this.loop = loop;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.Looping);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pitch of the audio, also the speed of playback.
|
||||
*
|
||||
* @see AudioNode#setPitch(float)
|
||||
*/
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pitch of the audio, also the speed of playback.
|
||||
* The value must be between 0.5 and 2.0.
|
||||
*
|
||||
* @param pitch The pitch to set.
|
||||
* @throws IllegalArgumentException If pitch is not between 0.5 and 2.0.
|
||||
*/
|
||||
public void setPitch(float pitch) {
|
||||
if (pitch < 0.5f || pitch > 2.0f) {
|
||||
throw new IllegalArgumentException("Pitch must be between 0.5 and 2.0");
|
||||
@ -167,10 +310,23 @@ public class AudioNode extends Node {
|
||||
renderer.updateSourceParam(this, AudioParam.Pitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The volume of this audio node.
|
||||
*
|
||||
* @see AudioNode#setVolume(float)
|
||||
*/
|
||||
public float getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the volume of this audio node.
|
||||
*
|
||||
* The volume is specified as gain. 1.0 is the default.
|
||||
*
|
||||
* @param volume The volume to set.
|
||||
* @throws IllegalArgumentException If volume is negative
|
||||
*/
|
||||
public void setVolume(float volume) {
|
||||
if (volume < 0f) {
|
||||
throw new IllegalArgumentException("Volume cannot be negative");
|
||||
@ -181,10 +337,19 @@ public class AudioNode extends Node {
|
||||
renderer.updateSourceParam(this, AudioParam.Volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The time offset in seconds when the sound will start playing.
|
||||
*/
|
||||
public float getTimeOffset() {
|
||||
return timeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time offset in seconds when the sound will start playing.
|
||||
*
|
||||
* @param timeOffset The time offset
|
||||
* @throws IllegalArgumentException If timeOffset is negative
|
||||
*/
|
||||
public void setTimeOffset(float timeOffset) {
|
||||
if (timeOffset < 0f) {
|
||||
throw new IllegalArgumentException("Time offset cannot be negative");
|
||||
@ -193,30 +358,72 @@ public class AudioNode extends Node {
|
||||
this.timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The velocity of the audio node.
|
||||
*
|
||||
* @see AudioNode#setVelocity(com.jme3.math.Vector3f)
|
||||
*/
|
||||
public Vector3f getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the velocity of the audio node. The velocity is expected
|
||||
* to be in meters. Does nothing if the audio node is not positional.
|
||||
*
|
||||
* @param velocity The velocity to set.
|
||||
* @see AudioNode#setPositional(boolean)
|
||||
*/
|
||||
public void setVelocity(Vector3f velocity) {
|
||||
this.velocity.set(velocity);
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.Velocity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if reverb is enabled, otherwise false.
|
||||
*
|
||||
* @see AudioNode#setReverbEnabled(boolean)
|
||||
*/
|
||||
public boolean isReverbEnabled() {
|
||||
return reverbEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to enable reverberation effects for this audio node.
|
||||
* Does nothing if the audio node is not positional.
|
||||
* <br/>
|
||||
* When enabled, the audio environment set with
|
||||
* {@link AudioRenderer#setEnvironment(com.jme3.audio.Environment) }
|
||||
* will apply a reverb effect to the audio playing from this audio node.
|
||||
*
|
||||
* @param reverbEnabled True to enable reverb.
|
||||
*/
|
||||
public void setReverbEnabled(boolean reverbEnabled) {
|
||||
this.reverbEnabled = reverbEnabled;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.ReverbEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Filter for the reverberations of this audio node.
|
||||
*
|
||||
* @see AudioNode#setReverbFilter(com.jme3.audio.Filter)
|
||||
*/
|
||||
public Filter getReverbFilter() {
|
||||
return reverbFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reverb filter for this audio node.
|
||||
* <br/>
|
||||
* The reverb filter will influence the reverberations
|
||||
* of the audio node playing. This only has an effect if
|
||||
* reverb is enabled.
|
||||
*
|
||||
* @param reverbFilter The reverb filter to set.
|
||||
* @see AudioNode#setDryFilter(com.jme3.audio.Filter)
|
||||
*/
|
||||
public void setReverbFilter(Filter reverbFilter) {
|
||||
if (this.reverbFilter != null) {
|
||||
throw new IllegalStateException("Filter already set");
|
||||
@ -227,10 +434,25 @@ public class AudioNode extends Node {
|
||||
renderer.updateSourceParam(this, AudioParam.ReverbFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Max distance for this audio node.
|
||||
*
|
||||
* @see AudioNode#setMaxDistance(float)
|
||||
*/
|
||||
public float getMaxDistance() {
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum playing distance for the audio node.
|
||||
* Does nothing if the audio node is not positional.
|
||||
* <br/>
|
||||
* The maximum distance is the distance beyond which the audio
|
||||
* node will no longer be heard.
|
||||
*
|
||||
* @param maxDistance The maximum playing distance.
|
||||
* @throws IllegalArgumentException If maxDistance is negative
|
||||
*/
|
||||
public void setMaxDistance(float maxDistance) {
|
||||
if (maxDistance < 0) {
|
||||
throw new IllegalArgumentException("Max distance cannot be negative");
|
||||
@ -241,10 +463,25 @@ public class AudioNode extends Node {
|
||||
renderer.updateSourceParam(this, AudioParam.MaxDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The reference playing distance for the audio node.
|
||||
*
|
||||
* @see AudioNode#setRefDistance(float)
|
||||
*/
|
||||
public float getRefDistance() {
|
||||
return refDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reference playing distance for the audio node.
|
||||
* Does nothing if the audio node is not positional.
|
||||
* <br/>
|
||||
* The reference playing distance is the distance at which the
|
||||
* audio node will be exactly half of its volume.
|
||||
*
|
||||
* @param refDistance The reference playing distance.
|
||||
* @throws IllegalArgumentException If refDistance is negative
|
||||
*/
|
||||
public void setRefDistance(float refDistance) {
|
||||
if (refDistance < 0) {
|
||||
throw new IllegalArgumentException("Reference distance cannot be negative");
|
||||
@ -255,52 +492,114 @@ public class AudioNode extends Node {
|
||||
renderer.updateSourceParam(this, AudioParam.RefDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the audio node is directional
|
||||
*
|
||||
* @see AudioNode#setDirectional(boolean)
|
||||
*/
|
||||
public boolean isDirectional() {
|
||||
return directional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the audio node to be directional.
|
||||
* Does nothing if the audio node is not positional.
|
||||
* <br/>
|
||||
* After setting directional, you should call
|
||||
* {@link AudioNode#setDirection(com.jme3.math.Vector3f) }
|
||||
* to set the audio node's direction.
|
||||
*
|
||||
* @param directional If the audio node is directional
|
||||
*/
|
||||
public void setDirectional(boolean directional) {
|
||||
this.directional = directional;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.IsDirectional);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The direction of this audio node.
|
||||
*
|
||||
* @see AudioNode#setDirection(com.jme3.math.Vector3f)
|
||||
*/
|
||||
public Vector3f getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the direction of this audio node.
|
||||
* Does nothing if the audio node is not directional.
|
||||
*
|
||||
* @param direction
|
||||
* @see AudioNode#setDirectional(boolean)
|
||||
*/
|
||||
public void setDirection(Vector3f direction) {
|
||||
this.direction = direction;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.Direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The directional audio node, cone inner angle.
|
||||
*
|
||||
* @see AudioNode#setInnerAngle(float)
|
||||
*/
|
||||
public float getInnerAngle() {
|
||||
return innerAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directional audio node cone inner angle.
|
||||
* Does nothing if the audio node is not directional.
|
||||
*
|
||||
* @param innerAngle The cone inner angle.
|
||||
*/
|
||||
public void setInnerAngle(float innerAngle) {
|
||||
this.innerAngle = innerAngle;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.InnerAngle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The directional audio node, cone outer angle.
|
||||
*
|
||||
* @see AudioNode#setOuterAngle(float)
|
||||
*/
|
||||
public float getOuterAngle() {
|
||||
return outerAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directional audio node cone outer angle.
|
||||
* Does nothing if the audio node is not directional.
|
||||
*
|
||||
* @param outerAngle The cone outer angle.
|
||||
*/
|
||||
public void setOuterAngle(float outerAngle) {
|
||||
this.outerAngle = outerAngle;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.OuterAngle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the audio node is positional.
|
||||
*
|
||||
* @see AudioNode#setPositional(boolean)
|
||||
*/
|
||||
public boolean isPositional() {
|
||||
return positional;
|
||||
}
|
||||
|
||||
public void setPositional(boolean inHeadspace) {
|
||||
this.positional = inHeadspace;
|
||||
/**
|
||||
* Set the audio node as positional.
|
||||
* The position, velocity, and distance parameters effect positional
|
||||
* audio nodes. Set to false if the audio node should play in "headspace".
|
||||
*
|
||||
* @param positional True if the audio node should be positional, otherwise
|
||||
* false if it should be headspace.
|
||||
*/
|
||||
public void setPositional(boolean positional) {
|
||||
this.positional = positional;
|
||||
if (channel >= 0)
|
||||
renderer.updateSourceParam(this, AudioParam.IsPositional);
|
||||
}
|
||||
@ -318,14 +617,15 @@ public class AudioNode extends Node {
|
||||
renderer.updateSourceParam(this, AudioParam.Position);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public AudioNode clone(){
|
||||
// try{
|
||||
// return (AudioNode) super.clone();
|
||||
// }catch (CloneNotSupportedException ex){
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
@Override
|
||||
public AudioNode clone(){
|
||||
AudioNode clone = (AudioNode) super.clone();
|
||||
|
||||
clone.direction = direction.clone();
|
||||
clone.velocity = velocity.clone();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
@ -348,6 +648,8 @@ public class AudioNode extends Node {
|
||||
oc.write(direction, "direction", null);
|
||||
oc.write(innerAngle, "inner_angle", 360);
|
||||
oc.write(outerAngle, "outer_angle", 360);
|
||||
|
||||
oc.write(positional, "positional", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -371,6 +673,9 @@ public class AudioNode extends Node {
|
||||
direction = (Vector3f) ic.readSavable("direction", null);
|
||||
innerAngle = ic.readFloat("inner_angle", 360);
|
||||
outerAngle = ic.readFloat("outer_angle", 360);
|
||||
|
||||
positional = ic.readBoolean("positional", false);
|
||||
|
||||
data = im.getAssetManager().loadAudio(key);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user