зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
5c9b087388
Коммит
57ace7e27d
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче