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