OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 19 matching lines...) Expand all Loading... |
30 #if ENABLE(WEB_AUDIO) | 30 #if ENABLE(WEB_AUDIO) |
31 #include "modules/webaudio/PeriodicWave.h" | 31 #include "modules/webaudio/PeriodicWave.h" |
32 | 32 |
33 #include "modules/webaudio/OscillatorNode.h" | 33 #include "modules/webaudio/OscillatorNode.h" |
34 #include "platform/audio/FFTFrame.h" | 34 #include "platform/audio/FFTFrame.h" |
35 #include "platform/audio/VectorMath.h" | 35 #include "platform/audio/VectorMath.h" |
36 #include <algorithm> | 36 #include <algorithm> |
37 | 37 |
38 namespace blink { | 38 namespace blink { |
39 | 39 |
40 const unsigned PeriodicWaveSize = 4096; // This must be a power of two. | 40 // The number of bands per octave. Each octave will have this many entries in t
he wave tables. |
41 const unsigned NumberOfRanges = 36; // There should be 3 * log2(PeriodicWaveSize
) 1/3 octave ranges. | 41 const unsigned kNumberOfOctaveBands = 3; |
42 const float CentsPerRange = 1200 / 3; // 1/3 Octave. | |
43 | 42 |
44 const unsigned PeriodicWave::kMaxPeriodicWaveArraySize = PeriodicWaveSize / 2; | 43 // The max length of a periodic wave. This must be a power of two greater than o
r equal to 2048 and |
| 44 // must be supported by the FFT routines. |
| 45 const unsigned kMaxPeriodicWaveSize = 16384; |
| 46 |
| 47 const float CentsPerRange = 1200 / kNumberOfOctaveBands; |
45 | 48 |
46 using namespace VectorMath; | 49 using namespace VectorMath; |
47 | 50 |
48 PeriodicWave* PeriodicWave::create(float sampleRate, DOMFloat32Array* real, DOMF
loat32Array* imag) | 51 PeriodicWave* PeriodicWave::create(float sampleRate, DOMFloat32Array* real, DOMF
loat32Array* imag) |
49 { | 52 { |
50 bool isGood = real && imag && real->length() == imag->length(); | 53 bool isGood = real && imag && real->length() == imag->length(); |
51 ASSERT(isGood); | 54 ASSERT(isGood); |
52 if (isGood) { | 55 if (isGood) { |
53 PeriodicWave* periodicWave = new PeriodicWave(sampleRate); | 56 PeriodicWave* periodicWave = new PeriodicWave(sampleRate); |
54 size_t numberOfComponents = real->length(); | 57 size_t numberOfComponents = real->length(); |
(...skipping 26 matching lines...) Expand all Loading... |
81 | 84 |
82 PeriodicWave* PeriodicWave::createTriangle(float sampleRate) | 85 PeriodicWave* PeriodicWave::createTriangle(float sampleRate) |
83 { | 86 { |
84 PeriodicWave* periodicWave = new PeriodicWave(sampleRate); | 87 PeriodicWave* periodicWave = new PeriodicWave(sampleRate); |
85 periodicWave->generateBasicWaveform(OscillatorHandler::TRIANGLE); | 88 periodicWave->generateBasicWaveform(OscillatorHandler::TRIANGLE); |
86 return periodicWave; | 89 return periodicWave; |
87 } | 90 } |
88 | 91 |
89 PeriodicWave::PeriodicWave(float sampleRate) | 92 PeriodicWave::PeriodicWave(float sampleRate) |
90 : m_sampleRate(sampleRate) | 93 : m_sampleRate(sampleRate) |
91 , m_periodicWaveSize(PeriodicWaveSize) | |
92 , m_numberOfRanges(NumberOfRanges) | |
93 , m_centsPerRange(CentsPerRange) | 94 , m_centsPerRange(CentsPerRange) |
94 { | 95 { |
95 float nyquist = 0.5 * m_sampleRate; | 96 float nyquist = 0.5 * m_sampleRate; |
96 m_lowestFundamentalFrequency = nyquist / maxNumberOfPartials(); | 97 m_lowestFundamentalFrequency = nyquist / maxNumberOfPartials(); |
97 m_rateScale = m_periodicWaveSize / m_sampleRate; | 98 m_rateScale = periodicWaveSize() / m_sampleRate; |
| 99 // Compute the number of ranges needed to cover the entire frequency range,
assuming |
| 100 // kNumberOfOctaveBands per octave. |
| 101 m_numberOfRanges = 0.5 + kNumberOfOctaveBands * log2f(periodicWaveSize()); |
| 102 } |
| 103 |
| 104 unsigned PeriodicWave::periodicWaveSize() const |
| 105 { |
| 106 // Choose an appropriate wave size for the given sample rate. This allows u
s to use shorter |
| 107 // FFTs when possible to limit the complexity. The breakpoints here are som
ewhat arbitrary, but |
| 108 // we want sample rates around 44.1 kHz or so to have a size of 4096 to pres
erve backward |
| 109 // compatibility. |
| 110 if (m_sampleRate <= 24000) { |
| 111 return 2048; |
| 112 } |
| 113 |
| 114 if (m_sampleRate <= 88200) { |
| 115 return 4096; |
| 116 } |
| 117 |
| 118 return kMaxPeriodicWaveSize; |
| 119 } |
| 120 |
| 121 unsigned PeriodicWave::maxNumberOfPartials() const |
| 122 { |
| 123 return periodicWaveSize() / 2; |
98 } | 124 } |
99 | 125 |
100 void PeriodicWave::waveDataForFundamentalFrequency(float fundamentalFrequency, f
loat*& lowerWaveData, float*& higherWaveData, float& tableInterpolationFactor) | 126 void PeriodicWave::waveDataForFundamentalFrequency(float fundamentalFrequency, f
loat*& lowerWaveData, float*& higherWaveData, float& tableInterpolationFactor) |
101 { | 127 { |
102 // Negative frequencies are allowed, in which case we alias to the positive
frequency. | 128 // Negative frequencies are allowed, in which case we alias to the positive
frequency. |
103 fundamentalFrequency = fabsf(fundamentalFrequency); | 129 fundamentalFrequency = fabsf(fundamentalFrequency); |
104 | 130 |
105 // Calculate the pitch range. | 131 // Calculate the pitch range. |
106 float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / m_lowestFund
amentalFrequency : 0.5; | 132 float ratio = fundamentalFrequency > 0 ? fundamentalFrequency / m_lowestFund
amentalFrequency : 0.5; |
107 float centsAboveLowestFrequency = log2f(ratio) * 1200; | 133 float centsAboveLowestFrequency = log2f(ratio) * 1200; |
108 | 134 |
109 // Add one to round-up to the next range just in time to truncate partials b
efore aliasing occurs. | 135 // Add one to round-up to the next range just in time to truncate partials b
efore aliasing occurs. |
110 float pitchRange = 1 + centsAboveLowestFrequency / m_centsPerRange; | 136 float pitchRange = 1 + centsAboveLowestFrequency / m_centsPerRange; |
111 | 137 |
112 pitchRange = std::max(pitchRange, 0.0f); | 138 pitchRange = std::max(pitchRange, 0.0f); |
113 pitchRange = std::min(pitchRange, static_cast<float>(m_numberOfRanges - 1)); | 139 pitchRange = std::min(pitchRange, static_cast<float>(numberOfRanges() - 1)); |
114 | 140 |
115 // The words "lower" and "higher" refer to the table data having the lower a
nd higher numbers of partials. | 141 // The words "lower" and "higher" refer to the table data having the lower a
nd higher numbers of partials. |
116 // It's a little confusing since the range index gets larger the more partia
ls we cull out. | 142 // It's a little confusing since the range index gets larger the more partia
ls we cull out. |
117 // So the lower table data will have a larger range index. | 143 // So the lower table data will have a larger range index. |
118 unsigned rangeIndex1 = static_cast<unsigned>(pitchRange); | 144 unsigned rangeIndex1 = static_cast<unsigned>(pitchRange); |
119 unsigned rangeIndex2 = rangeIndex1 < m_numberOfRanges - 1 ? rangeIndex1 + 1
: rangeIndex1; | 145 unsigned rangeIndex2 = rangeIndex1 < numberOfRanges() - 1 ? rangeIndex1 + 1
: rangeIndex1; |
120 | 146 |
121 lowerWaveData = m_bandLimitedTables[rangeIndex2]->data(); | 147 lowerWaveData = m_bandLimitedTables[rangeIndex2]->data(); |
122 higherWaveData = m_bandLimitedTables[rangeIndex1]->data(); | 148 higherWaveData = m_bandLimitedTables[rangeIndex1]->data(); |
123 | 149 |
124 // Ranges from 0 -> 1 to interpolate between lower -> higher. | 150 // Ranges from 0 -> 1 to interpolate between lower -> higher. |
125 tableInterpolationFactor = pitchRange - rangeIndex1; | 151 tableInterpolationFactor = pitchRange - rangeIndex1; |
126 } | 152 } |
127 | 153 |
128 unsigned PeriodicWave::maxNumberOfPartials() const | |
129 { | |
130 return m_periodicWaveSize / 2; | |
131 } | |
132 | |
133 unsigned PeriodicWave::numberOfPartialsForRange(unsigned rangeIndex) const | 154 unsigned PeriodicWave::numberOfPartialsForRange(unsigned rangeIndex) const |
134 { | 155 { |
135 // Number of cents below nyquist where we cull partials. | 156 // Number of cents below nyquist where we cull partials. |
136 float centsToCull = rangeIndex * m_centsPerRange; | 157 float centsToCull = rangeIndex * m_centsPerRange; |
137 | 158 |
138 // A value from 0 -> 1 representing what fraction of the partials to keep. | 159 // A value from 0 -> 1 representing what fraction of the partials to keep. |
139 float cullingScale = pow(2, -centsToCull / 1200); | 160 float cullingScale = pow(2, -centsToCull / 1200); |
140 | 161 |
141 // The very top range will have all the partials culled. | 162 // The very top range will have all the partials culled. |
142 unsigned numberOfPartials = cullingScale * maxNumberOfPartials(); | 163 unsigned numberOfPartials = cullingScale * maxNumberOfPartials(); |
143 | 164 |
144 return numberOfPartials; | 165 return numberOfPartials; |
145 } | 166 } |
146 | 167 |
147 // Convert into time-domain wave buffers. | 168 // Convert into time-domain wave buffers. |
148 // One table is created for each range for non-aliasing playback at different pl
ayback rates. | 169 // One table is created for each range for non-aliasing playback at different pl
ayback rates. |
149 // Thus, higher ranges have more high-frequency partials culled out. | 170 // Thus, higher ranges have more high-frequency partials culled out. |
150 void PeriodicWave::createBandLimitedTables(const float* realData, const float* i
magData, unsigned numberOfComponents) | 171 void PeriodicWave::createBandLimitedTables(const float* realData, const float* i
magData, unsigned numberOfComponents) |
151 { | 172 { |
152 float normalizationScale = 1; | 173 float normalizationScale = 1; |
153 | 174 |
154 unsigned fftSize = m_periodicWaveSize; | 175 unsigned fftSize = periodicWaveSize(); |
155 unsigned halfSize = fftSize / 2; | 176 unsigned halfSize = fftSize / 2; |
156 unsigned i; | 177 unsigned i; |
157 | 178 |
158 numberOfComponents = std::min(numberOfComponents, halfSize); | 179 numberOfComponents = std::min(numberOfComponents, halfSize); |
159 | 180 |
160 m_bandLimitedTables.reserveCapacity(m_numberOfRanges); | 181 m_bandLimitedTables.reserveCapacity(numberOfRanges()); |
161 | 182 |
162 for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) { | 183 for (unsigned rangeIndex = 0; rangeIndex < numberOfRanges(); ++rangeIndex) { |
163 // This FFTFrame is used to cull partials (represented by frequency bins
). | 184 // This FFTFrame is used to cull partials (represented by frequency bins
). |
164 FFTFrame frame(fftSize); | 185 FFTFrame frame(fftSize); |
165 float* realP = frame.realData(); | 186 float* realP = frame.realData(); |
166 float* imagP = frame.imagData(); | 187 float* imagP = frame.imagData(); |
167 | 188 |
168 // Copy from loaded frequency data and scale. | 189 // Copy from loaded frequency data and generate the complex conjugate be
cause of the way the |
169 float scale = fftSize; | 190 // inverse FFT is defined versus the values in the arrays. Note also th
at although the IFFT |
170 vsmul(realData, 1, &scale, realP, 1, numberOfComponents); | 191 // does a scaling by 1/N, we take care of this when the normalization sc
aling is done. |
171 vsmul(imagData, 1, &scale, imagP, 1, numberOfComponents); | 192 float minusOne = -1; |
| 193 memcpy(realP, realData, numberOfComponents * sizeof(*realP)); |
| 194 vsmul(imagData, 1, &minusOne, imagP, 1, numberOfComponents); |
| 195 |
| 196 // Find the starting bin where we should start culling. We need to clea
r out the highest |
| 197 // frequencies to band-limit the waveform. |
| 198 unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex); |
172 | 199 |
173 // If fewer components were provided than 1/2 FFT size, then clear the r
emaining bins. | 200 // If fewer components were provided than 1/2 FFT size, then clear the r
emaining bins. |
174 for (i = numberOfComponents; i < halfSize; ++i) { | 201 // We also need to cull the aliasing partials for this pitch range. |
| 202 for (i = std::min(numberOfComponents, numberOfPartials + 1); i < halfSiz
e; ++i) { |
175 realP[i] = 0; | 203 realP[i] = 0; |
176 imagP[i] = 0; | 204 imagP[i] = 0; |
177 } | 205 } |
178 | 206 |
179 // Generate complex conjugate because of the way the inverse FFT is defi
ned. | 207 // Clear packed-nyquist and any DC-offset. |
180 float minusOne = -1; | |
181 vsmul(imagP, 1, &minusOne, imagP, 1, halfSize); | |
182 | |
183 // Find the starting bin where we should start culling. | |
184 // We need to clear out the highest frequencies to band-limit the wavefo
rm. | |
185 unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex); | |
186 | |
187 // Cull the aliasing partials for this pitch range. | |
188 for (i = numberOfPartials + 1; i < halfSize; ++i) { | |
189 realP[i] = 0; | |
190 imagP[i] = 0; | |
191 } | |
192 // Clear packed-nyquist if necessary. | |
193 if (numberOfPartials < halfSize) | |
194 imagP[0] = 0; | |
195 | |
196 // Clear any DC-offset. | |
197 realP[0] = 0; | 208 realP[0] = 0; |
| 209 imagP[0] = 0; |
198 | 210 |
199 // Create the band-limited table. | 211 // Create the band-limited table. |
200 OwnPtr<AudioFloatArray> table = adoptPtr(new AudioFloatArray(m_periodicW
aveSize)); | 212 OwnPtr<AudioFloatArray> table = adoptPtr(new AudioFloatArray(periodicWav
eSize())); |
201 m_bandLimitedTables.append(table.release()); | 213 m_bandLimitedTables.append(table.release()); |
202 | 214 |
203 // Apply an inverse FFT to generate the time-domain table data. | 215 // Apply an inverse FFT to generate the time-domain table data. |
204 float* data = m_bandLimitedTables[rangeIndex]->data(); | 216 float* data = m_bandLimitedTables[rangeIndex]->data(); |
205 frame.doInverseFFT(data); | 217 frame.doInverseFFT(data); |
206 | 218 |
207 // For the first range (which has the highest power), calculate its peak
value then compute normalization scale. | 219 // For the first range (which has the highest power), calculate its peak
value then compute normalization scale. |
208 if (!rangeIndex) { | 220 if (!rangeIndex) { |
209 float maxValue; | 221 float maxValue; |
210 vmaxmgv(data, 1, &maxValue, m_periodicWaveSize); | 222 vmaxmgv(data, 1, &maxValue, fftSize); |
211 | 223 |
212 if (maxValue) | 224 if (maxValue) |
213 normalizationScale = 1.0f / maxValue; | 225 normalizationScale = 1.0f / maxValue; |
214 } | 226 } |
215 | 227 |
216 // Apply normalization scale. | 228 // Apply normalization scale. |
217 vsmul(data, 1, &normalizationScale, data, 1, m_periodicWaveSize); | 229 vsmul(data, 1, &normalizationScale, data, 1, fftSize); |
218 } | 230 } |
219 } | 231 } |
220 | 232 |
221 void PeriodicWave::generateBasicWaveform(int shape) | 233 void PeriodicWave::generateBasicWaveform(int shape) |
222 { | 234 { |
223 unsigned fftSize = periodicWaveSize(); | 235 unsigned fftSize = periodicWaveSize(); |
224 unsigned halfSize = fftSize / 2; | 236 unsigned halfSize = fftSize / 2; |
225 | 237 |
226 AudioFloatArray real(halfSize); | 238 AudioFloatArray real(halfSize); |
227 AudioFloatArray imag(halfSize); | 239 AudioFloatArray imag(halfSize); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 realP[n] = 0; | 307 realP[n] = 0; |
296 imagP[n] = b; | 308 imagP[n] = b; |
297 } | 309 } |
298 | 310 |
299 createBandLimitedTables(realP, imagP, halfSize); | 311 createBandLimitedTables(realP, imagP, halfSize); |
300 } | 312 } |
301 | 313 |
302 } // namespace blink | 314 } // namespace blink |
303 | 315 |
304 #endif // ENABLE(WEB_AUDIO) | 316 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |