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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 } else { | 62 } else { |
63 ASSERT(!stageOffset); | 63 ASSERT(!stageOffset); |
64 ASSERT(stageLength <= fftSize / 2); | 64 ASSERT(stageLength <= fftSize / 2); |
65 | 65 |
66 m_directKernel = wrapUnique(new AudioFloatArray(fftSize / 2)); | 66 m_directKernel = wrapUnique(new AudioFloatArray(fftSize / 2)); |
67 m_directKernel->copyToRange(impulseResponse, 0, stageLength); | 67 m_directKernel->copyToRange(impulseResponse, 0, stageLength); |
68 m_directConvolver = wrapUnique(new DirectConvolver(renderSliceSize)); | 68 m_directConvolver = wrapUnique(new DirectConvolver(renderSliceSize)); |
69 } | 69 } |
70 m_temporaryBuffer.allocate(renderSliceSize); | 70 m_temporaryBuffer.allocate(renderSliceSize); |
71 | 71 |
72 // The convolution stage at offset stageOffset needs to have a corresponding d
elay to cancel out the offset. | 72 // The convolution stage at offset stageOffset needs to have a corresponding |
| 73 // delay to cancel out the offset. |
73 size_t totalDelay = stageOffset + reverbTotalLatency; | 74 size_t totalDelay = stageOffset + reverbTotalLatency; |
74 | 75 |
75 // But, the FFT convolution itself incurs fftSize / 2 latency, so subtract thi
s out... | 76 // But, the FFT convolution itself incurs fftSize / 2 latency, so subtract |
| 77 // this out... |
76 size_t halfSize = fftSize / 2; | 78 size_t halfSize = fftSize / 2; |
77 if (!m_directMode) { | 79 if (!m_directMode) { |
78 ASSERT(totalDelay >= halfSize); | 80 ASSERT(totalDelay >= halfSize); |
79 if (totalDelay >= halfSize) | 81 if (totalDelay >= halfSize) |
80 totalDelay -= halfSize; | 82 totalDelay -= halfSize; |
81 } | 83 } |
82 | 84 |
83 // We divide up the total delay, into pre and post delay sections so that we c
an schedule at exactly the moment when the FFT will happen. | 85 // We divide up the total delay, into pre and post delay sections so that we |
84 // This is coordinated with the other stages, so they don't all do their FFTs
at the same time... | 86 // can schedule at exactly the moment when the FFT will happen. This is |
| 87 // coordinated with the other stages, so they don't all do their FFTs at the |
| 88 // same time... |
85 int maxPreDelayLength = std::min(halfSize, totalDelay); | 89 int maxPreDelayLength = std::min(halfSize, totalDelay); |
86 m_preDelayLength = totalDelay > 0 ? renderPhase % maxPreDelayLength : 0; | 90 m_preDelayLength = totalDelay > 0 ? renderPhase % maxPreDelayLength : 0; |
87 if (m_preDelayLength > totalDelay) | 91 if (m_preDelayLength > totalDelay) |
88 m_preDelayLength = 0; | 92 m_preDelayLength = 0; |
89 | 93 |
90 m_postDelayLength = totalDelay - m_preDelayLength; | 94 m_postDelayLength = totalDelay - m_preDelayLength; |
91 m_preReadWriteIndex = 0; | 95 m_preReadWriteIndex = 0; |
92 m_framesProcessed = 0; // total frames processed so far | 96 m_framesProcessed = 0; // total frames processed so far |
93 | 97 |
94 size_t delayBufferSize = | 98 size_t delayBufferSize = |
(...skipping 17 matching lines...) Expand all Loading... |
112 if (!source) | 116 if (!source) |
113 return; | 117 return; |
114 | 118 |
115 // Deal with pre-delay stream : note special handling of zero delay. | 119 // Deal with pre-delay stream : note special handling of zero delay. |
116 | 120 |
117 const float* preDelayedSource; | 121 const float* preDelayedSource; |
118 float* preDelayedDestination; | 122 float* preDelayedDestination; |
119 float* temporaryBuffer; | 123 float* temporaryBuffer; |
120 bool isTemporaryBufferSafe = false; | 124 bool isTemporaryBufferSafe = false; |
121 if (m_preDelayLength > 0) { | 125 if (m_preDelayLength > 0) { |
122 // Handles both the read case (call to process() ) and the write case (memcp
y() ) | 126 // Handles both the read case (call to process() ) and the write case |
| 127 // (memcpy() ) |
123 bool isPreDelaySafe = | 128 bool isPreDelaySafe = |
124 m_preReadWriteIndex + framesToProcess <= m_preDelayBuffer.size(); | 129 m_preReadWriteIndex + framesToProcess <= m_preDelayBuffer.size(); |
125 ASSERT(isPreDelaySafe); | 130 ASSERT(isPreDelaySafe); |
126 if (!isPreDelaySafe) | 131 if (!isPreDelaySafe) |
127 return; | 132 return; |
128 | 133 |
129 isTemporaryBufferSafe = framesToProcess <= m_temporaryBuffer.size(); | 134 isTemporaryBufferSafe = framesToProcess <= m_temporaryBuffer.size(); |
130 | 135 |
131 preDelayedDestination = m_preDelayBuffer.data() + m_preReadWriteIndex; | 136 preDelayedDestination = m_preDelayBuffer.data() + m_preReadWriteIndex; |
132 preDelayedSource = preDelayedDestination; | 137 preDelayedSource = preDelayedDestination; |
133 temporaryBuffer = m_temporaryBuffer.data(); | 138 temporaryBuffer = m_temporaryBuffer.data(); |
134 } else { | 139 } else { |
135 // Zero delay | 140 // Zero delay |
136 preDelayedDestination = 0; | 141 preDelayedDestination = 0; |
137 preDelayedSource = source; | 142 preDelayedSource = source; |
138 temporaryBuffer = m_preDelayBuffer.data(); | 143 temporaryBuffer = m_preDelayBuffer.data(); |
139 | 144 |
140 isTemporaryBufferSafe = framesToProcess <= m_preDelayBuffer.size(); | 145 isTemporaryBufferSafe = framesToProcess <= m_preDelayBuffer.size(); |
141 } | 146 } |
142 | 147 |
143 ASSERT(isTemporaryBufferSafe); | 148 ASSERT(isTemporaryBufferSafe); |
144 if (!isTemporaryBufferSafe) | 149 if (!isTemporaryBufferSafe) |
145 return; | 150 return; |
146 | 151 |
147 if (m_framesProcessed < m_preDelayLength) { | 152 if (m_framesProcessed < m_preDelayLength) { |
148 // For the first m_preDelayLength frames don't process the convolver, instea
d simply buffer in the pre-delay. | 153 // For the first m_preDelayLength frames don't process the convolver, |
149 // But while buffering the pre-delay, we still need to update our index. | 154 // instead simply buffer in the pre-delay. But while buffering the |
| 155 // pre-delay, we still need to update our index. |
150 m_accumulationBuffer->updateReadIndex(&m_accumulationReadIndex, | 156 m_accumulationBuffer->updateReadIndex(&m_accumulationReadIndex, |
151 framesToProcess); | 157 framesToProcess); |
152 } else { | 158 } else { |
153 // Now, run the convolution (into the delay buffer). | 159 // Now, run the convolution (into the delay buffer). |
154 // An expensive FFT will happen every fftSize / 2 frames. | 160 // An expensive FFT will happen every fftSize / 2 frames. |
155 // We process in-place here... | 161 // We process in-place here... |
156 if (!m_directMode) | 162 if (!m_directMode) |
157 m_fftConvolver->process(m_fftKernel.get(), preDelayedSource, | 163 m_fftConvolver->process(m_fftKernel.get(), preDelayedSource, |
158 temporaryBuffer, framesToProcess); | 164 temporaryBuffer, framesToProcess); |
159 else | 165 else |
(...skipping 24 matching lines...) Expand all Loading... |
184 m_fftConvolver->reset(); | 190 m_fftConvolver->reset(); |
185 else | 191 else |
186 m_directConvolver->reset(); | 192 m_directConvolver->reset(); |
187 m_preDelayBuffer.zero(); | 193 m_preDelayBuffer.zero(); |
188 m_accumulationReadIndex = 0; | 194 m_accumulationReadIndex = 0; |
189 m_inputReadIndex = 0; | 195 m_inputReadIndex = 0; |
190 m_framesProcessed = 0; | 196 m_framesProcessed = 0; |
191 } | 197 } |
192 | 198 |
193 } // namespace blink | 199 } // namespace blink |
OLD | NEW |