Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Side by Side Diff: Source/modules/webaudio/PeriodicWave.cpp

Issue 1180613007: Allow larger arrays up to size 8192 for PeriodicWave (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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());
hongchan 2015/07/22 22:30:32 I am aware that it is not a critical or relevant c
Raymond Toy 2015/07/23 18:23:05 Despite what I said (offline), I don't want to do
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
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)
OLDNEW
« LayoutTests/webaudio/resources/audio-testing.js ('K') | « Source/modules/webaudio/PeriodicWave.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698