summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/audio/HRTFElevation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/audio/HRTFElevation.cpp')
-rw-r--r--WebCore/platform/audio/HRTFElevation.cpp266
1 files changed, 0 insertions, 266 deletions
diff --git a/WebCore/platform/audio/HRTFElevation.cpp b/WebCore/platform/audio/HRTFElevation.cpp
deleted file mode 100644
index 06d03ea..0000000
--- a/WebCore/platform/audio/HRTFElevation.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2010 Google 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:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions 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.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if ENABLE(WEB_AUDIO)
-
-#include "HRTFElevation.h"
-
-#include "AudioBus.h"
-#include "AudioFileReader.h"
-#include "Biquad.h"
-#include "FFTFrame.h"
-#include "HRTFPanner.h"
-#include <algorithm>
-#include <math.h>
-#include <wtf/OwnPtr.h>
-
-using namespace std;
-
-namespace WebCore {
-
-const unsigned HRTFElevation::AzimuthSpacing = 15;
-const unsigned HRTFElevation::NumberOfRawAzimuths = 360 / AzimuthSpacing;
-const unsigned HRTFElevation::InterpolationFactor = 8;
-const unsigned HRTFElevation::NumberOfTotalAzimuths = NumberOfRawAzimuths * InterpolationFactor;
-
-// Takes advantage of the symmetry and creates a composite version of the two measured versions. For example, we have both azimuth 30 and -30 degrees
-// where the roles of left and right ears are reversed with respect to each other.
-bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName,
- RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR)
-{
- RefPtr<HRTFKernel> kernelL1;
- RefPtr<HRTFKernel> kernelR1;
- bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampleRate, subjectName, kernelL1, kernelR1);
- if (!success)
- return false;
-
- // And symmetric version
- int symmetricAzimuth = !azimuth ? 0 : 360 - azimuth;
-
- RefPtr<HRTFKernel> kernelL2;
- RefPtr<HRTFKernel> kernelR2;
- success = calculateKernelsForAzimuthElevation(symmetricAzimuth, elevation, sampleRate, subjectName, kernelL2, kernelR2);
- if (!success)
- return false;
-
- // Notice L/R reversal in symmetric version.
- kernelL = HRTFKernel::createInterpolatedKernel(kernelL1.get(), kernelR2.get(), 0.5);
- kernelR = HRTFKernel::createInterpolatedKernel(kernelR1.get(), kernelL2.get(), 0.5);
-
- return true;
-}
-
-bool HRTFElevation::calculateKernelsForAzimuthElevation(int azimuth, int elevation, double sampleRate, const String& subjectName,
- RefPtr<HRTFKernel>& kernelL, RefPtr<HRTFKernel>& kernelR)
-{
- // Valid values for azimuth are 0 -> 345 in 15 degree increments.
- // Valid values for elevation are -45 -> +90 in 15 degree increments.
-
- bool isAzimuthGood = azimuth >= 0 && azimuth <= 345 && (azimuth / 15) * 15 == azimuth;
- ASSERT(isAzimuthGood);
- if (!isAzimuthGood)
- return false;
-
- bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation;
- ASSERT(isElevationGood);
- if (!isElevationGood)
- return false;
-
- // Construct the resource name from the subject name, azimuth, and elevation, for example:
- // "IRC_Composite_C_R0195_T015_P000"
- // Note: the passed in subjectName is not a string passed in via JavaScript or the web.
- // It's passed in as an internal ASCII identifier and is an implementation detail.
- int positiveElevation = elevation < 0 ? elevation + 360 : elevation;
- String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectName.utf8().data(), azimuth, positiveElevation);
-
- OwnPtr<AudioBus> impulseResponse(AudioBus::loadPlatformResource(resourceName.utf8().data(), sampleRate));
-
- ASSERT(impulseResponse.get());
- if (!impulseResponse.get())
- return false;
-
- size_t responseLength = impulseResponse->length();
- size_t expectedLength = static_cast<size_t>(256 * (sampleRate / 44100.0));
-
- // Check number of channels and length. For now these are fixed and known.
- bool isBusGood = responseLength == expectedLength && impulseResponse->numberOfChannels() == 2;
- ASSERT(isBusGood);
- if (!isBusGood)
- return false;
-
- AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelLeft);
- AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(AudioBus::ChannelRight);
-
- // Note that depending on the fftSize returned by the panner, we may be truncating the impulse response we just loaded in.
- const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate);
- kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate, true);
- kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate, true);
-
- return true;
-}
-
-// The range of elevations for the IRCAM impulse responses varies depending on azimuth, but the minimum elevation appears to always be -45.
-//
-// Here's how it goes:
-static int maxElevations[] = {
- // Azimuth
- //
- 90, // 0
- 45, // 15
- 60, // 30
- 45, // 45
- 75, // 60
- 45, // 75
- 60, // 90
- 45, // 105
- 75, // 120
- 45, // 135
- 60, // 150
- 45, // 165
- 75, // 180
- 45, // 195
- 60, // 210
- 45, // 225
- 75, // 240
- 45, // 255
- 60, // 270
- 45, // 285
- 75, // 300
- 45, // 315
- 60, // 330
- 45 // 345
-};
-
-PassOwnPtr<HRTFElevation> HRTFElevation::createForSubject(const String& subjectName, int elevation, double sampleRate)
-{
- bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 15) * 15 == elevation;
- ASSERT(isElevationGood);
- if (!isElevationGood)
- return 0;
-
- OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
- OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
-
- // Load convolution kernels from HRTF files.
- int interpolatedIndex = 0;
- for (unsigned rawIndex = 0; rawIndex < NumberOfRawAzimuths; ++rawIndex) {
- // Don't let elevation exceed maximum for this azimuth.
- int maxElevation = maxElevations[rawIndex];
- int actualElevation = min(elevation, maxElevation);
-
- bool success = calculateKernelsForAzimuthElevation(rawIndex * AzimuthSpacing, actualElevation, sampleRate, subjectName, kernelListL->at(interpolatedIndex), kernelListR->at(interpolatedIndex));
- if (!success)
- return 0;
-
- interpolatedIndex += InterpolationFactor;
- }
-
- // Now go back and interpolate intermediate azimuth values.
- for (unsigned i = 0; i < NumberOfTotalAzimuths; i += InterpolationFactor) {
- int j = (i + InterpolationFactor) % NumberOfTotalAzimuths;
-
- // Create the interpolated convolution kernels and delays.
- for (unsigned jj = 1; jj < InterpolationFactor; ++jj) {
- double x = double(jj) / double(InterpolationFactor); // interpolate from 0 -> 1
-
- (*kernelListL)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListL->at(i).get(), kernelListL->at(j).get(), x);
- (*kernelListR)[i + jj] = HRTFKernel::createInterpolatedKernel(kernelListR->at(i).get(), kernelListR->at(j).get(), x);
- }
- }
-
- OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), elevation, sampleRate));
- return hrtfElevation.release();
-}
-
-PassOwnPtr<HRTFElevation> HRTFElevation::createByInterpolatingSlices(HRTFElevation* hrtfElevation1, HRTFElevation* hrtfElevation2, double x, double sampleRate)
-{
- ASSERT(hrtfElevation1 && hrtfElevation2);
- if (!hrtfElevation1 || !hrtfElevation2)
- return 0;
-
- ASSERT(x >= 0.0 && x < 1.0);
-
- OwnPtr<HRTFKernelList> kernelListL = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
- OwnPtr<HRTFKernelList> kernelListR = adoptPtr(new HRTFKernelList(NumberOfTotalAzimuths));
-
- HRTFKernelList* kernelListL1 = hrtfElevation1->kernelListL();
- HRTFKernelList* kernelListR1 = hrtfElevation1->kernelListR();
- HRTFKernelList* kernelListL2 = hrtfElevation2->kernelListL();
- HRTFKernelList* kernelListR2 = hrtfElevation2->kernelListR();
-
- // Interpolate kernels of corresponding azimuths of the two elevations.
- for (unsigned i = 0; i < NumberOfTotalAzimuths; ++i) {
- (*kernelListL)[i] = HRTFKernel::createInterpolatedKernel(kernelListL1->at(i).get(), kernelListL2->at(i).get(), x);
- (*kernelListR)[i] = HRTFKernel::createInterpolatedKernel(kernelListR1->at(i).get(), kernelListR2->at(i).get(), x);
- }
-
- // Interpolate elevation angle.
- double angle = (1.0 - x) * hrtfElevation1->elevationAngle() + x * hrtfElevation2->elevationAngle();
-
- OwnPtr<HRTFElevation> hrtfElevation = adoptPtr(new HRTFElevation(kernelListL.release(), kernelListR.release(), static_cast<int>(angle), sampleRate));
- return hrtfElevation.release();
-}
-
-void HRTFElevation::getKernelsFromAzimuth(double azimuthBlend, unsigned azimuthIndex, HRTFKernel* &kernelL, HRTFKernel* &kernelR, double& frameDelayL, double& frameDelayR)
-{
- bool checkAzimuthBlend = azimuthBlend >= 0.0 && azimuthBlend < 1.0;
- ASSERT(checkAzimuthBlend);
- if (!checkAzimuthBlend)
- azimuthBlend = 0.0;
-
- unsigned numKernels = m_kernelListL->size();
-
- bool isIndexGood = azimuthIndex < numKernels;
- ASSERT(isIndexGood);
- if (!isIndexGood) {
- kernelL = 0;
- kernelR = 0;
- return;
- }
-
- // Return the left and right kernels.
- kernelL = m_kernelListL->at(azimuthIndex).get();
- kernelR = m_kernelListR->at(azimuthIndex).get();
-
- frameDelayL = m_kernelListL->at(azimuthIndex)->frameDelay();
- frameDelayR = m_kernelListR->at(azimuthIndex)->frameDelay();
-
- int azimuthIndex2 = (azimuthIndex + 1) % numKernels;
- double frameDelay2L = m_kernelListL->at(azimuthIndex2)->frameDelay();
- double frameDelay2R = m_kernelListR->at(azimuthIndex2)->frameDelay();
-
- // Linearly interpolate delays.
- frameDelayL = (1.0 - azimuthBlend) * frameDelayL + azimuthBlend * frameDelay2L;
- frameDelayR = (1.0 - azimuthBlend) * frameDelayR + azimuthBlend * frameDelay2R;
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(WEB_AUDIO)