diff --git a/dom/media/webaudio/blink/PeriodicWave.cpp b/dom/media/webaudio/blink/PeriodicWave.cpp index 24903f6319ca..763c52fecb9e 100644 --- a/dom/media/webaudio/blink/PeriodicWave.cpp +++ b/dom/media/webaudio/blink/PeriodicWave.cpp @@ -121,7 +121,7 @@ PeriodicWave::PeriodicWave(float sampleRate, size_t numberOfComponents) } m_numberOfRanges = (unsigned)(3.0f*logf(m_periodicWaveSize)/logf(2.0f)); - m_bandLimitedTables.SetCapacity(m_numberOfRanges); + m_bandLimitedTables.SetLength(m_numberOfRanges); m_lowestFundamentalFrequency = nyquist / maxNumberOfPartials(); m_rateScale = m_periodicWaveSize / m_sampleRate; } @@ -148,7 +148,13 @@ void PeriodicWave::waveDataForFundamentalFrequency(float fundamentalFrequency, f fundamentalFrequency = fabsf(fundamentalFrequency); if (fundamentalFrequency < m_lowestRequestedFundamentalFrequency) { - createBandLimitedTables(fundamentalFrequency); + for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) { + m_bandLimitedTables[rangeIndex] = 0; + } + + // We need to create the first table to determine the normalization + // constant. + createBandLimitedTables(fundamentalFrequency, 0); m_lowestRequestedFundamentalFrequency = fundamentalFrequency; } @@ -170,6 +176,12 @@ void PeriodicWave::waveDataForFundamentalFrequency(float fundamentalFrequency, f unsigned rangeIndex1 = static_cast(pitchRange); unsigned rangeIndex2 = rangeIndex1 < m_numberOfRanges - 1 ? rangeIndex1 + 1 : rangeIndex1; + if (!m_bandLimitedTables[rangeIndex1].get()) + createBandLimitedTables(fundamentalFrequency, rangeIndex1); + + if (!m_bandLimitedTables[rangeIndex2].get()) + createBandLimitedTables(fundamentalFrequency, rangeIndex2); + lowerWaveData = m_bandLimitedTables[rangeIndex2]->Elements(); higherWaveData = m_bandLimitedTables[rangeIndex1]->Elements(); @@ -200,69 +212,64 @@ unsigned PeriodicWave::numberOfPartialsForRange(unsigned rangeIndex) const // One table is created for each range for non-aliasing playback // at different playback rates. Thus, higher ranges have more // high-frequency partials culled out. -void PeriodicWave::createBandLimitedTables(float fundamentalFrequency) +void PeriodicWave::createBandLimitedTables(float fundamentalFrequency, + unsigned rangeIndex) { - float normalizationScale = 1; - unsigned fftSize = m_periodicWaveSize; unsigned i; const float *realData = m_realComponents->Elements(); const float *imagData = m_imagComponents->Elements(); - m_bandLimitedTables.Clear(); + // This FFTBlock is used to cull partials (represented by frequency bins). + FFTBlock frame(fftSize); - for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) { - // This FFTBlock is used to cull partials (represented by frequency bins). - FFTBlock frame(fftSize); + // Find the starting bin where we should start culling the aliasing + // partials for this pitch range. We need to clear out the highest + // frequencies to band-limit the waveform. + unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex); + // Also limit to the number of components that are provided. + numberOfPartials = std::min(numberOfPartials, m_numberOfComponents - 1); - // Find the starting bin where we should start culling the aliasing - // partials for this pitch range. We need to clear out the highest - // frequencies to band-limit the waveform. - unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex); - // Also limit to the number of components that are provided. - numberOfPartials = std::min(numberOfPartials, m_numberOfComponents - 1); + // Limit number of partials to those below Nyquist frequency + float nyquist = 0.5 * m_sampleRate; + numberOfPartials = std::min(numberOfPartials, + (unsigned)(nyquist / fundamentalFrequency)); - // Limit number of partials to those below Nyquist frequency - float nyquist = 0.5 * m_sampleRate; - numberOfPartials = std::min(numberOfPartials, - (unsigned)(nyquist / fundamentalFrequency)); - - // Copy from loaded frequency data and generate complex conjugate - // because of the way the inverse FFT is defined. - // The coefficients of higher partials remain zero, as initialized in - // the FFTBlock constructor. - for (i = 0; i < numberOfPartials + 1; ++i) { - frame.RealData(i) = realData[i]; - frame.ImagData(i) = -imagData[i]; - } - - // Clear any DC-offset. - frame.RealData(0) = 0; - // Clear value which has no effect. - frame.ImagData(0) = 0; - - // Create the band-limited table. - AlignedAudioFloatArray* table = new AlignedAudioFloatArray(m_periodicWaveSize); - m_bandLimitedTables.AppendElement(table); - - // Apply an inverse FFT to generate the time-domain table data. - float* data = m_bandLimitedTables[rangeIndex]->Elements(); - frame.GetInverseWithoutScaling(data); - - // For the first range (which has the highest power), calculate - // its peak value then compute normalization scale. - if (!rangeIndex) { - float maxValue; - maxValue = AudioBufferPeakValue(data, m_periodicWaveSize); - - if (maxValue) - normalizationScale = 1.0f / maxValue; - } - - // Apply normalization scale. - AudioBufferInPlaceScale(data, normalizationScale, m_periodicWaveSize); + // Copy from loaded frequency data and generate complex conjugate + // because of the way the inverse FFT is defined. + // The coefficients of higher partials remain zero, as initialized in + // the FFTBlock constructor. + for (i = 0; i < numberOfPartials + 1; ++i) { + frame.RealData(i) = realData[i]; + frame.ImagData(i) = -imagData[i]; } + + // Clear any DC-offset. + frame.RealData(0) = 0; + // Clear value which has no effect. + frame.ImagData(0) = 0; + + // Create the band-limited table. + AlignedAudioFloatArray* table = new AlignedAudioFloatArray(m_periodicWaveSize); + m_bandLimitedTables[rangeIndex] = table; + + // Apply an inverse FFT to generate the time-domain table data. + float* data = m_bandLimitedTables[rangeIndex]->Elements(); + frame.GetInverseWithoutScaling(data); + + // For the first range (which has the highest power), calculate + // its peak value then compute normalization scale. + if (!rangeIndex) { + float maxValue; + maxValue = AudioBufferPeakValue(data, m_periodicWaveSize); + + if (maxValue) + m_normalizationScale = 1.0f / maxValue; + } + + // Apply normalization scale. + AudioBufferInPlaceScale(data, m_normalizationScale, m_periodicWaveSize); } void PeriodicWave::generateBasicWaveform(OscillatorType shape) diff --git a/dom/media/webaudio/blink/PeriodicWave.h b/dom/media/webaudio/blink/PeriodicWave.h index 25d4b4c3e2c6..a0b6cdd111f1 100644 --- a/dom/media/webaudio/blink/PeriodicWave.h +++ b/dom/media/webaudio/blink/PeriodicWave.h @@ -104,9 +104,10 @@ private: unsigned numberOfPartialsForRange(unsigned rangeIndex) const; - // Creates tables based on numberOfComponents Fourier coefficients. - void createBandLimitedTables(float fundamentalFrequency); + // Creates table for specified index based on fundamental frequency. + void createBandLimitedTables(float fundamentalFrequency, unsigned rangeIndex); float m_lowestRequestedFundamentalFrequency; + float m_normalizationScale; nsTArray > m_bandLimitedTables; };