~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/Modules/webaudio/WaveTable.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2012 Google Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 *
 
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.
 
16
 *
 
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.
 
27
 */
 
28
 
 
29
#include "config.h"
 
30
 
 
31
#if ENABLE(WEB_AUDIO)
 
32
 
 
33
#include "WaveTable.h"
 
34
 
 
35
#include "FFTFrame.h"
 
36
#include "OscillatorNode.h"
 
37
#include "VectorMath.h"
 
38
#include <algorithm>
 
39
#include <wtf/OwnPtr.h>
 
40
 
 
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.
 
44
 
 
45
namespace WebCore {
 
46
    
 
47
using namespace VectorMath;
 
48
 
 
49
PassRefPtr<WaveTable> WaveTable::create(float sampleRate, Float32Array* real, Float32Array* imag)
 
50
{
 
51
    bool isGood = real && imag && real->length() == imag->length();
 
52
    ASSERT(isGood);
 
53
    if (isGood) {
 
54
        RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
 
55
        size_t numberOfComponents = real->length();
 
56
        waveTable->createBandLimitedTables(real->data(), imag->data(), numberOfComponents);
 
57
        return waveTable;
 
58
    }
 
59
    return 0;
 
60
}
 
61
 
 
62
PassRefPtr<WaveTable> WaveTable::createSine(float sampleRate)
 
63
{
 
64
    RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
 
65
    waveTable->generateBasicWaveform(OscillatorNode::SINE);
 
66
    return waveTable;
 
67
}
 
68
 
 
69
PassRefPtr<WaveTable> WaveTable::createSquare(float sampleRate)
 
70
{
 
71
    RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
 
72
    waveTable->generateBasicWaveform(OscillatorNode::SQUARE);
 
73
    return waveTable;
 
74
}
 
75
 
 
76
PassRefPtr<WaveTable> WaveTable::createSawtooth(float sampleRate)
 
77
{
 
78
    RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
 
79
    waveTable->generateBasicWaveform(OscillatorNode::SAWTOOTH);
 
80
    return waveTable;
 
81
}
 
82
 
 
83
PassRefPtr<WaveTable> WaveTable::createTriangle(float sampleRate)
 
84
{
 
85
    RefPtr<WaveTable> waveTable = adoptRef(new WaveTable(sampleRate));
 
86
    waveTable->generateBasicWaveform(OscillatorNode::TRIANGLE);
 
87
    return waveTable;
 
88
}
 
89
 
 
90
WaveTable::WaveTable(float sampleRate)
 
91
    : m_sampleRate(sampleRate)
 
92
    , m_waveTableSize(WaveTableSize)
 
93
    , m_numberOfRanges(NumberOfRanges)
 
94
    , m_centsPerRange(CentsPerRange)
 
95
{
 
96
    float nyquist = 0.5 * m_sampleRate;
 
97
    m_lowestFundamentalFrequency = nyquist / maxNumberOfPartials();
 
98
    m_rateScale = m_waveTableSize / m_sampleRate;
 
99
}
 
100
 
 
101
void WaveTable::waveDataForFundamentalFrequency(float fundamentalFrequency, float* &lowerWaveData, float* &higherWaveData, float& tableInterpolationFactor)
 
102
{
 
103
    // Negative frequencies are allowed, in which case we alias to the positive frequency.
 
104
    fundamentalFrequency = fabsf(fundamentalFrequency);
 
105
 
 
106
    // Calculate the pitch range.
 
107
    float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / m_lowestFundamentalFrequency : 0.5;
 
108
    float centsAboveLowestFrequency = log2f(ratio) * 1200;
 
109
 
 
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;
 
112
 
 
113
    pitchRange = std::max(pitchRange, 0.0f);
 
114
    pitchRange = std::min(pitchRange, static_cast<float>(m_numberOfRanges - 1));
 
115
 
 
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;
 
121
 
 
122
    lowerWaveData = m_bandLimitedTables[rangeIndex2]->data();
 
123
    higherWaveData = m_bandLimitedTables[rangeIndex1]->data();
 
124
    
 
125
    // Ranges from 0 -> 1 to interpolate between lower -> higher.
 
126
    tableInterpolationFactor = pitchRange - rangeIndex1;
 
127
}
 
128
 
 
129
unsigned WaveTable::maxNumberOfPartials() const
 
130
{
 
131
    return m_waveTableSize / 2;
 
132
}
 
133
 
 
134
unsigned WaveTable::numberOfPartialsForRange(unsigned rangeIndex) const
 
135
{
 
136
    // Number of cents below nyquist where we cull partials.
 
137
    float centsToCull = rangeIndex * m_centsPerRange;
 
138
 
 
139
    // A value from 0 -> 1 representing what fraction of the partials to keep.
 
140
    float cullingScale = pow(2, -centsToCull / 1200);
 
141
 
 
142
    // The very top range will have all the partials culled.
 
143
    unsigned numberOfPartials = cullingScale * maxNumberOfPartials();
 
144
 
 
145
    return numberOfPartials;
 
146
}
 
147
 
 
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)
 
152
{
 
153
    float normalizationScale = 1;
 
154
 
 
155
    unsigned fftSize = m_waveTableSize;
 
156
    unsigned halfSize = fftSize / 2;
 
157
    unsigned i;
 
158
    
 
159
    numberOfComponents = std::min(numberOfComponents, halfSize);
 
160
 
 
161
    m_bandLimitedTables.reserveCapacity(m_numberOfRanges);
 
162
 
 
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();
 
168
 
 
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);
 
173
 
 
174
        // If fewer components were provided than 1/2 FFT size, then clear the remaining bins.
 
175
        for (i = numberOfComponents; i < halfSize; ++i) {
 
176
            realP[i] = 0;
 
177
            imagP[i] = 0;
 
178
        }
 
179
        
 
180
        // Generate complex conjugate because of the way the inverse FFT is defined.
 
181
        float minusOne = -1;
 
182
        vsmul(imagP, 1, &minusOne, imagP, 1, halfSize);
 
183
 
 
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);
 
187
 
 
188
        // Cull the aliasing partials for this pitch range.
 
189
        for (i = numberOfPartials + 1; i < halfSize; ++i) {
 
190
            realP[i] = 0;
 
191
            imagP[i] = 0;
 
192
        }
 
193
        // Clear packed-nyquist if necessary.
 
194
        if (numberOfPartials < halfSize)
 
195
            imagP[0] = 0;
 
196
 
 
197
        // Clear any DC-offset.
 
198
        realP[0] = 0;
 
199
 
 
200
        // Create the band-limited table.
 
201
        OwnPtr<AudioFloatArray> table = adoptPtr(new AudioFloatArray(m_waveTableSize));
 
202
        m_bandLimitedTables.append(table.release());
 
203
 
 
204
        // Apply an inverse FFT to generate the time-domain table data.
 
205
        float* data = m_bandLimitedTables[rangeIndex]->data();
 
206
        frame.doInverseFFT(data);
 
207
 
 
208
        // For the first range (which has the highest power), calculate its peak value then compute normalization scale.
 
209
        if (!rangeIndex) {
 
210
            float maxValue;
 
211
            vmaxmgv(data, 1, &maxValue, m_waveTableSize);
 
212
 
 
213
            if (maxValue)
 
214
                normalizationScale = 1.0f / maxValue;
 
215
        }
 
216
 
 
217
        // Apply normalization scale.
 
218
        vsmul(data, 1, &normalizationScale, data, 1, m_waveTableSize);          
 
219
    }
 
220
}
 
221
 
 
222
void WaveTable::generateBasicWaveform(int shape)
 
223
{
 
224
    unsigned fftSize = waveTableSize();
 
225
    unsigned halfSize = fftSize / 2;
 
226
 
 
227
    AudioFloatArray real(halfSize);
 
228
    AudioFloatArray imag(halfSize);
 
229
    float* realP = real.data();
 
230
    float* imagP = imag.data();
 
231
 
 
232
    // Clear DC and Nyquist.
 
233
    realP[0] = 0;
 
234
    imagP[0] = 0;
 
235
 
 
236
    for (unsigned n = 1; n < halfSize; ++n) {
 
237
        float omega = 2 * piFloat * n;
 
238
        float invOmega = 1 / omega;
 
239
 
 
240
        // Fourier coefficients according to standard definition.
 
241
        float a; // Coefficient for cos().
 
242
        float b; // Coefficient for sin().
 
243
 
 
244
        // Calculate Fourier coefficients depending on the shape.
 
245
        // Note that the overall scaling (magnitude) of the waveforms is normalized in createBandLimitedTables().
 
246
        switch (shape) {
 
247
        case OscillatorNode::SINE:
 
248
            // Standard sine wave function.
 
249
            a = 0;
 
250
            b = (n == 1) ? 1 : 0;
 
251
            break;
 
252
        case OscillatorNode::SQUARE:
 
253
            // Square-shaped waveform with the first half its maximum value and the second half its minimum value.
 
254
            a = 0;
 
255
            b = invOmega * ((n & 1) ? 2 : 0);
 
256
            break;
 
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.
 
259
            a = 0;
 
260
            b = -invOmega * cos(0.5 * omega);
 
261
            break;
 
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);
 
265
            b = 0;
 
266
            break;
 
267
        default:
 
268
            ASSERT_NOT_REACHED();
 
269
            a = 0;
 
270
            b = 0;
 
271
            break;
 
272
        }
 
273
 
 
274
        realP[n] = a;
 
275
        imagP[n] = b;
 
276
    }
 
277
 
 
278
    createBandLimitedTables(realP, imagP, halfSize);
 
279
}
 
280
 
 
281
} // namespace WebCore
 
282
 
 
283
#endif // ENABLE(WEB_AUDIO)