20constexpr double twoPi = 6.28318530717958647692f;
30inline float lagrange6(
const float (&smp)[6],
float t)
34 auto ym1_y1 = y[-1] + y[1];
35 auto twentyfourth_ym2_y2 = 1.f / 24.f * (y[-2] + y[2]);
37 auto c1 = 0.05f * y[-2] - 0.5f * y[-1] - 1.f / 3.f * y[0] + y[1] - 0.25f * y[2] + 1.f / 30.f * y[3];
38 auto c2 = 2.f / 3.f * ym1_y1 - 1.25f * y[0] - twentyfourth_ym2_y2;
39 auto c3 = 5.f / 12.f * y[0] - 7.f / 12.f * y[1] + 7.f / 24.f * y[2] - 1.f / 24.f * (y[-2] + y[-1] + y[3]);
40 auto c4 = 0.25f * y[0] - 1.f / 6.f * ym1_y1 + twentyfourth_ym2_y2;
41 auto c5 = 1.f / 120.f * (y[3] - y[-2]) + 1.f / 24.f * (y[-1] - y[2]) + 1.f / 12.f * (y[1] - y[0]);
45 return (c0 + c1 * t) + (c2 + c3 * t) * t2 + (c4 + c5 * t) * t2 * t2;
50 std::vector<std::complex<float>> v(
size);
51 std::uniform_real_distribution<float> dis(
52 -3.14159265358979323846f, 3.14159265358979323846f);
53 std::for_each(dst, dst +
size, [&dis, &gen](
auto& a) { a = dis(gen); });
93 , _reduceImaging(reduceImaging)
94 , _shiftTimbreCb(
std::move(shiftTimbreCb))
105 assert(numChannels == 1 || numChannels == 2);
108 d = std::make_unique<impl>(
fftSize);
119 d->inCircularBuffer[ch].setSize(
fftSize);
120 d->outCircularBuffer[ch].setSize(outBufferSize);
122 d->normalizationBuffer.setSize(outBufferSize);
133 d->random_phases.getPtr(0),
_numBins,
d->randomGenerator);
141 auto* w =
d->cosWindow.getPtr(0);
142 auto* sqw =
d->sqWindow.getPtr(0);
143 for (
int i = 0; i <
fftSize; ++i)
145 w[i] = -0.5f * std::cos(
float(
twoPi * (
float)i / (
float)
fftSize)) + 0.5f;
146 sqw[i] = w[i] * w[i];
153 d->fft.forwardReal(
d->fft_timeseries,
d->spectrum);
175 d->inResampleInputBuffer[ch].reset();
176 d->inCircularBuffer[ch].reset();
177 d->outCircularBuffer[ch].reset();
179 d->normalizationBuffer.reset();
180 d->last_norm.zeroOut();
181 d->last_phase.zeroOut();
182 d->phase_accum.zeroOut();
186 d->exact_hop_s = 0.0;
195 using namespace audio::simd;
196 return arg -
rint(arg * 0.15915494309f) * 6.283185307f;
207 assert((n & 1) == 0);
238template <
int num_channels>
241 auto alpha = a_s / a_a;
244 const auto* norms =
d->norm.getPtr(0);
245 const auto* norms_last =
d->last_norm.getPtr(0);
247 d->peak_index.clear();
248 d->trough_index.clear();
249 float lowest = norms[0];
251 if (norms_last[0] >= norms[1])
253 d->peak_index.emplace_back(0);
254 d->trough_index.emplace_back(0);
256 for (
int i = 1; i <
_numBins - 1; ++i)
258 if (norms_last[i] >= norms[i - 1] && norms_last[i] >= norms[i + 1])
260 d->peak_index.emplace_back(i);
261 d->trough_index.emplace_back(trough);
265 else if (norms[i] < lowest)
273 d->peak_index.emplace_back(
_numBins - 1);
274 d->trough_index.emplace_back(trough);
277 if (
d->peak_index.size() == 0)
281 float max_norm = 0.f;
283 d->peak_index.emplace_back(max_idx);
286 const float** p =
const_cast<const float**
>(
d->phase.getPtrs());
287 const float** p_l =
const_cast<const float**
>(
d->last_phase.getPtrs());
288 float** acc =
d->phase_accum.getPtrs();
293 int num_peaks = (int)
d->peak_index.size();
295 for (
int i = 0; i < num_peaks; ++i)
297 const int n =
d->peak_index[i];
301 float fn_expChange_a =
fn * expChange_a;
302 float fn_expChange_s =
fn * expChange_s;
304 for (
int ch = 0; ch < num_channels; ++ch)
305 acc[ch][n] = acc[ch][n] + alpha *
_unwrapPhase(p[ch][n] - p_l[ch][n] - fn_expChange_a) + fn_expChange_s;
309 for (
int n =
d->peak_index[0]; n > 0; --n)
311 for (
int ch = 0; ch < num_channels; ++ch)
312 acc[ch][n - 1] = acc[ch][n] - alpha *
_unwrapPhase(p[ch][n] - p[ch][n - 1]);
316 for (
int i = 0; i < num_peaks - 1; ++i)
318 const int mid =
d->trough_index[i + 1];
319 for (
int n =
d->peak_index[i]; n < mid; ++n)
321 for (
int ch = 0; ch < num_channels; ++ch)
322 acc[ch][n + 1] = acc[ch][n] + alpha *
_unwrapPhase(p[ch][n + 1] - p[ch][n]);
324 for (
int n =
d->peak_index[i + 1]; n > mid + 1; --n)
326 for (
int ch = 0; ch < num_channels; ++ch)
327 acc[ch][n - 1] = acc[ch][n] - alpha *
_unwrapPhase(p[ch][n] - p[ch][n - 1]);
332 for (
int n =
d->peak_index[num_peaks - 1]; n <
_numBins - 1; ++n)
334 for (
int ch = 0; ch < num_channels; ++ch)
335 acc[ch][n + 1] = acc[ch][n] + alpha *
_unwrapPhase(p[ch][n + 1] - p[ch][n]);
338 d->last_norm.assignSamples(
d->norm);
339 d->last_phase.assignSamples(
d->phase);
352 constexpr auto alignment = 64 /
sizeof(float);
353 const int imagingBeginBin =
359 const auto n =
_numBins - imagingBeginBin;
360 auto pSpec =
d->spectrum.getPtr(0);
361 auto pRand =
d->random_phases.getPtr(0);
362 vo::rotate(
nullptr, pRand, pSpec + imagingBeginBin, n);
365 std::uniform_int_distribution<size_t> dis(0, n - 1);
366 const auto middle = dis(
d->randomGenerator);
373 if (
d->exact_hop_a !=
d->exact_hop_s)
380 vo::multiply(
d->fft_timeseries.getPtr(ch),
d->cosWindow.getPtr(0),
d->fft_timeseries.getPtr(ch),
fftSize);
385 d->fft.forwardReal(
d->fft_timeseries,
d->spectrum);
388 vo::calcNorms(
d->spectrum.getPtr(0),
d->norm.getPtr(0),
d->spectrum.getNumSamples());
390 vo::calcPhases(
d->spectrum.getPtr(ch),
d->phase.getPtr(ch),
d->spectrum.getNumSamples());
400 _time_stretch<1>((
float)hop_a, (
float)hop_s);
402 _time_stretch<2>((
float)hop_a, (
float)hop_s);
408 vo::rotate(
d->phase.getPtr(ch),
d->phase_accum.getPtr(ch),
d->spectrum.getPtr(ch),
409 d->spectrum.getNumSamples());
410 d->fft.inverseReal(
d->spectrum,
d->fft_timeseries);
414 d->fft_timeseries.getNumSamples());
422 vo::multiply(
d->fft_timeseries.getPtr(ch),
d->cosWindow.getPtr(0),
d->fft_timeseries.getPtr(ch),
fftSize);
446 assert(timeScale > 0.0);
447 assert(pitchFactor > 0.0);
461 d->exact_hop_s = double(
fftSize) / overlap_s;
466 d->next_exact_hop_s = double(
fftSize) / overlap_s;
467 if (
d->exact_hop_s == 0.0)
468 d->exact_hop_s =
d->next_exact_hop_s;
477 d->inResampleInputBuffer[ch].writeBlock(0, numSamples, input_smp[ch]);
478 d->inResampleInputBuffer[ch].advance(numSamples);
485 if (
d->exact_hop_s == 0.0)
486 d->exact_hop_s =
d->next_exact_hop_s;
488 const int hop_s = int(
d->exact_hop_s +
d->hop_s_err);
489 const int hop_a = int(
d->exact_hop_a +
d->hop_a_err);
493 while (read_pos < 0.0)
495 auto int_pos = int(std::floor(read_pos));
496 float frac_pos = float(read_pos - int_pos);
500 d->inResampleInputBuffer[ch].readBlock(int_pos - 6, 6, smp);
501 float s = (frac_pos == 0) ? smp[2] :
lagrange6(smp, frac_pos);
502 d->inCircularBuffer[ch].writeOffset0(s);
503 d->inCircularBuffer[ch].advance(1);
511 d->hop_s_err +=
d->exact_hop_s - hop_s;
512 d->hop_a_err +=
d->exact_hop_a - hop_a;
514 d->inCircularBuffer[ch].readBlock(-
fftSize,
fftSize,
d->fft_timeseries.getPtr(ch));
527 d->outCircularBuffer[ch].readAndClearBlock(0, numSamples, out_smp[ch]);
530 constexpr float curve =
532 for (
int i = 0; i < numSamples; ++i)
534 float x =
d->normalizationBuffer.read(i);
535 out_smp[ch][i] *= x / (x * x + 1 / curve);
538 d->outCircularBuffer[ch].advance(numSamples);
541 d->normalizationBuffer.clearBlock(0, numSamples);
542 d->normalizationBuffer.advance(numSamples);
548 d->exact_hop_s =
d->next_exact_hop_s;
566 const float coeff = (timeStretch < 1.f) ? (1.f / 3.f) : (2.f / 3.f);
void _applyImagingReduction()
int getNumAvailableOutputSamples() const
void setTimeStretchAndPitchFactor(double timeStretch, double pitchFactor)
int _availableOutputSamples
const bool _reduceImaging
int getSamplesToNextHop() const
void _time_stretch(float hop_a, float hop_s)
std::function< void(double factor, std::complex< float > *spectrum, const float *magnitude)> ShiftTimbreCb
void setup(int numChannels, int maxBlockSize)
void retrieveAudio(float *const *out_smp, int numSamples)
const ShiftTimbreCb _shiftTimbreCb
void _process_hop(int hop_a, int hop_s)
process one hop/chunk in _fft_timeSeries and add the result to output circular buffer
int getLatencySamples() const
static constexpr bool normalize_window
double _expectedPhaseChangePerBinPerSample
void processPitchShift(float *const *smp, int numSamples, double pitchFactor)
int getLatencySamplesForStretchRatio(float timeStretch) const
TimeAndPitch(int fftSize, bool reduceImaging=true, ShiftTimbreCb shiftTimbreCb={})
int _analysis_hop_counter
std::shared_ptr< impl > d
int _outBufferWriteOffset
static constexpr bool modulate_synthesis_hop
void feedAudio(const float *const *in_smp, int numSamples)
static constexpr int overlap
constexpr auto maxBlockSize
void generateRandomPhaseVector(float *dst, size_t size, std::mt19937 &gen)
float _unwrapPhase(float arg)
void _fft_shift(float *v, int n)
rotate even-sized array by half its size to align fft phase at the center
float lagrange6(const float(&smp)[6], float t)
void _lr_to_ms(float *ch1, float *ch2, int n)
void _ms_to_lr(float *ch1, float *ch2, int n)
void _unwrapPhaseVec(float *v, int n)
__finl float __vecc rint(float a)
__finl void perform_parallel_simd_aligned(float *a, float *b, int n, const fnc &f)
void multiply(const T *src1, const T *src2, T *dst, int32_t n)
void calcPhases(const std::complex< float > *src, float *dst, int32_t n)
void rotate(const float *oldPhase, const float *newPhase, std::complex< float > *dst, int32_t n)
void findMaxElement(const T *src, int32_t n, int32_t &maxIndex, T &maxValue)
void calcNorms(const std::complex< float > *src, float *dst, int32_t n)
void constantMultiply(const T *src, T constant, T *dst, int32_t n)
std::vector< int > trough_index
CircularSampleBuffer< float > inCircularBuffer[2]
CircularSampleBuffer< float > normalizationBuffer
std::vector< int > peak_index
CircularSampleBuffer< float > outCircularBuffer[2]
CircularSampleBuffer< float > inResampleInputBuffer[2]
std::mt19937 randomGenerator
SamplesReal random_phases
SamplesReal fft_timeseries