zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit a8432e8cbb8fb928c43660a1380fd72dfb2ef7b4
parent 1428628fdd9036983fe4fd19ea14ca6cb60bfe49
Author: Johannes Lorenz <j.git@lorenz-ho.me>
Date:   Fri,  7 Jan 2022 05:53:11 +0100

Enable parallel computations in OscilGen

Sole refactoring, no functional changes.

Diffstat:
Msrc/Synth/OscilGen.cpp | 389++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/Synth/OscilGen.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
2 files changed, 280 insertions(+), 218 deletions(-)

diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -118,10 +118,11 @@ const rtosc::Ports OscilGen::non_realtime_ports = { strcpy(edit, "prepare"); OscilGen &o = *((OscilGen*)d.obj); FFTfreqBuffer freqs = o.fft->allocFreqBuf(); - o.prepare(freqs); + OscilGenBuffers& bfrs = o.myBuffers(); + o.prepare(bfrs, freqs); // fprintf(stderr, "sending '%p' of fft data\n", data); d.chain(repath, "b", sizeof(fft_t*), &freqs.data); - o.myBuffers.pendingfreqs = freqs.data; + bfrs.pendingfreqs = freqs.data; d.broadcast(d.loc, "i", phase); } }}, @@ -145,10 +146,11 @@ const rtosc::Ports OscilGen::non_realtime_ports = { strcpy(edit, "prepare"); OscilGen &o = *((OscilGen*)d.obj); FFTfreqBuffer freqs = o.fft->allocFreqBuf(); - o.prepare(freqs); + OscilGenBuffers& bfrs = o.myBuffers(); + o.prepare(bfrs, freqs); // fprintf(stderr, "sending '%p' of fft data\n", data); d.chain(repath, "b", sizeof(fft_t*), &freqs.data); - o.myBuffers.pendingfreqs = freqs.data; + bfrs.pendingfreqs = freqs.data; d.broadcast(d.loc, "i", mag); } }}, @@ -177,10 +179,11 @@ const rtosc::Ports OscilGen::non_realtime_ports = { //fprintf(stderr, "prepare: got a message from '%s'\n", m); OscilGen &o = *(OscilGen*)d.obj; FFTfreqBuffer freqs = o.fft->allocFreqBuf(); - o.prepare(freqs); + OscilGenBuffers& bfrs = o.myBuffers(); + o.prepare(bfrs, freqs); // fprintf(stderr, "sending '%p' of fft data\n", data); d.chain(d.loc, "b", sizeof(fft_t*), &freqs.data); - o.myBuffers.pendingfreqs = freqs.data; + bfrs.pendingfreqs = freqs.data; }}, {"convert2sine:", rProp(non-realtime) rDoc("Translates waveform into FS"), NULL, [](const char *, rtosc::RtData &d) { @@ -232,7 +235,7 @@ const rtosc::Ports OscilGen::realtime_ports{ float *smps = new float[n]; // XXXRT memset(smps, 0, 4*n); //printf("%d\n", o->needPrepare()); - o.get(smps,-1.0); + o.get(o.myBuffers(),smps,-1.0); //printf("wave: %f %f %f %f\n", smps[0], smps[1], smps[2], smps[3]); d.reply(d.loc, "b", n*sizeof(float), smps); delete[] smps; @@ -251,10 +254,11 @@ const rtosc::Ports OscilGen::realtime_ports{ NULL, [](const char *m, rtosc::RtData &d) { // fprintf(stderr, "prepare:b got a message from '%s'\n", m); OscilGen &o = *(OscilGen*)d.obj; + OscilGenBuffers& bfrs = o.myBuffers(); assert(rtosc_argument(m,0).b.len == sizeof(void*)); - d.reply("/free", "sb", "fft_t", sizeof(void*), &o.myBuffers.oscilFFTfreqs.data); - assert(o.myBuffers.oscilFFTfreqs.data !=*(fft_t**)rtosc_argument(m,0).b.data); - o.myBuffers.oscilFFTfreqs.data = *(fft_t**)rtosc_argument(m,0).b.data; + d.reply("/free", "sb", "fft_t", sizeof(void*), &bfrs.oscilFFTfreqs.data); + assert(bfrs.oscilFFTfreqs.data !=*(fft_t**)rtosc_argument(m,0).b.data); + bfrs.oscilFFTfreqs.data = *(fft_t**)rtosc_argument(m,0).b.data; }}, }; @@ -338,7 +342,7 @@ void rmsNormalize(fft_t *freqs, int oscilsize) freqs[i] *= gain; } -#define DIFF(par) (old ## par != P ## par) +#define DIFF(par) (bfrs.old ## par != P ## par) FFTfreqBuffer ctorAllocFreqs(FFTwrapper* fft, int oscilsize) { return fft ? fft->allocFreqBuf() : FFTwrapper::riskAllocFreqBufWithSize(oscilsize); @@ -348,26 +352,68 @@ FFTsampleBuffer ctorAllocSamples(FFTwrapper* fft, int oscilsize) { return fft ? fft->allocSampleBuf() : FFTwrapper::riskAllocSampleBufWithSize(oscilsize); } -OscilGenBuffers::OscilGenBuffers(FFTwrapper *fft_, int oscilsize) : +OscilGenBuffers::OscilGenBuffers(zyn::OscilGenBuffersCreator c) : + oscilsize(c.oscilsize), // fft_ can be nullptr in case of pasting - oscilFFTfreqs(ctorAllocFreqs(fft_, oscilsize)), - tmpsmps(ctorAllocSamples(fft_, oscilsize)), - outoscilFFTfreqs(ctorAllocFreqs(fft_, oscilsize)), - cachedbasefunc(ctorAllocSamples(fft_, oscilsize)), + oscilFFTfreqs(ctorAllocFreqs(c.fft, c.oscilsize)), + pendingfreqs(oscilFFTfreqs.data), + tmpsmps(ctorAllocSamples(c.fft, c.oscilsize)), + outoscilFFTfreqs(ctorAllocFreqs(c.fft, c.oscilsize)), + cachedbasefunc(ctorAllocSamples(c.fft, c.oscilsize)), cachedbasevalid(false), - basefuncFFTfreqs(ctorAllocFreqs(fft_, oscilsize)), - scratchFreqs(ctorAllocFreqs(fft_, oscilsize)) + basefuncFFTfreqs(ctorAllocFreqs(c.fft, c.oscilsize)), + scratchFreqs(ctorAllocFreqs(c.fft, c.oscilsize)) { + defaults(); +} + +OscilGenBuffers::~OscilGenBuffers() +{ + delete[] tmpsmps.data; + delete[] outoscilFFTfreqs.data; + delete[] basefuncFFTfreqs.data; + delete[] oscilFFTfreqs.data; + delete[] cachedbasefunc.data; + delete[] scratchFreqs.data; } -OscilGenBuffers OscilGen::createOscilGenBuffers() const +zyn::OscilGenBuffersCreator OscilGen::createOscilGenBuffers() const { - return OscilGenBuffers(fft, synth.oscilsize); + return OscilGenBuffersCreator(fft, synth.oscilsize); +} + +void OscilGenBuffers::defaults() +{ + oldbasefunc = 0; + oldbasepar = 64; + oldhmagtype = 0; + oldwaveshapingfunction = 0; + oldwaveshaping = 64; + oldbasefuncmodulation = 0; + oldharmonicshift = 0; + oldbasefuncmodulationpar1 = 0; + oldbasefuncmodulationpar2 = 0; + oldbasefuncmodulationpar3 = 0; + oldmodulation = 0; + oldmodulationpar1 = 0; + oldmodulationpar2 = 0; + oldmodulationpar3 = 0; + + for(int i = 0; i < MAX_AD_HARMONICS; ++i) { + hmag[i] = 0.0f; + hphase[i] = 0.0f; + } + + clearAll(oscilFFTfreqs.data, oscilsize); + clearAll(basefuncFFTfreqs.data, oscilsize); + oscilprepared = 0; + oldfilterpars = 0; + oldsapars = 0; } OscilGen::OscilGen(const SYNTH_T &synth_, FFTwrapper *fft_, Resonance *res_) :Presets(), - myBuffers(fft_, synth_.oscilsize), + m_myBuffers(OscilGenBuffersCreator(fft_, synth_.oscilsize)), fft(fft_), res(res_), synth(synth_) @@ -381,45 +427,15 @@ OscilGen::OscilGen(const SYNTH_T &synth_, FFTwrapper *fft_, Resonance *res_) setpresettype("Poscilgen"); - myBuffers.pendingfreqs = myBuffers.oscilFFTfreqs.data; - - randseed = 1; + randseed = 1; // TODO: take care of random? ADvsPAD = false; defaults(); } -OscilGen::~OscilGen() -{ - delete[] myBuffers.tmpsmps.data; - delete[] myBuffers.outoscilFFTfreqs.data; - delete[] myBuffers.basefuncFFTfreqs.data; - delete[] myBuffers.oscilFFTfreqs.data; - delete[] myBuffers.cachedbasefunc.data; - delete[] myBuffers.scratchFreqs.data; -} - - void OscilGen::defaults() { - oldbasefunc = 0; - oldbasepar = 64; - oldhmagtype = 0; - oldwaveshapingfunction = 0; - oldwaveshaping = 64; - oldbasefuncmodulation = 0; - oldharmonicshift = 0; - oldbasefuncmodulationpar1 = 0; - oldbasefuncmodulationpar2 = 0; - oldbasefuncmodulationpar3 = 0; - oldmodulation = 0; - oldmodulationpar1 = 0; - oldmodulationpar2 = 0; - oldmodulationpar3 = 0; - for(int i = 0; i < MAX_AD_HARMONICS; ++i) { - hmag[i] = 0.0f; - hphase[i] = 0.0f; Phmag[i] = 64; Phphase[i] = 64; } @@ -463,33 +479,29 @@ void OscilGen::defaults() Padaptiveharmonicsbasefreq = 128; Padaptiveharmonicspar = 50; - clearAll(myBuffers.oscilFFTfreqs.data, synth.oscilsize); - clearAll(myBuffers.basefuncFFTfreqs.data, synth.oscilsize); - oscilprepared = 0; - oldfilterpars = 0; - oldsapars = 0; - prepare(); + prepare(myBuffers()); } void OscilGen::convert2sine() { + OscilGenBuffers& bfrs = myBuffers(); float mag[MAX_AD_HARMONICS], phase[MAX_AD_HARMONICS]; { FFTwrapper *fft = new FFTwrapper(synth.oscilsize); FFTsampleBuffer oscil = fft->allocSampleBuf(); get(oscil.data, -1.0f); - fft->smps2freqs_noconst_input(oscil, myBuffers.scratchFreqs); + fft->smps2freqs_noconst_input(oscil, bfrs.scratchFreqs); delete (fft); } - normalize(myBuffers.scratchFreqs.data, synth.oscilsize); + normalize(bfrs.scratchFreqs.data, synth.oscilsize); mag[0] = 0; phase[0] = 0; for(int i = 0; i < MAX_AD_HARMONICS; ++i) { - mag[i] = abs(myBuffers.scratchFreqs.data, i + 1); - phase[i] = arg(myBuffers.scratchFreqs.data, i + 1); + mag[i] = abs(bfrs.scratchFreqs.data, i + 1); + phase[i] = arg(bfrs.scratchFreqs.data, i + 1); } defaults(); @@ -510,15 +522,15 @@ void OscilGen::convert2sine() prepare(); } -float OscilGen::userfunc(float x) +float OscilGen::userfunc(OscilGenBuffers& bfrs, float x) const { if (!fft) return 0; - if (!myBuffers.cachedbasevalid) { - fft->freqs2smps(myBuffers.basefuncFFTfreqs, myBuffers.cachedbasefunc, myBuffers.scratchFreqs); - myBuffers.cachedbasevalid = true; + if (!bfrs.cachedbasevalid) { + fft->freqs2smps(bfrs.basefuncFFTfreqs, bfrs.cachedbasefunc, bfrs.scratchFreqs); + bfrs.cachedbasevalid = true; } - return cinterpolate(myBuffers.cachedbasefunc.data, + return cinterpolate(bfrs.cachedbasefunc.data, synth.oscilsize, synth.oscilsize * (x + 1) - 1); } @@ -526,7 +538,7 @@ float OscilGen::userfunc(float x) /* * Get the base function */ -void OscilGen::getbasefunction(FFTsampleBuffer smps) +void OscilGen::getbasefunction(OscilGenBuffers& bfrs, FFTsampleBuffer smps) const { float par = (Pbasefuncpar + 0.5f) / 128.0f; if(Pbasefuncpar == 64) @@ -580,7 +592,7 @@ void OscilGen::getbasefunction(FFTsampleBuffer smps) else if (Pcurrentbasefunc == 0) smps[i] = -sinf(2.0f * PI * i / synth.oscilsize); else - smps[i] = userfunc(t); + smps[i] = userfunc(bfrs, t); } } @@ -588,7 +600,7 @@ void OscilGen::getbasefunction(FFTsampleBuffer smps) /* * Filter the oscillator */ -void OscilGen::oscilfilter(fft_t *freqs) +void OscilGen::oscilfilter(fft_t *freqs) const { if(Pfiltertype == 0) return; @@ -607,23 +619,23 @@ void OscilGen::oscilfilter(fft_t *freqs) /* * Change the base function */ -void OscilGen::changebasefunction(void) +void OscilGen::changebasefunction(OscilGenBuffers& bfrs) const { if(Pcurrentbasefunc != 0) { - getbasefunction(myBuffers.tmpsmps); + getbasefunction(bfrs, bfrs.tmpsmps); if(fft) - fft->smps2freqs_noconst_input(myBuffers.tmpsmps, myBuffers.basefuncFFTfreqs); - clearDC(myBuffers.basefuncFFTfreqs.data); + fft->smps2freqs_noconst_input(bfrs.tmpsmps, bfrs.basefuncFFTfreqs); + clearDC(bfrs.basefuncFFTfreqs.data); } - else //in this case myBuffers.basefuncFFTfreqs are not used - clearAll(myBuffers.basefuncFFTfreqs.data, synth.oscilsize); - oscilprepared = 0; - oldbasefunc = Pcurrentbasefunc; - oldbasepar = Pbasefuncpar; - oldbasefuncmodulation = Pbasefuncmodulation; - oldbasefuncmodulationpar1 = Pbasefuncmodulationpar1; - oldbasefuncmodulationpar2 = Pbasefuncmodulationpar2; - oldbasefuncmodulationpar3 = Pbasefuncmodulationpar3; + else //in this case bfrs.basefuncFFTfreqs are not used + clearAll(bfrs.basefuncFFTfreqs.data, synth.oscilsize); + bfrs.oscilprepared = 0; + bfrs.oldbasefunc = Pcurrentbasefunc; + bfrs.oldbasepar = Pbasefuncpar; + bfrs.oldbasefuncmodulation = Pbasefuncmodulation; + bfrs.oldbasefuncmodulationpar1 = Pbasefuncmodulationpar1; + bfrs.oldbasefuncmodulationpar2 = Pbasefuncmodulationpar2; + bfrs.oldbasefuncmodulationpar3 = Pbasefuncmodulationpar3; } inline void normalize(float *smps, size_t N) @@ -644,10 +656,10 @@ inline void normalize(float *smps, size_t N) /* * Waveshape */ -void OscilGen::waveshape(FFTfreqBuffer freqs) +void OscilGen::waveshape(OscilGenBuffers& bfrs, FFTfreqBuffer freqs) const { - oldwaveshapingfunction = Pwaveshapingfunction; - oldwaveshaping = Pwaveshaping; + bfrs.oldwaveshapingfunction = Pwaveshapingfunction; + bfrs.oldwaveshaping = Pwaveshaping; if(Pwaveshapingfunction == 0) return; @@ -657,27 +669,27 @@ void OscilGen::waveshape(FFTfreqBuffer freqs) float gain = i / (synth.oscilsize / 8.0f); freqs[synth.oscilsize / 2 - i] *= gain; } - fft->freqs2smps_noconst_input(freqs, myBuffers.tmpsmps); + fft->freqs2smps_noconst_input(freqs, bfrs.tmpsmps); //Normalize - normalize(myBuffers.tmpsmps.data, synth.oscilsize); + normalize(bfrs.tmpsmps.data, synth.oscilsize); //Do the waveshaping - waveShapeSmps(synth.oscilsize, myBuffers.tmpsmps.data, Pwaveshapingfunction, Pwaveshaping); + waveShapeSmps(synth.oscilsize, bfrs.tmpsmps.data, Pwaveshapingfunction, Pwaveshaping); - fft->smps2freqs_noconst_input(myBuffers.tmpsmps, freqs); //perform FFT + fft->smps2freqs_noconst_input(bfrs.tmpsmps, freqs); //perform FFT } /* * Do the Frequency Modulation of the Oscil */ -void OscilGen::modulation(FFTfreqBuffer freqs) +void OscilGen::modulation(OscilGenBuffers& bfrs, FFTfreqBuffer freqs) const { - oldmodulation = Pmodulation; - oldmodulationpar1 = Pmodulationpar1; - oldmodulationpar2 = Pmodulationpar2; - oldmodulationpar3 = Pmodulationpar3; + bfrs.oldmodulation = Pmodulation; + bfrs.oldmodulationpar1 = Pmodulationpar1; + bfrs.oldmodulationpar2 = Pmodulationpar2; + bfrs.oldmodulationpar3 = Pmodulationpar3; if(Pmodulation == 0) return; @@ -711,17 +723,17 @@ void OscilGen::modulation(FFTfreqBuffer freqs) const float tmp = i / (synth.oscilsize / 8.0f); freqs[synth.oscilsize / 2 - i] *= tmp; } - fft->freqs2smps_noconst_input(freqs, myBuffers.tmpsmps); + fft->freqs2smps_noconst_input(freqs, bfrs.tmpsmps); const int extra_points = 2; float *in = new float[synth.oscilsize + extra_points]; //Normalize - normalize(myBuffers.tmpsmps.data, synth.oscilsize); + normalize(bfrs.tmpsmps.data, synth.oscilsize); for(int i = 0; i < synth.oscilsize; ++i) - in[i] = myBuffers.tmpsmps[i]; + in[i] = bfrs.tmpsmps[i]; for(int i = 0; i < extra_points; ++i) - in[i + synth.oscilsize] = myBuffers.tmpsmps[i]; + in[i + synth.oscilsize] = bfrs.tmpsmps[i]; //Do the modulation for(int i = 0; i < synth.oscilsize; ++i) { @@ -749,18 +761,18 @@ void OscilGen::modulation(FFTfreqBuffer freqs) const int poshi = (int) t; const float poslo = t - floorf(t); - myBuffers.tmpsmps[i] = in[poshi] * (1.0f - poslo) + in[poshi + 1] * poslo; + bfrs.tmpsmps[i] = in[poshi] * (1.0f - poslo) + in[poshi + 1] * poslo; } delete [] in; - fft->smps2freqs_noconst_input(myBuffers.tmpsmps, freqs); //perform FFT + fft->smps2freqs_noconst_input(bfrs.tmpsmps, freqs); //perform FFT } /* * Adjust the spectrum */ -void OscilGen::spectrumadjust(fft_t *freqs) +void OscilGen::spectrumadjust(fft_t *freqs) const { if(Psatype == 0) return; @@ -805,7 +817,7 @@ void OscilGen::spectrumadjust(fft_t *freqs) } } -void OscilGen::shiftharmonics(fft_t *freqs) +void OscilGen::shiftharmonics(fft_t *freqs) const { if(Pharmonicshift == 0) return; @@ -842,57 +854,57 @@ void OscilGen::shiftharmonics(fft_t *freqs) /* * Prepare the Oscillator */ -void OscilGen::prepare(void) +void OscilGen::prepare(OscilGenBuffers& bfrs) const { - prepare(myBuffers.oscilFFTfreqs); + prepare(bfrs, bfrs.oscilFFTfreqs); } -void OscilGen::prepare(FFTfreqBuffer freqs) +void OscilGen::prepare(OscilGenBuffers& bfrs, FFTfreqBuffer freqs) const { - if((oldbasepar != Pbasefuncpar) || (oldbasefunc != Pcurrentbasefunc) + if((bfrs.oldbasepar != Pbasefuncpar) || (bfrs.oldbasefunc != Pcurrentbasefunc) || DIFF(basefuncmodulation) || DIFF(basefuncmodulationpar1) || DIFF(basefuncmodulationpar2) || DIFF(basefuncmodulationpar3)) - changebasefunction(); + changebasefunction(bfrs); for(int i = 0; i < MAX_AD_HARMONICS; ++i) - hphase[i] = (Phphase[i] - 64.0f) / 64.0f * PI / (i + 1); + bfrs.hphase[i] = (Phphase[i] - 64.0f) / 64.0f * PI / (i + 1); for(int i = 0; i < MAX_AD_HARMONICS; ++i) { const float hmagnew = 1.0f - fabsf(Phmag[i] / 64.0f - 1.0f); switch(Phmagtype) { case 1: - hmag[i] = expf(hmagnew * logf(0.01f)); + bfrs.hmag[i] = expf(hmagnew * logf(0.01f)); break; case 2: - hmag[i] = expf(hmagnew * logf(0.001f)); + bfrs.hmag[i] = expf(hmagnew * logf(0.001f)); break; case 3: - hmag[i] = expf(hmagnew * logf(0.0001f)); + bfrs.hmag[i] = expf(hmagnew * logf(0.0001f)); break; case 4: - hmag[i] = expf(hmagnew * logf(0.00001f)); + bfrs.hmag[i] = expf(hmagnew * logf(0.00001f)); break; default: - hmag[i] = 1.0f - hmagnew; + bfrs.hmag[i] = 1.0f - hmagnew; break; } if(Phmag[i] < 64) - hmag[i] = -hmag[i]; + bfrs.hmag[i] = -bfrs.hmag[i]; } //remove the harmonics where Phmag[i]==64 for(int i = 0; i < MAX_AD_HARMONICS; ++i) if(Phmag[i] == 64) - hmag[i] = 0.0f; + bfrs.hmag[i] = 0.0f; clearAll(freqs.data, synth.oscilsize); if(Pcurrentbasefunc == 0) //the sine case for(int i = 0; i < MAX_AD_HARMONICS - 1; ++i) { freqs[i + 1] = - std::complex<float>(-hmag[i] * sinf(hphase[i] * (i + 1)) / 2.0f, - hmag[i] * cosf(hphase[i] * (i + 1)) / 2.0f); + std::complex<float>(-bfrs.hmag[i] * sinf(bfrs.hphase[i] * (i + 1)) / 2.0f, + bfrs.hmag[i] * cosf(bfrs.hphase[i] * (i + 1)) / 2.0f); } else for(int j = 0; j < MAX_AD_HARMONICS; ++j) { @@ -902,9 +914,9 @@ void OscilGen::prepare(FFTfreqBuffer freqs) int k = i * (j + 1); if(k >= synth.oscilsize / 2) break; - freqs[k] += myBuffers.basefuncFFTfreqs[i] * FFTpolar<fftwf_real>( - hmag[j], - hphase[j] * k); + freqs[k] += bfrs.basefuncFFTfreqs[i] * FFTpolar<fftwf_real>( + bfrs.hmag[j], + bfrs.hphase[j] * k); } } @@ -913,23 +925,23 @@ void OscilGen::prepare(FFTfreqBuffer freqs) if(Pfilterbeforews) { oscilfilter(freqs.data); - waveshape(freqs); + waveshape(bfrs, freqs); } else { - waveshape(freqs); + waveshape(bfrs, freqs); oscilfilter(freqs.data); } - modulation(freqs); + modulation(bfrs, freqs); spectrumadjust(freqs.data); if(Pharmonicshiftfirst == 0) shiftharmonics(freqs.data); clearDC(freqs.data); - oldhmagtype = Phmagtype; - oldharmonicshift = Pharmonicshift + Pharmonicshiftfirst * 256; + bfrs.oldhmagtype = Phmagtype; + bfrs.oldharmonicshift = Pharmonicshift + Pharmonicshiftfirst * 256; - oscilprepared = 1; + bfrs.oscilprepared = 1; } fft_t operator*(float a, fft_t b) @@ -937,7 +949,7 @@ fft_t operator*(float a, fft_t b) return std::complex<float>((float)(a*b.real()), (float)(a*b.imag())); } -void OscilGen::adaptiveharmonic(fft_t *f, float freq) +void OscilGen::adaptiveharmonic(fft_t *f, float freq) const { if(Padaptiveharmonics == 0 /*||(freq<1.0f)*/) return; @@ -986,7 +998,7 @@ void OscilGen::adaptiveharmonic(fft_t *f, float freq) delete[] inf; } -void OscilGen::adaptiveharmonicpostprocess(fft_t *f, int size) +void OscilGen::adaptiveharmonicpostprocess(fft_t *f, int size) const { if(Padaptiveharmonics <= 1) return; @@ -1026,27 +1038,27 @@ void OscilGen::newrandseed(unsigned int randseed) this->randseed = randseed; } -bool OscilGen::needPrepare(void) +bool OscilGen::needPrepare(OscilGenBuffers& bfrs) const { bool outdated = false; //Check function parameters - if((oldbasepar != Pbasefuncpar) || (oldbasefunc != Pcurrentbasefunc) + if((bfrs.oldbasepar != Pbasefuncpar) || (bfrs.oldbasefunc != Pcurrentbasefunc) || DIFF(hmagtype) || DIFF(waveshaping) || DIFF(waveshapingfunction)) outdated = true; //Check filter parameters - if(oldfilterpars != Pfiltertype * 256 + Pfilterpar1 + Pfilterpar2 * 65536 + if(bfrs.oldfilterpars != Pfiltertype * 256 + Pfilterpar1 + Pfilterpar2 * 65536 + Pfilterbeforews * 16777216) { outdated = true; - oldfilterpars = Pfiltertype * 256 + Pfilterpar1 + Pfilterpar2 * 65536 + bfrs.oldfilterpars = Pfiltertype * 256 + Pfilterpar1 + Pfilterpar2 * 65536 + Pfilterbeforews * 16777216; } //Check spectrum adjustments - if(oldsapars != Psatype * 256 + Psapar) { + if(bfrs.oldsapars != Psatype * 256 + Psapar) { outdated = true; - oldsapars = Psatype * 256 + Psapar; + bfrs.oldsapars = Psatype * 256 + Psapar; } //Check function modulation @@ -1060,21 +1072,21 @@ bool OscilGen::needPrepare(void) outdated = true; //Check harmonic shifts - if(oldharmonicshift != Pharmonicshift + Pharmonicshiftfirst * 256) + if(bfrs.oldharmonicshift != Pharmonicshift + Pharmonicshiftfirst * 256) outdated = true; - return outdated == true || oscilprepared == false; + return outdated == true || bfrs.oscilprepared == false; } /* * Get the oscillator function */ -short int OscilGen::get(float* smps, float freqHz, int resonance) +short int OscilGen::get(OscilGenBuffers& bfrs, float* smps, float freqHz, int resonance) const { - if(needPrepare()) - prepare(); + if(needPrepare(bfrs)) + prepare(bfrs); - fft_t *input = freqHz > 0.0f ? myBuffers.oscilFFTfreqs.data : myBuffers.pendingfreqs; + fft_t *input = freqHz > 0.0f ? bfrs.oscilFFTfreqs.data : bfrs.pendingfreqs; unsigned int realrnd = prng(); sprng(randseed); @@ -1085,7 +1097,7 @@ short int OscilGen::get(float* smps, float freqHz, int resonance) outpos = (outpos + 2 * synth.oscilsize) % synth.oscilsize; - clearAll(myBuffers.outoscilFFTfreqs.data, synth.oscilsize); + clearAll(bfrs.outoscilFFTfreqs.data, synth.oscilsize); int nyquist = (int)(0.5f * synth.samplerate_f / fabsf(freqHz)) + 2; if(ADvsPAD) @@ -1100,10 +1112,10 @@ short int OscilGen::get(float* smps, float freqHz, int resonance) if(Padaptiveharmonics != 0) nyquist = synth.oscilsize / 2; for(int i = 1; i < nyquist - 1; ++i) - myBuffers.outoscilFFTfreqs[i] = input[i]; + bfrs.outoscilFFTfreqs[i] = input[i]; - adaptiveharmonic(myBuffers.outoscilFFTfreqs.data, freqHz); - adaptiveharmonicpostprocess(&myBuffers.outoscilFFTfreqs[1], + adaptiveharmonic(bfrs.outoscilFFTfreqs.data, freqHz); + adaptiveharmonicpostprocess(&bfrs.outoscilFFTfreqs[1], synth.oscilsize / 2 - 1); nyquist = realnyquist; @@ -1111,14 +1123,14 @@ short int OscilGen::get(float* smps, float freqHz, int resonance) if(Padaptiveharmonics) //do the antialiasing in the case of adaptive harmonics for(int i = nyquist; i < synth.oscilsize / 2; ++i) - myBuffers.outoscilFFTfreqs[i] = fft_t(0.0f, 0.0f); + bfrs.outoscilFFTfreqs[i] = fft_t(0.0f, 0.0f); // Randomness (each harmonic), the block type is computed // in ADnote by setting start position according to this setting if((Prand > 64) && (freqHz >= 0.0f) && (!ADvsPAD)) { const float rnd = PI * powf((Prand - 64.0f) / 64.0f, 2.0f); for(int i = 1; i < nyquist - 1; ++i) //to Nyquist only for AntiAliasing - myBuffers.outoscilFFTfreqs[i] *= + bfrs.outoscilFFTfreqs[i] *= FFTpolar<fftwf_real>(1.0f, (float)(rnd * i * RND)); } @@ -1132,31 +1144,31 @@ short int OscilGen::get(float* smps, float freqHz, int resonance) power = power * 2.0f - 0.5f; power = powf(15.0f, power); for(int i = 1; i < nyquist - 1; ++i) - myBuffers.outoscilFFTfreqs[i] *= powf(RND, power) * normalize; + bfrs.outoscilFFTfreqs[i] *= powf(RND, power) * normalize; break; case 2: power = power * 2.0f - 0.5f; power = powf(15.0f, power) * 2.0f; float rndfreq = 2 * PI * RND; for(int i = 1; i < nyquist - 1; ++i) - myBuffers.outoscilFFTfreqs[i] *= powf(fabsf(sinf(i * rndfreq)), power) + bfrs.outoscilFFTfreqs[i] *= powf(fabsf(sinf(i * rndfreq)), power) * normalize; break; } } if((freqHz > 0.1f) && (resonance != 0)) - res->applyres(nyquist - 1, myBuffers.outoscilFFTfreqs.data, freqHz); + res->applyres(nyquist - 1, bfrs.outoscilFFTfreqs.data, freqHz); - rmsNormalize(myBuffers.outoscilFFTfreqs.data, synth.oscilsize); + rmsNormalize(bfrs.outoscilFFTfreqs.data, synth.oscilsize); if((ADvsPAD) && (freqHz > 0.1f)) //in this case the smps will contain the freqs for(int i = 1; i < synth.oscilsize / 2; ++i) - smps[i - 1] = abs(myBuffers.outoscilFFTfreqs.data, i); + smps[i - 1] = abs(bfrs.outoscilFFTfreqs.data, i); else { - fft->freqs2smps(myBuffers.outoscilFFTfreqs, myBuffers.tmpsmps, myBuffers.scratchFreqs); + fft->freqs2smps(bfrs.outoscilFFTfreqs, bfrs.tmpsmps, bfrs.scratchFreqs); for(int i = 0; i < synth.oscilsize; ++i) - smps[i] = myBuffers.tmpsmps[i] * 0.25f; //correct the amplitude + smps[i] = bfrs.tmpsmps[i] * 0.25f; //correct the amplitude } sprng(realrnd + 1); @@ -1175,21 +1187,21 @@ short int OscilGen::get(float* smps, float freqHz, int resonance) // if(needPrepare()) // prepare(); // -// clearAll(myBuffers.outoscilFFTfreqs); +// clearAll(bfrs.outoscilFFTfreqs); // // const int nyquist = (synth.oscilsize / 2); // // //Process harmonics // for(int i = 1; i < nyquist - 1; ++i) -// myBuffers.outoscilFFTfreqs[i] = myBuffers.oscilFFTfreqs[i]; +// bfrs.outoscilFFTfreqs[i] = bfrs.oscilFFTfreqs[i]; // -// adaptiveharmonic(myBuffers.outoscilFFTfreqs, freqHz); -// adaptiveharmonicpostprocess(&myBuffers.outoscilFFTfreqs[1], nyquist - 1); +// adaptiveharmonic(bfrs.outoscilFFTfreqs, freqHz); +// adaptiveharmonicpostprocess(&bfrs.outoscilFFTfreqs[1], nyquist - 1); // -// rmsNormalize(myBuffers.outoscilFFTfreqs); +// rmsNormalize(bfrs.outoscilFFTfreqs); // // for(int i = 1; i < nyquist; ++i) -// smps[i - 1] = abs(myBuffers.outoscilFFTfreqs, i); +// smps[i - 1] = abs(bfrs.outoscilFFTfreqs, i); //} // @@ -1198,30 +1210,32 @@ short int OscilGen::get(float* smps, float freqHz, int resonance) */ void OscilGen::getspectrum(int n, float *spc, int what) { + OscilGenBuffers& bfrs = myBuffers(); + if(n > synth.oscilsize / 2) n = synth.oscilsize / 2; for(int i = 1; i < n; ++i) { if(what == 0) - spc[i] = abs(myBuffers.pendingfreqs, i); + spc[i] = abs(bfrs.pendingfreqs, i); else { if(Pcurrentbasefunc == 0) spc[i] = ((i == 1) ? (1.0f) : (0.0f)); else - spc[i] = abs(myBuffers.basefuncFFTfreqs.data, i); + spc[i] = abs(bfrs.basefuncFFTfreqs.data, i); } } spc[0]=0; if(what == 0) { for(int i = 0; i < n; ++i) - myBuffers.outoscilFFTfreqs[i] = fft_t(spc[i], spc[i]); + bfrs.outoscilFFTfreqs[i] = fft_t(spc[i], spc[i]); fft_t zero = 0; - std::fill_n(myBuffers.outoscilFFTfreqs.data + n, synth.oscilsize / 2 - n, zero); - adaptiveharmonic(myBuffers.outoscilFFTfreqs.data, 0.0f); - adaptiveharmonicpostprocess(myBuffers.outoscilFFTfreqs.data, n - 1); + std::fill_n(bfrs.outoscilFFTfreqs.data + n, synth.oscilsize / 2 - n, zero); + adaptiveharmonic(bfrs.outoscilFFTfreqs.data, 0.0f); + adaptiveharmonicpostprocess(bfrs.outoscilFFTfreqs.data, n - 1); for(int i = 0; i < n; ++i) - spc[i] = (float)myBuffers.outoscilFFTfreqs[i].imag(); + spc[i] = (float)bfrs.outoscilFFTfreqs[i].imag(); } } @@ -1231,12 +1245,14 @@ void OscilGen::getspectrum(int n, float *spc, int what) */ void OscilGen::useasbase() { + OscilGenBuffers& bfrs = myBuffers(); + for(int i = 0; i < synth.oscilsize / 2; ++i) - myBuffers.basefuncFFTfreqs[i] = myBuffers.oscilFFTfreqs[i]; + bfrs.basefuncFFTfreqs[i] = bfrs.oscilFFTfreqs[i]; - oldbasefunc = Pcurrentbasefunc = 127; - prepare(); - myBuffers.cachedbasevalid = false; + bfrs.oldbasefunc = Pcurrentbasefunc = 127; + prepare(bfrs); + bfrs.cachedbasevalid = false; } @@ -1245,15 +1261,18 @@ void OscilGen::useasbase() */ void OscilGen::getcurrentbasefunction(FFTsampleBuffer smps) { + OscilGenBuffers& bfrs = myBuffers(); if(Pcurrentbasefunc != 0) - fft->freqs2smps(myBuffers.basefuncFFTfreqs, smps, myBuffers.scratchFreqs); + fft->freqs2smps(bfrs.basefuncFFTfreqs, smps, bfrs.scratchFreqs); else - getbasefunction(smps); //the sine case + getbasefunction(bfrs, smps); //the sine case } #define COPY(y) this->y = o.y void OscilGen::paste(OscilGen &o) { + OscilGenBuffers& bfrs = myBuffers(); + //XXX Figure out a better implementation of this sensitive to RT issues... for(int i=0; i<MAX_AD_HARMONICS; ++i) { COPY(Phmag[i]); @@ -1296,13 +1315,15 @@ void OscilGen::paste(OscilGen &o) if(this->Pcurrentbasefunc) - changebasefunction(); - this->prepare(); + changebasefunction(bfrs); + this->prepare(bfrs); } #undef COPY void OscilGen::add2XML(XMLwrapper& xml) { + const OscilGenBuffers& bfrs = myBuffers(); + xml.addpar("harmonic_mag_type", Phmagtype); xml.addpar("base_function", Pcurrentbasefunc); @@ -1352,12 +1373,12 @@ void OscilGen::add2XML(XMLwrapper& xml) xml.endbranch(); if(Pcurrentbasefunc == 127) { - normalize(myBuffers.basefuncFFTfreqs.data, synth.oscilsize); + normalize(bfrs.basefuncFFTfreqs.data, synth.oscilsize); xml.beginbranch("BASE_FUNCTION"); for(int i = 1; i < synth.oscilsize / 2; ++i) { - float xc = (float)myBuffers.basefuncFFTfreqs[i].real(); - float xs = (float)myBuffers.basefuncFFTfreqs[i].imag(); + float xc = (float)bfrs.basefuncFFTfreqs[i].real(); + float xs = (float)bfrs.basefuncFFTfreqs[i].imag(); if((fabsf(xs) > 1e-6f) || (fabsf(xc) > 1e-6f)) { xml.beginbranch("BF_HARMONIC", i); xml.addparreal("cos", xc); @@ -1371,6 +1392,8 @@ void OscilGen::add2XML(XMLwrapper& xml) void OscilGen::getfromXML(XMLwrapper& xml) { + OscilGenBuffers& bfrs = myBuffers(); + Phmagtype = xml.getpar127("harmonic_mag_type", Phmagtype); Pcurrentbasefunc = xml.getpar127("base_function", Pcurrentbasefunc); @@ -1450,21 +1473,21 @@ void OscilGen::getfromXML(XMLwrapper& xml) } if(Pcurrentbasefunc != 0) - changebasefunction(); + changebasefunction(bfrs); if(xml.enterbranch("BASE_FUNCTION")) { for(int i = 1; i < synth.oscilsize / 2; ++i) if(xml.enterbranch("BF_HARMONIC", i)) { - myBuffers.basefuncFFTfreqs[i] = + bfrs.basefuncFFTfreqs[i] = std::complex<float>(xml.getparreal("cos", 0.0f), xml.getparreal("sin", 0.0f)); xml.exitbranch(); } xml.exitbranch(); - clearDC(myBuffers.basefuncFFTfreqs.data); - normalize(myBuffers.basefuncFFTfreqs.data, synth.oscilsize); - myBuffers.cachedbasevalid = false; + clearDC(bfrs.basefuncFFTfreqs.data); + normalize(bfrs.basefuncFFTfreqs.data, synth.oscilsize); + bfrs.cachedbasevalid = false; }} diff --git a/src/Synth/OscilGen.h b/src/Synth/OscilGen.h @@ -21,13 +21,40 @@ namespace zyn { -// all temporary stuff -class OscilGenBuffers +class NoCopyNoMove { - friend class OscilGen; - OscilGenBuffers(FFTwrapper *fft_, int oscilsize); +public: + NoCopyNoMove() = default; + NoCopyNoMove(const NoCopyNoMove& other) = delete; + NoCopyNoMove& operator=(const NoCopyNoMove& other) = delete; + NoCopyNoMove(NoCopyNoMove&& other) = delete; + NoCopyNoMove& operator=(NoCopyNoMove&& other) = delete; +}; + +//Temporary args to safely create OscilGenBuffers +struct OscilGenBuffersCreator +{ + FFTwrapper* const fft; + const int oscilsize; + OscilGenBuffersCreator(FFTwrapper* fft, int oscilsize) : + fft(fft), oscilsize(oscilsize) {} +}; +//All temporary variables and buffers for OscilGen computations +class OscilGenBuffers : NoCopyNoMove +{ public: + OscilGenBuffers(OscilGenBuffersCreator creator); + ~OscilGenBuffers(); + void defaults(); + +private: + // OscilGen needs to work with this data + // Anyone else should not touch these + friend class OscilGen; + + const int oscilsize; + FFTfreqBuffer oscilFFTfreqs; fft_t *pendingfreqs; @@ -39,27 +66,44 @@ public: FFTfreqBuffer basefuncFFTfreqs; //Base function frequencies FFTfreqBuffer scratchFreqs; //Yet another tmp buffer + + //Internal Data + unsigned char oldbasefunc, oldbasepar, oldhmagtype, + oldwaveshapingfunction, oldwaveshaping; + int oldfilterpars, oldsapars, oldbasefuncmodulation, + oldbasefuncmodulationpar1, oldbasefuncmodulationpar2, + oldbasefuncmodulationpar3, oldharmonicshift; + int oldmodulation, oldmodulationpar1, oldmodulationpar2, + oldmodulationpar3; + + int oscilprepared; //1 if the oscil is prepared, 0 if it is not prepared and is need to call ::prepare() before ::get() + + float hmag[MAX_AD_HARMONICS], hphase[MAX_AD_HARMONICS]; //the magnituides and the phases of the sine/nonsine harmonics }; -class OscilGen:public Presets +class OscilGen:public Presets, NoCopyNoMove { public: OscilGen(const SYNTH_T &synth, FFTwrapper *fft_, Resonance *res_); - ~OscilGen() override; - OscilGenBuffers createOscilGenBuffers() const; + //You need to call this func if you need your own buffers for get() etc. + OscilGenBuffersCreator createOscilGenBuffers() const; /**computes the full spectrum of oscil from harmonics,phases and basefunc*/ - void prepare(); + void prepare(OscilGenBuffers& bfrs) const; + void prepare() { return prepare(myBuffers()); } - void prepare(FFTfreqBuffer data); + void prepare(OscilGenBuffers& bfrs, FFTfreqBuffer data) const; /**do the antialiasing(cut off higher freqs.),apply randomness and do a IFFT*/ //returns where should I start getting samples, used in block type randomness - short get(float *smps, float freqHz, int resonance = 0); + short get(OscilGenBuffers& bfrs, float *smps, float freqHz, int resonance = 0) const; + short get(float *smps, float freqHz, int resonance = 0) { + return get(myBuffers(), smps, freqHz, resonance); + } //if freqHz is smaller than 0, return the "un-randomized" sample for UI - void getbasefunction(FFTsampleBuffer smps); + void getbasefunction(OscilGenBuffers& bfrs, FFTsampleBuffer smps) const; //called by UI void getspectrum(int n, float *spc, int what); //what=0 pt. oscil,1 pt. basefunc @@ -138,56 +182,51 @@ class OscilGen:public Presets * this is different than the harmonics set-up by the user, * it may contain time-domain data if the antialiasing is turned off*/ - private: + //Access m_myBuffers. Should be avoided. + OscilGenBuffers& myBuffers() { return m_myBuffers; } - OscilGenBuffers myBuffers; + private: - float hmag[MAX_AD_HARMONICS], hphase[MAX_AD_HARMONICS]; //the magnituides and the phases of the sine/nonsine harmonics + //This has the advantage that it is the "old", "stable" code, and that + //prepare can be re-used. The disadvantage is that, if multiple threads + //work on this variable in parallel, race conditions would be possible. + //So this might vanish, soon + OscilGenBuffers m_myBuffers; FFTwrapper *fft; //computes the basefunction and make the FFT; newbasefunc<0 = same basefunc - void changebasefunction(void); + void changebasefunction(OscilGenBuffers& bfrs) const; //Waveshaping - void waveshape(FFTfreqBuffer freqs); + void waveshape(OscilGenBuffers& bfrs, FFTfreqBuffer freqs) const; //Filter the oscillator accotding to Pfiltertype and Pfilterpar - void oscilfilter(fft_t *freqs); + void oscilfilter(fft_t *freqs) const; //Adjust the spectrum - void spectrumadjust(fft_t *freqs); + void spectrumadjust(fft_t *freqs) const; //Shift the harmonics - void shiftharmonics(fft_t *freqs); + void shiftharmonics(fft_t *freqs) const; //Do the oscil modulation stuff - void modulation(FFTfreqBuffer freqs); + void modulation(OscilGenBuffers& bfrs, FFTfreqBuffer freqs) const; - float userfunc(float x); + float userfunc(OscilGenBuffers& bfrs, float x) const; public: //Check system for needed updates - bool needPrepare(void); + bool needPrepare(OscilGenBuffers& bfrs) const; + bool needPrepare() { return needPrepare(myBuffers()); } private: //Do the adaptive harmonic stuff - void adaptiveharmonic(fft_t *f, float freq); + void adaptiveharmonic(fft_t *f, float freq) const; //Do the adaptive harmonic postprocessing (2n+1,2xS,2xA,etc..) //this function is called even for the user interface //this can be called for the sine and components, and for the spectrum //(that's why the sine and cosine components should be processed with a separate call) - void adaptiveharmonicpostprocess(fft_t *f, int size); - - //Internal Data - unsigned char oldbasefunc, oldbasepar, oldhmagtype, - oldwaveshapingfunction, oldwaveshaping; - int oldfilterpars, oldsapars, oldbasefuncmodulation, - oldbasefuncmodulationpar1, oldbasefuncmodulationpar2, - oldbasefuncmodulationpar3, oldharmonicshift; - int oldmodulation, oldmodulationpar1, oldmodulationpar2, - oldmodulationpar3; - - int oscilprepared; //1 if the oscil is prepared, 0 if it is not prepared and is need to call ::prepare() before ::get() + void adaptiveharmonicpostprocess(fft_t *f, int size) const; Resonance *res;