diff options
author | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
---|---|---|
committer | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
commit | 7a2e20caac9db6f789a7b3fab344b9758af45335 (patch) | |
tree | b5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/AuralAttributesRetained.java | |
parent | f76ce302c4bb2a9f03bbee571ec5d05c29633023 (diff) |
j3dcore: flatten the directory structure a bit
Signed-off-by: Harvey Harrison <[email protected]>
Diffstat (limited to 'src/javax/media/j3d/AuralAttributesRetained.java')
-rw-r--r-- | src/javax/media/j3d/AuralAttributesRetained.java | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/src/javax/media/j3d/AuralAttributesRetained.java b/src/javax/media/j3d/AuralAttributesRetained.java new file mode 100644 index 0000000..f5e3d6a --- /dev/null +++ b/src/javax/media/j3d/AuralAttributesRetained.java @@ -0,0 +1,667 @@ +/* + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package javax.media.j3d; + +import javax.vecmath.Point2f; + +/** + * The AuralAttributesRetained object defines all rendering state that can + * be set as a component object of a retained Soundscape node. + */ +class AuralAttributesRetained extends NodeComponentRetained { + + /** + * Gain Scale Factor applied to source with this attribute + */ + float attributeGain = 1.0f; // Valid values are >= 0.0. + + /** + * Atmospheric Rolloff - speed of sound - coeff + * Normal gain attenuation based on distance of sound from + * listener is scaled by a rolloff factor, which can increase + * or decrease the usual inverse-distance-square value. + */ + float rolloff = 1.0f; // Valid values are >= 0.0 + static final float SPEED_OF_SOUND = 0.344f; // in meters/milliseconds + + /* + * Reverberation + * + * Within Java 3D's model for auralization, the components to + * reverberation for a particular space are: + * Reflection and Reverb Coefficients - + * attenuation of sound (uniform for all frequencies) due to + * absorption of reflected sound off materials within the + * listening space. + * Reflection and Reverb Delay - + * approximating time from the start of the direct sound that + * initial early and late reflection waves take to reach listener. + * Reverb Decay - + * approximating time from the start of the direct sound that + * reverberation is audible. + */ + + /** + * Coefficients for reverberation + * The (early) Reflection and Reverberation coefficient scale factors + * are used to approximate the reflective/absorptive characteristics + * of the surfaces in this bounded Auralizaton environment. + * Theses scale factors is applied to sound's amplitude regardless + * of sound's position. + * Value of 1.0 represents complete (unattenuated) sound reflection. + * Value of 0.0 represents full absorption; reverberation is disabled. + */ + float reflectionCoefficient = 0.0f; // Range of values 0.0 to 1.0 + float reverbCoefficient = 1.0f; // Range of values 0.0 to 1.0 + + /** + * Time Delays in milliseconds + * Set with either explicitly with time, or impliciticly by supplying + * bounds volume and having the delay time calculated. + * Bounds of reverberation space does not have to be the same as + * Attribute bounds. + */ + float reflectionDelay = 20.0f; // in milliseconds + float reverbDelay = 40.0f; // in milliseconds + Bounds reverbBounds = null; + + /** + * Decay parameters + * Length and timbre of reverb decay tail + */ + float decayTime = 1000.0f; // in milliseconds + float decayFilter = 5000.0f; // low-pass cutoff frequency + + /** + * Reverb Diffusion and Density ratios (0=min, 1=max) + */ + float diffusion = 1.0f; + float density = 1.0f; + + /** + * Reverberation order + * This limits the number of Reverberation iterations executed while + * sound is being reverberated. As long as reflection coefficient is + * small enough, the reverberated sound decreases (as it would naturally) + * each successive iteration. + * Value of > zero defines the greatest reflection order to be used by + * the reverberator. + * All positive values are used as the number of loop iteration. + * Value of <= zero signifies that reverberation is to loop until reverb + * gain reaches zero (-60dB or 1/1000 of sound amplitude). + */ + int reverbOrder = 0; + + /** + * Distance Filter + * Each sound source is attenuated by a filter based on it's distance + * from the listener. + * For now the only supported filterType will be LOW_PASS frequency cutoff. + * At some time full FIR filtering will be supported. + */ + static final int NO_FILTERING = -1; + static final int LOW_PASS = 1; + + int filterType = NO_FILTERING; + float[] distance = null; + float[] frequencyCutoff = null; + + /** + * Doppler Effect parameters + * Between two snapshots of the head and sound source positions some + * delta time apart, the distance between head and source is compared. + * If there has been no change in the distance between head and sound + * source over this delta time: + * f' = f + * + * If there has been a change in the distance between head and sound: + * f' = f * Af * v + * + * When head and sound are moving towards each other then + * | (S * Ar) + (deltaV(h,t) * Av) | + * v = | -------------------------------- | + * | (S * Ar) - (deltaV(s,t) * Av) | + * + * When head and sound are moving away from each other then + * | (S * Ar) - (deltaV(h,t) * Av) | + * v = | -------------------------------- | + * | (S * Ar) + (deltaV(s,t) * Av) | + * + * + * Af = AuralAttribute frequency scalefactor + * Ar = AuralAttribute rolloff scalefactor + * Av = AuralAttribute velocity scalefactor + * deltaV = delta velocity + * f = frequency of sound + * h = Listeners head position + * v = Ratio of delta velocities + * Vh = Vector from center ear to sound source + * S = Speed of sound + * s = Sound source position + * t = time + * + * If adjusted velocity of head or adjusted velocity of sound is + * greater than adjusted speed of sound, f' is undefined. + */ + /** + * Frequency Scale Factor + * used to increase or reduce the change of frequency associated + * with normal rate of playback. + * Value of zero causes sounds to be paused. + */ + float frequencyScaleFactor = 1.0f; + /** + * Velocity Scale Factor + * Float value applied to the Change of distance between Sound Source + * and Listener over some delta time. Non-zero if listener moving + * even if sound is not. Value of zero implies no Doppler applied. + */ + float velocityScaleFactor = 0.0f; + + /** + * This boolean is set when something changes in the attributes + */ + boolean aaDirty = true; + + /** + * The mirror copy of this AuralAttributes. + */ + AuralAttributesRetained mirrorAa = null; + + /** + ** Debug print mechanism for Sound nodes + **/ + static final // 'static final' so compiler doesn't include debugPrint calls + boolean debugFlag = false; + + static final // 'static final' so internal error message are not compiled + boolean internalErrors = false; + + void debugPrint(String message) { + if (debugFlag) // leave test in in case debugFlag made non-static final + System.err.println(message); + } + + + // **************************************** + // + // Set and Get individual attribute values + // + // **************************************** + + /** + * Set Attribute Gain (amplitude) + * @param gain scale factor applied to amplitude + */ + void setAttributeGain(float gain) { + this.attributeGain = gain; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Attribute Gain (amplitude) + * @return gain amplitude scale factor + */ + float getAttributeGain() { + return this.attributeGain; + } + + /** + * Set Attribute Gain Rolloff + * @param rolloff atmospheric gain scale factor (changing speed of sound) + */ + void setRolloff(float rolloff) { + this.rolloff = rolloff; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Attribute Gain Rolloff + * @return rolloff atmospheric gain scale factor (changing speed of sound) + */ + float getRolloff() { + return this.rolloff; + } + + /** + * Set Reflective Coefficient + * @param reflectionCoefficient reflection/absorption factor applied to + * early reflections. + */ + void setReflectionCoefficient(float reflectionCoefficient) { + this.reflectionCoefficient = reflectionCoefficient; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reflective Coefficient + * @return reflection coeff reflection/absorption factor applied to + * early reflections. + */ + float getReflectionCoefficient() { + return this.reflectionCoefficient; + } + + /** + * Set Reflection Delay Time + * @param reflectionDelay time before the start of early (first order) + * reflections. + */ + void setReflectionDelay(float reflectionDelay) { + this.reflectionDelay = reflectionDelay; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reflection Delay Time + * @return reflection delay time + */ + float getReflectionDelay() { + return this.reflectionDelay; + } + + /** + * Set Reverb Coefficient + * @param reverbCoefficient reflection/absorption factor applied to + * late reflections. + */ + void setReverbCoefficient(float reverbCoefficient) { + this.reverbCoefficient = reverbCoefficient; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reverb Coefficient + * @return reverb coeff reflection/absorption factor applied to late + * reflections. + */ + float getReverbCoefficient() { + return this.reverbCoefficient; + } + + /** + * Set Revereration Delay Time + * @param reverbDelay time between each order of reflection + */ + void setReverbDelay(float reverbDelay) { + this.reverbDelay = reverbDelay; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Revereration Delay Time + * @return reverb delay time between each order of reflection + */ + float getReverbDelay() { + return this.reverbDelay; + } + /** + * Set Decay Time + * @param decayTime length of time reverb takes to decay + */ + void setDecayTime(float decayTime) { + this.decayTime = decayTime; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Revereration Decay Time + * @return reverb delay time + */ + float getDecayTime() { + return this.decayTime; + } + + /** + * Set Decay Filter + * @param decayFilter frequency referenced used in low-pass filtering + */ + void setDecayFilter(float decayFilter) { + this.decayFilter = decayFilter; + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Revereration Decay Filter + * @return reverb delay Filter + */ + float getDecayFilter() { + return this.decayFilter; + } + + /** + * Set Reverb Diffusion + * @param diffusion ratio between min and max device diffusion settings + */ + void setDiffusion(float diffusion) { + this.diffusion = diffusion; + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Revereration Decay Diffusion + * @return reverb diffusion + */ + float getDiffusion() { + return this.diffusion; + } + + /** + * Set Reverb Density + * @param density ratio between min and max device density settings + */ + void setDensity(float density) { + this.density = density; + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Revereration Density + * @return reverb density + */ + float getDensity() { + return this.density; + } + + + /** + * Set Revereration Bounds + * @param reverbVolume bounds used to approximate reverb time. + */ + synchronized void setReverbBounds(Bounds reverbVolume) { + this.reverbBounds = reverbVolume; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Revereration Delay Bounds volume + * @return reverb bounds volume that defines the Reverberation space and + * indirectly the delay + */ + Bounds getReverbBounds() { + return this.reverbBounds; + } + + /** + * Set Reverberation Order of Reflections + * @param reverbOrder number of times reflections added to reverb signal + */ + void setReverbOrder(int reverbOrder) { + this.reverbOrder = reverbOrder; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Reverberation Order of Reflections + * @return reverb order number of times reflections added to reverb signal + */ + int getReverbOrder() { + return this.reverbOrder; + } + + /** + * Set Distance Filter (based on distances and frequency cutoff) + * @param attenuation array of pairs defining distance frequency cutoff + */ + synchronized void setDistanceFilter(Point2f[] attenuation) { + if (attenuation == null) { + this.filterType = NO_FILTERING; + return; + } + int attenuationLength = attenuation.length; + if (attenuationLength == 0) { + this.filterType = NO_FILTERING; + return; + } + this.filterType = LOW_PASS; + // Reallocate every time unless size of new array equal old array + if ( distance == null || + (distance != null && (distance.length != attenuationLength) ) ) { + this.distance = new float[attenuationLength]; + this.frequencyCutoff = new float[attenuationLength]; + } + for (int i = 0; i< attenuationLength; i++) { + this.distance[i] = attenuation[i].x; + this.frequencyCutoff[i] = attenuation[i].y; + } + this.aaDirty = true; + notifyUsers(); + } + /** + * Set Distance Filter (based on distances and frequency cutoff) using + * separate arrays + * @param distance array containing distance values + * @param filter array containing low-pass frequency cutoff values + */ + synchronized void setDistanceFilter(float[] distance, float[] filter) { + if (distance == null || filter == null) { + this.filterType = NO_FILTERING; + return; + } + int distanceLength = distance.length; + int filterLength = filter.length; + if (distanceLength == 0 || filterLength == 0) { + this.filterType = NO_FILTERING; + return; + } + // Reallocate every time unless size of new array equal old array + if ( this.distance == null || + ( this.distance != null && + (this.distance.length != filterLength) ) ) { + this.distance = new float[distanceLength]; + this.frequencyCutoff = new float[distanceLength]; + } + this.filterType = LOW_PASS; + // Copy the distance array into nodes field + System.arraycopy(distance, 0, this.distance, 0, distanceLength); + // Copy the filter array an array of same length as the distance array + if (distanceLength <= filterLength) { + System.arraycopy(filter, 0, this.frequencyCutoff,0, distanceLength); + } + else { + System.arraycopy(filter, 0, this.frequencyCutoff, 0, filterLength); + // Extend filter array to length of distance array by + // replicate last filter values. + for (int i=filterLength; i< distanceLength; i++) { + this.frequencyCutoff[i] = filter[filterLength - 1]; + } + } + if (debugFlag) { + debugPrint("AAR setDistanceFilter(D,F)"); + for (int jj=0;jj<distanceLength;jj++) { + debugPrint(" from distance, freq = " + distance[jj] + ", " + + filter[jj]); + debugPrint(" into distance, freq = " + this.distance[jj] + ", " + + this.frequencyCutoff[jj]); + } + } + this.aaDirty = true; + notifyUsers(); + } + + /** + * Retrieve Distance Filter array length + * @return attenuation array length + */ + int getDistanceFilterLength() { + if (distance == null) + return 0; + else + return this.distance.length; + } + + + /** + * Retrieve Distance Filter (distances and frequency cutoff) + * @return attenaution pairs of distance and frequency cutoff filter + */ + void getDistanceFilter(Point2f[] attenuation) { + // Write into existing param array already allocated + if (attenuation == null) + return; + if (this.distance == null || this.frequencyCutoff == null) + return; + // The two filter attenuation arrays length should be the same + // We can assume that distance and filter lengths are the same + // and are non-zero. + int distanceLength = this.distance.length; + // check that attenuation array large enough to contain + // auralAttribute arrays + if (distanceLength > attenuation.length) + distanceLength = attenuation.length; + for (int i=0; i< distanceLength; i++) { + attenuation[i].x = this.distance[i]; + if (filterType == NO_FILTERING) + attenuation[i].y = Sound.NO_FILTER; + else if (filterType == LOW_PASS) + attenuation[i].y = this.frequencyCutoff[i]; + if (debugFlag) + debugPrint("AAR: getDistF: " + attenuation[i].x + ", " + + attenuation[i].y); + } + } + /** + * Retrieve Distance Filter as arrays distances and frequency cutoff array + * @param distance array of float values + * @param frequencyCutoff array of float cutoff filter values in Hertz + */ + void getDistanceFilter(float[] distance, float[] filter) { + // Write into existing param arrays already allocated + if (distance == null || filter == null) + return; + if (this.distance == null || this.frequencyCutoff == null) + return; + int distanceLength = this.distance.length; + // check that distance parameter large enough to contain auralAttribute + // distance array + // We can assume that distance and filter lengths are the same + // and are non-zero. + if (distance.length < distanceLength) + // parameter array not large enough to hold all this.distance data + distanceLength = distance.length; + System.arraycopy(this.distance, 0, distance, 0, distanceLength); + if (debugFlag) + debugPrint("AAR getDistanceFilter(D,F) " + this.distance[0]); + int filterLength = this.frequencyCutoff.length; + if (filter.length < filterLength) + // parameter array not large enough to hold all this.filter data + filterLength = filter.length; + if (filterType == NO_FILTERING) { + for (int i=0; i< filterLength; i++) + filter[i] = Sound.NO_FILTER; + } + if (filterType == LOW_PASS) { + System.arraycopy(this.frequencyCutoff, 0, filter, 0, filterLength); + } + if (debugFlag) + debugPrint(", " + this.frequencyCutoff[0]); + } + + /** + * Set Frequency Scale Factor + * @param frequencyScaleFactor factor applied to sound's base frequency + */ + void setFrequencyScaleFactor(float frequencyScaleFactor) { + this.frequencyScaleFactor = frequencyScaleFactor; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Frequency Scale Factor + * @return frequency scale factor applied to sound's base frequency + */ + float getFrequencyScaleFactor() { + return this.frequencyScaleFactor; + } + + /** + * Set Velocity ScaleFactor used in calculating Doppler Effect + * @param velocityScaleFactor applied to velocity of sound in relation to listener + */ + void setVelocityScaleFactor(float velocityScaleFactor) { + this.velocityScaleFactor = velocityScaleFactor; + this.aaDirty = true; + notifyUsers(); + } + /** + * Retrieve Velocity ScaleFactor used in calculating Doppler Effect + * @return velocity scale factor + */ + float getVelocityScaleFactor() { + return this.velocityScaleFactor; + } + + synchronized void reset(AuralAttributesRetained aa) { + int i; + + this.attributeGain = aa.attributeGain; + this.rolloff = aa.rolloff; + this.reflectionCoefficient = aa.reflectionCoefficient; + this.reverbCoefficient = aa.reverbCoefficient; + this.reflectionDelay = aa.reflectionDelay; + this.reverbDelay = aa.reverbDelay; + this.reverbBounds = aa.reverbBounds; + this.reverbOrder = aa.reverbOrder; + this.decayTime = aa.decayTime; + this.decayFilter = aa.decayFilter; + this.diffusion = aa.diffusion; + this.density = aa.density; + this.frequencyScaleFactor = aa.frequencyScaleFactor; + this.velocityScaleFactor = aa.velocityScaleFactor; + + if (aa.distance != null) { + this.distance = new float[aa.distance.length]; + if (debugFlag) + debugPrint("reset aa; aa.distance.length = " + this.distance.length); + System.arraycopy(aa.distance, 0, this.distance, 0, this.distance.length); + } + else + if (debugFlag) + debugPrint("reset aa; aa.distance = null"); + if (aa.frequencyCutoff != null) { + this.frequencyCutoff = new float[aa.frequencyCutoff.length]; + if (debugFlag) + debugPrint("reset aa; aa.frequencyCutoff.length = " + this.frequencyCutoff.length); + System.arraycopy(aa.frequencyCutoff, 0, this.frequencyCutoff, 0, + this.frequencyCutoff.length); + } + else + if (debugFlag) + debugPrint("reset aa; aa.frequencyCutoff = null"); + // XXXX: (Enhancement) Why are these dirtyFlag cleared rather than aa->this + this.aaDirty = false; + aa.aaDirty = false; + } + + void update(AuralAttributesRetained aa) { + this.reset(aa); + } + +} |