|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (c) 2009-2012 jMonkeyEngine
|
|
|
+ * Copyright (c) 2009-2025 jMonkeyEngine
|
|
|
* All rights reserved.
|
|
|
*
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -34,49 +34,80 @@ package com.jme3.audio;
|
|
|
import com.jme3.math.FastMath;
|
|
|
|
|
|
/**
|
|
|
- * Audio environment, for reverb effects.
|
|
|
+ * Represents an audio environment, primarily used to define reverb effects.
|
|
|
+ * This class provides parameters that correspond to the properties controllable
|
|
|
+ * through the OpenAL EFX (Environmental Effects Extension) library.
|
|
|
+ * By adjusting these parameters, developers can simulate various acoustic spaces
|
|
|
+ * like rooms, caves, and concert halls, adding depth and realism to the audio experience.
|
|
|
+ *
|
|
|
* @author Kirill
|
|
|
*/
|
|
|
public class Environment {
|
|
|
|
|
|
- private float airAbsorbGainHf = 0.99426f;
|
|
|
+ /** High-frequency air absorption gain (0.0f to 1.0f). */
|
|
|
+ private float airAbsorbGainHf = 0.99426f;
|
|
|
+ /** Factor controlling room effect rolloff with distance. */
|
|
|
private float roomRolloffFactor = 0;
|
|
|
-
|
|
|
- private float decayTime = 1.49f;
|
|
|
- private float decayHFRatio = 0.54f;
|
|
|
-
|
|
|
- private float density = 1.0f;
|
|
|
- private float diffusion = 0.3f;
|
|
|
-
|
|
|
- private float gain = 0.316f;
|
|
|
- private float gainHf = 0.022f;
|
|
|
-
|
|
|
- private float lateReverbDelay = 0.088f;
|
|
|
- private float lateReverbGain = 0.768f;
|
|
|
-
|
|
|
- private float reflectDelay = 0.162f;
|
|
|
- private float reflectGain = 0.052f;
|
|
|
-
|
|
|
- private boolean decayHfLimit = true;
|
|
|
-
|
|
|
- public static final Environment Garage, Dungeon, Cavern, AcousticLab, Closet;
|
|
|
-
|
|
|
- static {
|
|
|
- Garage = new Environment(1, 1, 1, 1, .9f, .5f, .751f, .0039f, .661f, .0137f);
|
|
|
- Dungeon = new Environment(.75f, 1, 1, .75f, 1.6f, 1, 0.95f, 0.0026f, 0.93f, 0.0103f);
|
|
|
- Cavern = new Environment(.5f, 1, 1, .5f, 2.25f, 1, .908f, .0103f, .93f, .041f);
|
|
|
- AcousticLab = new Environment(.5f, 1, 1, 1, .28f, 1, .87f, .002f, .81f, .008f);
|
|
|
- Closet = new Environment(1, 1, 1, 1, .15f, 1, .6f, .0025f, .5f, .0006f);
|
|
|
- }
|
|
|
-
|
|
|
+ /** Overall decay time of the reverberation (in seconds). */
|
|
|
+ private float decayTime = 1.49f;
|
|
|
+ /** Ratio of high-frequency decay time to overall decay time (0.0f to 1.0f). */
|
|
|
+ private float decayHFRatio = 0.54f;
|
|
|
+ /** Density of the medium affecting reverb smoothness (0.0f to 1.0f). */
|
|
|
+ private float density = 1.0f;
|
|
|
+ /** Diffusion of reflections affecting echo distinctness (0.0f to 1.0f). */
|
|
|
+ private float diffusion = 0.3f;
|
|
|
+ /** Overall gain of the environment effect (linear scale). */
|
|
|
+ private float gain = 0.316f;
|
|
|
+ /** High-frequency gain of the environment effect (linear scale). */
|
|
|
+ private float gainHf = 0.022f;
|
|
|
+ /** Delay time for late reverberation relative to early reflections (in seconds). */
|
|
|
+ private float lateReverbDelay = 0.088f;
|
|
|
+ /** Gain of the late reverberation (linear scale). */
|
|
|
+ private float lateReverbGain = 0.768f;
|
|
|
+ /** Delay time for the initial reflections (in seconds). */
|
|
|
+ private float reflectDelay = 0.162f;
|
|
|
+ /** Gain of the initial reflections (linear scale). */
|
|
|
+ private float reflectGain = 0.052f;
|
|
|
+ /** Flag limiting high-frequency decay by the overall decay time. */
|
|
|
+ private boolean decayHfLimit = true;
|
|
|
+
|
|
|
+ public static final Environment Garage = new Environment(
|
|
|
+ 1, 1, 1, 1, .9f, .5f, .751f, .0039f, .661f, .0137f);
|
|
|
+ public static final Environment Dungeon = new Environment(
|
|
|
+ .75f, 1, 1, .75f, 1.6f, 1, 0.95f, 0.0026f, 0.93f, 0.0103f);
|
|
|
+ public static final Environment Cavern = new Environment(
|
|
|
+ .5f, 1, 1, .5f, 2.25f, 1, .908f, .0103f, .93f, .041f);
|
|
|
+ public static final Environment AcousticLab = new Environment(
|
|
|
+ .5f, 1, 1, 1, .28f, 1, .87f, .002f, .81f, .008f);
|
|
|
+ public static final Environment Closet = new Environment(
|
|
|
+ 1, 1, 1, 1, .15f, 1, .6f, .0025f, .5f, .0006f);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Utility method to convert an EAX decibel value to an amplitude factor.
|
|
|
+ * EAX often expresses gain and attenuation in decibels scaled by 1000.
|
|
|
+ * This method performs the reverse of that conversion to obtain a linear
|
|
|
+ * amplitude value suitable for OpenAL.
|
|
|
+ *
|
|
|
+ * @param eaxDb The EAX decibel value (scaled by 1000).
|
|
|
+ * @return The corresponding amplitude factor.
|
|
|
+ */
|
|
|
private static float eaxDbToAmp(float eaxDb) {
|
|
|
float dB = eaxDb / 2000f;
|
|
|
return FastMath.pow(10f, dB);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Constructs a new, default {@code Environment}. The default values are
|
|
|
+ * typically chosen to represent a neutral or common acoustic space.
|
|
|
+ */
|
|
|
public Environment() {
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates a new {@code Environment} as a copy of the provided {@code Environment}.
|
|
|
+ *
|
|
|
+ * @param source The {@code Environment} to copy the settings from.
|
|
|
+ */
|
|
|
public Environment(Environment source) {
|
|
|
this.airAbsorbGainHf = source.airAbsorbGainHf;
|
|
|
this.roomRolloffFactor = source.roomRolloffFactor;
|
|
@@ -93,9 +124,24 @@ public class Environment {
|
|
|
this.decayHfLimit = source.decayHfLimit;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates a new {@code Environment} with the specified parameters. These parameters
|
|
|
+ * directly influence the properties of the reverb effect as managed by OpenAL EFX.
|
|
|
+ *
|
|
|
+ * @param density The density of the medium.
|
|
|
+ * @param diffusion The diffusion of the reflections.
|
|
|
+ * @param gain Overall gain applied to the environment effect.
|
|
|
+ * @param gainHf High-frequency gain applied to the environment effect.
|
|
|
+ * @param decayTime The overall decay time of the reflected sound.
|
|
|
+ * @param decayHf Ratio of high-frequency decay time to the overall decay time.
|
|
|
+ * @param reflectGain Gain applied to the initial reflections.
|
|
|
+ * @param reflectDelay Delay time for the initial reflections.
|
|
|
+ * @param lateGain Gain applied to the late reverberation.
|
|
|
+ * @param lateDelay Delay time for the late reverberation.
|
|
|
+ */
|
|
|
public Environment(float density, float diffusion, float gain, float gainHf,
|
|
|
- float decayTime, float decayHf, float reflectGain,
|
|
|
- float reflectDelay, float lateGain, float lateDelay) {
|
|
|
+ float decayTime, float decayHf, float reflectGain, float reflectDelay,
|
|
|
+ float lateGain, float lateDelay) {
|
|
|
this.decayTime = decayTime;
|
|
|
this.decayHFRatio = decayHf;
|
|
|
this.density = density;
|
|
@@ -108,6 +154,16 @@ public class Environment {
|
|
|
this.reflectGain = reflectGain;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Creates a new {@code Environment} by interpreting an array of 28 float values
|
|
|
+ * as an EAX preset. This constructor attempts to map the EAX preset values to
|
|
|
+ * the corresponding OpenAL EFX parameters. Note that not all EAX parameters
|
|
|
+ * have a direct equivalent in standard OpenAL EFX, so some values might be
|
|
|
+ * approximated or ignored.
|
|
|
+ *
|
|
|
+ * @param e An array of 28 float values representing an EAX preset.
|
|
|
+ * @throws IllegalArgumentException If the provided array does not have a length of 28.
|
|
|
+ */
|
|
|
public Environment(float[] e) {
|
|
|
if (e.length != 28)
|
|
|
throw new IllegalArgumentException("Not an EAX preset");
|
|
@@ -254,27 +310,71 @@ public class Environment {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public boolean equals(Object env2) {
|
|
|
- if (env2 == null)
|
|
|
+ public boolean equals(Object obj) {
|
|
|
+
|
|
|
+ if (!(obj instanceof Environment))
|
|
|
return false;
|
|
|
- if (env2 == this)
|
|
|
+
|
|
|
+ if (obj == this)
|
|
|
return true;
|
|
|
- if (!(env2 instanceof Environment))
|
|
|
- return false;
|
|
|
|
|
|
- Environment e2 = (Environment) env2;
|
|
|
- return (e2.airAbsorbGainHf == airAbsorbGainHf
|
|
|
- && e2.decayHFRatio == decayHFRatio
|
|
|
- && e2.decayHfLimit == decayHfLimit
|
|
|
- && e2.decayTime == decayTime
|
|
|
- && e2.density == density
|
|
|
- && e2.diffusion == diffusion
|
|
|
- && e2.gain == gain
|
|
|
- && e2.gainHf == gainHf
|
|
|
- && e2.lateReverbDelay == lateReverbDelay
|
|
|
- && e2.lateReverbGain == lateReverbGain
|
|
|
- && e2.reflectDelay == reflectDelay
|
|
|
- && e2.reflectGain == reflectGain
|
|
|
- && e2.roomRolloffFactor == roomRolloffFactor);
|
|
|
- }
|
|
|
+ Environment other = (Environment) obj;
|
|
|
+ float epsilon = 1e-6f;
|
|
|
+
|
|
|
+ float[] thisFloats = {
|
|
|
+ this.airAbsorbGainHf,
|
|
|
+ this.decayHFRatio,
|
|
|
+ this.decayTime,
|
|
|
+ this.density,
|
|
|
+ this.diffusion,
|
|
|
+ this.gain,
|
|
|
+ this.gainHf,
|
|
|
+ this.lateReverbDelay,
|
|
|
+ this.lateReverbGain,
|
|
|
+ this.reflectDelay,
|
|
|
+ this.reflectGain,
|
|
|
+ this.roomRolloffFactor
|
|
|
+ };
|
|
|
+
|
|
|
+ float[] otherFloats = {
|
|
|
+ other.airAbsorbGainHf,
|
|
|
+ other.decayHFRatio,
|
|
|
+ other.decayTime,
|
|
|
+ other.density,
|
|
|
+ other.diffusion,
|
|
|
+ other.gain,
|
|
|
+ other.gainHf,
|
|
|
+ other.lateReverbDelay,
|
|
|
+ other.lateReverbGain,
|
|
|
+ other.reflectDelay,
|
|
|
+ other.reflectGain,
|
|
|
+ other.roomRolloffFactor
|
|
|
+ };
|
|
|
+
|
|
|
+ for (int i = 0; i < thisFloats.length; i++) {
|
|
|
+ if (Math.abs(thisFloats[i] - otherFloats[i]) >= epsilon) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return this.decayHfLimit == other.decayHfLimit;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int hashCode() {
|
|
|
+ int result = (airAbsorbGainHf != +0.0f ? Float.floatToIntBits(airAbsorbGainHf) : 0);
|
|
|
+ result = 31 * result + (roomRolloffFactor != +0.0f ? Float.floatToIntBits(roomRolloffFactor) : 0);
|
|
|
+ result = 31 * result + (decayTime != +0.0f ? Float.floatToIntBits(decayTime) : 0);
|
|
|
+ result = 31 * result + (decayHFRatio != +0.0f ? Float.floatToIntBits(decayHFRatio) : 0);
|
|
|
+ result = 31 * result + (density != +0.0f ? Float.floatToIntBits(density) : 0);
|
|
|
+ result = 31 * result + (diffusion != +0.0f ? Float.floatToIntBits(diffusion) : 0);
|
|
|
+ result = 31 * result + (gain != +0.0f ? Float.floatToIntBits(gain) : 0);
|
|
|
+ result = 31 * result + (gainHf != +0.0f ? Float.floatToIntBits(gainHf) : 0);
|
|
|
+ result = 31 * result + (lateReverbDelay != +0.0f ? Float.floatToIntBits(lateReverbDelay) : 0);
|
|
|
+ result = 31 * result + (lateReverbGain != +0.0f ? Float.floatToIntBits(lateReverbGain) : 0);
|
|
|
+ result = 31 * result + (reflectDelay != +0.0f ? Float.floatToIntBits(reflectDelay) : 0);
|
|
|
+ result = 31 * result + (reflectGain != +0.0f ? Float.floatToIntBits(reflectGain) : 0);
|
|
|
+ result = 31 * result + (decayHfLimit ? 1 : 0);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
}
|