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 // Lazily load a concatenated HRTF database for given subject and store it in a | |
66 // local hash table to ensure quick efficient future retrievals. | |
67 static AudioBus* getConcatenatedImpulseResponsesForSubject(const String& subject Name) | |
68 { | |
69 typedef HashMap<String, AudioBus*> AudioBusMap; | |
70 DEFINE_STATIC_LOCAL(AudioBusMap, audioBusMap, ()); | |
71 | |
72 AudioBus* bus; | |
73 AudioBusMap::iterator iterator = audioBusMap.find(subjectName); | |
74 if (iterator == audioBusMap.end()) { | |
75 OwnPtr<AudioBus> concatenatedImpulseResponses = AudioBus::loadPlatformRe source(subjectName.utf8().data(), ResponseSampleRate); | |
76 ASSERT(concatenatedImpulseResponses); | |
77 if (!concatenatedImpulseResponses) | |
78 return 0; | |
79 | |
80 bus = concatenatedImpulseResponses.leakPtr(); | |
81 audioBusMap.set(subjectName, bus); | |
82 } else | |
83 bus = iterator->value; | |
84 | |
85 size_t responseLength = bus->length(); | |
86 size_t expectedLength = static_cast<size_t>(TotalNumberOfResponses * Respons eFrameSize); | |
87 | |
88 // Check number of channels and length. For now these are fixed and known. | |
89 bool isBusGood = responseLength == expectedLength && bus->numberOfChannels() == 2; | |
90 ASSERT(isBusGood); | |
91 if (!isBusGood) | |
92 return 0; | |
93 | |
94 return bus; | |
95 } | |
96 | |
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 | 97 // 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 |
66 // where the roles of left and right ears are reversed with respect to each othe r. | 98 // where the roles of left and right ears are reversed with respect to each othe r. |
67 bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, in t elevation, float sampleRate, const String& subjectName, | 99 bool HRTFElevation::calculateSymmetricKernelsForAzimuthElevation(int azimuth, in t elevation, float sampleRate, const String& subjectName, |
68 RefPtr<HRTFKern el>& kernelL, RefPtr<HRTFKernel>& kernelR) | 100 RefPtr<HRTFKern el>& kernelL, RefPtr<HRTFKernel>& kernelR) |
69 { | 101 { |
70 RefPtr<HRTFKernel> kernelL1; | 102 RefPtr<HRTFKernel> kernelL1; |
71 RefPtr<HRTFKernel> kernelR1; | 103 RefPtr<HRTFKernel> kernelR1; |
72 bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampl eRate, subjectName, kernelL1, kernelR1); | 104 bool success = calculateKernelsForAzimuthElevation(azimuth, elevation, sampl eRate, subjectName, kernelL1, kernelR1); |
73 if (!success) | 105 if (!success) |
74 return false; | 106 return false; |
(...skipping 23 matching lines...) Expand all Loading... | |
98 bool isAzimuthGood = azimuth >= 0 && azimuth <= 345 && (azimuth / 15) * 15 = = azimuth; | 130 bool isAzimuthGood = azimuth >= 0 && azimuth <= 345 && (azimuth / 15) * 15 = = azimuth; |
99 ASSERT(isAzimuthGood); | 131 ASSERT(isAzimuthGood); |
100 if (!isAzimuthGood) | 132 if (!isAzimuthGood) |
101 return false; | 133 return false; |
102 | 134 |
103 bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 1 5) * 15 == elevation; | 135 bool isElevationGood = elevation >= -45 && elevation <= 90 && (elevation / 1 5) * 15 == elevation; |
104 ASSERT(isElevationGood); | 136 ASSERT(isElevationGood); |
105 if (!isElevationGood) | 137 if (!isElevationGood) |
106 return false; | 138 return false; |
107 | 139 |
108 // Construct the resource name from the subject name, azimuth, and elevation , for example: | 140 int positiveElevation = elevation < 0 ? elevation + 360 : elevation; |
109 // "IRC_Composite_C_R0195_T015_P000" | 141 |
110 // Note: the passed in subjectName is not a string passed in via JavaScript or the web. | 142 // Note: the passed in subjectName is not a string passed in via JavaScript or the web. |
111 // It's passed in as an internal ASCII identifier and is an implementation d etail. | 143 // It's passed in as an internal ASCII identifier and is an implementation d etail. |
Chris Rogers
2013/04/23 19:51:44
This comment used to be just before line 140 and y
| |
112 int positiveElevation = elevation < 0 ? elevation + 360 : elevation; | 144 AudioBus* bus(getConcatenatedImpulseResponsesForSubject(subjectName)); |
113 | 145 |
114 String resourceName = String::format("IRC_%s_C_R0195_T%03d_P%03d", subjectNa me.utf8().data(), azimuth, positiveElevation); | 146 if (!bus) |
147 return false; | |
115 | 148 |
116 OwnPtr<AudioBus> impulseResponse(AudioBus::loadPlatformResource(resourceName .utf8().data(), sampleRate)); | 149 int elevationIndex = positiveElevation / AzimuthSpacing; |
150 if (positiveElevation > 90) | |
151 elevationIndex -= AzimuthSpacing; | |
117 | 152 |
118 ASSERT(impulseResponse.get()); | 153 // The concatenated impulse response is a bus containing all |
119 if (!impulseResponse.get()) | 154 // the elevations per azimuth, for all azimuths by increasing |
155 // order. So for a given azimuth and elevation we need to compute | |
156 // the index of the wanted audio frames in the concatenated table. | |
157 unsigned index = ((azimuth / AzimuthSpacing) * HRTFDatabase::NumberOfRawElev ations) + elevationIndex; | |
158 bool isIndexGood = index < TotalNumberOfResponses; | |
159 ASSERT(isIndexGood); | |
160 if (!isIndexGood) | |
120 return false; | 161 return false; |
121 | |
122 size_t responseLength = impulseResponse->length(); | |
123 size_t expectedLength = static_cast<size_t>(256 * (sampleRate / 44100.0)); | |
124 | 162 |
125 // Check number of channels and length. For now these are fixed and known. | 163 // Extract the individual impulse response from the concatenated |
126 bool isBusGood = responseLength == expectedLength && impulseResponse->number OfChannels() == 2; | 164 // responses and potentially sample-rate convert it to the desired |
127 ASSERT(isBusGood); | 165 // (hardware) sample-rate. |
128 if (!isBusGood) | 166 unsigned startFrame = index * ResponseFrameSize; |
129 return false; | 167 unsigned stopFrame = startFrame + ResponseFrameSize; |
130 | 168 OwnPtr<AudioBus> preSampleRateConvertedResponse = AudioBus::createBufferFrom Range(bus, startFrame, stopFrame); |
131 AudioChannel* leftEarImpulseResponse = impulseResponse->channelByType(AudioB us::ChannelLeft); | 169 OwnPtr<AudioBus> response = AudioBus::createBySampleRateConverting(preSample RateConvertedResponse.get(), false, sampleRate); |
132 AudioChannel* rightEarImpulseResponse = impulseResponse->channelByType(Audio Bus::ChannelRight); | 170 AudioChannel* leftEarImpulseResponse = response->channel(AudioBus::ChannelLe ft); |
171 AudioChannel* rightEarImpulseResponse = response->channel(AudioBus::ChannelR ight); | |
133 | 172 |
134 // Note that depending on the fftSize returned by the panner, we may be trun cating the impulse response we just loaded in. | 173 // Note that depending on the fftSize returned by the panner, we may be trun cating the impulse response we just loaded in. |
135 const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate); | 174 const size_t fftSize = HRTFPanner::fftSizeForSampleRate(sampleRate); |
136 kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate); | 175 kernelL = HRTFKernel::create(leftEarImpulseResponse, fftSize, sampleRate); |
137 kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate); | 176 kernelR = HRTFKernel::create(rightEarImpulseResponse, fftSize, sampleRate); |
138 | 177 |
139 return true; | 178 return true; |
140 } | 179 } |
141 | 180 |
142 // The range of elevations for the IRCAM impulse responses varies depending on a zimuth, but the minimum elevation appears to always be -45. | 181 // 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... | |
277 void HRTFElevation::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | 316 void HRTFElevation::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const |
278 { | 317 { |
279 MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioShare dData); | 318 MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioShare dData); |
280 info.addMember(m_kernelListL, "kernelListL"); | 319 info.addMember(m_kernelListL, "kernelListL"); |
281 info.addMember(m_kernelListR, "kernelListR"); | 320 info.addMember(m_kernelListR, "kernelListR"); |
282 } | 321 } |
283 | 322 |
284 } // namespace WebCore | 323 } // namespace WebCore |
285 | 324 |
286 #endif // ENABLE(WEB_AUDIO) | 325 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |