Chromium Code Reviews| 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 if (normalize && scale) | 112 if (normalize && scale) |
| 113 impulseResponse->scale(1 / scale); | 113 impulseResponse->scale(1 / scale); |
| 114 } | 114 } |
| 115 | 115 |
| 116 void Reverb::initialize(AudioBus* impulseResponseBuffer, | 116 void Reverb::initialize(AudioBus* impulseResponseBuffer, |
| 117 size_t renderSliceSize, | 117 size_t renderSliceSize, |
| 118 size_t maxFFTSize, | 118 size_t maxFFTSize, |
| 119 size_t numberOfChannels, | 119 size_t numberOfChannels, |
| 120 bool useBackgroundThreads) { | 120 bool useBackgroundThreads) { |
| 121 m_impulseResponseLength = impulseResponseBuffer->length(); | 121 m_impulseResponseLength = impulseResponseBuffer->length(); |
| 122 m_numberOfChannels = numberOfChannels; | |
| 122 | 123 |
| 123 // The reverb can handle a mono impulse response and still do stereo | 124 // The reverb can handle a mono impulse response and still do stereo |
| 124 // processing | 125 // processing |
|
hongchan
2017/03/28 16:44:35
nit: a missing period.
| |
| 125 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); | 126 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); |
|
hongchan
2017/03/28 16:44:35
This can be unsigned.
Raymond Toy
2017/03/28 18:26:50
This requires changing various other bits of code
| |
| 126 m_convolvers.reserveCapacity(numberOfChannels); | 127 size_t numConvolvers = std::max(numResponseChannels, static_cast<size_t>(2)); |
| 128 m_convolvers.reserveCapacity(numConvolvers); | |
|
hongchan
2017/03/28 16:44:35
Is |numConvolvers| properly named? Isn't it more o
Raymond Toy
2017/03/28 18:17:20
numberOfConvolverChannels is confusing too since t
| |
| 127 | 129 |
| 128 int convolverRenderPhase = 0; | 130 int convolverRenderPhase = 0; |
| 129 for (size_t i = 0; i < numResponseChannels; ++i) { | 131 for (size_t i = 0; i < numConvolvers; ++i) { |
| 130 AudioChannel* channel = impulseResponseBuffer->channel(i); | 132 AudioChannel* channel = |
| 133 impulseResponseBuffer->channel(std::min(i, numResponseChannels - 1)); | |
| 131 | 134 |
| 132 std::unique_ptr<ReverbConvolver> convolver = WTF::wrapUnique( | 135 std::unique_ptr<ReverbConvolver> convolver = WTF::wrapUnique( |
| 133 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, | 136 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, |
| 134 convolverRenderPhase, useBackgroundThreads)); | 137 convolverRenderPhase, useBackgroundThreads)); |
| 135 m_convolvers.push_back(std::move(convolver)); | 138 m_convolvers.push_back(std::move(convolver)); |
| 136 | 139 |
| 137 convolverRenderPhase += renderSliceSize; | 140 convolverRenderPhase += renderSliceSize; |
| 138 } | 141 } |
| 139 | 142 |
| 140 // For "True" stereo processing we allocate a temporary buffer to avoid | 143 // For "True" stereo processing we allocate a temporary buffer to avoid |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 166 destinationBus->zero(); | 169 destinationBus->zero(); |
| 167 return; | 170 return; |
| 168 } | 171 } |
| 169 | 172 |
| 170 AudioChannel* destinationChannelL = destinationBus->channel(0); | 173 AudioChannel* destinationChannelL = destinationBus->channel(0); |
| 171 const AudioChannel* sourceChannelL = sourceBus->channel(0); | 174 const AudioChannel* sourceChannelL = sourceBus->channel(0); |
| 172 | 175 |
| 173 // Handle input -> output matrixing... | 176 // Handle input -> output matrixing... |
| 174 size_t numInputChannels = sourceBus->numberOfChannels(); | 177 size_t numInputChannels = sourceBus->numberOfChannels(); |
| 175 size_t numOutputChannels = destinationBus->numberOfChannels(); | 178 size_t numOutputChannels = destinationBus->numberOfChannels(); |
| 176 size_t numReverbChannels = m_convolvers.size(); | 179 size_t numReverbChannels = m_numberOfChannels; |
|
hongchan
2017/03/28 16:44:35
I can't make a clear distinction between numReverb
Raymond Toy
2017/03/28 18:17:20
numReverbChannels is the number of channels in the
hongchan
2017/03/28 19:01:44
Yeah, this name seems to be problematic.
| |
| 177 | 180 |
| 178 if (numInputChannels == 2 && numReverbChannels == 2 && | 181 DCHECK_LE(numInputChannels, 2ul); |
| 182 DCHECK_LE(numOutputChannels, 2ul); | |
| 183 DCHECK(numReverbChannels == 1 || numReverbChannels == 2 || | |
| 184 numReverbChannels == 4); | |
| 185 | |
| 186 // These are the possible combinations of number inputs, response | |
| 187 // channels and outputs channels that need to be supported: | |
| 188 // | |
| 189 // numInputChannels: 1 or 2 | |
| 190 // numReverbChannels: 1, 2, or 4 | |
| 191 // numOutputChannels: 1 or 2 | |
| 192 // | |
| 193 // Not all possible combinations are valid. numOutputChannels is | |
| 194 // one only if both numInputChannels and numReverbChannels are 1. | |
| 195 // Otherwise numOutputChannels MUST be 2. | |
| 196 // | |
| 197 // The valid combinations are | |
| 198 // | |
| 199 // Case in -> resp -> out | |
| 200 // 1 1 -> 1 -> 1 | |
| 201 // 2 1 -> 2 -> 2 | |
| 202 // 3 1 -> 4 -> 2 | |
| 203 // 4 2 -> 1 -> 2 | |
| 204 // 5 2 -> 2 -> 2 | |
| 205 // 6 2 -> 4 -> 2 | |
| 206 | |
| 207 if (numInputChannels == 2 && | |
| 208 (numReverbChannels == 1 || numReverbChannels == 2) && | |
| 179 numOutputChannels == 2) { | 209 numOutputChannels == 2) { |
| 180 // 2 -> 2 -> 2 | 210 // Case 4 and 5: 2 -> 2 -> 2 or 2 -> 1 -> 2. |
| 211 // | |
| 212 // These can be handled in the same way because in the latter | |
| 213 // case, two connvolvers are still created with the second being a | |
| 214 // copy of the first. | |
| 181 const AudioChannel* sourceChannelR = sourceBus->channel(1); | 215 const AudioChannel* sourceChannelR = sourceBus->channel(1); |
| 182 AudioChannel* destinationChannelR = destinationBus->channel(1); | 216 AudioChannel* destinationChannelR = destinationBus->channel(1); |
| 183 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 217 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
| 184 framesToProcess); | 218 framesToProcess); |
| 185 m_convolvers[1]->process(sourceChannelR, destinationChannelR, | 219 m_convolvers[1]->process(sourceChannelR, destinationChannelR, |
| 186 framesToProcess); | 220 framesToProcess); |
| 187 } else if (numInputChannels == 1 && numOutputChannels == 2 && | 221 } else if (numInputChannels == 1 && numOutputChannels == 2 && |
| 188 numReverbChannels == 2) { | 222 numReverbChannels == 2) { |
| 189 // 1 -> 2 -> 2 | 223 // Case 2: 1 -> 2 -> 2 |
| 190 for (int i = 0; i < 2; ++i) { | 224 for (int i = 0; i < 2; ++i) { |
| 191 AudioChannel* destinationChannel = destinationBus->channel(i); | 225 AudioChannel* destinationChannel = destinationBus->channel(i); |
| 192 m_convolvers[i]->process(sourceChannelL, destinationChannel, | 226 m_convolvers[i]->process(sourceChannelL, destinationChannel, |
| 193 framesToProcess); | 227 framesToProcess); |
| 194 } | 228 } |
| 195 } else if (numInputChannels == 1 && numReverbChannels == 1 && | 229 } else if (numInputChannels == 1 && numReverbChannels == 1) { |
| 196 numOutputChannels == 2) { | 230 // Case 1: 1 -> 1 -> 1 |
| 197 // 1 -> 1 -> 2 | 231 DCHECK_EQ(numOutputChannels, 1ul); |
| 198 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | |
| 199 framesToProcess); | |
| 200 | |
| 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, | 232 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
| 216 framesToProcess); | 233 framesToProcess); |
| 217 } else if (numInputChannels == 2 && numReverbChannels == 4 && | 234 } else if (numInputChannels == 2 && numReverbChannels == 4 && |
| 218 numOutputChannels == 2) { | 235 numOutputChannels == 2) { |
| 219 // 2 -> 4 -> 2 ("True" stereo) | 236 // Case 6: 2 -> 4 -> 2 ("True" stereo) |
| 220 const AudioChannel* sourceChannelR = sourceBus->channel(1); | 237 const AudioChannel* sourceChannelR = sourceBus->channel(1); |
| 221 AudioChannel* destinationChannelR = destinationBus->channel(1); | 238 AudioChannel* destinationChannelR = destinationBus->channel(1); |
| 222 | 239 |
| 223 AudioChannel* tempChannelL = m_tempBuffer->channel(0); | 240 AudioChannel* tempChannelL = m_tempBuffer->channel(0); |
| 224 AudioChannel* tempChannelR = m_tempBuffer->channel(1); | 241 AudioChannel* tempChannelR = m_tempBuffer->channel(1); |
| 225 | 242 |
| 226 // Process left virtual source | 243 // Process left virtual source |
| 227 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 244 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
| 228 framesToProcess); | 245 framesToProcess); |
| 229 m_convolvers[1]->process(sourceChannelL, destinationChannelR, | 246 m_convolvers[1]->process(sourceChannelL, destinationChannelR, |
| 230 framesToProcess); | 247 framesToProcess); |
| 231 | 248 |
| 232 // Process right virtual source | 249 // Process right virtual source |
| 233 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); | 250 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); |
| 234 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); | 251 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); |
| 235 | 252 |
| 236 destinationBus->sumFrom(*m_tempBuffer); | 253 destinationBus->sumFrom(*m_tempBuffer); |
| 237 } else if (numInputChannels == 1 && numReverbChannels == 4 && | 254 } else if (numInputChannels == 1 && numReverbChannels == 4 && |
| 238 numOutputChannels == 2) { | 255 numOutputChannels == 2) { |
| 239 // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) | 256 // 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 | 257 // response) This is an inefficient use of a four-channel impulse |
| 241 // should handle the case. | 258 // response, but we should handle the case. |
| 242 AudioChannel* destinationChannelR = destinationBus->channel(1); | 259 AudioChannel* destinationChannelR = destinationBus->channel(1); |
| 243 | 260 |
| 244 AudioChannel* tempChannelL = m_tempBuffer->channel(0); | 261 AudioChannel* tempChannelL = m_tempBuffer->channel(0); |
| 245 AudioChannel* tempChannelR = m_tempBuffer->channel(1); | 262 AudioChannel* tempChannelR = m_tempBuffer->channel(1); |
| 246 | 263 |
| 247 // Process left virtual source | 264 // Process left virtual source |
| 248 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 265 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
| 249 framesToProcess); | 266 framesToProcess); |
| 250 m_convolvers[1]->process(sourceChannelL, destinationChannelR, | 267 m_convolvers[1]->process(sourceChannelL, destinationChannelR, |
| 251 framesToProcess); | 268 framesToProcess); |
| 252 | 269 |
| 253 // Process right virtual source | 270 // Process right virtual source |
| 254 m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess); | 271 m_convolvers[2]->process(sourceChannelL, tempChannelL, framesToProcess); |
| 255 m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess); | 272 m_convolvers[3]->process(sourceChannelL, tempChannelR, framesToProcess); |
| 256 | 273 |
| 257 destinationBus->sumFrom(*m_tempBuffer); | 274 destinationBus->sumFrom(*m_tempBuffer); |
| 258 } else { | 275 } else { |
| 259 // Handle gracefully any unexpected / unsupported matrixing | 276 NOTREACHED(); |
| 260 // FIXME: add code for 5.1 support... | |
| 261 destinationBus->zero(); | 277 destinationBus->zero(); |
| 262 } | 278 } |
| 263 } | 279 } |
| 264 | 280 |
| 265 void Reverb::reset() { | 281 void Reverb::reset() { |
| 266 for (size_t i = 0; i < m_convolvers.size(); ++i) | 282 for (size_t i = 0; i < m_convolvers.size(); ++i) |
| 267 m_convolvers[i]->reset(); | 283 m_convolvers[i]->reset(); |
| 268 } | 284 } |
| 269 | 285 |
| 270 size_t Reverb::latencyFrames() const { | 286 size_t Reverb::latencyFrames() const { |
| 271 return !m_convolvers.isEmpty() ? m_convolvers.front()->latencyFrames() : 0; | 287 return !m_convolvers.isEmpty() ? m_convolvers.front()->latencyFrames() : 0; |
| 272 } | 288 } |
| 273 | 289 |
| 274 } // namespace blink | 290 } // namespace blink |
| OLD | NEW |