From 8aeefdc5f0c96b00b52a051c370cc634a57cd96e Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 20 Mar 2014 22:57:47 +0000 Subject: [PATCH] part 4 --- .../zynaddsubfx/Synth/ADnote.cpp | 49 +++++++++++++------ .../zynaddsubfx/Synth/SUBnote.cpp | 45 +++++++++++------ .../zynaddsubfx/Synth/SUBnote.h | 1 - 3 files changed, 62 insertions(+), 33 deletions(-) diff --git a/source/modules/native-plugins/zynaddsubfx/Synth/ADnote.cpp b/source/modules/native-plugins/zynaddsubfx/Synth/ADnote.cpp index cd376f6cd..f4d169ced 100644 --- a/source/modules/native-plugins/zynaddsubfx/Synth/ADnote.cpp +++ b/source/modules/native-plugins/zynaddsubfx/Synth/ADnote.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "../globals.h" #include "../Misc/Util.h" @@ -38,7 +40,7 @@ ADnote::ADnote(ADnoteParameters *pars, int portamento_, int midinote_, bool besilent) - :SynthNote(freq, velocity, portamento_, midinote, besilent) + :SynthNote(freq, velocity, portamento_, midinote_, besilent) { tmpwavel = new float [synth->buffersize]; tmpwaver = new float [synth->buffersize]; @@ -139,7 +141,13 @@ ADnote::ADnote(ADnoteParameters *pars, for(int k = 0; k < unison; ++k) { float step = (k / (float) (unison - 1)) * 2.0f - 1.0f; //this makes the unison spread more uniform float val = step + (RND * 2.0f - 1.0f) / (unison - 1); - unison_values[k] = limit(val, min, max); + unison_values[k] = val; + if (min > val) { + min = val; + } + if (max < val) { + max = val; + } } float diff = max - min; for(int k = 0; k < unison; ++k) { @@ -1102,30 +1110,39 @@ inline void ADnote::fadein(float *smps) const /* * Computes the Oscillator (Without Modulation) - LinearInterpolation */ + +/* As the code here is a bit odd due to optimization, here is what happens + * First the current possition and frequency are retrieved from the running + * state. These are broken up into high and low portions to indicate how many + * samples are skipped in one step and how many fractional samples are skipped. + * Outside of this method the fractional samples are just handled with floating + * point code, but that's a bit slower than it needs to be. In this code the low + * portions are known to exist between 0.0 and 1.0 and it is known that they are + * stored in single precision floating point IEEE numbers. This implies that + * a maximum of 24 bits are significant. The below code does your standard + * linear interpolation that you'll see throughout this codebase, but by + * sticking to integers for tracking the overflow of the low portion, around 15% + * of the execution time was shaved off in the ADnote test. + */ inline void ADnote::ComputeVoiceOscillator_LinearInterpolation(int nvoice) { - int i, poshi; - float poslo; - for(int k = 0; k < unison_size[nvoice]; ++k) { - poshi = oscposhi[nvoice][k]; - poslo = oscposlo[nvoice][k]; + int poshi = oscposhi[nvoice][k]; + int poslo = oscposlo[nvoice][k] * (1<<24); int freqhi = oscfreqhi[nvoice][k]; - float freqlo = oscfreqlo[nvoice][k]; + int freqlo = oscfreqlo[nvoice][k] * (1<<24); float *smps = NoteVoicePar[nvoice].OscilSmp; float *tw = tmpwave_unison[k]; - for(i = 0; i < synth->buffersize; ++i) { - tw[i] = smps[poshi] * (1.0f - poslo) + smps[poshi + 1] * poslo; + assert(oscfreqlo[nvoice][k] < 1.0f); + for(int i = 0; i < synth->buffersize; ++i) { + tw[i] = (smps[poshi] * ((1<<24) - poslo) + smps[poshi + 1] * poslo)/(1.0f*(1<<24)); poslo += freqlo; - if(poslo >= 1.0f) { - poslo -= 1.0f; - poshi++; - } - poshi += freqhi; + poshi += freqhi + (poslo>>24); + poslo &= 0xffffff; poshi &= synth->oscilsize - 1; } oscposhi[nvoice][k] = poshi; - oscposlo[nvoice][k] = poslo; + oscposlo[nvoice][k] = poslo/(1.0f*(1<<24)); } } diff --git a/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.cpp b/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.cpp index eb9b0dfa0..91045c56f 100644 --- a/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.cpp +++ b/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.cpp @@ -322,30 +322,43 @@ void SUBnote::initfilter(bpfilter &filter, /* * Do the filtering */ -inline float SUBnote::SubFilter(bpfilter &filter, const float input) const + +inline void SubFilterA(const float coeff[4], float &src, float work[4]) { - const float out = input * filter.b0 + filter.b2 * filter.xn2 - - filter.a1 * filter.yn1 - filter.a2 * filter.yn2; - filter.xn2 = filter.xn1; - filter.xn1 = input; - filter.yn2 = filter.yn1; - filter.yn1 = out; - return out; + work[3] = src*coeff[0]+work[1]*coeff[1]+work[2]*coeff[2]+work[3]*coeff[3]; + work[1] = src; + src = work[3]; } +inline void SubFilterB(const float coeff[4], float &src, float work[4]) +{ + work[2] = src*coeff[0]+work[0]*coeff[1]+work[3]*coeff[2]+work[2]*coeff[3]; + work[0] = src; + src = work[2]; +} + +//This dance is designed to minimize unneeded memory operations which can result +//in quite a bit of wasted time void SUBnote::filter(bpfilter &filter, float *smps) { assert(synth->buffersize % 8 == 0); + float coeff[4] = {filter.b0, filter.b2, -filter.a1, -filter.a2}; + float work[4] = {filter.xn1, filter.xn2, filter.yn1, filter.yn2}; + for(int i = 0; i < synth->buffersize; i += 8) { - smps[i] = SubFilter(filter, smps[i]); - smps[i + 1] = SubFilter(filter, smps[i + 1]); - smps[i + 2] = SubFilter(filter, smps[i + 2]); - smps[i + 3] = SubFilter(filter, smps[i + 3]); - smps[i + 4] = SubFilter(filter, smps[i + 4]); - smps[i + 5] = SubFilter(filter, smps[i + 5]); - smps[i + 6] = SubFilter(filter, smps[i + 6]); - smps[i + 7] = SubFilter(filter, smps[i + 7]); + SubFilterA(coeff, smps[i + 0], work); + SubFilterB(coeff, smps[i + 1], work); + SubFilterA(coeff, smps[i + 2], work); + SubFilterB(coeff, smps[i + 3], work); + SubFilterA(coeff, smps[i + 4], work); + SubFilterB(coeff, smps[i + 5], work); + SubFilterA(coeff, smps[i + 6], work); + SubFilterB(coeff, smps[i + 7], work); } + filter.xn1 = work[0]; + filter.xn2 = work[1]; + filter.yn1 = work[2]; + filter.yn2 = work[3]; } /* diff --git a/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.h b/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.h index 21e406233..cd95b8104 100644 --- a/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.h +++ b/source/modules/native-plugins/zynaddsubfx/Synth/SUBnote.h @@ -95,7 +95,6 @@ class SUBnote:public SynthNote float freq, float bw, float gain); - inline float SubFilter(bpfilter &filter, float input) const; inline void filter(bpfilter &filter, float *smps); bpfilter *lfilter, *rfilter;