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 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 // impulseResponse. | 109 // impulseResponse. |
| 110 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy | 110 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy |
| 111 // instead of scaling and unscaling in place. | 111 // instead of scaling and unscaling in place. |
| 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 numberOfResponseChannels, |
| 120 bool useBackgroundThreads) { | 120 bool useBackgroundThreads) { |
| 121 m_impulseResponseLength = impulseResponseBuffer->length(); | 121 m_impulseResponseLength = impulseResponseBuffer->length(); |
| 122 m_numberOfResponseChannels = numberOfResponseChannels; | |
| 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. |
| 125 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); | 126 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); |
|
hongchan
2017/03/28 19:01:44
How this |numResponseChannels| is different from |
Raymond Toy
2017/03/28 20:18:02
Good point. I don't think there is anymore and num
| |
| 126 m_convolvers.reserveCapacity(numberOfChannels); | 127 size_t numConvolvers = std::max(numResponseChannels, static_cast<size_t>(2)); |
|
hongchan
2017/03/28 19:01:44
If |numResponseChannel| is unsigned we don't need
| |
| 128 m_convolvers.reserveCapacity(numConvolvers); | |
|
hongchan
2017/03/28 19:01:44
Then we can do .reserveCapacity(static_cast<size_t
Raymond Toy
2017/03/28 20:18:02
This is ok. Just means we also need more casting i
| |
| 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 numberOfResponseChannels = m_numberOfResponseChannels; |
| 177 | 180 |
| 178 if (numInputChannels == 2 && numReverbChannels == 2 && | 181 DCHECK_LE(numInputChannels, 2ul); |
| 182 DCHECK_LE(numOutputChannels, 2ul); | |
| 183 DCHECK(numberOfResponseChannels == 1 || numberOfResponseChannels == 2 || | |
| 184 numberOfResponseChannels == 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 // numberOfResponseChannels: 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 numberOfResponseChannels 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 (numberOfResponseChannels == 1 || numberOfResponseChannels == 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 numberOfResponseChannels == 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 && numberOfResponseChannels == 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, | 232 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
| 199 framesToProcess); | 233 framesToProcess); |
| 200 | 234 } 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) { | 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 && numberOfResponseChannels == 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 |