2
* Copyright (C) 2012 Google Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14
* its contributors may be used to endorse or promote products derived
15
* from this software without specific prior written permission.
17
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
#include "WaveTable.h"
36
#include "OscillatorNode.h"
37
#include "VectorMath.h"
39
#include <wtf/OwnPtr.h>
41
const unsigned WaveTableSize = 4096; // This must be a power of two.
42
const unsigned NumberOfRanges = 36; // There should be 3 * log2(WaveTableSize) 1/3 octave ranges.
43
const float CentsPerRange = 1200 / 3; // 1/3 Octave.
47
using namespace VectorMath;
49
PassRefPtr<WaveTable> WaveTable::create(float sampleRate, Float32Array* real, Float32Array* imag)
51
bool isGood = real && imag && real->length() == imag->length();
54
RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
55
size_t numberOfComponents = real->length();
56
waveTable->createBandLimitedTables(real->data(), imag->data(), numberOfComponents);
62
PassRefPtr<WaveTable> WaveTable::createSine(float sampleRate)
64
RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
65
waveTable->generateBasicWaveform(OscillatorNode::SINE);
69
PassRefPtr<WaveTable> WaveTable::createSquare(float sampleRate)
71
RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
72
waveTable->generateBasicWaveform(OscillatorNode::SQUARE);
76
PassRefPtr<WaveTable> WaveTable::createSawtooth(float sampleRate)
78
RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
79
waveTable->generateBasicWaveform(OscillatorNode::SAWTOOTH);
83
PassRefPtr<WaveTable> WaveTable::createTriangle(float sampleRate)
85
RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
86
waveTable->generateBasicWaveform(OscillatorNode::TRIANGLE);
90
WaveTable::WaveTable(float sampleRate)
91
: m_sampleRate(sampleRate)
92
, m_waveTableSize(WaveTableSize)
93
, m_numberOfRanges(NumberOfRanges)
94
, m_centsPerRange(CentsPerRange)
96
float nyquist = 0.5 * m_sampleRate;
97
m_lowestFundamentalFrequency = nyquist / maxNumberOfPartials();
98
m_rateScale = m_waveTableSize / m_sampleRate;
101
void WaveTable::waveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData, float& tableInterpolationFactor)
103
// Negative frequencies are allowed, in which case we alias to the positive frequency.
104
fundamentalFrequency = fabsf(fundamentalFrequency);
106
// Calculate the pitch range.
107
float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / m_lowestFundamentalFrequency : 0.5;
108
float centsAboveLowestFrequency = log2f(ratio) * 1200;
110
// Add one to round-up to the next range just in time to truncate partials before aliasing occurs.
111
float pitchRange = 1 + centsAboveLowestFrequency / m_centsPerRange;
113
pitchRange = std::max(pitchRange, 0.0f);
114
pitchRange = std::min(pitchRange, static_cast<float>(m_numberOfRanges - 1));
116
// The words "lower" and "higher" refer to the table data having the lower and higher numbers of partials.
117
// It's a little confusing since the range index gets larger the more partials we cull out.
118
// So the lower table data will have a larger range index.
119
unsigned rangeIndex1 = static_cast<unsigned>(pitchRange);
120
unsigned rangeIndex2 = rangeIndex1 < m_numberOfRanges - 1 ? rangeIndex1 + 1 : rangeIndex1;
122
lowerWaveData = m_bandLimitedTables[rangeIndex2]->data();
123
higherWaveData = m_bandLimitedTables[rangeIndex1]->data();
125
// Ranges from 0 -> 1 to interpolate between lower -> higher.
126
tableInterpolationFactor = pitchRange - rangeIndex1;
129
unsigned WaveTable::maxNumberOfPartials() const
131
return m_waveTableSize / 2;
134
unsigned WaveTable::numberOfPartialsForRange(unsigned rangeIndex) const
136
// Number of cents below nyquist where we cull partials.
137
float centsToCull = rangeIndex * m_centsPerRange;
139
// A value from 0 -> 1 representing what fraction of the partials to keep.
140
float cullingScale = pow(2, -centsToCull / 1200);
142
// The very top range will have all the partials culled.
143
unsigned numberOfPartials = cullingScale * maxNumberOfPartials();
145
return numberOfPartials;
148
// Convert into time-domain wave tables.
149
// One table is created for each range for non-aliasing playback at different playback rates.
150
// Thus, higher ranges have more high-frequency partials culled out.
151
void WaveTable::createBandLimitedTables(const float* realData, const float* imagData, unsigned numberOfComponents)
153
float normalizationScale = 1;
155
unsigned fftSize = m_waveTableSize;
156
unsigned halfSize = fftSize / 2;
159
numberOfComponents = std::min(numberOfComponents, halfSize);
161
m_bandLimitedTables.reserveCapacity(m_numberOfRanges);
163
for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) {
164
// This FFTFrame is used to cull partials (represented by frequency bins).
165
FFTFrame frame(fftSize);
166
float* realP = frame.realData();
167
float* imagP = frame.imagData();
169
// Copy from loaded frequency data and scale.
170
float scale = fftSize;
171
vsmul(realData, 1, &scale, realP, 1, numberOfComponents);
172
vsmul(imagData, 1, &scale, imagP, 1, numberOfComponents);
174
// If fewer components were provided than 1/2 FFT size, then clear the remaining bins.
175
for (i = numberOfComponents; i < halfSize; ++i) {
180
// Generate complex conjugate because of the way the inverse FFT is defined.
182
vsmul(imagP, 1, &minusOne, imagP, 1, halfSize);
184
// Find the starting bin where we should start culling.
185
// We need to clear out the highest frequencies to band-limit the waveform.
186
unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex);
188
// Cull the aliasing partials for this pitch range.
189
for (i = numberOfPartials + 1; i < halfSize; ++i) {
193
// Clear packed-nyquist if necessary.
194
if (numberOfPartials < halfSize)
197
// Clear any DC-offset.
200
// Create the band-limited table.
201
OwnPtr<AudioFloatArray> table = adoptPtr(new AudioFloatArray(m_waveTableSize));
202
m_bandLimitedTables.append(table.release());
204
// Apply an inverse FFT to generate the time-domain table data.
205
float* data = m_bandLimitedTables[rangeIndex]->data();
206
frame.doInverseFFT(data);
208
// For the first range (which has the highest power), calculate its peak value then compute normalization scale.
211
vmaxmgv(data, 1, &maxValue, m_waveTableSize);
214
normalizationScale = 1.0f / maxValue;
217
// Apply normalization scale.
218
vsmul(data, 1, &normalizationScale, data, 1, m_waveTableSize);
222
void WaveTable::generateBasicWaveform(int shape)
224
unsigned fftSize = waveTableSize();
225
unsigned halfSize = fftSize / 2;
227
AudioFloatArray real(halfSize);
228
AudioFloatArray imag(halfSize);
229
float* realP = real.data();
230
float* imagP = imag.data();
232
// Clear DC and Nyquist.
236
for (unsigned n = 1; n < halfSize; ++n) {
237
float omega = 2 * piFloat * n;
238
float invOmega = 1 / omega;
240
// Fourier coefficients according to standard definition.
241
float a; // Coefficient for cos().
242
float b; // Coefficient for sin().
244
// Calculate Fourier coefficients depending on the shape.
245
// Note that the overall scaling (magnitude) of the waveforms is normalized in createBandLimitedTables().
247
case OscillatorNode::SINE:
248
// Standard sine wave function.
250
b = (n == 1) ? 1 : 0;
252
case OscillatorNode::SQUARE:
253
// Square-shaped waveform with the first half its maximum value and the second half its minimum value.
255
b = invOmega * ((n & 1) ? 2 : 0);
257
case OscillatorNode::SAWTOOTH:
258
// Sawtooth-shaped waveform with the first half ramping from zero to maximum and the second half from minimum to zero.
260
b = -invOmega * cos(0.5 * omega);
262
case OscillatorNode::TRIANGLE:
263
// Triangle-shaped waveform going from its maximum value to its minimum value then back to the maximum value.
264
a = (4 - 4 * cos(0.5 * omega)) / (n * n * piFloat * piFloat);
268
ASSERT_NOT_REACHED();
278
createBandLimitedTables(realP, imagP, halfSize);
281
} // namespace WebCore
283
#endif // ENABLE(WEB_AUDIO)