Chromium Code Reviews| 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()); |
|
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 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 |