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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 // True-stereo compensation | 83 // True-stereo compensation |
84 if (response->numberOfChannels() == 4) | 84 if (response->numberOfChannels() == 4) |
85 scale *= 0.5f; | 85 scale *= 0.5f; |
86 | 86 |
87 return scale; | 87 return scale; |
88 } | 88 } |
89 | 89 |
90 Reverb::Reverb(AudioBus* impulseResponse, | 90 Reverb::Reverb(AudioBus* impulseResponse, |
91 size_t renderSliceSize, | 91 size_t renderSliceSize, |
92 size_t maxFFTSize, | 92 size_t maxFFTSize, |
93 size_t numberOfChannels, | |
94 bool useBackgroundThreads, | 93 bool useBackgroundThreads, |
95 bool normalize) { | 94 bool normalize) { |
96 float scale = 1; | 95 float scale = 1; |
97 | 96 |
98 if (normalize) { | 97 if (normalize) { |
99 scale = calculateNormalizationScale(impulseResponse); | 98 scale = calculateNormalizationScale(impulseResponse); |
100 | 99 |
101 if (scale) | 100 if (scale) |
102 impulseResponse->scale(scale); | 101 impulseResponse->scale(scale); |
103 } | 102 } |
104 | 103 |
105 initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, | 104 initialize(impulseResponse, renderSliceSize, maxFFTSize, |
106 useBackgroundThreads); | 105 useBackgroundThreads); |
107 | 106 |
108 // Undo scaling since this shouldn't be a destructive operation on | 107 // Undo scaling since this shouldn't be a destructive operation on |
109 // impulseResponse. | 108 // impulseResponse. |
110 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy | 109 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy |
111 // instead of scaling and unscaling in place. | 110 // instead of scaling and unscaling in place. |
112 if (normalize && scale) | 111 if (normalize && scale) |
113 impulseResponse->scale(1 / scale); | 112 impulseResponse->scale(1 / scale); |
114 } | 113 } |
115 | 114 |
116 void Reverb::initialize(AudioBus* impulseResponseBuffer, | 115 void Reverb::initialize(AudioBus* impulseResponseBuffer, |
117 size_t renderSliceSize, | 116 size_t renderSliceSize, |
118 size_t maxFFTSize, | 117 size_t maxFFTSize, |
119 size_t numberOfChannels, | |
120 bool useBackgroundThreads) { | 118 bool useBackgroundThreads) { |
121 m_impulseResponseLength = impulseResponseBuffer->length(); | 119 m_impulseResponseLength = impulseResponseBuffer->length(); |
| 120 m_numberOfResponseChannels = impulseResponseBuffer->numberOfChannels(); |
122 | 121 |
123 // The reverb can handle a mono impulse response and still do stereo | 122 // The reverb can handle a mono impulse response and still do stereo |
124 // processing | 123 // processing. |
125 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); | 124 unsigned numConvolvers = std::max(m_numberOfResponseChannels, 2u); |
126 m_convolvers.reserveCapacity(numberOfChannels); | 125 m_convolvers.reserveCapacity(numConvolvers); |
127 | 126 |
128 int convolverRenderPhase = 0; | 127 int convolverRenderPhase = 0; |
129 for (size_t i = 0; i < numResponseChannels; ++i) { | 128 for (unsigned i = 0; i < numConvolvers; ++i) { |
130 AudioChannel* channel = impulseResponseBuffer->channel(i); | 129 AudioChannel* channel = impulseResponseBuffer->channel( |
| 130 std::min(i, m_numberOfResponseChannels - 1)); |
131 | 131 |
132 std::unique_ptr<ReverbConvolver> convolver = WTF::wrapUnique( | 132 std::unique_ptr<ReverbConvolver> convolver = WTF::wrapUnique( |
133 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, | 133 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, |
134 convolverRenderPhase, useBackgroundThreads)); | 134 convolverRenderPhase, useBackgroundThreads)); |
135 m_convolvers.push_back(std::move(convolver)); | 135 m_convolvers.push_back(std::move(convolver)); |
136 | 136 |
137 convolverRenderPhase += renderSliceSize; | 137 convolverRenderPhase += renderSliceSize; |
138 } | 138 } |
139 | 139 |
140 // For "True" stereo processing we allocate a temporary buffer to avoid | 140 // For "True" stereo processing we allocate a temporary buffer to avoid |
141 // repeatedly allocating it in the process() method. It can be bad to | 141 // repeatedly allocating it in the process() method. It can be bad to |
142 // allocate memory in a real-time thread. | 142 // allocate memory in a real-time thread. |
143 if (numResponseChannels == 4) | 143 if (m_numberOfResponseChannels == 4) |
144 m_tempBuffer = AudioBus::create(2, MaxFrameSize); | 144 m_tempBuffer = AudioBus::create(2, MaxFrameSize); |
145 } | 145 } |
146 | 146 |
147 void Reverb::process(const AudioBus* sourceBus, | 147 void Reverb::process(const AudioBus* sourceBus, |
148 AudioBus* destinationBus, | 148 AudioBus* destinationBus, |
149 size_t framesToProcess) { | 149 size_t framesToProcess) { |
150 // Do a fairly comprehensive sanity check. | 150 // Do a fairly comprehensive sanity check. |
151 // If these conditions are satisfied, all of the source and destination | 151 // If these conditions are satisfied, all of the source and destination |
152 // pointers will be valid for the various matrixing cases. | 152 // pointers will be valid for the various matrixing cases. |
153 bool isSafeToProcess = sourceBus && destinationBus && | 153 bool isSafeToProcess = sourceBus && destinationBus && |
(...skipping 12 matching lines...) Expand all Loading... |
166 destinationBus->zero(); | 166 destinationBus->zero(); |
167 return; | 167 return; |
168 } | 168 } |
169 | 169 |
170 AudioChannel* destinationChannelL = destinationBus->channel(0); | 170 AudioChannel* destinationChannelL = destinationBus->channel(0); |
171 const AudioChannel* sourceChannelL = sourceBus->channel(0); | 171 const AudioChannel* sourceChannelL = sourceBus->channel(0); |
172 | 172 |
173 // Handle input -> output matrixing... | 173 // Handle input -> output matrixing... |
174 size_t numInputChannels = sourceBus->numberOfChannels(); | 174 size_t numInputChannels = sourceBus->numberOfChannels(); |
175 size_t numOutputChannels = destinationBus->numberOfChannels(); | 175 size_t numOutputChannels = destinationBus->numberOfChannels(); |
176 size_t numReverbChannels = m_convolvers.size(); | 176 size_t numberOfResponseChannels = m_numberOfResponseChannels; |
177 | 177 |
178 if (numInputChannels == 2 && numReverbChannels == 2 && | 178 DCHECK_LE(numInputChannels, 2ul); |
| 179 DCHECK_LE(numOutputChannels, 2ul); |
| 180 DCHECK(numberOfResponseChannels == 1 || numberOfResponseChannels == 2 || |
| 181 numberOfResponseChannels == 4); |
| 182 |
| 183 // These are the possible combinations of number inputs, response |
| 184 // channels and outputs channels that need to be supported: |
| 185 // |
| 186 // numInputChannels: 1 or 2 |
| 187 // numberOfResponseChannels: 1, 2, or 4 |
| 188 // numOutputChannels: 1 or 2 |
| 189 // |
| 190 // Not all possible combinations are valid. numOutputChannels is |
| 191 // one only if both numInputChannels and numberOfResponseChannels are 1. |
| 192 // Otherwise numOutputChannels MUST be 2. |
| 193 // |
| 194 // The valid combinations are |
| 195 // |
| 196 // Case in -> resp -> out |
| 197 // 1 1 -> 1 -> 1 |
| 198 // 2 1 -> 2 -> 2 |
| 199 // 3 1 -> 4 -> 2 |
| 200 // 4 2 -> 1 -> 2 |
| 201 // 5 2 -> 2 -> 2 |
| 202 // 6 2 -> 4 -> 2 |
| 203 |
| 204 if (numInputChannels == 2 && |
| 205 (numberOfResponseChannels == 1 || numberOfResponseChannels == 2) && |
179 numOutputChannels == 2) { | 206 numOutputChannels == 2) { |
180 // 2 -> 2 -> 2 | 207 // Case 4 and 5: 2 -> 2 -> 2 or 2 -> 1 -> 2. |
| 208 // |
| 209 // These can be handled in the same way because in the latter |
| 210 // case, two connvolvers are still created with the second being a |
| 211 // copy of the first. |
181 const AudioChannel* sourceChannelR = sourceBus->channel(1); | 212 const AudioChannel* sourceChannelR = sourceBus->channel(1); |
182 AudioChannel* destinationChannelR = destinationBus->channel(1); | 213 AudioChannel* destinationChannelR = destinationBus->channel(1); |
183 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 214 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
184 framesToProcess); | 215 framesToProcess); |
185 m_convolvers[1]->process(sourceChannelR, destinationChannelR, | 216 m_convolvers[1]->process(sourceChannelR, destinationChannelR, |
186 framesToProcess); | 217 framesToProcess); |
187 } else if (numInputChannels == 1 && numOutputChannels == 2 && | 218 } else if (numInputChannels == 1 && numOutputChannels == 2 && |
188 numReverbChannels == 2) { | 219 numberOfResponseChannels == 2) { |
189 // 1 -> 2 -> 2 | 220 // Case 2: 1 -> 2 -> 2 |
190 for (int i = 0; i < 2; ++i) { | 221 for (int i = 0; i < 2; ++i) { |
191 AudioChannel* destinationChannel = destinationBus->channel(i); | 222 AudioChannel* destinationChannel = destinationBus->channel(i); |
192 m_convolvers[i]->process(sourceChannelL, destinationChannel, | 223 m_convolvers[i]->process(sourceChannelL, destinationChannel, |
193 framesToProcess); | 224 framesToProcess); |
194 } | 225 } |
195 } else if (numInputChannels == 1 && numReverbChannels == 1 && | 226 } else if (numInputChannels == 1 && numberOfResponseChannels == 1) { |
196 numOutputChannels == 2) { | 227 // Case 1: 1 -> 1 -> 1 |
197 // 1 -> 1 -> 2 | 228 DCHECK_EQ(numOutputChannels, 1ul); |
198 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 229 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
199 framesToProcess); | 230 framesToProcess); |
200 | 231 } else if (numInputChannels == 2 && numberOfResponseChannels == 4 && |
201 // simply copy L -> R | |
202 AudioChannel* destinationChannelR = destinationBus->channel(1); | |
203 bool isCopySafe = destinationChannelL->data() && | |
204 destinationChannelR->data() && | |
205 destinationChannelL->length() >= framesToProcess && | |
206 destinationChannelR->length() >= framesToProcess; | |
207 ASSERT(isCopySafe); | |
208 if (!isCopySafe) | |
209 return; | |
210 memcpy(destinationChannelR->mutableData(), destinationChannelL->data(), | |
211 sizeof(float) * framesToProcess); | |
212 } else if (numInputChannels == 1 && numReverbChannels == 1 && | |
213 numOutputChannels == 1) { | |
214 // 1 -> 1 -> 1 | |
215 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | |
216 framesToProcess); | |
217 } else if (numInputChannels == 2 && numReverbChannels == 4 && | |
218 numOutputChannels == 2) { | 232 numOutputChannels == 2) { |
219 // 2 -> 4 -> 2 ("True" stereo) | 233 // Case 6: 2 -> 4 -> 2 ("True" stereo) |
220 const AudioChannel* sourceChannelR = sourceBus->channel(1); | 234 const AudioChannel* sourceChannelR = sourceBus->channel(1); |
221 AudioChannel* destinationChannelR = destinationBus->channel(1); | 235 AudioChannel* destinationChannelR = destinationBus->channel(1); |
222 | 236 |
223 AudioChannel* tempChannelL = m_tempBuffer->channel(0); | 237 AudioChannel* tempChannelL = m_tempBuffer->channel(0); |
224 AudioChannel* tempChannelR = m_tempBuffer->channel(1); | 238 AudioChannel* tempChannelR = m_tempBuffer->channel(1); |
225 | 239 |
226 // Process left virtual source | 240 // Process left virtual source |
227 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 241 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
228 framesToProcess); | 242 framesToProcess); |
229 m_convolvers[1]->process(sourceChannelL, destinationChannelR, | 243 m_convolvers[1]->process(sourceChannelL, destinationChannelR, |
230 framesToProcess); | 244 framesToProcess); |
231 | 245 |
232 // Process right virtual source | 246 // Process right virtual source |
233 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); | 247 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); |
234 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); | 248 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); |
235 | 249 |
236 destinationBus->sumFrom(*m_tempBuffer); | 250 destinationBus->sumFrom(*m_tempBuffer); |
237 } else if (numInputChannels == 1 && numReverbChannels == 4 && | 251 } else if (numInputChannels == 1 && numberOfResponseChannels == 4 && |
238 numOutputChannels == 2) { | 252 numOutputChannels == 2) { |
239 // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) | 253 // Case 3: 1 -> 4 -> 2 (Processing mono with "True" stereo impulse |
240 // This is an inefficient use of a four-channel impulse response, but we | 254 // response) This is an inefficient use of a four-channel impulse |
241 // should handle the case. | 255 // response, but we should handle the case. |
242 AudioChannel* destinationChannelR = destinationBus->channel(1); | 256 AudioChannel* destinationChannelR = destinationBus->channel(1); |
243 | 257 |
244 AudioChannel* tempChannelL = m_tempBuffer->channel(0); | 258 AudioChannel* tempChannelL = m_tempBuffer->channel(0); |
245 AudioChannel* tempChannelR = m_tempBuffer->channel(1); | 259 AudioChannel* tempChannelR = m_tempBuffer->channel(1); |
246 | 260 |
247 // Process left virtual source | 261 // Process left virtual source |
248 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 262 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
249 framesToProcess); | 263 framesToProcess); |
250 m_convolvers[1]->process(sourceChannelL, destinationChannelR, | 264 m_convolvers[1]->process(sourceChannelL, destinationChannelR, |
251 framesToProcess); | 265 framesToProcess); |
252 | 266 |
253 // Process right virtual source | 267 // Process right virtual source |
254 m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess); | 268 m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess); |
255 m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess); | 269 m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess); |
256 | 270 |
257 destinationBus->sumFrom(*m_tempBuffer); | 271 destinationBus->sumFrom(*m_tempBuffer); |
258 } else { | 272 } else { |
259 // Handle gracefully any unexpected / unsupported matrixing | 273 NOTREACHED(); |
260 // FIXME: add code for 5.1 support... | |
261 destinationBus->zero(); | 274 destinationBus->zero(); |
262 } | 275 } |
263 } | 276 } |
264 | 277 |
265 void Reverb::reset() { | 278 void Reverb::reset() { |
266 for (size_t i = 0; i < m_convolvers.size(); ++i) | 279 for (size_t i = 0; i < m_convolvers.size(); ++i) |
267 m_convolvers[i]->reset(); | 280 m_convolvers[i]->reset(); |
268 } | 281 } |
269 | 282 |
270 size_t Reverb::latencyFrames() const { | 283 size_t Reverb::latencyFrames() const { |
271 return !m_convolvers.isEmpty() ? m_convolvers.front()->latencyFrames() : 0; | 284 return !m_convolvers.isEmpty() ? m_convolvers.front()->latencyFrames() : 0; |
272 } | 285 } |
273 | 286 |
274 } // namespace blink | 287 } // namespace blink |
OLD | NEW |