| 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 24 matching lines...) Expand all Loading... |
| 35 #include <memory> | 35 #include <memory> |
| 36 | 36 |
| 37 #if OS(MACOSX) | 37 #if OS(MACOSX) |
| 38 using namespace std; | 38 using namespace std; |
| 39 #endif | 39 #endif |
| 40 | 40 |
| 41 namespace blink { | 41 namespace blink { |
| 42 | 42 |
| 43 using namespace VectorMath; | 43 using namespace VectorMath; |
| 44 | 44 |
| 45 // Empirical gain calibration tested across many impulse responses to ensure per
ceived volume is same as dry (unprocessed) signal | 45 // Empirical gain calibration tested across many impulse responses to ensure |
| 46 // perceived volume is same as dry (unprocessed) signal |
| 46 const float GainCalibration = -58; | 47 const float GainCalibration = -58; |
| 47 const float GainCalibrationSampleRate = 44100; | 48 const float GainCalibrationSampleRate = 44100; |
| 48 | 49 |
| 49 // A minimum power value to when normalizing a silent (or very quiet) impulse re
sponse | 50 // A minimum power value to when normalizing a silent (or very quiet) impulse |
| 51 // response |
| 50 const float MinPower = 0.000125f; | 52 const float MinPower = 0.000125f; |
| 51 | 53 |
| 52 static float calculateNormalizationScale(AudioBus* response) { | 54 static float calculateNormalizationScale(AudioBus* response) { |
| 53 // Normalize by RMS power | 55 // Normalize by RMS power |
| 54 size_t numberOfChannels = response->numberOfChannels(); | 56 size_t numberOfChannels = response->numberOfChannels(); |
| 55 size_t length = response->length(); | 57 size_t length = response->length(); |
| 56 | 58 |
| 57 float power = 0; | 59 float power = 0; |
| 58 | 60 |
| 59 for (size_t i = 0; i < numberOfChannels; ++i) { | 61 for (size_t i = 0; i < numberOfChannels; ++i) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 if (normalize) { | 98 if (normalize) { |
| 97 scale = calculateNormalizationScale(impulseResponse); | 99 scale = calculateNormalizationScale(impulseResponse); |
| 98 | 100 |
| 99 if (scale) | 101 if (scale) |
| 100 impulseResponse->scale(scale); | 102 impulseResponse->scale(scale); |
| 101 } | 103 } |
| 102 | 104 |
| 103 initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, | 105 initialize(impulseResponse, renderSliceSize, maxFFTSize, numberOfChannels, |
| 104 useBackgroundThreads); | 106 useBackgroundThreads); |
| 105 | 107 |
| 106 // Undo scaling since this shouldn't be a destructive operation on impulseResp
onse. | 108 // Undo scaling since this shouldn't be a destructive operation on |
| 109 // impulseResponse. |
| 107 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy | 110 // FIXME: What about roundoff? Perhaps consider making a temporary scaled copy |
| 108 // instead of scaling and unscaling in place. | 111 // instead of scaling and unscaling in place. |
| 109 if (normalize && scale) | 112 if (normalize && scale) |
| 110 impulseResponse->scale(1 / scale); | 113 impulseResponse->scale(1 / scale); |
| 111 } | 114 } |
| 112 | 115 |
| 113 void Reverb::initialize(AudioBus* impulseResponseBuffer, | 116 void Reverb::initialize(AudioBus* impulseResponseBuffer, |
| 114 size_t renderSliceSize, | 117 size_t renderSliceSize, |
| 115 size_t maxFFTSize, | 118 size_t maxFFTSize, |
| 116 size_t numberOfChannels, | 119 size_t numberOfChannels, |
| 117 bool useBackgroundThreads) { | 120 bool useBackgroundThreads) { |
| 118 m_impulseResponseLength = impulseResponseBuffer->length(); | 121 m_impulseResponseLength = impulseResponseBuffer->length(); |
| 119 | 122 |
| 120 // The reverb can handle a mono impulse response and still do stereo processin
g | 123 // The reverb can handle a mono impulse response and still do stereo |
| 124 // processing |
| 121 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); | 125 size_t numResponseChannels = impulseResponseBuffer->numberOfChannels(); |
| 122 m_convolvers.reserveCapacity(numberOfChannels); | 126 m_convolvers.reserveCapacity(numberOfChannels); |
| 123 | 127 |
| 124 int convolverRenderPhase = 0; | 128 int convolverRenderPhase = 0; |
| 125 for (size_t i = 0; i < numResponseChannels; ++i) { | 129 for (size_t i = 0; i < numResponseChannels; ++i) { |
| 126 AudioChannel* channel = impulseResponseBuffer->channel(i); | 130 AudioChannel* channel = impulseResponseBuffer->channel(i); |
| 127 | 131 |
| 128 std::unique_ptr<ReverbConvolver> convolver = wrapUnique( | 132 std::unique_ptr<ReverbConvolver> convolver = wrapUnique( |
| 129 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, | 133 new ReverbConvolver(channel, renderSliceSize, maxFFTSize, |
| 130 convolverRenderPhase, useBackgroundThreads)); | 134 convolverRenderPhase, useBackgroundThreads)); |
| 131 m_convolvers.append(std::move(convolver)); | 135 m_convolvers.append(std::move(convolver)); |
| 132 | 136 |
| 133 convolverRenderPhase += renderSliceSize; | 137 convolverRenderPhase += renderSliceSize; |
| 134 } | 138 } |
| 135 | 139 |
| 136 // For "True" stereo processing we allocate a temporary buffer to avoid repeat
edly allocating it in the process() method. | 140 // For "True" stereo processing we allocate a temporary buffer to avoid |
| 137 // It can be bad to allocate memory in a real-time thread. | 141 // repeatedly allocating it in the process() method. It can be bad to |
| 142 // allocate memory in a real-time thread. |
| 138 if (numResponseChannels == 4) | 143 if (numResponseChannels == 4) |
| 139 m_tempBuffer = AudioBus::create(2, MaxFrameSize); | 144 m_tempBuffer = AudioBus::create(2, MaxFrameSize); |
| 140 } | 145 } |
| 141 | 146 |
| 142 void Reverb::process(const AudioBus* sourceBus, | 147 void Reverb::process(const AudioBus* sourceBus, |
| 143 AudioBus* destinationBus, | 148 AudioBus* destinationBus, |
| 144 size_t framesToProcess) { | 149 size_t framesToProcess) { |
| 145 // Do a fairly comprehensive sanity check. | 150 // Do a fairly comprehensive sanity check. |
| 146 // If these conditions are satisfied, all of the source and destination pointe
rs will be valid for the various matrixing cases. | 151 // If these conditions are satisfied, all of the source and destination |
| 152 // pointers will be valid for the various matrixing cases. |
| 147 bool isSafeToProcess = sourceBus && destinationBus && | 153 bool isSafeToProcess = sourceBus && destinationBus && |
| 148 sourceBus->numberOfChannels() > 0 && | 154 sourceBus->numberOfChannels() > 0 && |
| 149 destinationBus->numberOfChannels() > 0 && | 155 destinationBus->numberOfChannels() > 0 && |
| 150 framesToProcess <= MaxFrameSize && | 156 framesToProcess <= MaxFrameSize && |
| 151 framesToProcess <= sourceBus->length() && | 157 framesToProcess <= sourceBus->length() && |
| 152 framesToProcess <= destinationBus->length(); | 158 framesToProcess <= destinationBus->length(); |
| 153 | 159 |
| 154 ASSERT(isSafeToProcess); | 160 ASSERT(isSafeToProcess); |
| 155 if (!isSafeToProcess) | 161 if (!isSafeToProcess) |
| 156 return; | 162 return; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 framesToProcess); | 230 framesToProcess); |
| 225 | 231 |
| 226 // Process right virtual source | 232 // Process right virtual source |
| 227 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); | 233 m_convolvers[2]->process(sourceChannelR, tempChannelL, framesToProcess); |
| 228 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); | 234 m_convolvers[3]->process(sourceChannelR, tempChannelR, framesToProcess); |
| 229 | 235 |
| 230 destinationBus->sumFrom(*m_tempBuffer); | 236 destinationBus->sumFrom(*m_tempBuffer); |
| 231 } else if (numInputChannels == 1 && numReverbChannels == 4 && | 237 } else if (numInputChannels == 1 && numReverbChannels == 4 && |
| 232 numOutputChannels == 2) { | 238 numOutputChannels == 2) { |
| 233 // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) | 239 // 1 -> 4 -> 2 (Processing mono with "True" stereo impulse response) |
| 234 // This is an inefficient use of a four-channel impulse response, but we sho
uld handle the case. | 240 // This is an inefficient use of a four-channel impulse response, but we |
| 241 // should handle the case. |
| 235 AudioChannel* destinationChannelR = destinationBus->channel(1); | 242 AudioChannel* destinationChannelR = destinationBus->channel(1); |
| 236 | 243 |
| 237 AudioChannel* tempChannelL = m_tempBuffer->channel(0); | 244 AudioChannel* tempChannelL = m_tempBuffer->channel(0); |
| 238 AudioChannel* tempChannelR = m_tempBuffer->channel(1); | 245 AudioChannel* tempChannelR = m_tempBuffer->channel(1); |
| 239 | 246 |
| 240 // Process left virtual source | 247 // Process left virtual source |
| 241 m_convolvers[0]->process(sourceChannelL, destinationChannelL, | 248 m_convolvers[0]->process(sourceChannelL, destinationChannelL, |
| 242 framesToProcess); | 249 framesToProcess); |
| 243 m_convolvers[1]->process(sourceChannelL, destinationChannelR, | 250 m_convolvers[1]->process(sourceChannelL, destinationChannelR, |
| 244 framesToProcess); | 251 framesToProcess); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 258 void Reverb::reset() { | 265 void Reverb::reset() { |
| 259 for (size_t i = 0; i < m_convolvers.size(); ++i) | 266 for (size_t i = 0; i < m_convolvers.size(); ++i) |
| 260 m_convolvers[i]->reset(); | 267 m_convolvers[i]->reset(); |
| 261 } | 268 } |
| 262 | 269 |
| 263 size_t Reverb::latencyFrames() const { | 270 size_t Reverb::latencyFrames() const { |
| 264 return !m_convolvers.isEmpty() ? m_convolvers.first()->latencyFrames() : 0; | 271 return !m_convolvers.isEmpty() ? m_convolvers.first()->latencyFrames() : 0; |
| 265 } | 272 } |
| 266 | 273 |
| 267 } // namespace blink | 274 } // namespace blink |
| OLD | NEW |