/* * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
constunsigned MinPeriodicWaveSize = 4096; // This must be a power of two. constunsigned MaxPeriodicWaveSize = 8192; // This must be a power of two. constfloat CentsPerRange = 1200 / 3; // 1/3 Octave.
usingnamespace mozilla; using mozilla::dom::OscillatorType;
// Limit the number of components used to those for frequencies below the // Nyquist of the fixed length inverse FFT.
size_t halfSize = periodicWave->m_periodicWaveSize / 2;
numberOfComponents = std::min(numberOfComponents, halfSize);
periodicWave->m_numberOfComponents = numberOfComponents;
periodicWave->m_realComponents =
MakeUnique<AudioFloatArray>(numberOfComponents);
periodicWave->m_imagComponents =
MakeUnique<AudioFloatArray>(numberOfComponents);
memcpy(periodicWave->m_realComponents->Elements(), real,
numberOfComponents * sizeof(float));
memcpy(periodicWave->m_imagComponents->Elements(), imag,
numberOfComponents * sizeof(float));
amount += m_bandLimitedTables.ShallowSizeOfExcludingThis(aMallocSizeOf); for (size_t i = 0; i < m_bandLimitedTables.Length(); i++) { if (m_bandLimitedTables[i]) {
amount +=
m_bandLimitedTables[i]->ShallowSizeOfIncludingThis(aMallocSizeOf);
}
}
return amount;
}
void PeriodicWave::waveDataForFundamentalFrequency( float fundamentalFrequency, float*& lowerWaveData, float*& higherWaveData, float& tableInterpolationFactor) { // Negative frequencies are allowed, in which case we alias // to the positive frequency.
fundamentalFrequency = fabsf(fundamentalFrequency);
// We only need to rebuild to the tables if the new fundamental // frequency is low enough to allow for more partials below the // Nyquist frequency. unsigned numberOfPartials = numberOfPartialsForRange(0); float nyquist = 0.5 * m_sampleRate; if (fundamentalFrequency != 0.0) {
numberOfPartials =
std::min(numberOfPartials, (unsigned)(nyquist / fundamentalFrequency));
} if (numberOfPartials > m_maxPartialsInBandLimitedTable) { 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_maxPartialsInBandLimitedTable = numberOfPartials;
}
// Add one to round-up to the next range just in time to truncate // partials before aliasing occurs. float pitchRange = 1 + centsAboveLowestFrequency / m_centsPerRange;
// The words "lower" and "higher" refer to the table data having // the lower and higher numbers of partials. It's a little confusing // since the range index gets larger the more partials we cull out. // So the lower table data will have a larger range index. 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);
unsigned PeriodicWave::numberOfPartialsForRange(unsigned rangeIndex) const { // Number of cents below nyquist where we cull partials. float centsToCull = rangeIndex * m_centsPerRange;
// A value from 0 -> 1 representing what fraction of the partials to keep. float cullingScale = fdlibm_exp2f(-centsToCull / 1200);
// The very top range will have all the partials culled. unsigned numberOfPartials = cullingScale * maxNumberOfPartials();
return numberOfPartials;
}
// Convert into time-domain wave buffers. // 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, unsigned rangeIndex) { unsigned fftSize = m_periodicWaveSize; unsigned i;
// 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);
// Limit number of partials to those below Nyquist frequency float nyquist = 0.5 * m_sampleRate; if (fundamentalFrequency != 0.0) {
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.
m_bandLimitedTables[rangeIndex] =
MakeUnique<AlignedAudioFloatArray>(m_periodicWaveSize);
// Apply an inverse FFT to generate the time-domain table data. float* data = m_bandLimitedTables[rangeIndex]->Elements();
frame.GetInverse(data);
// For the first range (which has the highest power), calculate // its peak value then compute normalization scale. if (m_disableNormalization) { // See Bug 1424906, results need to be scaled by 0.5 even // when normalization is disabled.
m_normalizationScale = 0.5;
} elseif (!rangeIndex) { float maxValue;
maxValue = AudioBufferPeakValue(data, m_periodicWaveSize);
if (maxValue) m_normalizationScale = 1.0f / maxValue;
}
// Clear DC and imag value which is ignored.
realP[0] = 0;
imagP[0] = 0;
for (unsigned n = 1; n < halfSize; ++n) { float omega = 2 * piFloat * n; float invOmega = 1 / omega;
// Fourier coefficients according to standard definition. float a; // Coefficient for cos(). float b; // Coefficient for sin().
// Calculate Fourier coefficients depending on the shape. // Note that the overall scaling (magnitude) of the waveforms // is normalized in createBandLimitedTables(). switch (shape) { case OscillatorType::Sine: // Standard sine wave function.
a = 0;
b = (n == 1) ? 1 : 0; break; case OscillatorType::Square: // Square-shaped waveform with the first half its maximum value // and the second half its minimum value.
a = 0;
b = invOmega * ((n & 1) ? 2 : 0); break; case OscillatorType::Sawtooth: // Sawtooth-shaped waveform with the first half ramping from // zero to maximum and the second half from minimum to zero.
a = 0;
b = -invOmega * fdlibm_cos(0.5 * omega); break; case OscillatorType::Triangle: // Triangle-shaped waveform going from its maximum value to // its minimum value then back to the maximum value.
a = 0; if (n & 1) {
b = 2 * (2 / (n * piFloat) * 2 / (n * piFloat)) *
((((n - 1) >> 1) & 1) ? -1 : 1);
} else {
b = 0;
} break; default:
MOZ_ASSERT_UNREACHABLE("invalid oscillator type");
a = 0;
b = 0; break;
}
realP[n] = a;
imagP[n] = b;
}
}
} // namespace WebCore
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.