void RealtimeAnalyser::convertToByteData(DOMUint8Array* destinationArray) { // Convert from linear magnitude to unsigned-byte decibels. unsigned sourceLength = magnitudeBuffer().size(); size_t len = std::min(sourceLength, destinationArray->length()); if (len > 0) { const double rangeScaleFactor = m_maxDecibels == m_minDecibels ? 1 : 1 / (m_maxDecibels - m_minDecibels); const double minDecibels = m_minDecibels; const float* source = magnitudeBuffer().data(); unsigned char* destination = destinationArray->data(); for (unsigned i = 0; i < len; ++i) { float linearValue = source[i]; double dbMag = AudioUtilities::linearToDecibels(linearValue); // The range m_minDecibels to m_maxDecibels will be scaled to byte values // from 0 to UCHAR_MAX. double scaledValue = UCHAR_MAX * (dbMag - minDecibels) * rangeScaleFactor; // Clip to valid range. if (scaledValue < 0) scaledValue = 0; if (scaledValue > UCHAR_MAX) scaledValue = UCHAR_MAX; destination[i] = static_cast<unsigned char>(scaledValue); } } }
void RealtimeAnalyser::getByteFrequencyData(Uint8Array* destinationArray) { ASSERT(isMainThread()); if (!destinationArray) return; doFFTAnalysis(); // Convert from linear magnitude to unsigned-byte decibels. unsigned sourceLength = magnitudeBuffer().size(); size_t len = min(sourceLength, destinationArray->length()); if (len > 0) { const double RangeScaleFactor = m_maxDecibels == m_minDecibels ? 1.0 : 1.0 / (m_maxDecibels - m_minDecibels); const float* source = magnitudeBuffer().data(); unsigned char* destination = destinationArray->data(); for (unsigned i = 0; i < len; ++i) { float linearValue = source[i]; double dbMag = !linearValue ? m_minDecibels : AudioUtilities::linearToDecibels(linearValue); // The range m_minDecibels to m_maxDecibels will be scaled to byte values from 0 to UCHAR_MAX. double scaledValue = UCHAR_MAX * (dbMag - m_minDecibels) * RangeScaleFactor; // Clip to valid range. if (scaledValue < 0.0) scaledValue = 0.0; if (scaledValue > UCHAR_MAX) scaledValue = UCHAR_MAX; destination[i] = static_cast<unsigned char>(scaledValue); } } }
void RealtimeAnalyser::doFFTAnalysis() { DCHECK(isMainThread()); // Unroll the input buffer into a temporary buffer, where we'll apply an // analysis window followed by an FFT. size_t fftSize = this->fftSize(); AudioFloatArray temporaryBuffer(fftSize); float* inputBuffer = m_inputBuffer.data(); float* tempP = temporaryBuffer.data(); // Take the previous fftSize values from the input buffer and copy into the // temporary buffer. unsigned writeIndex = m_writeIndex; if (writeIndex < fftSize) { memcpy(tempP, inputBuffer + writeIndex - fftSize + InputBufferSize, sizeof(*tempP) * (fftSize - writeIndex)); memcpy(tempP + fftSize - writeIndex, inputBuffer, sizeof(*tempP) * writeIndex); } else { memcpy(tempP, inputBuffer + writeIndex - fftSize, sizeof(*tempP) * fftSize); } // Window the input samples. applyWindow(tempP, fftSize); // Do the analysis. m_analysisFrame->doFFT(tempP); float* realP = m_analysisFrame->realData(); float* imagP = m_analysisFrame->imagData(); // Blow away the packed nyquist component. imagP[0] = 0; // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT // scaling factor). const double magnitudeScale = 1.0 / fftSize; // A value of 0 does no averaging with the previous result. Larger values // produce slower, but smoother changes. double k = m_smoothingTimeConstant; k = std::max(0.0, k); k = std::min(1.0, k); // Convert the analysis data from complex to magnitude and average with the // previous result. float* destination = magnitudeBuffer().data(); size_t n = magnitudeBuffer().size(); for (size_t i = 0; i < n; ++i) { std::complex<double> c(realP[i], imagP[i]); double scalarMagnitude = abs(c) * magnitudeScale; destination[i] = float(k * destination[i] + (1 - k) * scalarMagnitude); } }
void RealtimeAnalyser::convertFloatToDb(DOMFloat32Array* destinationArray) { // Convert from linear magnitude to floating-point decibels. unsigned sourceLength = magnitudeBuffer().size(); size_t len = std::min(sourceLength, destinationArray->length()); if (len > 0) { const float* source = magnitudeBuffer().data(); float* destination = destinationArray->data(); for (unsigned i = 0; i < len; ++i) { float linearValue = source[i]; double dbMag = AudioUtilities::linearToDecibels(linearValue); destination[i] = float(dbMag); } } }
void RealtimeAnalyser::doFFTAnalysis() { ASSERT(isMainThread()); // Unroll the input buffer into a temporary buffer, where we'll apply an analysis window followed by an FFT. size_t fftSize = this->fftSize(); AudioFloatArray temporaryBuffer(fftSize); float* inputBuffer = m_inputBuffer.data(); float* tempP = temporaryBuffer.data(); // Take the previous fftSize values from the input buffer and copy into the temporary buffer. // FIXME : optimize with memcpy(). unsigned writeIndex = m_writeIndex; for (unsigned i = 0; i < fftSize; ++i) tempP[i] = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize]; // Window the input samples. applyWindow(tempP, fftSize); // Do the analysis. m_analysisFrame->doFFT(tempP); float* realP = m_analysisFrame->realData(); float* imagP = m_analysisFrame->imagData(); // Blow away the packed nyquist component. imagP[0] = 0.0f; // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor). const double MagnitudeScale = 1.0 / DefaultFFTSize; // A value of 0 does no averaging with the previous result. Larger values produce slower, but smoother changes. double k = m_smoothingTimeConstant; k = max(0.0, k); k = min(1.0, k); // Convert the analysis data from complex to magnitude and average with the previous result. float* destination = magnitudeBuffer().data(); size_t n = magnitudeBuffer().size(); for (size_t i = 0; i < n; ++i) { Complex c(realP[i], imagP[i]); double scalarMagnitude = abs(c) * MagnitudeScale; destination[i] = float(k * destination[i] + (1.0 - k) * scalarMagnitude); } }
void RealtimeAnalyser::getFloatFrequencyData(DOMFloat32Array* destinationArray) { ASSERT(isMainThread()); ASSERT(destinationArray); doFFTAnalysis(); // Convert from linear magnitude to floating-point decibels. const double minDecibels = m_minDecibels; unsigned sourceLength = magnitudeBuffer().size(); size_t len = std::min(sourceLength, destinationArray->length()); if (len > 0) { const float* source = magnitudeBuffer().data(); float* destination = destinationArray->data(); for (unsigned i = 0; i < len; ++i) { float linearValue = source[i]; double dbMag = !linearValue ? minDecibels : AudioUtilities::linearToDecibels(linearValue); destination[i] = float(dbMag); } } }