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 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 | 42 |
43 using namespace std; | 43 using namespace std; |
44 | 44 |
45 namespace WebCore { | 45 namespace WebCore { |
46 | 46 |
47 const double RealtimeAnalyser::DefaultSmoothingTimeConstant = 0.8; | 47 const double RealtimeAnalyser::DefaultSmoothingTimeConstant = 0.8; |
48 const double RealtimeAnalyser::DefaultMinDecibels = -100.0; | 48 const double RealtimeAnalyser::DefaultMinDecibels = -100.0; |
49 const double RealtimeAnalyser::DefaultMaxDecibels = -30.0; | 49 const double RealtimeAnalyser::DefaultMaxDecibels = -30.0; |
50 | 50 |
51 const unsigned RealtimeAnalyser::DefaultFFTSize = 2048; | 51 const unsigned RealtimeAnalyser::DefaultFFTSize = 2048; |
| 52 // All FFT implementations are expected to handle power-of-two sizes MinFFTSize
<= size <= MaxFFTSize. |
| 53 const unsigned RealtimeAnalyser::MinFFTSize = 128; |
52 const unsigned RealtimeAnalyser::MaxFFTSize = 2048; | 54 const unsigned RealtimeAnalyser::MaxFFTSize = 2048; |
53 const unsigned RealtimeAnalyser::InputBufferSize = RealtimeAnalyser::MaxFFTSize
* 2; | 55 const unsigned RealtimeAnalyser::InputBufferSize = RealtimeAnalyser::MaxFFTSize
* 2; |
54 | 56 |
55 RealtimeAnalyser::RealtimeAnalyser() | 57 RealtimeAnalyser::RealtimeAnalyser() |
56 : m_inputBuffer(InputBufferSize) | 58 : m_inputBuffer(InputBufferSize) |
57 , m_writeIndex(0) | 59 , m_writeIndex(0) |
58 , m_fftSize(DefaultFFTSize) | 60 , m_fftSize(DefaultFFTSize) |
59 , m_magnitudeBuffer(DefaultFFTSize / 2) | 61 , m_magnitudeBuffer(DefaultFFTSize / 2) |
60 , m_smoothingTimeConstant(DefaultSmoothingTimeConstant) | 62 , m_smoothingTimeConstant(DefaultSmoothingTimeConstant) |
61 , m_minDecibels(DefaultMinDecibels) | 63 , m_minDecibels(DefaultMinDecibels) |
(...skipping 13 matching lines...) Expand all Loading... |
75 m_magnitudeBuffer.zero(); | 77 m_magnitudeBuffer.zero(); |
76 } | 78 } |
77 | 79 |
78 void RealtimeAnalyser::setFftSize(size_t size) | 80 void RealtimeAnalyser::setFftSize(size_t size) |
79 { | 81 { |
80 ASSERT(isMainThread()); | 82 ASSERT(isMainThread()); |
81 | 83 |
82 // Only allow powers of two. | 84 // Only allow powers of two. |
83 unsigned log2size = static_cast<unsigned>(log2(size)); | 85 unsigned log2size = static_cast<unsigned>(log2(size)); |
84 bool isPOT(1UL << log2size == size); | 86 bool isPOT(1UL << log2size == size); |
85 | 87 |
86 if (!isPOT || size > MaxFFTSize) { | 88 if (!isPOT || size > MaxFFTSize || size < MinFFTSize) { |
87 // FIXME: It would be good to also set an exception. | 89 // FIXME: It would be good to also set an exception. |
88 return; | 90 return; |
89 } | 91 } |
90 | 92 |
91 if (m_fftSize != size) { | 93 if (m_fftSize != size) { |
92 m_analysisFrame = adoptPtr(new FFTFrame(m_fftSize)); | 94 m_analysisFrame = adoptPtr(new FFTFrame(size)); |
93 m_magnitudeBuffer.allocate(size); | 95 // m_magnitudeBuffer has size = fftSize / 2 because it contains floats r
educed from complex values in m_analysisFrame. |
| 96 m_magnitudeBuffer.allocate(size / 2); |
94 m_fftSize = size; | 97 m_fftSize = size; |
95 } | 98 } |
96 } | 99 } |
97 | 100 |
98 void RealtimeAnalyser::writeInput(AudioBus* bus, size_t framesToProcess) | 101 void RealtimeAnalyser::writeInput(AudioBus* bus, size_t framesToProcess) |
99 { | 102 { |
100 bool isBusGood = bus && bus->numberOfChannels() > 0 && bus->channel(0)->leng
th() >= framesToProcess; | 103 bool isBusGood = bus && bus->numberOfChannels() > 0 && bus->channel(0)->leng
th() >= framesToProcess; |
101 ASSERT(isBusGood); | 104 ASSERT(isBusGood); |
102 if (!isBusGood) | 105 if (!isBusGood) |
103 return; | 106 return; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 unsigned writeIndex = m_writeIndex; | 161 unsigned writeIndex = m_writeIndex; |
159 for (unsigned i = 0; i < fftSize; ++i) | 162 for (unsigned i = 0; i < fftSize; ++i) |
160 tempP[i] = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % In
putBufferSize]; | 163 tempP[i] = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % In
putBufferSize]; |
161 | 164 |
162 // Window the input samples. | 165 // Window the input samples. |
163 applyWindow(tempP, fftSize); | 166 applyWindow(tempP, fftSize); |
164 | 167 |
165 // Do the analysis. | 168 // Do the analysis. |
166 m_analysisFrame->doFFT(tempP); | 169 m_analysisFrame->doFFT(tempP); |
167 | 170 |
168 size_t n = DefaultFFTSize / 2; | |
169 | |
170 float* realP = m_analysisFrame->realData(); | 171 float* realP = m_analysisFrame->realData(); |
171 float* imagP = m_analysisFrame->imagData(); | 172 float* imagP = m_analysisFrame->imagData(); |
172 | 173 |
173 // Blow away the packed nyquist component. | 174 // Blow away the packed nyquist component. |
174 imagP[0] = 0.0f; | 175 imagP[0] = 0.0f; |
175 | 176 |
176 // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FF
T scaling factor). | 177 // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FF
T scaling factor). |
177 const double MagnitudeScale = 1.0 / DefaultFFTSize; | 178 const double MagnitudeScale = 1.0 / DefaultFFTSize; |
178 | 179 |
179 // A value of 0 does no averaging with the previous result. Larger values p
roduce slower, but smoother changes. | 180 // A value of 0 does no averaging with the previous result. Larger values p
roduce slower, but smoother changes. |
180 double k = m_smoothingTimeConstant; | 181 double k = m_smoothingTimeConstant; |
181 k = max(0.0, k); | 182 k = max(0.0, k); |
182 k = min(1.0, k); | 183 k = min(1.0, k); |
183 | 184 |
184 // Convert the analysis data from complex to magnitude and average with the
previous result. | 185 // Convert the analysis data from complex to magnitude and average with the
previous result. |
185 float* destination = magnitudeBuffer().data(); | 186 float* destination = magnitudeBuffer().data(); |
186 for (unsigned i = 0; i < n; ++i) { | 187 size_t n = magnitudeBuffer().size(); |
| 188 for (size_t i = 0; i < n; ++i) { |
187 Complex c(realP[i], imagP[i]); | 189 Complex c(realP[i], imagP[i]); |
188 double scalarMagnitude = abs(c) * MagnitudeScale; | 190 double scalarMagnitude = abs(c) * MagnitudeScale; |
189 destination[i] = float(k * destination[i] + (1.0 - k) * scalarMagnitude)
; | 191 destination[i] = float(k * destination[i] + (1.0 - k) * scalarMagnitude)
; |
190 } | 192 } |
191 } | 193 } |
192 | 194 |
193 void RealtimeAnalyser::getFloatFrequencyData(Float32Array* destinationArray) | 195 void RealtimeAnalyser::getFloatFrequencyData(Float32Array* destinationArray) |
194 { | 196 { |
195 ASSERT(isMainThread()); | 197 ASSERT(isMainThread()); |
196 | 198 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 scaledValue = UCHAR_MAX; | 287 scaledValue = UCHAR_MAX; |
286 | 288 |
287 destination[i] = static_cast<unsigned char>(scaledValue); | 289 destination[i] = static_cast<unsigned char>(scaledValue); |
288 } | 290 } |
289 } | 291 } |
290 } | 292 } |
291 | 293 |
292 } // namespace WebCore | 294 } // namespace WebCore |
293 | 295 |
294 #endif // ENABLE(WEB_AUDIO) | 296 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |