Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: third_party/WebKit/Source/platform/audio/Reverb.cpp

Issue 2732523003: Make ConvolverNode conform to spec (Closed)
Patch Set: Remove unneeded numberOfChannels parameter and simplify code Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/audio/Reverb.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/audio/Reverb.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698