Bug 1222405 - (part 3) Build band limited tables lazily r=padenot

This builds the band limited tables for each range index individually as
required.

--HG--
extra : rebase_source : 022665e3b83b82bcdcec3cabf3ddda9c2dce2ebf
This commit is contained in:
Dan Minor 2015-11-27 15:01:28 -05:00
Родитель 5c9b087388
Коммит 57ace7e27d
2 изменённых файлов: 64 добавлений и 56 удалений

Просмотреть файл

@ -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<unsigned>(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)

Просмотреть файл

@ -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<nsAutoPtr<AlignedAudioFloatArray> > m_bandLimitedTables;
};