Make MAX_RESAMPLER_PADDING specify the total padding
[openal-soft.git] / alc / effects / pshifter.cpp
blobd7ba072e3ce5e57e44594808766530f52acbfa6a
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2018 by Raul Herraiz.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #ifdef HAVE_SSE_INTRINSICS
24 #include <emmintrin.h>
25 #endif
27 #include <cmath>
28 #include <cstdlib>
29 #include <array>
30 #include <complex>
31 #include <algorithm>
33 #include "al/auxeffectslot.h"
34 #include "alcmain.h"
35 #include "alcomplex.h"
36 #include "alcontext.h"
37 #include "alnumeric.h"
38 #include "alu.h"
41 namespace {
43 using complex_d = std::complex<double>;
45 #define STFT_SIZE 1024
46 #define STFT_HALF_SIZE (STFT_SIZE>>1)
47 #define OVERSAMP (1<<2)
49 #define STFT_STEP (STFT_SIZE / OVERSAMP)
50 #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1))
52 /* Define a Hann window, used to filter the STFT input and output. */
53 /* Making this constexpr seems to require C++14. */
54 std::array<ALdouble,STFT_SIZE> InitHannWindow()
56 std::array<ALdouble,STFT_SIZE> ret;
57 /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */
58 for(size_t i{0};i < STFT_SIZE>>1;i++)
60 constexpr double scale{al::MathDefs<double>::Pi() / double{STFT_SIZE-1}};
61 const double val{std::sin(static_cast<double>(i) * scale)};
62 ret[i] = ret[STFT_SIZE-1-i] = val * val;
64 return ret;
66 alignas(16) const std::array<ALdouble,STFT_SIZE> HannWindow = InitHannWindow();
69 struct ALphasor {
70 ALdouble Amplitude;
71 ALdouble Phase;
74 struct ALfrequencyDomain {
75 ALdouble Amplitude;
76 ALdouble Frequency;
80 /* Converts complex to ALphasor */
81 inline ALphasor rect2polar(const complex_d &number)
83 ALphasor polar;
84 polar.Amplitude = std::abs(number);
85 polar.Phase = std::arg(number);
86 return polar;
89 /* Converts ALphasor to complex */
90 inline complex_d polar2rect(const ALphasor &number)
91 { return std::polar<double>(number.Amplitude, number.Phase); }
94 struct PshifterState final : public EffectState {
95 /* Effect parameters */
96 size_t mCount;
97 ALuint mPitchShiftI;
98 ALfloat mPitchShift;
99 ALfloat mFreqPerBin;
101 /* Effects buffers */
102 ALfloat mInFIFO[STFT_SIZE];
103 ALfloat mOutFIFO[STFT_STEP];
104 ALdouble mLastPhase[STFT_HALF_SIZE+1];
105 ALdouble mSumPhase[STFT_HALF_SIZE+1];
106 ALdouble mOutputAccum[STFT_SIZE];
108 complex_d mFFTbuffer[STFT_SIZE];
110 ALfrequencyDomain mAnalysis_buffer[STFT_HALF_SIZE+1];
111 ALfrequencyDomain mSyntesis_buffer[STFT_HALF_SIZE+1];
113 alignas(16) ALfloat mBufferOut[BUFFERSIZE];
115 /* Effect gains for each output channel */
116 ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS];
117 ALfloat mTargetGains[MAX_OUTPUT_CHANNELS];
120 ALboolean deviceUpdate(const ALCdevice *device) override;
121 void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override;
122 void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut) override;
124 DEF_NEWDEL(PshifterState)
127 ALboolean PshifterState::deviceUpdate(const ALCdevice *device)
129 /* (Re-)initializing parameters and clear the buffers. */
130 mCount = FIFO_LATENCY;
131 mPitchShiftI = FRACTIONONE;
132 mPitchShift = 1.0f;
133 mFreqPerBin = static_cast<float>(device->Frequency) / float{STFT_SIZE};
135 std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f);
136 std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), 0.0f);
137 std::fill(std::begin(mLastPhase), std::end(mLastPhase), 0.0);
138 std::fill(std::begin(mSumPhase), std::end(mSumPhase), 0.0);
139 std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), 0.0);
140 std::fill(std::begin(mFFTbuffer), std::end(mFFTbuffer), complex_d{});
141 std::fill(std::begin(mAnalysis_buffer), std::end(mAnalysis_buffer), ALfrequencyDomain{});
142 std::fill(std::begin(mSyntesis_buffer), std::end(mSyntesis_buffer), ALfrequencyDomain{});
144 std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f);
145 std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f);
147 return AL_TRUE;
150 void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target)
152 const float pitch{std::pow(2.0f,
153 static_cast<ALfloat>(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f
155 mPitchShiftI = fastf2u(pitch*FRACTIONONE);
156 mPitchShift = static_cast<float>(mPitchShiftI) * (1.0f/FRACTIONONE);
158 ALfloat coeffs[MAX_AMBI_CHANNELS];
159 CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs);
161 mOutTarget = target.Main->Buffer;
162 ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains);
165 void PshifterState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
167 /* Pitch shifter engine based on the work of Stephan Bernsee.
168 * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
171 static constexpr ALdouble expected{al::MathDefs<double>::Tau() / OVERSAMP};
172 const ALdouble freq_per_bin{mFreqPerBin};
173 ALfloat *RESTRICT bufferOut{mBufferOut};
174 size_t count{mCount};
176 for(size_t i{0u};i < samplesToDo;)
178 do {
179 /* Fill FIFO buffer with samples data */
180 mInFIFO[count] = samplesIn[0][i];
181 bufferOut[i] = mOutFIFO[count - FIFO_LATENCY];
183 count++;
184 } while(++i < samplesToDo && count < STFT_SIZE);
186 /* Check whether FIFO buffer is filled */
187 if(count < STFT_SIZE) break;
188 count = FIFO_LATENCY;
190 /* Real signal windowing and store in FFTbuffer */
191 for(ALuint k{0u};k < STFT_SIZE;k++)
193 mFFTbuffer[k].real(mInFIFO[k] * HannWindow[k]);
194 mFFTbuffer[k].imag(0.0);
197 /* ANALYSIS */
198 /* Apply FFT to FFTbuffer data */
199 complex_fft(mFFTbuffer, -1.0);
201 /* Analyze the obtained data. Since the real FFT is symmetric, only
202 * STFT_HALF_SIZE+1 samples are needed.
204 for(ALuint k{0u};k < STFT_HALF_SIZE+1;k++)
206 /* Compute amplitude and phase */
207 ALphasor component{rect2polar(mFFTbuffer[k])};
209 /* Compute phase difference and subtract expected phase difference */
210 double tmp{(component.Phase - mLastPhase[k]) - k*expected};
212 /* Map delta phase into +/- Pi interval */
213 int qpd{double2int(tmp / al::MathDefs<double>::Pi())};
214 tmp -= al::MathDefs<double>::Pi() * (qpd + (qpd%2));
216 /* Get deviation from bin frequency from the +/- Pi interval */
217 tmp /= expected;
219 /* Compute the k-th partials' true frequency, twice the amplitude
220 * for maintain the gain (because half of bins are used) and store
221 * amplitude and true frequency in analysis buffer.
223 mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude;
224 mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin;
226 /* Store actual phase[k] for the calculations in the next frame*/
227 mLastPhase[k] = component.Phase;
230 /* PROCESSING */
231 /* pitch shifting */
232 for(ALuint k{0u};k < STFT_HALF_SIZE+1;k++)
234 mSyntesis_buffer[k].Amplitude = 0.0;
235 mSyntesis_buffer[k].Frequency = 0.0;
238 for(size_t k{0u};k < STFT_HALF_SIZE+1;k++)
240 size_t j{(k*mPitchShiftI) >> FRACTIONBITS};
241 if(j >= STFT_HALF_SIZE+1) break;
243 mSyntesis_buffer[j].Amplitude += mAnalysis_buffer[k].Amplitude;
244 mSyntesis_buffer[j].Frequency = mAnalysis_buffer[k].Frequency * mPitchShift;
247 /* SYNTHESIS */
248 /* Synthesis the processing data */
249 for(ALuint k{0u};k < STFT_HALF_SIZE+1;k++)
251 ALphasor component;
252 ALdouble tmp;
254 /* Compute bin deviation from scaled freq */
255 tmp = mSyntesis_buffer[k].Frequency/freq_per_bin - k;
257 /* Calculate actual delta phase and accumulate it to get bin phase */
258 mSumPhase[k] += (k + tmp) * expected;
260 component.Amplitude = mSyntesis_buffer[k].Amplitude;
261 component.Phase = mSumPhase[k];
263 /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/
264 mFFTbuffer[k] = polar2rect(component);
266 /* zero negative frequencies for recontruct a real signal */
267 for(ALuint k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++)
268 mFFTbuffer[k] = complex_d{};
270 /* Apply iFFT to buffer data */
271 complex_fft(mFFTbuffer, 1.0);
273 /* Windowing and add to output */
274 for(ALuint k{0u};k < STFT_SIZE;k++)
275 mOutputAccum[k] += HannWindow[k] * mFFTbuffer[k].real() /
276 (0.5 * STFT_HALF_SIZE * OVERSAMP);
278 /* Shift accumulator, input & output FIFO */
279 size_t j, k;
280 for(k = 0;k < STFT_STEP;k++) mOutFIFO[k] = static_cast<ALfloat>(mOutputAccum[k]);
281 for(j = 0;k < STFT_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k];
282 for(;j < STFT_SIZE;j++) mOutputAccum[j] = 0.0;
283 for(k = 0;k < FIFO_LATENCY;k++)
284 mInFIFO[k] = mInFIFO[k+STFT_STEP];
286 mCount = count;
288 /* Now, mix the processed sound data to the output. */
289 MixSamples({bufferOut, samplesToDo}, samplesOut, mCurrentGains, mTargetGains,
290 maxz(samplesToDo, 512), 0);
294 void Pshifter_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat)
295 { context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); }
296 void Pshifter_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*)
297 { context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param); }
299 void Pshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val)
301 switch(param)
303 case AL_PITCH_SHIFTER_COARSE_TUNE:
304 if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE))
305 SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range");
306 props->Pshifter.CoarseTune = val;
307 break;
309 case AL_PITCH_SHIFTER_FINE_TUNE:
310 if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE))
311 SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range");
312 props->Pshifter.FineTune = val;
313 break;
315 default:
316 context->setError(AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
317 param);
320 void Pshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals)
321 { Pshifter_setParami(props, context, param, vals[0]); }
323 void Pshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val)
325 switch(param)
327 case AL_PITCH_SHIFTER_COARSE_TUNE:
328 *val = props->Pshifter.CoarseTune;
329 break;
330 case AL_PITCH_SHIFTER_FINE_TUNE:
331 *val = props->Pshifter.FineTune;
332 break;
334 default:
335 context->setError(AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
336 param);
339 void Pshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals)
340 { Pshifter_getParami(props, context, param, vals); }
342 void Pshifter_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*)
343 { context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); }
344 void Pshifter_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*)
345 { context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); }
347 DEFINE_ALEFFECT_VTABLE(Pshifter);
350 struct PshifterStateFactory final : public EffectStateFactory {
351 EffectState *create() override;
352 EffectProps getDefaultProps() const noexcept override;
353 const EffectVtable *getEffectVtable() const noexcept override { return &Pshifter_vtable; }
356 EffectState *PshifterStateFactory::create()
357 { return new PshifterState{}; }
359 EffectProps PshifterStateFactory::getDefaultProps() const noexcept
361 EffectProps props{};
362 props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
363 props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
364 return props;
367 } // namespace
369 EffectStateFactory *PshifterStateFactory_getFactory()
371 static PshifterStateFactory PshifterFactory{};
372 return &PshifterFactory;