📄 jspositionalsample.java
字号:
/* * $RCSfile: JSPositionalSample.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. * * $Revision: 1.4 $ * $Date: 2007/02/09 17:20:03 $ * $State: Exp $ *//* * Java Sound PositionalSample object * * IMPLEMENTATION NOTE: The JavaSoundMixer is incomplete and really needs * to be rewritten. */package com.sun.j3d.audioengines.javasound;import javax.media.j3d.*;import javax.vecmath.*;import com.sun.j3d.audioengines.*;/** * The PostionalSample Class defines the data and methods associated with a * PointSound sample played thru the AudioDevice. */class JSPositionalSample extends JSSample{ // maintain fields for stereo channel rendering float leftGain = 1.0f; // scale factor float rightGain = 1.0f; // scale factor int leftDelay = 0; // left InterauralTimeDifference in millisec int rightDelay = 0; // right ITD in millisec // fields for reverb channel // debug flag for the verbose Doppler calculation methods static final protected boolean dopplerFlag = true; /** * For positional and directional sounds, TWO Hae streams or clips * are allocated, one each for the left and right channels, played at * a different (delayed) time and with a different gain value. */ int secondIndex = NULL_SAMPLE; /** * A third sample for control of reverb of the stream/clip is openned * and maintained for all directional/positional sounds. * For now, even if no aural attributes (using reverb) are active, * a reverb channel is always started with the other two. A sound could * be started without reverb and then reverb added later, but since there * is no way to offset properly into all sounds (considering non-cached * and nconsistent rate-changes during playing) this third sound is * always allocated and started. */ int reverbIndex = NULL_SAMPLE; /** * Save ear positions transformed into VirtualWorld coords from Head coords * These default positions are used when the real values cannot queried */ Point3f xformLeftEar = new Point3f(-0.09f, -0.03f, 0.095f); Point3f xformRightEar = new Point3f(0.09f, -0.03f, 0.095f); // Z axis in head space - looking into the screen Vector3f xformHeadZAxis = new Vector3f(0.0f, 0.0f, -1.0f); // Va /** * Save vectors from source source position to transformed ear parameters */ Vector3f sourceToCenterEar = new Vector3f(); // Vh Vector3f sourceToRightEar = new Vector3f(); // Vf or Vc Vector3f sourceToLeftEar = new Vector3f(); // Vf or Vc boolean averageDistances = false; long deltaTime = 0; double sourcePositionChange = -1.0; double headPositionChange = -1.0; /* * Maintain the last locations of sound and head as well as time the * sound was last processed. * Process delta distance and time as part of Doppler calculations. */ static int MAX_DISTANCES = 4; int numDistances = 0; // TODO: time is based on changes to position!!! only// TODO: must shap shot when either Position OR ear changes!!!// TODO: must grab all changes to VIEW parameters (could change ear)!!!// not just when pointer to View changes!! long[] times = new long[MAX_DISTANCES]; Point3f[] positions = new Point3f[MAX_DISTANCES]; // xformed sound source positions Point3f[] centerEars = new Point3f[MAX_DISTANCES]; // xformed center ear positions /* * a set of indices (first, last, and current) are maintained to point * into the above arrays */ int firstIndex = 0; int lastIndex = 0; int currentIndex = 0; /* * Allow changes in Doppler rate only small incremental values otherwise * you hear skips in the pitch of a sound during playback. * When playback is faster, allow delta changes: * (diff in Factor for octave (1.0))/(12 1/2-steps))*(1/4) of half-step * When playback is slower, allow delta changes: * (diff in Factor for octave (0.5))/(12 1/2-steps))*(1/4) of half-step */ double lastRequestedDopplerRateRatio = -1.0f; double lastActualDopplerRateRatio = -1.0f; static double maxRatio = 256.0f; // 8 times higher/lower /* * denotes movement of sound away or towards listener */ static int TOWARDS = 1; static int NO_CHANGE = 0; static int AWAY = -1; /* * Process request for Filtering fields */ boolean filterFlag = false; float filterFreq = -1.0f; /* * Construct a new audio device Sample object */ public JSPositionalSample() { super(); if (debugFlag) debugPrint("JSPositionalSample constructor"); // initiallize circular buffer for averaging distance values for (int i=0; i<MAX_DISTANCES; i++) { positions[i] = new Point3f(); centerEars[i] = new Point3f(0.09f, -0.03f, 0.095f); } clear(); } // TODO: get/set secondChannel to JSStream/Clip/MIDI // TODO: get/set reverbChannel to JSStream/Clip/MIDI /* * Process request for Filtering fields */ boolean getFilterFlag() { return filterFlag; } float getFilterFreq() { return filterFreq; } /** * Clears the fields associated with sample data for this sound, and * frees any device specific data associated with this sample. */ public void clear() { if (debugFlag) debugPrint("JSPositionalSample.clear() enter"); super.clear(); leftGain = 1.0f; rightGain = 1.0f; leftDelay = 0; rightDelay = 0; xformLeftEar.set(-0.09f, -0.03f, 0.095f); xformRightEar.set(0.09f, -0.03f, 0.095f); // Z axis in head space - looking into the screen xformHeadZAxis.set(0.0f, 0.0f, -1.0f); // Va sourceToCenterEar.set(0.0f, 0.0f, 0.0f); // Vh sourceToRightEar.set(0.0f, 0.0f, 0.0f); // Vf or Vc sourceToLeftEar.set(0.0f, 0.0f, 0.0f); // Vf or Vc reset(); if (debugFlag) debugPrint("JSPositionalSample.clear() exit"); } /** * Reset time and count based fields associated with sample data * for this sound */ void reset() { if (debugFlag) debugPrint("JSPositionalSample.reset() enter"); super.reset(); averageDistances = false; // denotes not previously processed deltaTime = 0; sourcePositionChange = -1.0; headPositionChange = -1.0; rateRatio = 1.0f; numDistances = 0; averageDistances = false; if (debugFlag) debugPrint("JSPositionalSample.reset() exit"); } // increments index counters and bumps index numbers if the end of // the circular buffer is reached void incrementIndices() { int maxIndex = MAX_DISTANCES - 1; if (numDistances < maxIndex) { averageDistances = false; currentIndex = numDistances; lastIndex = currentIndex - 1; firstIndex = 0; numDistances++; } else if (numDistances == maxIndex) { // we filled the data buffers completely and are ready to // calculate averages averageDistances = true; currentIndex = maxIndex; lastIndex = currentIndex - 1; firstIndex = 0; numDistances++; } else if (numDistances > maxIndex) { // increment each counter and loop around averageDistances = true; currentIndex++; lastIndex++; firstIndex++; currentIndex %= MAX_DISTANCES; lastIndex %= MAX_DISTANCES; firstIndex %= MAX_DISTANCES; } } // Not only do we transform position but delta time is calculated and // old transformed position is saved // Average the last MAX_DISTANCES delta time and change in position using // an array for both and circlularly storing the time and distance values // into this array. // Current transformed position and time in stored into maxIndex of their // respective arrays. void setXformedPosition() { Point3f newPosition = new Point3f(); if (debugFlag) debugPrint("*** setXformedPosition"); // xform Position if (getVWrldXfrmFlag()) { if (debugFlag) debugPrint(" Transform set so transform pos"); vworldXfrm.transform(position, newPosition); } else { if (debugFlag) debugPrint(" Transform NOT set so pos => xformPos"); newPosition.set(position); } // store position and increment indices ONLY if theres an actual change if (newPosition.x == positions[currentIndex].x && newPosition.y == positions[currentIndex].y && newPosition.z == positions[currentIndex].z ) { if (debugFlag) debugPrint(" No change in pos, so don't reset"); return; } incrementIndices(); // store new transformed position times[currentIndex] = System.currentTimeMillis(); positions[currentIndex].set(newPosition); if (debugFlag) debugPrint(" xform(sound)Position -" + " positions[" + currentIndex + "] = (" + positions[currentIndex].x + ", " + positions[currentIndex].y + ", " + positions[currentIndex].z + ")"); // since this is a change to the sound position and not the // head save the last head position into the current element if (numDistances > 1) centerEars[currentIndex].set(centerEars[lastIndex]); } /** * Set Doppler effect Rate * * Calculate the rate of change in for the head and sound * between the two time stamps (last two times position or * VirtualWorld transform was updated). * First determine if the head and sound source are moving * towards each other (distance between them is decreasing), * moving away from each other (distance between them is * increasing), or no change (distance is the same, not moving * or moving the same speed/direction). * The following equation is used for determining the change in frequency - * If there has been a change in the distance between the head and sound: * * f' = f * frequencyScaleFactor * velocityRatio * * For no change in the distance bewteen head and sound, velocityRatio is 1: * * f' = f * * For head and sound moving towards each other, velocityRatio (> 1.0) is: * * | speedOfSound*rollOff + velocityOfHead*velocityScaleFactor |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -