/* Copyright (C) 2011 Nasca Octavian Paul Author: Nasca Octavian Paul This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License (version 2) for more details. You should have received a copy of the GNU General Public License (version 2) along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include "Stretch.h" #include "../jcdp_envelope.h" struct ProcessParameters { ProcessParameters() { pitch_shift.cents=0; octave.om2=octave.om1=octave.o1=octave.o15=octave.o2=0.0f; octave.o0=1.0f; freq_shift.Hz=0; compressor.power=0.0f; filter.stop=false; filter.low=0.0f; filter.high=22000.0f; filter.hdamp=0.0f; harmonics.freq=440.0f; harmonics.bandwidth=25.0f; harmonics.nharmonics=10; harmonics.gauss=false; spread.bandwidth=0.3f; tonal_vs_noise.preserve=0.5f; tonal_vs_noise.bandwidth=0.9f; }; ~ProcessParameters(){ }; struct{ int cents; }pitch_shift; struct{ REALTYPE om2,om1,o0,o1,o15,o2; }octave; struct{ int Hz; }freq_shift; struct{ REALTYPE power; }compressor; struct{ REALTYPE low,high; REALTYPE hdamp; bool stop; }filter; struct{ REALTYPE freq; REALTYPE bandwidth; int nharmonics; bool gauss; }harmonics; struct{ REALTYPE bandwidth; }spread; struct{ REALTYPE preserve; REALTYPE bandwidth; }tonal_vs_noise; //FreeEdit free_filter; //FreeEdit stretch_multiplier; /* auto getMembers() const { return std::make_tuple(pitch_shift.enabled, pitch_shift.cents, octave.enabled, octave.o0, octave.o1, octave.o15, octave.o2, octave.om1, octave.om2, spread.enabled, spread.bandwidth, tonal_vs_noise.enabled, tonal_vs_noise.bandwidth, tonal_vs_noise.preserve, freq_shift.enabled, freq_shift.Hz, compressor.enabled, compressor.power, harmonics.bandwidth, harmonics.enabled, harmonics.freq, harmonics.gauss, harmonics.nharmonics, filter.enabled, filter.hdamp, filter.high, filter.low, filter.stop); } bool operator == (const ProcessParameters& other) const { return getMembers() == other.getMembers(); } */ bool operator == (const ProcessParameters& other) const noexcept { return pitch_shift.cents == other.pitch_shift.cents && octave.o0 == other.octave.o0 && octave.o1 == other.octave.o1 && octave.o15 == other.octave.o15 && octave.o2 == other.octave.o2 && octave.om1 == other.octave.om1 && octave.om2 == other.octave.om2 && spread.bandwidth == other.spread.bandwidth && tonal_vs_noise.bandwidth == other.tonal_vs_noise.bandwidth && tonal_vs_noise.preserve == other.tonal_vs_noise.preserve && freq_shift.Hz == other.freq_shift.Hz && compressor.power == other.compressor.power && harmonics.bandwidth == other.harmonics.bandwidth && harmonics.freq == other.harmonics.freq && harmonics.gauss == other.harmonics.gauss && harmonics.nharmonics == other.harmonics.nharmonics && filter.hdamp == other.filter.hdamp && filter.high == other.filter.high && filter.low == other.filter.low && filter.stop == other.filter.stop; } }; inline REALTYPE profile(REALTYPE fi, REALTYPE bwi) { REALTYPE x = fi / bwi; x *= x; if (x>14.71280603) return 0.0; return exp(-x);///bwi; }; inline void spectrum_copy(int nfreq, REALTYPE* freq1, REALTYPE* freq2) { for (int i = 0; i& tmpfreq1, REALTYPE *freq1, REALTYPE *freq2, REALTYPE spread_bandwidth) { //convert to log spectrum REALTYPE minfreq = 20.0f; REALTYPE maxfreq = 0.5f*samplerate; REALTYPE log_minfreq = log(minfreq); REALTYPE log_maxfreq = log(maxfreq); for (int i = 0; i= nfreq) x0 = nfreq - 1; int x1 = x0 + 1; if (x1 >= nfreq) x1 = nfreq - 1; REALTYPE xp = x - x0; if (x0; i--) { tmpfreq1[i] = tmpfreq1[i + 1] * a + tmpfreq1[i] * (1.0f - a); }; }; freq2[0] = 0; REALTYPE log_maxfreq_d_minfreq = log(maxfreq / minfreq); for (int i = 1; i0.0) && (x= nfreq) x0 = nfreq - 1; int x1 = x0 + 1; if (x1 >= nfreq) x1 = nfreq - 1; REALTYPE xp = x - x0; y = tmpfreq1[x0] * (1.0f - xp) + tmpfreq1[x1] * xp; }; freq2[i] = y; }; }; inline void spectrum_do_compressor(const ProcessParameters& pars, int nfreq, REALTYPE *freq1, REALTYPE *freq2) { REALTYPE rms = 0.0; for (int i = 0; i& tmpfreq1, REALTYPE *freq1, REALTYPE *freq2) { spectrum_spread(nfreq, samplerate, tmpfreq1, freq1, tmpfreq1.data(), pars.tonal_vs_noise.bandwidth); if (pars.tonal_vs_noise.preserve >= 0.0) { REALTYPE mul = (pow(10.0f, pars.tonal_vs_noise.preserve) - 1.0f); for (int i = 0; i& tmpfreq1, int nfreq, double samplerate, REALTYPE *freq1, REALTYPE *freq2) { REALTYPE freq = pars.harmonics.freq; REALTYPE bandwidth = pars.harmonics.bandwidth; int nharmonics = pars.harmonics.nharmonics; if (freq<10.0) freq = 10.0; REALTYPE *amp = tmpfreq1.data(); for (int i = 0; i= samplerate / 2) break; bw_Hz = (pow(2.0f, bandwidth / 1200.0f) - 1.0f)*f; bwi = bw_Hz / (2.0f*samplerate); fi = f / samplerate; REALTYPE sum = 0.0f; REALTYPE max = 0.0f; for (int i = 1; imax) max = amp[i]; }; if (max<1e-8f) max = 1e-8f; for (int i = 1; i0) && (i2= nfreq) break; freq2[i2] += freq1[i]; }; }; if (_rap >= 1.0) {//up _rap = 1.0f / _rap; for (int i = 0; i& sumfreq, std::vector& tmpfreq1, REALTYPE *freq1, REALTYPE *freq2) { spectrum_zero(nfreq,sumfreq.data()); if (pars.octave.om2>1e-3) { spectrum_do_pitch_shift(pars,nfreq, freq1, tmpfreq1.data(), 0.25); spectrum_add(nfreq, sumfreq.data(), tmpfreq1.data(), pars.octave.om2); }; if (pars.octave.om1>1e-3) { spectrum_do_pitch_shift(pars,nfreq, freq1, tmpfreq1.data(), 0.5); spectrum_add(nfreq,sumfreq.data(), tmpfreq1.data(), pars.octave.om1); }; if (pars.octave.o0>1e-3) { spectrum_add(nfreq,sumfreq.data(), freq1, pars.octave.o0); }; if (pars.octave.o1>1e-3) { spectrum_do_pitch_shift(pars,nfreq, freq1, tmpfreq1.data(), 2.0); spectrum_add(nfreq,sumfreq.data(), tmpfreq1.data(), pars.octave.o1); }; if (pars.octave.o15>1e-3) { spectrum_do_pitch_shift(pars,nfreq, freq1, tmpfreq1.data(), 3.0); spectrum_add(nfreq,sumfreq.data(), tmpfreq1.data(), pars.octave.o15); }; if (pars.octave.o2>1e-3) { spectrum_do_pitch_shift(pars, nfreq, freq1, tmpfreq1.data(), 4.0); spectrum_add(nfreq,sumfreq.data(), tmpfreq1.data(), pars.octave.o2); }; REALTYPE sum = 0.01f + pars.octave.om2 + pars.octave.om1 + pars.octave.o0 + pars.octave.o1 + pars.octave.o15 + pars.octave.o2; if (sum<0.5f) sum = 0.5f; for (int i = 0; i= ilow) && (i= 30.0) { double norm = 0.150542*log(0.0333333*binhz); double db = jmap(env->getTransformedValue(norm), 0.0, 1.0, -48.0, 12.0); freq2[i] = freq1[i] * Decibels::decibelsToGain(db); } else freq2[i] = freq1[i]; }; }; class SpectrumProcess { public: SpectrumProcess() {} SpectrumProcess(int index, bool enabled) : m_index(index), m_enabled(enabled) {} int m_index = -1; bool m_enabled = true; }; class ProcessedStretch final : public Stretch { public: //stereo_mode: 0=mono,1=left,2=right ProcessedStretch(REALTYPE rap_,int in_bufsize_,FFTWindow w=W_HAMMING,bool bypass_=false,REALTYPE samplerate_=44100.0f,int stereo_mode=0); ~ProcessedStretch(); void set_parameters(ProcessParameters *ppar); void setFreeFilterEnvelope(shared_envelope env); std::vector m_spectrum_processes; void setBufferSize(int sz) override; private: REALTYPE get_stretch_multiplier(REALTYPE pos_percents) override; // void process_output(REALTYPE *smps,int nsmps); void process_spectrum(REALTYPE *freq) override; shared_envelope m_free_filter_envelope; void copy(REALTYPE* freq1, REALTYPE* freq2); void add(REALTYPE *freq2,REALTYPE *freq1,REALTYPE a=1.0); void mul(REALTYPE *freq1,REALTYPE a); void zero(REALTYPE *freq1); void update_free_filter(); int nfreq=0; std::vector m_free_filter_freqs; ProcessParameters pars; std::vector m_infreq,m_sumfreq,m_tmpfreq1,m_tmpfreq2; //REALTYPE *fbfreq; };