📄 jspositionalsample.java
字号:
* | ------------------------------------------------------------- | * | speedOfSound*rollOff - velocityOfSource*velocityScaleFactor | * * For head and sound moving away from each other, velocityRatio (< 1.0) is: * * | speedOfSound*rollOff - velocityOfHead*velocityScaleFactor | * | ------------------------------------------------------------- | * | speedOfSound*rollOff + velocityOfSource*velocityScaleFactor | * * where frequencyScaleFactor, rollOff, velocityScaleFactor all come from * the active AuralAttributes parameters. * The following special cases must be test for AuralAttribute parameters: * rolloff * Value MUST be > zero for any sound to be heard! * If value is zero, all sounds affected by AuralAttribute region are silent. * velocityScaleFactor * Value MUST be > zero for any sound to be heard! * If value is zero, all sounds affected by AuralAttribute region are paused. * frequencyScaleFactor * Value of zero disables Doppler calculations: * Sfreq' = Sfreq * frequencyScaleFactor * * This rate is passed to device drive as a change to playback sample * rate, in this case the frequency need not be known. * * Return value of zero denotes no change * Return value of -1 denotes ERROR */ float calculateDoppler(AuralParameters attribs) { double sampleRateRatio = 1.0; double headVelocity = 0.0; // in milliseconds double soundVelocity = 0.0; // in milliseconds double distanceSourceToHead = 0.0; // in meters double lastDistanceSourceToHead = 0.0; // in meters float speedOfSound = attribs.SPEED_OF_SOUND; double numerator = 1.0; double denominator = 1.0; int direction = NO_CHANGE; // sound movement away or towards listener Point3f lastXformPosition; Point3f lastXformCenterEar; Point3f xformPosition; Point3f xformCenterEar; float averagedSoundDistances = 0.0f; float averagedEarsDistances = 0.0f; /* * Average the differences between the last MAX_DISTANCE * sound positions and head positions */ if (!averageDistances) { // TODO: Use some EPSilion to do 'equals' test against if (dopplerFlag) debugPrint("JSPositionalSample.calculateDoppler - " + "not enough distance data collected, " + "dopplerRatio set to zero"); // can't calculate change in direction return 0.0f; // sample rate ratio is zero } lastXformPosition = positions[lastIndex]; lastXformCenterEar = centerEars[lastIndex]; xformPosition = positions[currentIndex]; xformCenterEar = centerEars[currentIndex]; distanceSourceToHead = xformPosition.distance(xformCenterEar); lastDistanceSourceToHead = lastXformPosition.distance(lastXformCenterEar); if (dopplerFlag) { debugPrint("JSPositionalSample.calculateDoppler - distances: " + "current,last = " + distanceSourceToHead + ", " + lastDistanceSourceToHead ); debugPrint(" " + "current position = " + xformPosition.x + ", " + xformPosition.y + ", " + xformPosition.z); debugPrint(" " + "current ear = " + xformCenterEar.x + ", " + xformCenterEar.y + ", " + xformCenterEar.z); debugPrint(" " + "last position = " + lastXformPosition.x + ", " + lastXformPosition.y + ", " + lastXformPosition.z); debugPrint(" " + "last ear = " + lastXformCenterEar.x + ", " + lastXformCenterEar.y + ", " + lastXformCenterEar.z); } if (distanceSourceToHead == lastDistanceSourceToHead) { // TODO: Use some EPSilion to do 'equals' test against if (dopplerFlag) debugPrint("JSPositionalSample.calculateDoppler - " + "distance diff = 0, dopplerRatio set to zero"); // can't calculate change in direction return 0.0f; // sample rate ratio is zero } deltaTime = times[currentIndex] - times[firstIndex]; for (int i=0; i<(MAX_DISTANCES-1); i++) { averagedSoundDistances += positions[i+1].distance(positions[i]); averagedEarsDistances += centerEars[i+1].distance(centerEars[i]); } averagedSoundDistances /= (MAX_DISTANCES-1); averagedEarsDistances /= (MAX_DISTANCES-1); soundVelocity = averagedSoundDistances/deltaTime; headVelocity = averagedEarsDistances/deltaTime; if (dopplerFlag) { debugPrint(" " + "delta time = " + deltaTime ); debugPrint(" " + "soundPosition delta = " + xformPosition.distance(lastXformPosition)); debugPrint(" " + "soundVelocity = " + soundVelocity); debugPrint(" " + "headPosition delta = " + xformCenterEar.distance(lastXformCenterEar)); debugPrint(" " + "headVelocity = " + headVelocity); } if (attribs != null) { float rolloff = attribs.rolloff; float velocityScaleFactor = attribs.velocityScaleFactor; if (rolloff != 1.0f) { speedOfSound *= rolloff; if (dopplerFlag) debugPrint(" " + "attrib rollof = " + rolloff); } if (velocityScaleFactor != 1.0f) { soundVelocity *= velocityScaleFactor; headVelocity *= velocityScaleFactor; if (dopplerFlag) { debugPrint(" " + "attrib velocity scale factor = " + velocityScaleFactor ); debugPrint(" " + "new soundVelocity = " + soundVelocity); debugPrint(" " + "new headVelocity = " + headVelocity); } } } if (distanceSourceToHead < lastDistanceSourceToHead) { // sound and head moving towards each other if (dopplerFlag) debugPrint(" " + "moving towards..."); direction = TOWARDS; numerator = speedOfSound + headVelocity; denominator = speedOfSound - soundVelocity; } else { // sound and head moving away from each other // note: no change in distance case covered above if (dopplerFlag) debugPrint(" " + "moving away..."); direction = AWAY; numerator = speedOfSound - headVelocity; denominator = speedOfSound + soundVelocity; } if (numerator <= 0.0) { if (dopplerFlag) debugPrint("JSPositionalSample.calculateDoppler: " + "BOOM!! - velocity of head > speed of sound"); return -1.0f; } else if (denominator <= 0.0) { if (dopplerFlag) debugPrint("JSPositionalSample.calculateDoppler: " + "BOOM!! - velocity of sound source negative"); return -1.0f; } else { if (dopplerFlag) debugPrint("JSPositionalSample.calculateDoppler: " + "numerator = " + numerator + ", denominator = " + denominator ); sampleRateRatio = numerator / denominator; }/******** IF direction WERE important to calling method... * Return value greater than 0 denotes direction of sound source is * towards the listener * Return value less than 0 denotes direction of sound source is * away from the listener if (direction == AWAY) return -((float)sampleRateRatio); else return (float)sampleRateRatio;*********/ return (float)sampleRateRatio; } void updateEar(int dirtyFlags, View view) { if (debugFlag) debugPrint("*** updateEar fields"); // xform Ear Point3f xformCenterEar = new Point3f(); if (!calculateNewEar(dirtyFlags, view, xformCenterEar)) { if (debugFlag) debugPrint("calculateNewEar returned false"); return; } // store ear and increment indices ONLY if there is an actual change if (xformCenterEar.x == centerEars[currentIndex].x && xformCenterEar.y == centerEars[currentIndex].y && xformCenterEar.z == centerEars[currentIndex].z ) { if (debugFlag) debugPrint(" No change in ear, so don't reset"); return; } // store xform Ear incrementIndices(); times[currentIndex] = System.currentTimeMillis(); centerEars[currentIndex].set(xformCenterEar); // since this is a change to the head position and not the sound // position save the last sound position into the current element if (numDistances > 1) positions[currentIndex].set(positions[lastIndex]); } boolean calculateNewEar(int dirtyFlags, View view, Point3f xformCenterEar) { /* * Transform ear position (from Head) into Virtual World Coord space */ Point3d earPosition = new Point3d(); // temporary double Point // TODO: check dirty flags coming in // For now, recalculate ear positions by forcing earsXformed false boolean earsXformed = false; if (!earsXformed) { if (view != null) { PhysicalBody body = view.getPhysicalBody(); if (body != null) { // Get Head Coord. to Virtual World transform // TODO: re-enable this when userHeadToVworld is // implemented correctly!!! Transform3D headToVwrld = new Transform3D(); view.getUserHeadToVworld(headToVwrld); if (debugFlag) { debugPrint("user head to Vwrld colum-major:"); double[] matrix = new double[16]; headToVwrld.get(matrix); debugPrint("JSPosSample " + matrix[0]+", " + matrix[1]+", "+matrix[2]+", "+matrix[3]); debugPrint("JSPosSample " + matrix[4]+", " + matrix[5]+", "+matrix[6]+", "+matrix[7]); debugPrint("JSPosSample " + matrix[8]+", " + matrix[9]+", "+matrix[10]+", "+matrix[11]); debugPrint("JSPosSample " + matrix[12]+", " + matrix[13]+", "+matrix[14]+", "+matrix[15]); } // Get left and right ear positions in Head Coord.s // Transforms left and right ears to Virtual World coord.s body.getLeftEarPosition(earPosition); xformLeftEar.x = (float)earPosition.x; xformLeftEar.y = (float)earPosition.y; xformLeftEar.z = (float)earPosition.z; body.getRightEarPosition(earPosition); xformRightEar.x = (float)earPosition.x; xformRightEar.y = (float)earPosition.y; xformRightEar.z = (float)earPosition.z; headToVwrld.transform(xformRightEar); headToVwrld.transform(xformLeftEar); // Transform head viewing (Z) axis to Virtual World coord.s xformHeadZAxis.set(0.0f, 0.0f, -1.0f); // Va headToVwrld.transform(xformHeadZAxis); // calculate the new (current) mid-point between the ears // find the mid point between left and right ear positions xformCenterEar.x = xformLeftEar.x + ((xformRightEar.x - xformLeftEar.x)*0.5f); xformCenterEar.y = xformLeftEar.y + ((xformRightEar.y - xformLeftEar.y)*0.5f); xformCenterEar.z = xformLeftEar.z + ((xformRightEar.z - xformLeftEar.z)*0.5f); // TODO: when head changes earDirty should be set! // earDirty = false; if (debugFlag) { debugPrint(" earXformed CALCULATED"); debugPrint(" xformCenterEar = " + xformCenterEar.x + " " + xformCenterEar.y + " " + xformCenterEar.z ); } earsXformed = true; } // end of body NOT null } // end of view NOT null } // end of earsDirty else { // TODO: use existing transformed ear positions } if (!earsXformed) { // uses the default head position of (0.0, -0.03, 0.095) if (debugFlag) debugPrint(" earXformed NOT calculated"); } return earsXformed; } /** * Render this sample * * Calculate the audiodevice parameters necessary to spatially play this * sound. */ public void render(int dirtyFlags, View view, AuralParameters attribs) { if (debugFlag) debugPrint("JSPositionalSample.render"); updateEar(dirtyFlags, view); /* * Time to check velocities and change the playback rate if necessary... * * Rolloff value MUST be > zero for any sound to be heard! * If rolloff is zero, all sounds affected by AuralAttribute region * are silent. * FrequencyScaleFactor value MUST be > zero for any sound to be heard! * since Sfreq' = Sfreq * frequencyScaleFactor. * If FrequencyScaleFactor is zero, all sounds affected by * AuralAttribute region are paused. * VelocityScaleFactor value of zero disables Doppler calculations. * * Scale 'Doppler' rate (or lack of Doppler) by frequencyScaleFactor. */ float dopplerRatio = 1.0f; if (attribs != null) { float rolloff = attribs.rolloff; float frequencyScaleFactor = attribs.frequencyScaleFactor;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -