MCPcopy Create free account
hub / github.com/LabSound/LabSound / createBandLimitedTables

Method createBandLimitedTables

src/core/PeriodicWave.cpp:137–200  ·  view source on GitHub ↗

Convert into time-domain wave tables. One table is created for each range for non-aliasing playback at different playback rates. Thus, higher ranges have more high-frequency partials culled out.

Source from the content-addressed store, hash-verified

135// One table is created for each range for non-aliasing playback at different playback rates.
136// Thus, higher ranges have more high-frequency partials culled out.
137void PeriodicWave::createBandLimitedTables(const float * realData, const float * imagData, int numberOfComponents)
138{
139 float normalizationScale = 1.f;
140
141 int fftSize = periodicWaveSize();
142 int halfSize = fftSize / 2 + 1;
143 int i;
144
145 numberOfComponents = std::min(numberOfComponents, halfSize);
146
147 m_bandLimitedTables.reserve(numberOfRanges());
148
149 for (int rangeIndex = 0; rangeIndex < numberOfRanges(); ++rangeIndex)
150 {
151
152 // This FFTFrame is used to cull partials (represented by frequency bins).
153 FFTFrame frame(fftSize);
154 float * realP = frame.realData();
155 float * imagP = frame.imagData();
156
157 // Copy from loaded frequency data and generate the complex conjugate because of the way the
158 // inverse FFT is defined versus the values in the arrays. Note also that although the IFFT
159 // does a scaling by 1/N, we take care of this when the normalization scaling is done.
160 float minusOne = -1;
161 memcpy(realP, realData, numberOfComponents * sizeof(*realP));
162 vsmul(imagData, 1, &minusOne, imagP, 1, numberOfComponents);
163
164 // Find the starting bin where we should start culling. We need to clear out the highest
165 // frequencies to band-limit the waveform.
166 int numberOfPartials = numberOfPartialsForRange(rangeIndex);
167
168 // If fewer components were provided than 1/2 FFT size, then clear the remaining bins.
169 // We also need to cull the aliasing partials for this pitch range.
170 for (i = std::min(numberOfComponents, numberOfPartials + 1); i < halfSize; ++i)
171 {
172 realP[i] = 0;
173 imagP[i] = 0;
174 }
175
176 // Clear packed-nyquist and any DC-offset.
177 realP[0] = 0;
178 imagP[0] = 0;
179
180 // Create the band-limited table.
181 m_bandLimitedTables.push_back(std::unique_ptr<lab::AudioFloatArray>(new lab::AudioFloatArray(periodicWaveSize())));
182
183 // Apply an inverse FFT to generate the time-domain table data.
184 float * data = m_bandLimitedTables[rangeIndex]->data();
185 frame.computeInverseFFT(data);
186
187 // For the first range (which has the highest power), calculate its peak value then compute normalization scale.
188 if (!rangeIndex)
189 {
190 float maxValue;
191 vmaxmgv(data, 1, &maxValue, fftSize);
192
193 if (maxValue)
194 normalizationScale = 1.0f / maxValue;

Callers

nothing calls this directly

Calls 6

vsmulFunction · 0.85
vmaxmgvFunction · 0.85
realDataMethod · 0.45
imagDataMethod · 0.45
dataMethod · 0.45
computeInverseFFTMethod · 0.45

Tested by

no test coverage detected