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 24 matching lines...) Expand all Loading... |
35 #include <memory> | 35 #include <memory> |
36 | 36 |
37 #if OS(MACOSX) | 37 #if OS(MACOSX) |
38 using namespace std; | 38 using namespace std; |
39 #endif | 39 #endif |
40 | 40 |
41 namespace blink { | 41 namespace blink { |
42 | 42 |
43 using namespace VectorMath; | 43 using namespace VectorMath; |
44 | 44 |
45 // Empirical gain calibration tested across many impulse responses to ensure per
ceived volume is same as dry (unprocessed) signal | 45 // Empirical gain calibration tested across many impulse responses to ensure |
| 46 // perceived volume is same as dry (unprocessed) signal |
46 const float GainCalibration = -58; | 47 const float GainCalibration = -58; |
47 const float GainCalibrationSampleRate = 44100; | 48 const float GainCalibrationSampleRate = 44100; |
48 | 49 |
49 // A minimum power value to when normalizing a silent (or very quiet) impulse re
sponse | 50 // A minimum power value to when normalizing a silent (or very quiet) impulse |
| 51 // response |
50 const float MinPower = 0.000125f; | 52 const float MinPower = 0.000125f; |
51 | 53 |
52 static float calculateNormalizationScale(AudioBus* response) { | 54 static float calculateNormalizationScale(AudioBus* response) { |
53 // Normalize by RMS power | 55 // Normalize by RMS power |
54 size_t numberOfChannels = response->numberOfChannels(); | 56 size_t numberOfChannels = response->numberOfChannels(); |
55 size_t length = response->length(); | 57 size_t length = response->length(); |
56 | 58 |
57 float power = 0; | 59 float power = 0; |
58 | 60 |
59 for (size_t i = 0; i < numberOfChannels; ++i) { | 61 for (size_t i = 0; i < numberOfChannels; ++i) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 if (normalize) { | 98 if (normalize) { |
97 scale = calculateNormalizationScale(impulseResponse); | 99 scale = calculateNormalizationScale(impulseResponse); |
98 | 100 |
99 if (scale) | 101 if (scale) |
100 impulseResponse->scale(scale); | 102 impulseResponse->scale(scale); |
101 } | 103 } |
102 | 104 |
103 initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, | 105 initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, |
104 useBackgroundThreads); | 106 useBackgroundThreads); |
105 | 107 |
106 // Undo scaling since this shouldn't be a destructive operation on impulseResp
onse. | 108 // Undo scaling since this shouldn't be a destructive operation on |
| 109 // impulseResponse. |
107 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy | 110 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy |
108 // instead of scaling and unscaling in place. | 111 // instead of scaling and unscaling in place. |
109 if (normalize && scale) | 112 if (normalize && scale) |
110 impulseResponse->scale(1 / scale); | 113 impulseResponse->scale(1 / scale); |
111 } | 114 } |
112 | 115 |
113 void Reverb::initialize(AudioBus* impulseResponseBuffer, | 116 void Reverb::initialize(AudioBus* impulseResponseBuffer, |
114 size_t renderSliceSize, | 117 size_t renderSliceSize, |
115 size_t maxFFTSize, | 118 size_t maxFFTSize, |
116 size_t numberOfChannels, | 119 size_t numberOfChannels, |
117 bool useBackgroundThreads) { | 120 bool useBackgroundThreads) { |
118 m_impulseResponseLength = impulseResponseBuffer->length(); | 121 m_impulseResponseLength = impulseResponseBuffer->length(); |
119 | 122 |
120 // The reverb can handle a mono impulse response and still do stereo processin
g | 123 // The reverb can handle a mono impulse response and still do stereo |
| 124 // processing |
121 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); | 125 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); |
122 m_convolvers.reserveCapacity(numberOfChannels); | 126 m_convolvers.reserveCapacity(numberOfChannels); |
123 | 127 |
124 int convolverRenderPhase = 0; | 128 int convolverRenderPhase = 0; |
125 for (size_t i = 0; i < numResponseChannels; ++i) { | 129 for (size_t i = 0; i < numResponseChannels; ++i) { |
126 AudioChannel* channel = impulseResponseBuffer->channel(i); | 130 AudioChannel* channel = impulseResponseBuffer->channel(i); |
127 | 131 |
128 std::unique_ptr<ReverbConvolver> convolver = wrapUnique( | 132 std::unique_ptr<ReverbConvolver> convolver = wrapUnique( |
129 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, | 133 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, |
130 convolverRenderPhase, useBackgroundThreads)); | 134 convolverRenderPhase, useBackgroundThreads)); |
131 m_convolvers.append(std::move(convolver)); | 135 m_convolvers.append(std::move(convolver)); |
132 | 136 |
133 convolverRenderPhase += renderSliceSize; | 137 convolverRenderPhase += renderSliceSize; |
134 } | 138 } |
135 | 139 |
136 // For "True" stereo processing we allocate a temporary buffer to avoid repeat
edly allocating it in the process() method. | 140 // For "True" stereo processing we allocate a temporary buffer to avoid |
137 // It can be bad to allocate memory in a real-time thread. | 141 // repeatedly allocating it in the process() method. It can be bad to |
| 142 // allocate memory in a real-time thread. |
138 if (numResponseChannels == 4) | 143 if (numResponseChannels == 4) |
139 m_tempBuffer = AudioBus::create(2, MaxFrameSize); | 144 m_tempBuffer = AudioBus::create(2, MaxFrameSize); |
140 } | 145 } |
141 | 146 |
142 void Reverb::process(const AudioBus* sourceBus, | 147 void Reverb::process(const AudioBus* sourceBus, |
143 AudioBus* destinationBus, | 148 AudioBus* destinationBus, |
144 size_t framesToProcess) { | 149 size_t framesToProcess) { |
145 // Do a fairly comprehensive sanity check. | 150 // Do a fairly comprehensive sanity check. |
146 // If these conditions are satisfied, all of the source and destination pointe
rs will be valid for the various matrixing cases. | 151 // If these conditions are satisfied, all of the source and destination |
| 152 // pointers will be valid for the various matrixing cases. |
147 bool isSafeToProcess = sourceBus && destinationBus && | 153 bool isSafeToProcess = sourceBus && destinationBus && |
148 sourceBus->numberOfChannels() > 0 && | 154 sourceBus->numberOfChannels() > 0 && |
149 destinationBus->numberOfChannels() > 0 && | 155 destinationBus->numberOfChannels() > 0 && |
150 framesToProcess <= MaxFrameSize && | 156 framesToProcess <= MaxFrameSize && |
151 framesToProcess <= sourceBus->length() && | 157 framesToProcess <= sourceBus->length() && |
152 framesToProcess <= destinationBus->length(); | 158 framesToProcess <= destinationBus->length(); |
153 | 159 |
154 ASSERT(isSafeToProcess); | 160 ASSERT(isSafeToProcess); |
155 if (!isSafeToProcess) | 161 if (!isSafeToProcess) |
156 return; | 162 return; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 framesToProcess); | 230 framesToProcess); |
225 | 231 |
226 // Process right virtual source | 232 // Process right virtual source |
227 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); | 233 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); |
228 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); | 234 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); |
229 | 235 |
230 destinationBus->sumFrom(*m_tempBuffer); | 236 destinationBus->sumFrom(*m_tempBuffer); |
231 } else if (numInputChannels == 1 && numReverbChannels == 4 && | 237 } else if (numInputChannels == 1 && numReverbChannels == 4 && |
232 numOutputChannels == 2) { | 238 numOutputChannels == 2) { |
233 // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) | 239 // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) |
234 // This is an inefficient use of a four-channel impulse response, but we sho
uld handle the case. | 240 // This is an inefficient use of a four-channel impulse response, but we |
| 241 // should handle the case. |
235 AudioChannel* destinationChannelR = destinationBus->channel(1); | 242 AudioChannel* destinationChannelR = destinationBus->channel(1); |
236 | 243 |
237 AudioChannel* tempChannelL = m_tempBuffer->channel(0); | 244 AudioChannel* tempChannelL = m_tempBuffer->channel(0); |
238 AudioChannel* tempChannelR = m_tempBuffer->channel(1); | 245 AudioChannel* tempChannelR = m_tempBuffer->channel(1); |
239 | 246 |
240 // Process left virtual source | 247 // Process left virtual source |
241 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 248 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
242 framesToProcess); | 249 framesToProcess); |
243 m_convolvers[1]->process(sourceChannelL, destinationChannelR, | 250 m_convolvers[1]->process(sourceChannelL, destinationChannelR, |
244 framesToProcess); | 251 framesToProcess); |
(...skipping 13 matching lines...) Expand all Loading... |
258 void Reverb::reset() { | 265 void Reverb::reset() { |
259 for (size_t i = 0; i < m_convolvers.size(); ++i) | 266 for (size_t i = 0; i < m_convolvers.size(); ++i) |
260 m_convolvers[i]->reset(); | 267 m_convolvers[i]->reset(); |
261 } | 268 } |
262 | 269 |
263 size_t Reverb::latencyFrames() const { | 270 size_t Reverb::latencyFrames() const { |
264 return !m_convolvers.isEmpty() ? m_convolvers.first()->latencyFrames() : 0; | 271 return !m_convolvers.isEmpty() ? m_convolvers.first()->latencyFrames() : 0; |
265 } | 272 } |
266 | 273 |
267 } // namespace blink | 274 } // namespace blink |
OLD | NEW |