| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 // Total number of components of an HRTF database. | 55 // Total number of components of an HRTF database. |
| 56 const size_t TotalNumberOfResponses = 240; | 56 const size_t TotalNumberOfResponses = 240; |
| 57 | 57 |
| 58 // Number of frames in an individual impulse response. | 58 // Number of frames in an individual impulse response. |
| 59 const size_t ResponseFrameSize = 256; | 59 const size_t ResponseFrameSize = 256; |
| 60 | 60 |
| 61 // Sample-rate of the spatialization impulse responses as stored in the resource
file. | 61 // Sample-rate of the spatialization impulse responses as stored in the resource
file. |
| 62 // The impulse responses may be resampled to a different sample-rate (depending
on the audio hardware) when they are loaded. | 62 // The impulse responses may be resampled to a different sample-rate (depending
on the audio hardware) when they are loaded. |
| 63 const float ResponseSampleRate = 44100; | 63 const float ResponseSampleRate = 44100; |
| 64 | 64 |
| 65 #if USE(WEBAUDIO_GSTREAMER) | |
| 66 #define USE_CONCATENATED_IMPULSE_RESPONSES | |
| 67 #endif | |
| 68 | |
| 69 #ifdef USE_CONCATENATED_IMPULSE_RESPONSES | |
| 70 // Lazily load a concatenated HRTF database for given subject and store it in a | |
| 71 // local hash table to ensure quick efficient future retrievals. | |
| 72 static AudioBus* getConcatenatedImpulseResponsesForSubject(const String& subject
Name) | |
| 73 { | |
| 74 typedef HashMap<String, AudioBus*> AudioBusMap; | |
| 75 DEFINE_STATIC_LOCAL(AudioBusMap, audioBusMap, ()); | |
| 76 | |
| 77 AudioBus* bus; | |
| 78 AudioBusMap::iterator iterator = audioBusMap.find(subjectName); | |
| 79 if (iterator == audioBusMap.end()) { | |
| 80 OwnPtr<AudioBus> concatenatedImpulseResponses = AudioBus::loadPlatformRe
source(subjectName.utf8().data(), ResponseSampleRate); | |
| 81 ASSERT(concatenatedImpulseResponses); | |
| 82 if (!concatenatedImpulseResponses) | |
| 83 return 0; | |
| 84 | |
| 85 bus = concatenatedImpulseResponses.leakPtr(); | |
| 86 audioBusMap.set(subjectName, bus); | |
| 87 } else | |
| 88 bus = iterator->value; | |
| 89 | |
| 90 size_t responseLength = bus->length(); | |
| 91 size_t expectedLength = static_cast<size_t>(TotalNumberOfResponses * Respons
eFrameSize); | |
| 92 | |
| 93 // Check number of channels and length. For now these are fixed and known. | |
| 94 bool isBusGood = responseLength == expectedLength && bus->numberOfChannels()
== 2; | |
| 95 ASSERT(isBusGood); | |
| 96 if (!isBusGood) | |
| 97 return 0; | |
| 98 | |
| 99 return bus; | |
| 100 } | |
| 101 #endif | |
| 102 | |
| 103 // Takes advantage of the symmetry and creates a composite version of the two me
asured versions. For example, we have both azimuth 30 and -30 degrees | 65 // Takes advantage of the symmetry and creates a composite version of the two me
asured versions. For example, we have both azimuth 30 and -30 degrees |
| 104 // where the roles of left and right ears are reversed with respect to each othe
r. | 66 // where the roles of left and right ears are reversed with respect to each othe
r. |
| 105 bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, in
t elevation, float sampleRate, const String& subjectName, | 67 bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, in
t elevation, float sampleRate, const String& subjectName, |
| 106 RefPtr<HRTFKern
el>& kernelL, RefPtr<HRTFKernel>& kernelR) | 68 RefPtr<HRTFKern
el>& kernelL, RefPtr<HRTFKernel>& kernelR) |
| 107 { | 69 { |
| 108 RefPtr<HRTFKernel> kernelL1; | 70 RefPtr<HRTFKernel> kernelL1; |
| 109 RefPtr<HRTFKernel> kernelR1; | 71 RefPtr<HRTFKernel> kernelR1; |
| 110 bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampl
eRate, subjectName, kernelL1, kernelR1); | 72 bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampl
eRate, subjectName, kernelL1, kernelR1); |
| 111 if (!success) | 73 if (!success) |
| 112 return false; | 74 return false; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 142 ASSERT(isElevationGood); | 104 ASSERT(isElevationGood); |
| 143 if (!isElevationGood) | 105 if (!isElevationGood) |
| 144 return false; | 106 return false; |
| 145 | 107 |
| 146 // Construct the resource name from the subject name, azimuth, and elevation
, for example: | 108 // Construct the resource name from the subject name, azimuth, and elevation
, for example: |
| 147 // "IRC_Composite_C_R0195_T015_P000" | 109 // "IRC_Composite_C_R0195_T015_P000" |
| 148 // Note: the passed in subjectName is not a string passed in via JavaScript
or the web. | 110 // Note: the passed in subjectName is not a string passed in via JavaScript
or the web. |
| 149 // It's passed in as an internal ASCII identifier and is an implementation d
etail. | 111 // It's passed in as an internal ASCII identifier and is an implementation d
etail. |
| 150 int positiveElevation = elevation < 0 ? elevation + 360 : elevation; | 112 int positiveElevation = elevation < 0 ? elevation + 360 : elevation; |
| 151 | 113 |
| 152 #ifdef USE_CONCATENATED_IMPULSE_RESPONSES | |
| 153 AudioBus* bus(getConcatenatedImpulseResponsesForSubject(subjectName)); | |
| 154 | |
| 155 if (!bus) | |
| 156 return false; | |
| 157 | |
| 158 int elevationIndex = positiveElevation / AzimuthSpacing; | |
| 159 if (positiveElevation > 90) | |
| 160 elevationIndex -= AzimuthSpacing; | |
| 161 | |
| 162 // The concatenated impulse response is a bus containing all | |
| 163 // the elevations per azimuth, for all azimuths by increasing | |
| 164 // order. So for a given azimuth and elevation we need to compute | |
| 165 // the index of the wanted audio frames in the concatenated table. | |
| 166 unsigned index = ((azimuth / AzimuthSpacing) * HRTFDatabase::NumberOfRawElev
ations) + elevationIndex; | |
| 167 bool isIndexGood = index < TotalNumberOfResponses; | |
| 168 ASSERT(isIndexGood); | |
| 169 if (!isIndexGood) | |
| 170 return false; | |
| 171 | |
| 172 // Extract the individual impulse response from the concatenated | |
| 173 // responses and potentially sample-rate convert it to the desired | |
| 174 // (hardware) sample-rate. | |
| 175 unsigned startFrame = index * ResponseFrameSize; | |
| 176 unsigned stopFrame = startFrame + ResponseFrameSize; | |
| 177 OwnPtr<AudioBus> preSampleRateConvertedResponse = AudioBus::createBufferFrom
Range(bus, startFrame, stopFrame); | |
| 178 OwnPtr<AudioBus> response = AudioBus::createBySampleRateConverting(preSample
RateConvertedResponse.get(), false, sampleRate); | |
| 179 AudioChannel* leftEarImpulseResponse = response->channel(AudioBus::ChannelLe
ft); | |
| 180 AudioChannel* rightEarImpulseResponse = response->channel(AudioBus::ChannelR
ight); | |
| 181 #else | |
| 182 String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectNa
me.utf8().data(), azimuth, positiveElevation); | 114 String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectNa
me.utf8().data(), azimuth, positiveElevation); |
| 183 | 115 |
| 184 OwnPtr<AudioBus> impulseResponse(AudioBus::loadPlatformResource(resourceName
.utf8().data(), sampleRate)); | 116 OwnPtr<AudioBus> impulseResponse(AudioBus::loadPlatformResource(resourceName
.utf8().data(), sampleRate)); |
| 185 | 117 |
| 186 ASSERT(impulseResponse.get()); | 118 ASSERT(impulseResponse.get()); |
| 187 if (!impulseResponse.get()) | 119 if (!impulseResponse.get()) |
| 188 return false; | 120 return false; |
| 189 | 121 |
| 190 size_t responseLength = impulseResponse->length(); | 122 size_t responseLength = impulseResponse->length(); |
| 191 size_t expectedLength = static_cast<size_t>(256 * (sampleRate / 44100.0)); | 123 size_t expectedLength = static_cast<size_t>(256 * (sampleRate / 44100.0)); |
| 192 | 124 |
| 193 // Check number of channels and length. For now these are fixed and known. | 125 // Check number of channels and length. For now these are fixed and known. |
| 194 bool isBusGood = responseLength == expectedLength && impulseResponse->number
OfChannels() == 2; | 126 bool isBusGood = responseLength == expectedLength && impulseResponse->number
OfChannels() == 2; |
| 195 ASSERT(isBusGood); | 127 ASSERT(isBusGood); |
| 196 if (!isBusGood) | 128 if (!isBusGood) |
| 197 return false; | 129 return false; |
| 198 | 130 |
| 199 AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioB
us::ChannelLeft); | 131 AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioB
us::ChannelLeft); |
| 200 AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(Audio
Bus::ChannelRight); | 132 AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(Audio
Bus::ChannelRight); |
| 201 #endif | |
| 202 | 133 |
| 203 // Note that depending on the fftSize returned by the panner, we may be trun
cating the impulse response we just loaded in. | 134 // Note that depending on the fftSize returned by the panner, we may be trun
cating the impulse response we just loaded in. |
| 204 const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate); | 135 const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate); |
| 205 kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate); | 136 kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate); |
| 206 kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate); | 137 kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate); |
| 207 | 138 |
| 208 return true; | 139 return true; |
| 209 } | 140 } |
| 210 | 141 |
| 211 // The range of elevations for the IRCAM impulse responses varies depending on a
zimuth, but the minimum elevation appears to always be -45. | 142 // The range of elevations for the IRCAM impulse responses varies depending on a
zimuth, but the minimum elevation appears to always be -45. |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 void HRTFElevation::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | 277 void HRTFElevation::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const |
| 347 { | 278 { |
| 348 MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioShare
dData); | 279 MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioShare
dData); |
| 349 info.addMember(m_kernelListL, "kernelListL"); | 280 info.addMember(m_kernelListL, "kernelListL"); |
| 350 info.addMember(m_kernelListR, "kernelListR"); | 281 info.addMember(m_kernelListR, "kernelListR"); |
| 351 } | 282 } |
| 352 | 283 |
| 353 } // namespace WebCore | 284 } // namespace WebCore |
| 354 | 285 |
| 355 #endif // ENABLE(WEB_AUDIO) | 286 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |