| 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 |