zynaddsubfx

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

commit 2910076d7d79511883887c219c8b98de29318e19
parent d384e3236b6399562c301eb25269f7bc9ae066e9
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sat, 13 Sep 2014 15:10:07 -0400

Instate Realtime Safe Allocator

The realtime thread should no longer make *ANY* calls out to malloc
on note allocation.
The Realtime Allocator currently uses a fixed sized pool handed to
the TLSF Allocator.
One Allocator instance per Master instance is required.
Some buggyness is expected to be introduced in this patch to the effect
subsystem, as a parameter/runtime separation had to be made in order for
pointer swapping operations to remain possible.

Remaining Severe Realtime Threading Issues:
- Note Initialization for ADnote
  - Large FFT On noteOn:
    - Can be Fixed with A wavetable approach to ADnote like padnote,
      though this does introduce memory concerns for some cases
  - Possible path to prepare() detected by stoat
    - This should already be inactive, but some study needs to be done
- Bank Swap appears to be still in the RT side
  - Redirect midi to MiddleWare

Diffstat:
Msrc/CMakeLists.txt | 1+
Msrc/DSP/AnalogFilter.h | 4++--
Msrc/DSP/Filter.cpp | 10++++++----
Msrc/DSP/Filter.h | 2+-
Msrc/DSP/FormantFilter.cpp | 9+++++----
Msrc/DSP/FormantFilter.h | 4+++-
Msrc/Effects/Alienwah.cpp | 23++++++++++-------------
Msrc/Effects/Alienwah.h | 12+-----------
Msrc/Effects/Chorus.cpp | 13+++++++------
Msrc/Effects/Chorus.h | 2+-
Msrc/Effects/Distorsion.cpp | 21+++++++++++----------
Msrc/Effects/Distorsion.h | 2+-
Msrc/Effects/DynamicFilter.cpp | 21+++++++++++----------
Msrc/Effects/DynamicFilter.h | 2+-
Msrc/Effects/EQ.cpp | 9+++++----
Msrc/Effects/EQ.h | 2+-
Msrc/Effects/Echo.cpp | 13+++++++------
Msrc/Effects/Echo.h | 2+-
Msrc/Effects/Effect.cpp | 24++++++++++++++----------
Msrc/Effects/Effect.h | 41++++++++++++++++++++++++++++++-----------
Msrc/Effects/EffectMgr.cpp | 79+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/Effects/EffectMgr.h | 23++++++++++++++++-------
Msrc/Effects/Phaser.cpp | 54+++++++++++++++++++++---------------------------------
Msrc/Effects/Phaser.h | 2+-
Msrc/Effects/Reverb.cpp | 65+++++++++++++++++++++++++++--------------------------------------
Msrc/Effects/Reverb.h | 2+-
Asrc/Misc/Allocator.cpp | 26++++++++++++++++++++++++++
Asrc/Misc/Allocator.h | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Misc/CMakeLists.txt | 1+
Msrc/Misc/Master.cpp | 27++++++++++++++++++++-------
Msrc/Misc/Master.h | 9+++++++--
Msrc/Misc/MiddleWare.cpp | 202++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/Misc/Part.cpp | 525+++++++++++++++++++++++++++++--------------------------------------------------
Msrc/Misc/Part.h | 31+++++++++++++++++--------------
Msrc/Misc/Util.h | 6++++++
Msrc/Synth/ADnote.cpp | 241+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/Synth/ADnote.h | 19++++++-------------
Msrc/Synth/Envelope.cpp | 3+--
Msrc/Synth/OscilGen.cpp | 32+++++++++++---------------------
Msrc/Synth/PADnote.cpp | 75++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/Synth/PADnote.h | 13+++----------
Msrc/Synth/SUBnote.cpp | 72++++++++++++++++++++++++++++++++----------------------------------------
Msrc/Synth/SUBnote.h | 8+++-----
Msrc/Synth/SynthNote.cpp | 34+++++++++++++++++++---------------
Msrc/Synth/SynthNote.h | 39+++++++++++++++++++++++++++++++--------
Msrc/Tests/AdNoteTest.h | 11++++-------
Msrc/Tests/CMakeLists.txt | 6+++---
Msrc/Tests/EchoTest.h | 5++++-
Msrc/Tests/PadNoteTest.h | 11++++-------
Msrc/Tests/RtAllocTest.h | 4+++-
Msrc/Tests/SubNoteTest.h | 11++++-------
Msrc/Tests/UnisonTest.h | 5++++-
Mtlsf/tlsf.h | 5+++++
53 files changed, 986 insertions(+), 991 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -323,6 +323,7 @@ add_subdirectory(DSP) add_subdirectory(Nio) add_library(zynaddsubfx_core STATIC + ../tlsf/tlsf.c ${zynaddsubfx_dsp_SRCS} ${zynaddsubfx_effect_SRCS} ${zynaddsubfx_misc_SRCS} diff --git a/src/DSP/AnalogFilter.h b/src/DSP/AnalogFilter.h @@ -48,8 +48,8 @@ class AnalogFilter:public Filter void cleanup(); float H(float freq); //Obtains the response for a given frequency - - + + struct Coeff { float c[3], //Feed Forward d[3]; //Feed Back diff --git a/src/DSP/Filter.cpp b/src/DSP/Filter.cpp @@ -28,6 +28,7 @@ #include "FormantFilter.h" #include "SVFilter.h" #include "../Params/FilterParams.h" +#include "../Misc/Allocator.h" Filter::Filter(unsigned int srate, int bufsize) : outgain(1.0f), @@ -37,7 +38,8 @@ Filter::Filter(unsigned int srate, int bufsize) alias(); } -Filter *Filter::generate(FilterParams *pars, unsigned int srate, int bufsize) +Filter *Filter::generate(Allocator &memory, FilterParams *pars, + unsigned int srate, int bufsize) { if (srate == 0) srate = synth->samplerate; @@ -50,16 +52,16 @@ Filter *Filter::generate(FilterParams *pars, unsigned int srate, int bufsize) Filter *filter; switch(pars->Pcategory) { case 1: - filter = new FormantFilter(pars, srate, bufsize); + filter = memory.alloc<FormantFilter>(pars, memory, srate, bufsize); break; case 2: - filter = new SVFilter(Ftype, 1000.0f, pars->getq(), Fstages, srate, bufsize); + filter = memory.alloc<SVFilter>(Ftype, 1000.0f, pars->getq(), Fstages, srate, bufsize); filter->outgain = dB2rap(pars->getgain()); if(filter->outgain > 1.0f) filter->outgain = sqrt(filter->outgain); break; default: - filter = new AnalogFilter(Ftype, 1000.0f, pars->getq(), Fstages, srate, bufsize); + filter = memory.alloc<AnalogFilter>(Ftype, 1000.0f, pars->getq(), Fstages, srate, bufsize); if((Ftype >= 6) && (Ftype <= 8)) filter->setgain(pars->getgain()); else diff --git a/src/DSP/Filter.h b/src/DSP/Filter.h @@ -29,7 +29,7 @@ class Filter { public: static float getrealfreq(float freqpitch); - static Filter *generate(class FilterParams * pars, unsigned int srate = 0, int bufsize = 0); + static Filter *generate(class Allocator &memory, class FilterParams * pars, unsigned int srate = 0, int bufsize = 0); Filter(unsigned int srate, int bufsize); virtual ~Filter() {} diff --git a/src/DSP/FormantFilter.cpp b/src/DSP/FormantFilter.cpp @@ -23,16 +23,17 @@ #include <cmath> #include <cstdio> #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "FormantFilter.h" #include "AnalogFilter.h" #include "../Params/FilterParams.h" -FormantFilter::FormantFilter(FilterParams *pars, unsigned int srate, int bufsize) - : Filter(srate, bufsize) +FormantFilter::FormantFilter(FilterParams *pars, Allocator &alloc, unsigned int srate, int bufsize) + : Filter(srate, bufsize), memory(alloc) { numformants = pars->Pnumformants; for(int i = 0; i < numformants; ++i) - formant[i] = new AnalogFilter(4 /*BPF*/, 1000.0f, 10.0f, pars->Pstages, srate, bufsize); + formant[i] = memory.alloc<AnalogFilter>(4 /*BPF*/, 1000.0f, 10.0f, pars->Pstages, srate, bufsize); cleanup(); for(int j = 0; j < FF_MAX_VOWELS; ++j) @@ -78,7 +79,7 @@ FormantFilter::FormantFilter(FilterParams *pars, unsigned int srate, int bufsize FormantFilter::~FormantFilter() { for(int i = 0; i < numformants; ++i) - delete (formant[i]); + memory.dealloc(formant[i]); } void FormantFilter::cleanup() diff --git a/src/DSP/FormantFilter.h b/src/DSP/FormantFilter.h @@ -27,10 +27,11 @@ #include "Filter.h" +class Allocator; class FormantFilter:public Filter { public: - FormantFilter(class FilterParams *pars, unsigned int srate, int bufsize); + FormantFilter(class FilterParams *pars, Allocator &alloc, unsigned int srate, int bufsize); ~FormantFilter(); void filterout(float *smp); void setfreq(float frequency); @@ -61,6 +62,7 @@ class FormantFilter:public Filter float oldinput, slowinput; float Qfactor, formantslowness, oldQfactor; float vowelclearness, sequencestretch; + Allocator &memory; }; #endif diff --git a/src/Effects/Alienwah.cpp b/src/Effects/Alienwah.cpp @@ -21,11 +21,12 @@ */ #include <cmath> +#include "../Misc/Allocator.h" #include "Alienwah.h" -Alienwah::Alienwah(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), - lfo(srate, bufsize), +Alienwah::Alienwah(EffectParams pars) + :Effect(pars), + lfo(pars.srate, pars.bufsize), oldl(NULL), oldr(NULL) { @@ -37,10 +38,8 @@ Alienwah::Alienwah(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned i Alienwah::~Alienwah() { - if(oldl != NULL) - delete [] oldl; - if(oldr != NULL) - delete [] oldr; + delete [] oldl; + delete [] oldr; } @@ -139,13 +138,11 @@ void Alienwah::setphase(unsigned char _Pphase) void Alienwah::setdelay(unsigned char _Pdelay) { - if(oldl != NULL) - delete [] oldl; - if(oldr != NULL) - delete [] oldr; + memory.devalloc(oldl); + memory.devalloc(oldr); Pdelay = (_Pdelay >= MAX_ALIENWAH_DELAY) ? MAX_ALIENWAH_DELAY : _Pdelay; - oldl = new complex<float>[Pdelay]; - oldr = new complex<float>[Pdelay]; + oldl = memory.valloc<complex<float>>(Pdelay); + oldr = memory.valloc<complex<float>>(Pdelay); cleanup(); } diff --git a/src/Effects/Alienwah.h b/src/Effects/Alienwah.h @@ -35,17 +35,7 @@ using namespace std; class Alienwah:public Effect { public: - /** - * Constructor - * @param insertion_ true for insertion Effect - * @param efxoutl_ Pointer to Alienwah's left channel output buffer - * @param efxoutr_ Pointer to Alienwah's left channel output buffer - * @return Initialized Alienwah - */ - Alienwah(bool insertion_, - float *const efxoutl_, - float *const efxoutr_, - unsigned int srate, int bufsize); + Alienwah(EffectParams pars); ~Alienwah(); void out(const Stereo<float *> &smp); diff --git a/src/Effects/Chorus.cpp b/src/Effects/Chorus.cpp @@ -21,16 +21,17 @@ */ #include <cmath> +#include "../Misc/Allocator.h" #include "Chorus.h" #include <iostream> using namespace std; -Chorus::Chorus(bool insertion_, float *const efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), - lfo(srate, bufsize), +Chorus::Chorus(EffectParams pars) + :Effect(pars), + lfo(pars.srate, pars.bufsize), maxdelay((int)(MAX_CHORUS_DELAY / 1000.0f * samplerate_f)), - delaySample(new float[maxdelay], new float[maxdelay]) + delaySample(memory.valloc<float>(maxdelay), memory.valloc<float>(maxdelay)) { dlk = 0; drk = 0; @@ -44,8 +45,8 @@ Chorus::Chorus(bool insertion_, float *const efxoutl_, float *efxoutr_, unsigned Chorus::~Chorus() { - delete [] delaySample.l; - delete [] delaySample.r; + memory.devalloc(delaySample.l); + memory.devalloc(delaySample.r); } //get the delay value in samples; xlfo is the current lfo value diff --git a/src/Effects/Chorus.h b/src/Effects/Chorus.h @@ -32,7 +32,7 @@ class Chorus:public Effect { public: - Chorus(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + Chorus(EffectParams pars); /**Destructor*/ ~Chorus(); void out(const Stereo<float *> &input); diff --git a/src/Effects/Distorsion.cpp b/src/Effects/Distorsion.cpp @@ -23,10 +23,11 @@ #include "Distorsion.h" #include "../DSP/AnalogFilter.h" #include "../Misc/WaveShapeSmps.h" +#include "../Misc/Allocator.h" #include <cmath> -Distorsion::Distorsion(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), +Distorsion::Distorsion(EffectParams pars) + :Effect(pars), Pvolume(50), Pdrive(90), Plevel(64), @@ -37,20 +38,20 @@ Distorsion::Distorsion(bool insertion_, float *efxoutl_, float *efxoutr_, unsign Pstereo(0), Pprefiltering(0) { - lpfl = new AnalogFilter(2, 22000, 1, 0, srate, bufsize); - lpfr = new AnalogFilter(2, 22000, 1, 0, srate, bufsize); - hpfl = new AnalogFilter(3, 20, 1, 0, srate, bufsize); - hpfr = new AnalogFilter(3, 20, 1, 0, srate, bufsize); + lpfl = memory.alloc<AnalogFilter>(2, 22000, 1, 0, pars.srate, pars.bufsize); + lpfr = memory.alloc<AnalogFilter>(2, 22000, 1, 0, pars.srate, pars.bufsize); + hpfl = memory.alloc<AnalogFilter>(3, 20, 1, 0, pars.srate, pars.bufsize); + hpfr = memory.alloc<AnalogFilter>(3, 20, 1, 0, pars.srate, pars.bufsize); setpreset(Ppreset); cleanup(); } Distorsion::~Distorsion() { - delete lpfl; - delete lpfr; - delete hpfl; - delete hpfr; + memory.dealloc(lpfl); + memory.dealloc(lpfr); + memory.dealloc(hpfl); + memory.dealloc(hpfr); } //Cleanup the effect diff --git a/src/Effects/Distorsion.h b/src/Effects/Distorsion.h @@ -29,7 +29,7 @@ class Distorsion:public Effect { public: - Distorsion(bool insertion, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + Distorsion(EffectParams pars); ~Distorsion(); void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); diff --git a/src/Effects/DynamicFilter.cpp b/src/Effects/DynamicFilter.cpp @@ -23,10 +23,11 @@ #include <cmath> #include "DynamicFilter.h" #include "../DSP/Filter.h" +#include "../Misc/Allocator.h" -DynamicFilter::DynamicFilter(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, new FilterParams(0, 64, 64), 0, srate, bufsize), - lfo(srate, bufsize), +DynamicFilter::DynamicFilter(EffectParams pars) + :Effect(pars), + lfo(pars.srate, pars.bufsize), Pvolume(110), Pdepth(0), Pampsns(90), @@ -41,9 +42,9 @@ DynamicFilter::DynamicFilter(bool insertion_, float *efxoutl_, float *efxoutr_, DynamicFilter::~DynamicFilter() { - delete filterpars; - delete filterl; - delete filterr; + memory.dealloc(filterpars); + memory.dealloc(filterl); + memory.dealloc(filterr); } @@ -129,10 +130,10 @@ void DynamicFilter::setampsns(unsigned char _Pampsns) void DynamicFilter::reinitfilter(void) { - delete filterl; - delete filterr; - filterl = Filter::generate(filterpars, samplerate, buffersize); - filterr = Filter::generate(filterpars, samplerate, buffersize); + memory.dealloc(filterl); + memory.dealloc(filterr); + filterl = Filter::generate(memory, filterpars, samplerate, buffersize); + filterr = Filter::generate(memory, filterpars, samplerate, buffersize); } void DynamicFilter::setpreset(unsigned char npreset) diff --git a/src/Effects/DynamicFilter.h b/src/Effects/DynamicFilter.h @@ -30,7 +30,7 @@ class DynamicFilter:public Effect { public: - DynamicFilter(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + DynamicFilter(EffectParams pars); ~DynamicFilter(); void out(const Stereo<float *> &smp); diff --git a/src/Effects/EQ.cpp b/src/Effects/EQ.cpp @@ -23,9 +23,10 @@ #include <cmath> #include "EQ.h" #include "../DSP/AnalogFilter.h" +#include "../Misc/Allocator.h" -EQ::EQ(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize) +EQ::EQ(EffectParams pars) + :Effect(pars) { for(int i = 0; i < MAX_EQ_BANDS; ++i) { filter[i].Ptype = 0; @@ -33,8 +34,8 @@ EQ::EQ(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, in filter[i].Pgain = 64; filter[i].Pq = 64; filter[i].Pstages = 0; - filter[i].l = new AnalogFilter(6, 1000.0f, 1.0f, 0, srate, bufsize); - filter[i].r = new AnalogFilter(6, 1000.0f, 1.0f, 0, srate, bufsize); + filter[i].l = memory.alloc<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize); + filter[i].r = memory.alloc<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize); } //default values Pvolume = 50; diff --git a/src/Effects/EQ.h b/src/Effects/EQ.h @@ -29,7 +29,7 @@ class EQ:public Effect { public: - EQ(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + EQ(EffectParams pars); ~EQ() {} void out(const Stereo<float *> &smp); void setpreset(unsigned char npreset); diff --git a/src/Effects/Echo.cpp b/src/Effects/Echo.cpp @@ -23,12 +23,13 @@ */ #include <cmath> +#include "../Misc/Allocator.h" #include "Echo.h" #define MAX_DELAY 2 -Echo::Echo(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), +Echo::Echo(EffectParams pars) + :Effect(pars), Pvolume(50), Pdelay(60), Plrdelay(100), @@ -37,8 +38,8 @@ Echo::Echo(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate delayTime(1), lrdelay(0), avgDelay(0), - delay(new float[(int)(MAX_DELAY * srate)], - new float[(int)(MAX_DELAY * srate)]), + delay(memory.valloc<float>(MAX_DELAY * pars.srate), + memory.valloc<float>(MAX_DELAY * pars.srate)), old(0.0f), pos(0), delta(1), @@ -50,8 +51,8 @@ Echo::Echo(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate Echo::~Echo() { - delete[] delay.l; - delete[] delay.r; + memory.devalloc(delay.l); + memory.devalloc(delay.r); } //Cleanup the effect diff --git a/src/Effects/Echo.h b/src/Effects/Echo.h @@ -30,7 +30,7 @@ class Echo:public Effect { public: - Echo(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + Echo(EffectParams pars); ~Echo(); void out(const Stereo<float *> &input); diff --git a/src/Effects/Effect.cpp b/src/Effects/Effect.cpp @@ -25,16 +25,20 @@ #include "../Params/FilterParams.h" #include <cmath> -Effect::Effect(bool insertion_, float *efxoutl_, float *efxoutr_, - FilterParams *filterpars_, unsigned char Ppreset_, - unsigned int srate, int bufsize) - :Ppreset(Ppreset_), - efxoutl(efxoutl_), - efxoutr(efxoutr_), - filterpars(filterpars_), - insertion(insertion_), - samplerate(srate), - buffersize(bufsize) +EffectParams::EffectParams(Allocator &alloc_, bool insertion_, float *efxoutl_, float *efxoutr_, + unsigned char Ppreset_, unsigned int srate_, int bufsize_, FilterParams *filterpars_) + :alloc(alloc_), insertion(insertion_), efxoutl(efxoutl_), efxoutr(efxoutr_), + Ppreset(Ppreset_), srate(srate_), bufsize(bufsize_), filterpars(filterpars_) +{} +Effect::Effect(EffectParams pars) + :Ppreset(pars.Ppreset), + efxoutl(pars.efxoutl), + efxoutr(pars.efxoutr), + filterpars(pars.filterpars), + insertion(pars.insertion), + memory(pars.alloc), + samplerate(pars.srate), + buffersize(pars.bufsize) { alias(); } diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h @@ -29,22 +29,38 @@ #include "../Misc/Stereo.h" class FilterParams; +class Allocator; + +struct EffectParams +{ + /** + * Effect Parameter Constructor + * @param alloc Realtime Memory Allocator + * @param insertion_ 1 when it is an insertion Effect + * @param efxoutl_ Effect output buffer Left channel + * @param efxoutr_ Effect output buffer Right channel + * @param filterpars_ pointer to FilterParams array + * @param Ppreset_ chosen preset + * @return Initialized Effect Parameter object*/ + EffectParams(Allocator &alloc_, bool insertion_, float *efxoutl_, float *efxoutr_, + unsigned char Ppreset_, unsigned int srate, int bufsize, FilterParams *filterpars_=0); + + + Allocator &alloc; + bool insertion; + float *efxoutl; + float *efxoutr; + unsigned char Ppreset; + unsigned int srate; + int bufsize; + FilterParams *filterpars; +}; /**this class is inherited by the all effects(Reverb, Echo, ..)*/ class Effect { public: - /** - * Effect Constructor - * @param insertion_ 1 when it is an insertion Effect - * @param efxoutl_ Effect output buffer Left channel - * @param efxoutr_ Effect output buffer Right channel - * @param filterpars_ pointer to FilterParams array - * @param Ppreset_ chosen preset - * @return Initialized Effect object*/ - Effect(bool insertion_, float *efxoutl_, float *efxoutr_, - FilterParams *filterpars_, unsigned char Ppreset_, - unsigned int srate, int bufsize); + Effect(EffectParams pars); virtual ~Effect() {} /** * Choose a preset @@ -102,6 +118,9 @@ class Effect char Plrcross; // L/R mix float lrcross; + //Allocator + Allocator &memory; + // current setup unsigned int samplerate; int buffersize; diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp @@ -35,6 +35,7 @@ #include "../Misc/XMLwrapper.h" #include "../Misc/Util.h" #include "../Params/FilterParams.h" +#include "../Misc/Allocator.h" rtosc::Ports EffectMgr::ports = { @@ -49,7 +50,7 @@ rtosc::Ports EffectMgr::ports = { if(!rtosc_narguments(msg)) d.reply(d.loc, "c", eff->geteffectpar(atoi(mm))); else - eff->seteffectpar_nolock(atoi(mm), rtosc_argument(msg, 0).i); + eff->seteffectparrt(atoi(mm), rtosc_argument(msg, 0).i); }}, {"preset::c", rProp(alias) rDoc("Effect Preset Selector"), NULL, [](const char *msg, rtosc::RtData &d) @@ -58,7 +59,7 @@ rtosc::Ports EffectMgr::ports = { if(!rtosc_narguments(msg)) d.reply(d.loc, "c", eff->getpreset()); else - eff->changepreset_nolock(rtosc_argument(msg, 0).i); + eff->changepresetrt(rtosc_argument(msg, 0).i); }}, {"eq-coeffs:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL, [](const char *, rtosc::RtData &d) @@ -99,14 +100,15 @@ rtosc::Ports EffectMgr::ports = { }; -EffectMgr::EffectMgr(const bool insertion_) +EffectMgr::EffectMgr(Allocator &alloc, const bool insertion_) :insertion(insertion_), efxoutl(new float[synth->buffersize]), efxoutr(new float[synth->buffersize]), filterpars(NULL), nefx(0), efx(NULL), - dryonly(false) + dryonly(false), + memory(alloc) { setpresettype("Peffect"); memset(efxoutl, 0, synth->bufferbytes); @@ -117,7 +119,7 @@ EffectMgr::EffectMgr(const bool insertion_) EffectMgr::~EffectMgr() { - delete efx; + memory.dealloc(efx); delete [] efxoutl; delete [] efxoutr; } @@ -129,43 +131,41 @@ void EffectMgr::defaults(void) } //Change the effect -void EffectMgr::changeeffect(int _nefx) +void EffectMgr::changeeffectrt(int _nefx) { - //TODO there should be a sane way to upper bound the memory of every effect - //and just use placement new to eliminate any allocation/deallocation when - //chaning effects - cleanup(); if(nefx == _nefx) return; nefx = _nefx; memset(efxoutl, 0, synth->bufferbytes); memset(efxoutr, 0, synth->bufferbytes); - delete efx; + memory.dealloc(efx); + EffectParams pars(memory, insertion, efxoutl, efxoutr, 0, + synth->samplerate, synth->buffersize); switch(nefx) { case 1: - efx = new Reverb(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<Reverb>(pars); break; case 2: - efx = new Echo(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<Echo>(pars); break; case 3: - efx = new Chorus(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<Chorus>(pars); break; case 4: - efx = new Phaser(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<Phaser>(pars); break; case 5: - efx = new Alienwah(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<Alienwah>(pars); break; case 6: - efx = new Distorsion(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<Distorsion>(pars); break; case 7: - efx = new EQ(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<EQ>(pars); break; case 8: - efx = new DynamicFilter(insertion, efxoutl, efxoutr, synth->samplerate, synth->buffersize); + efx = memory.alloc<DynamicFilter>(pars); break; //put more effect here default: @@ -177,12 +177,28 @@ void EffectMgr::changeeffect(int _nefx) filterpars = efx->filterpars; } +void EffectMgr::changeeffect(int _nefx) +{ + effect_id = 0; + preset = 0; + memset(settings, 0, sizeof(settings)); +} + //Obtain the effect number int EffectMgr::geteffect(void) { return nefx; } +// Initialize An Effect in RT context +void EffectMgr::init(void) +{ + changeeffectrt(effect_id); + changepresetrt(preset); + for(int i=0; i<128; ++i) + seteffectparrt(i, settings[i]); +} + // Cleanup the current effect void EffectMgr::cleanup(void) { @@ -201,31 +217,30 @@ unsigned char EffectMgr::getpreset(void) } // Change the preset of the current effect -void EffectMgr::changepreset_nolock(unsigned char npreset) +void EffectMgr::changepreset(unsigned char npreset) { - if(efx) - efx->setpreset(npreset); + preset = npreset; } -//Change the preset of the current effect(with thread locking) -void EffectMgr::changepreset(unsigned char npreset) +// Change the preset of the current effect +void EffectMgr::changepresetrt(unsigned char npreset) { - abort(); + if(efx) + efx->setpreset(npreset); } - //Change a parameter of the current effect -void EffectMgr::seteffectpar_nolock(int npar, unsigned char value) +void EffectMgr::seteffectparrt(int npar, unsigned char value) { if(!efx) return; efx->changepar(npar, value); } -// Change a parameter of the current effect (with thread locking) +//Change a parameter of the current effect void EffectMgr::seteffectpar(int npar, unsigned char value) { - abort(); + settings[npar] = value; } //Get a parameter of the current effect @@ -305,7 +320,7 @@ void EffectMgr::out(float *smpsl, float *smpsr) // Get the effect volume for the system effect float EffectMgr::sysefxgetvolume(void) { - return (!efx) ? 1.0f : efx->outvolume; + return efx ? efx->outvolume : 1.0f; } @@ -357,11 +372,11 @@ void EffectMgr::getfromXML(XMLwrapper *xml) if(xml->enterbranch("EFFECT_PARAMETERS")) { for(int n = 0; n < 128; ++n) { - seteffectpar_nolock(n, 0); //erase effect parameter + seteffectpar(n, 0); //erase effect parameter if(xml->enterbranch("par_no", n) == 0) continue; int par = geteffectpar(n); - seteffectpar_nolock(n, xml->getpar127("par", par)); + seteffectpar(n, xml->getpar127("par", par)); xml->exitbranch(); } if(filterpars) diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h @@ -31,11 +31,11 @@ class Effect; class FilterParams; class XMLwrapper; +class Allocator; #include "Distorsion.h" #include "EQ.h" #include "DynamicFilter.h" -#include "../Misc/XMLwrapper.h" #include "../Params/FilterParams.h" #include "../Params/Presets.h" @@ -43,7 +43,7 @@ class XMLwrapper; class EffectMgr:public Presets { public: - EffectMgr(const bool insertion_); + EffectMgr(Allocator &alloc, const bool insertion_); ~EffectMgr(); void add2XML(XMLwrapper *xml); @@ -57,15 +57,17 @@ class EffectMgr:public Presets /**get the output(to speakers) volume of the systemeffect*/ float sysefxgetvolume(void); + void init(void) REALTIME; void cleanup(void) REALTIME; - void changeeffect(int nefx_); + void changeeffectrt(int nefx_) REALTIME; + void changeeffect(int nefx_) NONREALTIME; int geteffect(void); - void changepreset(unsigned char npreset) REALTIME; - void changepreset_nolock(unsigned char npreset); + void changepreset(unsigned char npreset) NONREALTIME; + void changepresetrt(unsigned char npreset) REALTIME; unsigned char getpreset(void); - void seteffectpar(int npar, unsigned char value) REALTIME; - void seteffectpar_nolock(int npar, unsigned char value); + void seteffectpar(int npar, unsigned char value) NONREALTIME; + void seteffectparrt(int npar, unsigned char value) REALTIME; unsigned char geteffectpar(int npar); const bool insertion; @@ -80,7 +82,14 @@ class EffectMgr:public Presets int nefx; Effect *efx; private: + + //Parameters Prior to initialization + char effect_id; + char preset; + char settings[128]; + bool dryonly; + Allocator &memory; }; #endif diff --git a/src/Effects/Phaser.cpp b/src/Effects/Phaser.cpp @@ -31,6 +31,7 @@ #include <cmath> #include <algorithm> +#include "../Misc/Allocator.h" #include "Phaser.h" using namespace std; @@ -39,8 +40,8 @@ using namespace std; #define ONE_ 0.99999f // To prevent LFO ever reaching 1.0f for filter stability purposes #define ZERO_ 0.00001f // Same idea as above. -Phaser::Phaser(const int &insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), lfo(srate, bufsize), old(NULL), xn1(NULL), +Phaser::Phaser(EffectParams pars) + :Effect(pars), lfo(pars.srate, pars.bufsize), old(NULL), xn1(NULL), yn1(NULL), diff(0.0f), oldgain(0.0f), fb(0.0f) { analog_setup(); @@ -78,18 +79,12 @@ void Phaser::analog_setup() Phaser::~Phaser() { - if(old.l) - delete[] old.l; - if(xn1.l) - delete[] xn1.l; - if(yn1.l) - delete[] yn1.l; - if(old.r) - delete[] old.r; - if(xn1.r) - delete[] xn1.r; - if(yn1.r) - delete[] yn1.r; + memory.devalloc(old.l); + memory.devalloc(old.r); + memory.devalloc(xn1.l); + memory.devalloc(xn1.r); + memory.devalloc(yn1.l); + memory.devalloc(yn1.r); } /* @@ -303,30 +298,23 @@ void Phaser::setoffset(unsigned char Poffset) void Phaser::setstages(unsigned char Pstages) { - if(old.l) - delete[] old.l; - if(xn1.l) - delete[] xn1.l; - if(yn1.l) - delete[] yn1.l; - if(old.r) - delete[] old.r; - if(xn1.r) - delete[] xn1.r; - if(yn1.r) - delete[] yn1.r; - + memory.devalloc(old.l); + memory.devalloc(old.r); + memory.devalloc(xn1.l); + memory.devalloc(xn1.r); + memory.devalloc(yn1.l); + memory.devalloc(yn1.r); this->Pstages = min(MAX_PHASER_STAGES, (int)Pstages); - old = Stereo<float *>(new float[Pstages * 2], - new float[Pstages * 2]); + old = Stereo<float *>(memory.valloc<float>(Pstages * 2), + memory.valloc<float>(Pstages * 2)); - xn1 = Stereo<float *>(new float[Pstages], - new float[Pstages]); + xn1 = Stereo<float *>(memory.valloc<float>(Pstages), + memory.valloc<float>(Pstages)); - yn1 = Stereo<float *>(new float[Pstages], - new float[Pstages]); + yn1 = Stereo<float *>(memory.valloc<float>(Pstages), + memory.valloc<float>(Pstages)); cleanup(); } diff --git a/src/Effects/Phaser.h b/src/Effects/Phaser.h @@ -35,7 +35,7 @@ class Phaser:public Effect { public: - Phaser(const int &insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + Phaser(EffectParams pars); ~Phaser(); void out(const Stereo<float *> &input); void setpreset(unsigned char npreset); diff --git a/src/Effects/Reverb.cpp b/src/Effects/Reverb.cpp @@ -22,12 +22,13 @@ #include "Reverb.h" #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "../DSP/AnalogFilter.h" #include "../DSP/Unison.h" #include <cmath> -Reverb::Reverb(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) - :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), +Reverb::Reverb(EffectParams pars) + :Effect(pars), // defaults Pvolume(48), Ptime(64), @@ -66,35 +67,33 @@ Reverb::Reverb(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int s Reverb::~Reverb() { - delete [] idelay; - delete hpf; - delete lpf; + memory.devalloc(idelay); + memory.dealloc(hpf); + memory.dealloc(lpf); for(int i = 0; i < REV_APS * 2; ++i) - delete [] ap[i]; + memory.devalloc(ap[i]); for(int i = 0; i < REV_COMBS * 2; ++i) - delete [] comb[i]; + memory.devalloc(comb[i]); - if(bandwidth) - delete bandwidth; + memory.dealloc(bandwidth); } //Cleanup the effect void Reverb::cleanup(void) { - int i, j; - for(i = 0; i < REV_COMBS * 2; ++i) { + for(int i = 0; i < REV_COMBS * 2; ++i) { lpcomb[i] = 0.0f; - for(j = 0; j < comblen[i]; ++j) + for(int j = 0; j < comblen[i]; ++j) comb[i][j] = 0.0f; } - for(i = 0; i < REV_APS * 2; ++i) - for(j = 0; j < aplen[i]; ++j) + for(int i = 0; i < REV_APS * 2; ++i) + for(int j = 0; j < aplen[i]; ++j) ap[i][j] = 0.0f; if(idelay) - for(i = 0; i < idelaylen; ++i) + for(int i = 0; i < idelaylen; ++i) idelay[i] = 0.0f; if(hpf) hpf->cleanup(); @@ -232,14 +231,12 @@ void Reverb::setidelay(unsigned char _Pidelay) Pidelay = _Pidelay; float delay = powf(50.0f * Pidelay / 127.0f, 2.0f) - 1.0f; - if(idelay) - delete [] idelay; - idelay = NULL; + memory.devalloc(idelay); idelaylen = (int) (samplerate_f * delay / 1000); if(idelaylen > 1) { idelayk = 0; - idelay = new float[idelaylen]; + idelay = memory.valloc<float>(idelaylen); memset(idelay, 0, idelaylen * sizeof(float)); } } @@ -254,14 +251,11 @@ void Reverb::sethpf(unsigned char _Phpf) { Phpf = _Phpf; if(Phpf == 0) { //No HighPass - if(hpf) - delete hpf; - hpf = NULL; - } - else { + memory.dealloc(hpf); + } else { float fr = expf(powf(Phpf / 127.0f, 0.5f) * logf(10000.0f)) + 20.0f; if(hpf == NULL) - hpf = new AnalogFilter(3, fr, 1, 0, samplerate, buffersize); + hpf = memory.alloc<AnalogFilter>(3, fr, 1, 0, samplerate, buffersize); else hpf->setfreq(fr); } @@ -271,14 +265,11 @@ void Reverb::setlpf(unsigned char _Plpf) { Plpf = _Plpf; if(Plpf == 127) { //No LowPass - if(lpf) - delete lpf; - lpf = NULL; - } - else { + memory.dealloc(lpf); + } else { float fr = expf(powf(Plpf / 127.0f, 0.5f) * logf(25000.0f)) + 40.0f; if(!lpf) - lpf = new AnalogFilter(2, fr, 1, 0, samplerate, buffersize); + lpf = memory.alloc<AnalogFilter>(2, fr, 1, 0, samplerate, buffersize); else lpf->setfreq(fr); } @@ -326,9 +317,8 @@ void Reverb::settype(unsigned char _Ptype) comblen[i] = (int) tmp; combk[i] = 0; lpcomb[i] = 0; - if(comb[i]) - delete [] comb[i]; - comb[i] = new float[comblen[i]]; + memory.devalloc(comb[i]); + comb[i] = memory.valloc<float>(comblen[i]); } for(int i = 0; i < REV_APS * 2; ++i) { @@ -344,9 +334,8 @@ void Reverb::settype(unsigned char _Ptype) tmp = 10; aplen[i] = (int) tmp; apk[i] = 0; - if(ap[i]) - delete [] ap[i]; - ap[i] = new float[aplen[i]]; + memory.devalloc(ap[i]); + ap[i] = memory.valloc<float>(aplen[i]); } delete bandwidth; bandwidth = NULL; @@ -355,7 +344,7 @@ void Reverb::settype(unsigned char _Ptype) //not been verified yet. //As this cannot be resized in a RT context, a good upper bound should //be found - bandwidth = new Unison(buffersize / 4 + 1, 2.0f, samplerate_f); + bandwidth = memory.alloc<Unison>(buffersize / 4 + 1, 2.0f, samplerate_f); bandwidth->setSize(50); bandwidth->setBaseFrequency(1.0f); } diff --git a/src/Effects/Reverb.h b/src/Effects/Reverb.h @@ -32,7 +32,7 @@ class Reverb:public Effect { public: - Reverb(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize); + Reverb(EffectParams pars); ~Reverb(); void out(const Stereo<float *> &smp); void cleanup(void); diff --git a/src/Misc/Allocator.cpp b/src/Misc/Allocator.cpp @@ -0,0 +1,26 @@ +#include <cstddef> +#include <cstdlib> +#include <utility> +#include <cstdio> +#include "../../tlsf/tlsf.h" +#include "Allocator.h" + +Allocator::Allocator(void) +{ + void *buf = malloc(1024*1024); + impl = tlsf_create_with_pool(buf, 1024*1024); +} + +void *Allocator::alloc_mem(size_t mem_size) +{ + void *mem = tlsf_malloc(impl, mem_size); + //fprintf(stderr, "Allocating memory (%p)\n", mem); + return mem; + //return malloc(mem_size); +} +void Allocator::dealloc_mem(void *memory) +{ + //fprintf(stderr, "Freeing memory (%p)\n", memory); + tlsf_free(impl, memory); + //free(memory); +} diff --git a/src/Misc/Allocator.h b/src/Misc/Allocator.h @@ -0,0 +1,114 @@ +#include <cstdlib> + +class Allocator +{ + public: + Allocator(void); + virtual void *alloc_mem(size_t mem_size); + virtual void dealloc_mem(void *memory); + + template <typename T, typename... Ts> + T *alloc(Ts... ts) + { + void *data = alloc_mem(sizeof(T)); + if(!data) + return nullptr; + return new (data) T(ts...); + } + + template <typename T, typename... Ts> + T *valloc(size_t len, Ts... ts) + { + T *data = (T*)alloc_mem(len*sizeof(T)); + if(!data) + return nullptr; + for(unsigned i=0; i<len; ++i) + new ((void*)&data[i]) T(ts...); + + return data; + } + + template <typename T> + void dealloc(T*&t) + { + if(t) { + t->~T(); + dealloc_mem((void*)t); + t = nullptr; + } + } + + //Destructor Free Version + template <typename T> + void devalloc(T*&t) + { + if(t) { + dealloc_mem(t); + t = nullptr; + } + } + + template <typename T> + void devalloc(size_t elms, T*&t) + { + if(t) { + for(size_t i=0; i<elms; ++i) + (t+i)->~T(); + + dealloc_mem(t); + t = nullptr; + } + } + + void addMemory(void *, size_t mem_size);//{(void)mem_size;}; + + //Return true if the current pool cannot allocate n chunks of chunk_size + bool lowMemory(unsigned n, size_t chunk_size);//{(void)n;(void)chunk_size; return false;}; + + void *impl; +}; + +//Memory that could either be from the heap or from the realtime allocator +//This should be avoided when possible, but it's not clear if it can be avoided +//in all cases +template<class T> +class HeapRtMem +{ +}; + + +//A helper class used to perform a series of allocations speculatively to verify +//that there is enough memory for a set transation to occur. +//Stuff will get weird if this ends up failing, but it will be able to at least +//detect where there is an issue +class StaticAllocFreeVerifyier +{ + void *scratch_buf[4096]; + unsigned alloc_count; +}; + + +/** + * General notes on Memory Allocation Within ZynAddSubFX + * ----------------------------------------------------- + * + * - Parameter Objects Are never allocated within the realtime thread + * - Effects, notes and note subcomponents must be allocated with an allocator + * - 5M Chunks are used to give the allocator the memory it wants + * - If there are 3 chunks that are unused then 1 will be deallocated + * - The system will request more allocated space if 5x 1MB chunks cannot be + * allocated at any given time (this is likely huge overkill, but if this is + * satisfied, then a lot of note spamming would be needed to run out of + * space) + * + * - Things will get a bit weird around the effects due to how pointer swaps + * occur + * * When a new Part instance is provided it may or may not come with some + * instrument effects + * * Merging blocks is an option, but one that is not going to likely be + * implmented too soon, thus all effects need to be reallocated when the + * pointer swap occurs + * * The old effect is extracted from the manager + * * A new one is constructed with a deep copy + * * The old one is returned to middleware for deallocation + */ diff --git a/src/Misc/CMakeLists.txt b/src/Misc/CMakeLists.txt @@ -13,6 +13,7 @@ set(zynaddsubfx_misc_SRCS Misc/WavFile.cpp Misc/WaveShapeSmps.cpp Misc/MiddleWare.cpp + Misc/Allocator.cpp ) diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -28,6 +28,7 @@ #include "../Params/LFOParams.h" #include "../Effects/EffectMgr.h" #include "../DSP/FFTwrapper.h" +#include "../Misc/Allocator.h" #include "../Nio/Nio.h" #include <rtosc/ports.h> @@ -177,6 +178,7 @@ vuData::vuData(void) Master::Master() :midi(Master::ports), frozenState(false) { + memory = new Allocator(); the_master = this; swaplr = 0; off = 0; @@ -193,15 +195,15 @@ Master::Master() } for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) - part[npart] = new Part(&microtonal, fft); + part[npart] = new Part(*memory, &microtonal, fft); //Insertion Effects init for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx) - insefx[nefx] = new EffectMgr(1); + insefx[nefx] = new EffectMgr(*memory, 1); //System Effects init for(int nefx = 0; nefx < NUM_SYS_EFX; ++nefx) - sysefx[nefx] = new EffectMgr(0); + sysefx[nefx] = new EffectMgr(*memory, 0); defaults(); @@ -325,11 +327,11 @@ void Master::setController(char chan, int type, int par) switch(parhi) { case 0x04: //System Effects if(parlo < NUM_SYS_EFX) - sysefx[parlo]->seteffectpar_nolock(valhi, vallo); + sysefx[parlo]->seteffectparrt(valhi, vallo); break; case 0x08: //Insertion Effects if(parlo < NUM_INS_EFX) - insefx[parlo]->seteffectpar_nolock(valhi, vallo); + insefx[parlo]->seteffectparrt(valhi, vallo); break; } } @@ -457,7 +459,7 @@ void Master::AudioOut(float *outl, float *outr) //fprintf(stdout, "address '%s'\n", uToB->peak()); ports.dispatch(msg+1, d); events++; - if(!d.matches && !ports.apropos(msg)) { + if(!d.matches) {// && !ports.apropos(msg)) { fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); fprintf(stderr, "Unknown address '%s'\n", uToB->peak()); fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); @@ -492,7 +494,7 @@ void Master::AudioOut(float *outl, float *outr) //Apply the part volumes and pannings (after insertion effects) for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) { - if(part[npart]->Penabled == 0) + if(part[npart]->Penabled) continue; Stereo<float> newvol(part[npart]->volume), @@ -733,6 +735,17 @@ void Master::applyparameters(void) part[npart]->applyparameters(); } +void Master::initialize_rt(void) +{ + for(int i=0; i<NUM_SYS_EFX; ++i) + sysefx[i]->init(); + for(int i=0; i<NUM_INS_EFX; ++i) + insefx[i]->init(); + + for(int i=0; i<NUM_MIDI_PARTS; ++i) + part[i]->initialize_rt(); +} + void Master::add2XML(XMLwrapper *xml) { xml->addpar("volume", Pvolume); diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -36,6 +36,7 @@ #include "../Params/Controller.h" +class Allocator; extern Dump dump; struct vuData { @@ -74,13 +75,16 @@ class Master /**Regenerate PADsynth and other non-RT parameters * It is NOT SAFE to call this from a RT context*/ - void applyparameters(void); + void applyparameters(void) NONREALTIME; + + //This must be called prior-to/at-the-time-of RT insertion + void initialize_rt(void) REALTIME; void getfromXML(XMLwrapper *xml); /**get all data to a newly allocated array (used for VST) * @return the datasize*/ - int getalldata(char **data); + int getalldata(char **data) NONREALTIME; /**put all data from the *data array to zynaddsubfx parameters (used for VST)*/ void putalldata(char *data, int size); @@ -163,6 +167,7 @@ class Master rtosc::MidiTable midi;//<1024,64> bool frozenState;//read-only parameters for threadsafe actions + Allocator *memory; private: float sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; float sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp @@ -18,8 +18,8 @@ #include "Master.h" #include "Part.h" #include "../Params/ADnoteParameters.h" +#include "../Params/SUBnoteParameters.h" #include "../Params/PADnoteParameters.h" -#include "../Effects/EffectMgr.h" #include <string> #include <future> @@ -136,8 +136,6 @@ void deallocate(const char *str, void *v) delete (Part*)v; else if(!strcmp(str, "Master")) delete (Master*)v; - else if(!strcmp(str, "EffectMgr")) - delete (EffectMgr*)v; else if(!strcmp(str, "fft_t")) delete[] (fft_t*)v; else @@ -146,16 +144,6 @@ void deallocate(const char *str, void *v) -/** - * - Fetches liblo messages and forward them to the backend - * - Grabs backend messages and distributes them to the frontends - */ -//void osc_check(cb_t cb, void *ui) -//{ -//} - - - void preparePadSynth(string path, PADnoteParameters *p) { printf("preparing padsynth parameters\n"); @@ -231,24 +219,6 @@ void bankPos(Bank &bank, Fl_Osc_Interface *osc) osc->tryLink(response); } -void createEffect(const char *msg) -{ - const bool insertion = !strstr(msg, "sysefx"); - const int efftype = rtosc_argument(msg, 0).i; - EffectMgr *em = new EffectMgr(insertion); - em->changeeffect(efftype); - uToB->write(msg, "b", sizeof(EffectMgr*), &em); -} - -// -//static rtosc::Ports padPorts= { -// {"prepare:", "::Prepares the padnote instance", 0, } -//}; -// -//static rtosc::Ports oscilPorts = { -// {"prepare:", "", 0, } -//}; - class DummyDataObj:public rtosc::RtData { public: @@ -308,12 +278,70 @@ class DummyDataObj:public rtosc::RtData }; -/** - * Forwarding logic - * if(!dispatch(msg, data)) - * forward(msg) - */ +//Storage For Objects which need to be interfaced with outside the realtime +//thread (aka they have long lived operations which can be done out-of-band) +struct NonRtObjStore +{ + std::map<std::string, void*> objmap; + + void extractMaster(Master *master) + { + for(int i=0; i < NUM_MIDI_PARTS; ++i) { + extractPart(master->part[i], i); + } + } + void extractPart(Part *part, int i) + { + for(int j=0; j < NUM_KIT_ITEMS; ++j) { + std::string base = "/part"+to_s(i)+"/kit"+to_s(j)+"/"; + auto &obj = part->kit[i]; + if(obj.padpars) { + objmap[base+"padpars/"] = obj.padpars; + objmap[base+"padpars/oscil/"] = obj.padpars->oscilgen; + } else { + objmap[base+"padpars/"] = nullptr; + objmap[base+"padpars/oscil/"] = nullptr; + } + + for(int k=0; k<NUM_VOICES; ++k) { + std::string nbase = base+"adpars/voice"+to_s(k)+"/"; + if(obj.adpars) { + auto &nobj = obj.adpars->VoicePar[k]; + objmap[nbase+"oscil/"] = nobj.OscilSmp; + objmap[nbase+"mod-oscil/"] = nobj.FMSmp; + } else { + objmap[nbase+"oscil/"] = nullptr; + objmap[nbase+"mod-oscil/"] = nullptr; + } + } + } + } + + void clear(void) + { + objmap.clear(); + } + + bool has(std::string loc) + { + return objmap.find(loc) != objmap.end(); + } + + void *get(std::string loc) + { + return objmap[loc]; + } +}; + +//Parameter Storage Used For Controlled/Safe Allocations +//(and possibly saving/loading) +struct ParamStore +{ + ADnoteParameters *add[NUM_MIDI_PARTS][NUM_KIT_ITEMS]; + SUBnoteParameters *sub[NUM_MIDI_PARTS][NUM_KIT_ITEMS]; + PADnoteParameters *pad[NUM_MIDI_PARTS][NUM_KIT_ITEMS]; +}; static Fl_Osc_Interface *genOscInterface(struct MiddleWareImpl*); @@ -356,20 +384,7 @@ public: osc = genOscInterface(this); //Grab objects of interest from master - for(int i=0; i < NUM_MIDI_PARTS; ++i) { - for(int j=0; j < NUM_KIT_ITEMS; ++j) { - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/padpars/"] = - master->part[i]->kit[j].padpars; - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/padpars/oscil/"] = - master->part[i]->kit[j].padpars->oscilgen; - for(int k=0; k<NUM_VOICES; ++k) { - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil/"] = - master->part[i]->kit[j].adpars->VoicePar[k].OscilSmp; - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/mod-oscil/"] = - master->part[i]->kit[j].adpars->VoicePar[k].FMSmp; - } - } - } + obj_store.extractMaster(master); //Null out Load IDs for(int i=0; i < NUM_MIDI_PARTS; ++i) { @@ -472,7 +487,6 @@ public: void loadPart(int npart, const char *filename, Master *master, Fl_Osc_Interface *osc) { - printf("loading part...\n"); actual_load[npart]++; if(actual_load[npart] != pending_load[npart]) @@ -480,43 +494,23 @@ public: assert(actual_load[npart] <= pending_load[npart]); auto alloc = std::async(std::launch::async, - [master,filename,this,npart](){Part *p = new Part(&master->microtonal, master->fft); + [master,filename,this,npart](){Part *p = new Part(*master->memory, &master->microtonal, master->fft); if(p->loadXMLinstrument(filename)) fprintf(stderr, "FAILED TO LOAD PART!!\n"); p->applyparameters([this,npart]{printf("%d vs %d\n", (int)actual_load[npart], (int)pending_load[npart]);return actual_load[npart] != pending_load[npart];}); return p;}); - //fprintf(stderr, "loading a part!!\n"); + //Load the part if(idle) { while(alloc.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { - printf("idle...\n"); idle(); } - } else - printf("no idle\n"); - printf("part allocated...\n"); - Part *p = alloc.get();//new Part(&master->microtonal, master->fft); - //fprintf(stderr, "Part[%d] is stored in '%s'\n", npart, filename); - //if(p->loadXMLinstrument(filename)) - // fprintf(stderr, "FAILED TO LOAD PART!!\n"); + } - //p->applyparameters(); + Part *p = alloc.get(); - //Update the resource locators - string base = "/part"+to_s(npart)+"/kit"; - for(int j=0; j < NUM_KIT_ITEMS; ++j) { - objmap[base+to_s(j)+"/padpars/"] = - p->kit[j].padpars; - objmap[base+to_s(j)+"/padpars/oscil/"] = - p->kit[j].padpars->oscilgen; - for(int k=0; k<NUM_VOICES; ++k) { - objmap[base+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil/"] = - p->kit[j].adpars->VoicePar[k].OscilSmp; - objmap[base+to_s(j)+"/adpars/voice"+to_s(k)+"/mod-oscil/"] = - p->kit[j].adpars->VoicePar[k].FMSmp; - } - } + obj_store.extractPart(p, npart); //Give it to the backend and wait for the old part to return for //deallocation @@ -534,21 +528,8 @@ public: m->applyparameters(); //Update resource locator table - objmap.clear(); - for(int i=0; i < NUM_MIDI_PARTS; ++i) { - for(int j=0; j < NUM_KIT_ITEMS; ++j) { - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/padpars/"] = - m->part[i]->kit[j].padpars; - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/padpars/oscil/"] = - m->part[i]->kit[j].padpars->oscilgen; - for(int k=0; k<NUM_VOICES; ++k) { - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/oscil/"] = - m->part[i]->kit[j].adpars->VoicePar[k].OscilSmp; - objmap["/part"+to_s(i)+"/kit"+to_s(j)+"/adpars/voice"+to_s(k)+"/mod-oscil/"] = - m->part[i]->kit[j].adpars->VoicePar[k].FMSmp; - } - } - } + obj_store.clear(); + obj_store.extractMaster(m); master = m; @@ -589,7 +570,7 @@ public: } } } else if(curr_url == "GUI" || !strcmp(rtmsg, "/close-ui")) { - cb(ui, rtmsg); //GUI::raiseUi(gui, bToU->read()); + cb(ui, rtmsg); } else{ lo_message msg = lo_message_deserialise((void*)rtmsg, rtosc_message_length(rtmsg, bToU->buffer_size()), NULL); @@ -618,20 +599,12 @@ public: DummyDataObj d(buffer, 1024, v, cb, ui, osc); strcpy(buffer, path.c_str()); - //for(auto &p:OscilGen::ports.ports) { - // if(strstr(p.name,msg) && strstr(p.metadata, "realtime") && - // !strcmp("b", rtosc_argument_string(msg))) { - // printf("sending along packet '%s'...\n", msg); - // return false; - // } - //} - PADnoteParameters::ports.dispatch(msg, d); if(!d.matches) { - //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); - //fprintf(stderr, "Unknown location '%s%s'<%s>\n", - // path.c_str(), msg, rtosc_argument_string(msg)); - //fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); + fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 1, 7 + 30, 0 + 40); + fprintf(stderr, "Unknown location '%s%s'<%s>\n", + path.c_str(), msg, rtosc_argument_string(msg)); + fprintf(stderr, "%c[%d;%d;%dm", 0x1B, 0, 7 + 30, 0 + 40); } return true; @@ -698,19 +671,17 @@ public: loadBank(master->bank, rtosc_argument(msg, 0).i, osc); } else if(!strcmp(msg, "/loadbank") && !strcmp(rtosc_argument_string(msg), "")) { bankPos(master->bank, osc); - } else if(strstr(msg, "efftype") && !strcmp(rtosc_argument_string(msg), "c")) { - createEffect(msg); - } else if(objmap.find(obj_rl) != objmap.end()) { + } else if(obj_store.has(obj_rl)) { //try some over simplified pattern matching if(strstr(msg, "oscil/")) { - if(!handleOscil(obj_rl, last_path+1, objmap[obj_rl])) + if(!handleOscil(obj_rl, last_path+1, obj_store.get(obj_rl))) uToB->raw_write(msg); //else if(strstr(obj_rl.c_str(), "kititem")) // handleKitItem(obj_rl, objmap[obj_rl],atoi(rindex(msg,'m')+1),rtosc_argument(msg,0).T); } else if(strstr(msg, "padpars/prepare")) - preparePadSynth(obj_rl,(PADnoteParameters *) objmap[obj_rl]); + preparePadSynth(obj_rl,(PADnoteParameters *) obj_store.get(obj_rl)); else if(strstr(msg, "padpars")) { - if(!handlePAD(obj_rl, last_path+1, objmap[obj_rl])) + if(!handlePAD(obj_rl, last_path+1, obj_store.get(obj_rl))) uToB->raw_write(msg); } else //just forward the message uToB->raw_write(msg); @@ -766,7 +737,7 @@ public: /** * TODO These pointers may invalidate when part/master is loaded via xml */ - std::map<std::string, void*> objmap; + NonRtObjStore obj_store; //This code will own the pointer to master, be prepared for odd things if //this assumption is broken @@ -776,6 +747,15 @@ public: //backend Fl_Osc_Interface *osc; + //Information to keep track of which kit parts are active + //Two classes of events are observed + // + //1. When a kit transitions from inactive to active then a set of parameter + // data must be allocated (no deallocation ever occurs here) + //2. When a part is rebuilt from a pointer swap all kit activity is set to + // their new values + ParamStore kits; + void(*idle)(void); cb_t cb; void *ui; diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -24,6 +24,7 @@ #include "Microtonal.h" #include "Util.h" #include "XMLwrapper.h" +#include "Allocator.h" #include "../Effects/EffectMgr.h" #include "../Params/ADnoteParameters.h" #include "../Params/SUBnoteParameters.h" @@ -62,6 +63,7 @@ static Ports partPorts = { rParam(Pvelsns, "Velocity sensing"), rParam(Pveloffs, "Velocity offset"), rToggle(Pnoteon, "If the channel accepts note on events"), + //TODO FIXME Change to 0=OFF 1=MULTI 2=SINGLE rToggle(Pkitmode, "Kit mode enable"), rToggle(Pdrummode, "Drum mode enable"), rToggle(Ppolymode, "Polyphoney mode"), @@ -102,16 +104,17 @@ static Ports partPorts = { //{"kit#16::T:F", "::Enables or disables kit item", 0, // [](const char *m, RtData &d) { + // auto loc = d.loc; // Part *p = (Part*)d.obj; // unsigned kitid = -1; // //Note that this event will be captured before transmitted, thus // //reply/broadcast don't matter - // for(int i=0; i<VOICES; ++i) { - // d.reply("/middleware/oscil", "siisb", loc, kitid, i, "oscil" - // sizeof(OscilGen*), + // for(int i=0; i<NUM_KIT_ITEMS; ++i) { + // d.reply("/middleware/oscil", "siisb", loc, kitid, i, + // "oscil", sizeof(void*), // p->kit[kitid]->adpars->voice[i]->OscilSmp); // d.reply("/middleware/oscil", "siisb", loc, kitid, i, "oscil-mod" - // sizeof(OscilGen*), + // sizeof(void*), // p->kit[kitid]->adpars->voice[i]->somethingelse); // } // d.reply("/middleware/pad", "sib", loc, kitid, @@ -142,7 +145,8 @@ static Ports kitPorts = { Ports &Part::Kit::ports = kitPorts; Ports &Part::ports = partPorts; -Part::Part(Microtonal *microtonal_, FFTwrapper *fft_) +Part::Part(Allocator &alloc, Microtonal *microtonal_, FFTwrapper *fft_) + :memory(alloc) { microtonal = microtonal_; fft = fft_; @@ -151,17 +155,16 @@ Part::Part(Microtonal *microtonal_, FFTwrapper *fft_) for(int n = 0; n < NUM_KIT_ITEMS; ++n) { kit[n].Pname = new char [PART_MAX_NAME_LEN]; - //XXX this is wasting memory, but making interfacing with the back - //layers more nice, if this seems to increase memory usage figure out a - //sane way of tracking the changing pointers (otherwise enjoy the bloat) - kit[n].adpars = new ADnoteParameters(fft); - kit[n].subpars = new SUBnoteParameters(); - kit[n].padpars = new PADnoteParameters(fft); + kit[n].adpars = nullptr; + kit[n].subpars = nullptr; + kit[n].padpars = nullptr; } + + kit[0].adpars = new ADnoteParameters(fft); //Part's Insertion Effects init for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) { - partefx[nefx] = new EffectMgr(1); + partefx[nefx] = new EffectMgr(memory, 1); Pefxbypass[nefx] = false; } @@ -252,13 +255,13 @@ void Part::defaultsinstrument() Pdrummode = 0; for(int n = 0; n < NUM_KIT_ITEMS; ++n) { - kit[n].Penabled = 0; - kit[n].Pmuted = 0; + kit[n].Penabled = false; + kit[n].Pmuted = false; kit[n].Pminkey = 0; kit[n].Pmaxkey = 127; - kit[n].Padenabled = 0; - kit[n].Psubenabled = 0; - kit[n].Ppadenabled = 0; + kit[n].Padenabled = false; + kit[n].Psubenabled = false; + kit[n].Ppadenabled = false; ZERO(kit[n].Pname, PART_MAX_NAME_LEN); kit[n].Psendtoparteffect = 0; if(n != 0) @@ -267,8 +270,6 @@ void Part::defaultsinstrument() kit[0].Penabled = 1; kit[0].Padenabled = 1; kit[0].adpars->defaults(); - kit[0].subpars->defaults(); - kit[0].padpars->defaults(); for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) { partefx[nefx]->defaults(); @@ -303,15 +304,9 @@ Part::~Part() { cleanup(true); for(int n = 0; n < NUM_KIT_ITEMS; ++n) { - if(kit[n].adpars != NULL) - delete (kit[n].adpars); - if(kit[n].subpars != NULL) - delete (kit[n].subpars); - if(kit[n].padpars != NULL) - delete (kit[n].padpars); - kit[n].adpars = NULL; - kit[n].subpars = NULL; - kit[n].padpars = NULL; + delete kit[n].adpars; + delete kit[n].subpars; + delete kit[n].padpars; delete [] kit[n].Pname; } @@ -319,7 +314,7 @@ Part::~Part() delete [] partoutl; delete [] partoutr; for(int nefx = 0; nefx < NUM_PART_EFX; ++nefx) - delete (partefx[nefx]); + delete partefx[nefx]; for(int n = 0; n < NUM_PART_EFX + 1; ++n) { delete [] partfxinputl[n]; delete [] partfxinputr[n]; @@ -333,7 +328,7 @@ void Part::NoteOn(unsigned char note, unsigned char velocity, int masterkeyshift) { - int i, pos; + int pos; // Legato and MonoMem used vars: int posb = POLIPHONY - 1; // Just a dummy initial value. @@ -343,9 +338,7 @@ void Part::NoteOn(unsigned char note, no other notes are held down or sustained.*/ int lastnotecopy = lastnote; //Useful after lastnote has been changed. - if(Pnoteon == 0) - return; - if((note < Pminkey) || (note > Pmaxkey)) + if(!Pnoteon || !inRange(note, Pminkey, Pmaxkey)) return; // MonoMem stuff: @@ -366,13 +359,13 @@ void Part::NoteOn(unsigned char note, lastnote = note; pos = -1; - for(i = 0; i < POLIPHONY; ++i) + for(int i = 0; i < POLIPHONY; ++i) if(partnote[i].status == KEY_OFF) { pos = i; break; } - if((Plegatomode != 0) && (Pdrummode == 0)) { + if(Plegatomode && !Pdrummode) { if(Ppolymode != 0) { fprintf( stderr, @@ -391,14 +384,14 @@ void Part::NoteOn(unsigned char note, } else { // Legato mode is valid, but this is only a first note. - for(i = 0; i < POLIPHONY; ++i) + for(int i = 0; i < POLIPHONY; ++i) if((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELASED_AND_SUSTAINED)) RelaseNotePos(i); // Set posb posb = (pos + 1) % POLIPHONY; //We really want it (if the following fails) - for(i = 0; i < POLIPHONY; ++i) + for(int i = 0; i < POLIPHONY; ++i) if((partnote[i].status == KEY_OFF) && (pos != i)) { posb = i; break; @@ -408,8 +401,8 @@ void Part::NoteOn(unsigned char note, } } else // Legato mode is either off or non-applicable. - if(Ppolymode == 0) { //if the mode is 'mono' turn off all other notes - for(i = 0; i < POLIPHONY; ++i) + if(!Ppolymode) { //if the mode is 'mono' turn off all other notes + for(int i = 0; i < POLIPHONY; ++i) if(partnote[i].status == KEY_PLAYING) RelaseNotePos(i); RelaseSustainedKeys(); @@ -417,7 +410,6 @@ void Part::NoteOn(unsigned char note, lastlegatomodevalid = legatomodevalid; if(pos == -1) - //test fprintf(stderr, "%s", "NOTES TOO MANY (> POLIPHONY) - (Part.cpp::NoteOn(..))\n"); @@ -434,12 +426,7 @@ void Part::NoteOn(unsigned char note, float vel = VelF(velocity / 127.0f, Pvelsns); //compute the velocity offset - vel += (Pveloffs - 64.0f) / 64.0f; - if(vel < 0.0f) - vel = 0.0f; - else - if(vel > 1.0f) - vel = 1.0f; + vel = limit(vel + (Pveloffs - 64.0f) / 64.0f, 0.0f, 1.0f); //compute the keyshift int partkeyshift = (int)Pkeyshift - 64; @@ -450,28 +437,27 @@ void Part::NoteOn(unsigned char note, if(Pdrummode == 0) { notebasefreq = microtonal->getnotefreq(note, keyshift); if(notebasefreq < 0.0f) - return; //the key is no mapped + return;//the key is no mapped } else notebasefreq = 440.0f * powf(2.0f, (note - 69.0f) / 12.0f); - ; //Portamento if(oldfreq < 1.0f) - oldfreq = notebasefreq; //this is only the first note is played + oldfreq = notebasefreq;//this is only the first note is played // For Mono/Legato: Force Portamento Off on first // notes. That means it is required that the previous note is // still held down or sustained for the Portamento to activate // (that's like Legato). - int portamento = 0; - if((Ppolymode != 0) || (not ismonofirstnote)) + bool portamento = false; + if(Ppolymode || !ismonofirstnote) // I added a third argument to the // ctl.initportamento(...) function to be able // to tell it if we're doing a legato note. portamento = ctl.initportamento(oldfreq, notebasefreq, doinglegato); - if(portamento != 0) + if(portamento) ctl.portamento.noteusing = pos; oldfreq = notebasefreq; @@ -480,94 +466,56 @@ void Part::NoteOn(unsigned char note, if(doinglegato) { // Do Legato note if(Pkitmode == 0) { // "normal mode" legato note - if((kit[0].Padenabled != 0) - && (partnote[pos].kititem[0].adnote != NULL) - && (partnote[posb].kititem[0].adnote != NULL)) { - partnote[pos].kititem[0].adnote->legatonote(notebasefreq, - vel, - portamento, - note, - true); //'true' is to tell it it's being called from here. - partnote[posb].kititem[0].adnote->legatonote(notebasefreq, - vel, - portamento, - note, - true); + + auto note1 = partnote[pos].kititem[0]; + auto note2 = partnote[posb].kititem[0]; + LegatoParams pars = {notebasefreq, vel, portamento, note, true}; + if(kit[0].Padenabled && note1.adnote && note2.adnote) { + note1.adnote->legatonote(pars); + note2.adnote->legatonote(pars); } - if((kit[0].Psubenabled != 0) - && (partnote[pos].kititem[0].subnote != NULL) - && (partnote[posb].kititem[0].subnote != NULL)) { - partnote[pos].kititem[0].subnote->legatonote( - notebasefreq, vel, portamento, note, true); - partnote[posb].kititem[0].subnote->legatonote( - notebasefreq, vel, portamento, note, true); + if(kit[0].Psubenabled && note1.subnote && note2.subnote) { + note1.subnote->legatonote(pars); + note2.subnote->legatonote(pars); } - if((kit[0].Ppadenabled != 0) - && (partnote[pos].kititem[0].padnote != NULL) - && (partnote[posb].kititem[0].padnote != NULL)) { - partnote[pos].kititem[0].padnote->legatonote( - notebasefreq, vel, portamento, note, true); - partnote[posb].kititem[0].padnote->legatonote( - notebasefreq, vel, portamento, note, true); + if(kit[0].Ppadenabled && note1.padnote && note2.padnote) { + note1.padnote->legatonote(pars); + note2.padnote->legatonote(pars); } } else { // "kit mode" legato note int ci = 0; for(int item = 0; item < NUM_KIT_ITEMS; ++item) { - if(kit[item].Pmuted != 0) - continue; - if((note < kit[item].Pminkey) || (note > kit[item].Pmaxkey)) + + //Make sure the key is valid and not across multiple ranges + if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey) + || !inRange((unsigned char)lastnotecopy, kit[item].Pminkey, kit[item].Pmaxkey)) continue; - if((lastnotecopy < kit[item].Pminkey) - || (lastnotecopy > kit[item].Pmaxkey)) - continue; // We will not perform legato across 2 key regions. - - partnote[pos].kititem[ci].sendtoparteffect = - (kit[item].Psendtoparteffect < - NUM_PART_EFX ? kit[item].Psendtoparteffect : - NUM_PART_EFX); //if this parameter is 127 for "unprocessed" - partnote[posb].kititem[ci].sendtoparteffect = - (kit[item].Psendtoparteffect < - NUM_PART_EFX ? kit[item].Psendtoparteffect : - NUM_PART_EFX); - - if((kit[item].Padenabled != 0) && (kit[item].adpars != NULL) - && (partnote[pos].kititem[ci].adnote != NULL) - && (partnote[posb].kititem[ci].adnote != NULL)) { - partnote[pos].kititem[ci].adnote->legatonote( - notebasefreq, vel, portamento, note, true); - partnote[posb].kititem[ci].adnote->legatonote( - notebasefreq, vel, portamento, note, true); + auto note1 = partnote[pos].kititem[ci]; + auto note2 = partnote[posb].kititem[ci]; + LegatoParams pars = {notebasefreq, vel, portamento, note, true}; + note1.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX); + note2.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX); + + if(kit[item].Padenabled && kit[item].adpars && note1.adnote && note2.adnote) { + note1.adnote->legatonote(pars); + note2.adnote->legatonote(pars); } - if((kit[item].Psubenabled != 0) - && (kit[item].subpars != NULL) - && (partnote[pos].kititem[ci].subnote != NULL) - && (partnote[posb].kititem[ci].subnote != NULL)) { - partnote[pos].kititem[ci].subnote->legatonote( - notebasefreq, vel, portamento, note, true); - partnote[posb].kititem[ci].subnote->legatonote( - notebasefreq, vel, portamento, note, true); + if(kit[item].Psubenabled && kit[item].subpars && note1.subnote && note2.subnote) { + note1.subnote->legatonote(pars); + note2.subnote->legatonote(pars); } - if((kit[item].Ppadenabled != 0) - && (kit[item].padpars != NULL) - && (partnote[pos].kititem[ci].padnote != NULL) - && (partnote[posb].kititem[ci].padnote != NULL)) { - partnote[pos].kititem[ci].padnote->legatonote( - notebasefreq, vel, portamento, note, true); - partnote[posb].kititem[ci].padnote->legatonote( - notebasefreq, vel, portamento, note, true); + if(kit[item].Ppadenabled && kit[item].padpars && note1.padnote && note2.padnote) { + note1.padnote->legatonote(pars); + note2.padnote->legatonote(pars); } - if((kit[item].adpars != NULL) - || (kit[item].subpars != NULL) - || (kit[item].padpars != NULL)) { + if(kit[item].adpars || kit[item].subpars || kit[item].padpars) { ci++; - if(((kit[item].Padenabled != 0) - || (kit[item].Psubenabled != 0) - || (kit[item].Ppadenabled != 0)) && (Pkitmode == 2)) + if((kit[item].Padenabled || kit[item].Psubenabled || kit[item].Ppadenabled) && (Pkitmode == 2)) break; } } @@ -586,162 +534,89 @@ void Part::NoteOn(unsigned char note, if(Pkitmode == 0) { //init the notes for the "normal mode" partnote[pos].kititem[0].sendtoparteffect = 0; - if(kit[0].Padenabled != 0) - partnote[pos].kititem[0].adnote = new ADnote(kit[0].adpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - false); - if(kit[0].Psubenabled != 0) - partnote[pos].kititem[0].subnote = new SUBnote(kit[0].subpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - false); - if(kit[0].Ppadenabled != 0) - partnote[pos].kititem[0].padnote = new PADnote(kit[0].padpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - false); - if((kit[0].Padenabled != 0) || (kit[0].Psubenabled != 0) - || (kit[0].Ppadenabled != 0)) + SynthParams pars{memory, ctl, notebasefreq, vel, (bool) portamento, note, false}; + + if(kit[0].Padenabled) + partnote[pos].kititem[0].adnote = + memory.alloc<ADnote>(kit[0].adpars, pars); + if(kit[0].Psubenabled) + partnote[pos].kititem[0].subnote = + memory.alloc<SUBnote>(kit[0].subpars, pars); + if(kit[0].Ppadenabled) + partnote[pos].kititem[0].padnote = + memory.alloc<PADnote>(kit[0].padpars, pars); + + + if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled) partnote[pos].itemsplaying++; // Spawn another note (but silent) if legatomodevalid==true if(legatomodevalid) { partnote[posb].kititem[0].sendtoparteffect = 0; - if(kit[0].Padenabled != 0) - partnote[posb].kititem[0].adnote = new ADnote(kit[0].adpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - true); //true for silent. - if(kit[0].Psubenabled != 0) - partnote[posb].kititem[0].subnote = new SUBnote( - kit[0].subpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - true); - if(kit[0].Ppadenabled != 0) - partnote[posb].kititem[0].padnote = new PADnote( - kit[0].padpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - true); - if((kit[0].Padenabled != 0) || (kit[0].Psubenabled != 0) - || (kit[0].Ppadenabled != 0)) + pars.quiet = true; + + if(kit[0].Padenabled) + partnote[posb].kititem[0].adnote = + memory.alloc<ADnote>(kit[0].adpars, pars); + if(kit[0].Psubenabled) + partnote[posb].kititem[0].subnote = + memory.alloc<SUBnote>(kit[0].subpars, pars); + if(kit[0].Ppadenabled) + partnote[posb].kititem[0].padnote = + memory.alloc<PADnote>(kit[0].padpars, pars); + + if(kit[0].Padenabled || kit[0].Psubenabled || kit[0].Ppadenabled) partnote[posb].itemsplaying++; } } else //init the notes for the "kit mode" for(int item = 0; item < NUM_KIT_ITEMS; ++item) { - if(kit[item].Pmuted != 0) - continue; - if((note < kit[item].Pminkey) || (note > kit[item].Pmaxkey)) + if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey)) continue; int ci = partnote[pos].itemsplaying; //ci=current item + auto &note1 = partnote[pos].kititem[ci]; //if this parameter is 127 for "unprocessed" - partnote[pos].kititem[ci].sendtoparteffect = - (kit[item].Psendtoparteffect < NUM_PART_EFX ? - kit[item].Psendtoparteffect : NUM_PART_EFX); - - if((kit[item].adpars != NULL) && ((kit[item].Padenabled) != 0)) - partnote[pos].kititem[ci].adnote = new ADnote( - kit[item].adpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - false); - - if((kit[item].subpars != NULL) && ((kit[item].Psubenabled) != 0)) - partnote[pos].kititem[ci].subnote = new SUBnote( - kit[item].subpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - false); - - if((kit[item].padpars != NULL) && ((kit[item].Ppadenabled) != 0)) - partnote[pos].kititem[ci].padnote = new PADnote( - kit[item].padpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - false); + note1.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX); + + SynthParams pars{memory, ctl, notebasefreq, vel, (bool) portamento, note, false}; + + if(kit[item].adpars && kit[item].Padenabled) + note1.adnote = + memory.alloc<ADnote>(kit[item].adpars, pars); + + if(kit[item].subpars && kit[item].Psubenabled) + note1.subnote = + memory.alloc<SUBnote>(kit[item].subpars, pars); + + if(kit[item].padpars && kit[item].Ppadenabled) + note1.padnote = + memory.alloc<PADnote>(kit[item].padpars, pars); // Spawn another note (but silent) if legatomodevalid==true if(legatomodevalid) { - - //if this parameter is 127 for "unprocessed" - partnote[posb].kititem[ci].sendtoparteffect = - (kit[item].Psendtoparteffect < - NUM_PART_EFX ? kit[item].Psendtoparteffect : - NUM_PART_EFX); - - if((kit[item].adpars != NULL) - && ((kit[item].Padenabled) != 0)) - partnote[posb].kititem[ci].adnote = new ADnote( - kit[item].adpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - true);//true for silent. - if((kit[item].subpars != NULL) - && ((kit[item].Psubenabled) != 0)) - partnote[posb].kititem[ci].subnote = - new SUBnote(kit[item].subpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - true); - if((kit[item].padpars != NULL) - && ((kit[item].Ppadenabled) != 0)) - partnote[posb].kititem[ci].padnote = - new PADnote(kit[item].padpars, - &ctl, - notebasefreq, - vel, - portamento, - note, - true); - - if((kit[item].adpars != NULL) || (kit[item].subpars != NULL)) + auto &note2 = partnote[pos].kititem[ci]; + note2.sendtoparteffect = limit((int)kit[item].Psendtoparteffect, 0, NUM_PART_EFX); + + pars.quiet = true; + if(kit[item].adpars && kit[item].Padenabled) + note2.adnote = + memory.alloc<ADnote>(kit[item].adpars, pars); + if(kit[item].subpars && kit[item].Psubenabled) + note2.subnote = + memory.alloc<SUBnote>(kit[item].subpars, pars); + if(kit[item].padpars && kit[item].Ppadenabled) + note2.padnote = + memory.alloc<PADnote>(kit[item].padpars, pars); + + if(kit[item].adpars || kit[item].subpars || kit[item].padpars) partnote[posb].itemsplaying++; } - if((kit[item].adpars != NULL) || (kit[item].subpars != NULL)) { + if(kit[item].adpars || kit[item].subpars) { partnote[pos].itemsplaying++; - if(((kit[item].Padenabled != 0) - || (kit[item].Psubenabled != 0) - || (kit[item].Ppadenabled != 0)) - && (Pkitmode == 2)) + if((kit[item].Padenabled || kit[item].Psubenabled || kit[item].Ppadenabled) && (Pkitmode == 2)) break; } } @@ -762,12 +637,11 @@ void Part::NoteOff(unsigned char note) //relase the key for(int i = POLIPHONY - 1; i >= 0; i--) //first note in, is first out if there are same note multiple times if((partnote[i].status == KEY_PLAYING) && (partnote[i].note == note)) { - if(ctl.sustain.sustain == 0) { //the sustain pedal is not pushed - if((Ppolymode == 0) && (not monomemnotes.empty())) - MonoMemRenote(); // To play most recent still held note. + if(!ctl.sustain.sustain) { //the sustain pedal is not pushed + if(!Ppolymode && !monomemnotes.empty()) + MonoMemRenote();//Play most recent still active note else RelaseNotePos(i); - /// break; } else //the sustain pedal is pushed partnote[i].status = KEY_RELASED_AND_SUSTAINED; @@ -779,14 +653,12 @@ void Part::PolyphonicAftertouch(unsigned char note, int masterkeyshift) { (void) masterkeyshift; - if(!Pnoteon || (note < Pminkey) || (note > Pmaxkey)) - return; - if(Pdrummode) + + if(!Pnoteon || !inRange(note, Pminkey, Pmaxkey) || Pdrummode) return; // MonoMem stuff: if(!Ppolymode) // if Poly is off - monomem[note].velocity = velocity; // Store this note's velocity. @@ -794,10 +666,8 @@ void Part::PolyphonicAftertouch(unsigned char note, if((partnote[i].note == note) && (partnote[i].status == KEY_PLAYING)) { /* update velocity */ // compute the velocity offset - float vel = - VelF(velocity / 127.0f, Pvelsns) + (Pveloffs - 64.0f) / 64.0f; - vel = (vel < 0.0f) ? 0.0f : vel; - vel = (vel > 1.0f) ? 1.0f : vel; + float vel = VelF(velocity / 127.0f, Pvelsns) + (Pveloffs - 64.0f) / 64.0f; + vel = limit(vel, 0.0f, 1.0f); if(!Pkitmode) { // "normal mode" if(kit[0].Padenabled && partnote[i].kititem[0].adnote) @@ -809,10 +679,7 @@ void Part::PolyphonicAftertouch(unsigned char note, } else // "kit mode" for(int item = 0; item < NUM_KIT_ITEMS; ++item) { - if(kit[item].Pmuted) - continue; - if((note < kit[item].Pminkey) - || (note > kit[item].Pmaxkey)) + if(kit[item].Pmuted || !inRange(note, kit[item].Pminkey, kit[item].Pmaxkey)) continue; if(kit[item].Padenabled && partnote[i].kititem[item].adnote) @@ -964,17 +831,14 @@ void Part::MonoMemRenote() void Part::RelaseNotePos(int pos) { for(int j = 0; j < NUM_KIT_ITEMS; ++j) { - if(partnote[pos].kititem[j].adnote != NULL) - if(partnote[pos].kititem[j].adnote) - partnote[pos].kititem[j].adnote->relasekey(); + if(partnote[pos].kititem[j].adnote) + partnote[pos].kititem[j].adnote->relasekey(); - if(partnote[pos].kititem[j].subnote != NULL) - if(partnote[pos].kititem[j].subnote != NULL) - partnote[pos].kititem[j].subnote->relasekey(); + if(partnote[pos].kititem[j].subnote) + partnote[pos].kititem[j].subnote->relasekey(); - if(partnote[pos].kititem[j].padnote != NULL) - if(partnote[pos].kititem[j].padnote) - partnote[pos].kititem[j].padnote->relasekey(); + if(partnote[pos].kititem[j].padnote) + partnote[pos].kititem[j].padnote->relasekey(); } partnote[pos].status = KEY_RELASED; } @@ -991,18 +855,9 @@ void Part::KillNotePos(int pos) partnote[pos].itemsplaying = 0; for(int j = 0; j < NUM_KIT_ITEMS; ++j) { - if(partnote[pos].kititem[j].adnote != NULL) { - delete (partnote[pos].kititem[j].adnote); - partnote[pos].kititem[j].adnote = NULL; - } - if(partnote[pos].kititem[j].subnote != NULL) { - delete (partnote[pos].kititem[j].subnote); - partnote[pos].kititem[j].subnote = NULL; - } - if(partnote[pos].kititem[j].padnote != NULL) { - delete (partnote[pos].kititem[j].padnote); - partnote[pos].kititem[j].padnote = NULL; - } + memory.dealloc(partnote[pos].kititem[j].adnote); + memory.dealloc(partnote[pos].kititem[j].subnote); + memory.dealloc(partnote[pos].kititem[j].padnote); } if(pos == ctl.portamento.noteusing) { ctl.portamento.noteusing = -1; @@ -1025,17 +880,14 @@ void Part::setkeylimit(unsigned char Pkeylimit) if(Ppolymode != 0) { int notecount = 0; for(int i = 0; i < POLIPHONY; ++i) - if((partnote[i].status == KEY_PLAYING) - || (partnote[i].status == KEY_RELASED_AND_SUSTAINED)) + if((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELASED_AND_SUSTAINED)) notecount++; int oldestnotepos = -1; if(notecount > keylimit) //find out the oldest note for(int i = 0; i < POLIPHONY; ++i) { int maxtime = 0; - if(((partnote[i].status == KEY_PLAYING) - || (partnote[i].status == KEY_RELASED_AND_SUSTAINED)) - && (partnote[i].time > maxtime)) { + if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) { maxtime = partnote[i].time; oldestnotepos = i; } @@ -1079,10 +931,8 @@ void Part::RunNote(unsigned int k) float tmpoutl[synth->buffersize]; (*note)->noteout(&tmpoutl[0], &tmpoutr[0]); - if((*note)->finished()) { - delete (*note); - (*note) = NULL; - } + if((*note)->finished()) + memory.dealloc(*note); for(int i = 0; i < synth->buffersize; ++i) { //add the note to part(mix) partfxinputl[sendcurrenttofx][i] += tmpoutl[i]; partfxinputr[sendcurrenttofx][i] += tmpoutr[i]; @@ -1091,7 +941,7 @@ void Part::RunNote(unsigned int k) } //Kill note if there is no synth on that note - if(noteplay == 0) + if(!noteplay) KillNotePos(k); } @@ -1165,12 +1015,7 @@ void Part::setPvolume(char Pvolume_) void Part::setPpanning(char Ppanning_) { Ppanning = Ppanning_; - panning = Ppanning / 127.0f + ctl.panning.pan; - if(panning < 0.0f) - panning = 0.0f; - else - if(panning > 1.0f) - panning = 1.0f; + panning = limit(Ppanning / 127.0f + ctl.panning.pan, 0.0f, 1.0f); } template<class T> @@ -1192,10 +1037,10 @@ void Part::setkititemstatus(unsigned kititem, bool Penabled_) return; kkit.Penabled = Penabled_; - if(Penabled_ == 0) { - //nullify(kkit.adpars); - //nullify(kkit.subpars); - //nullify(kkit.padpars); + if(!Penabled_) { + memory.dealloc(kkit.adpars); + memory.dealloc(kkit.subpars); + memory.dealloc(kkit.padpars); kkit.Pname[0] = '\0'; //Reset notes s.t. stale buffers will not get read @@ -1204,10 +1049,10 @@ void Part::setkititemstatus(unsigned kititem, bool Penabled_) } else { //All parameters must be NULL in this case - //assert(!(kkit.adpars || kkit.subpars || kkit.padpars)); - //kkit.adpars = new ADnoteParameters(fft); - //kkit.subpars = new SUBnoteParameters(); - //kkit.padpars = new PADnoteParameters(fft); + assert(!(kkit.adpars || kkit.subpars || kkit.padpars)); + kkit.adpars = new ADnoteParameters(fft); + kkit.subpars = new SUBnoteParameters(); + kkit.padpars = new PADnoteParameters(fft); } } @@ -1238,21 +1083,21 @@ void Part::add2XMLinstrument(XMLwrapper *xml) xml->addpar("send_to_instrument_effect", kit[i].Psendtoparteffect); xml->addparbool("add_enabled", kit[i].Padenabled); - if((kit[i].Padenabled != 0) && (kit[i].adpars != NULL)) { + if(kit[i].Padenabled && kit[i].adpars) { xml->beginbranch("ADD_SYNTH_PARAMETERS"); kit[i].adpars->add2XML(xml); xml->endbranch(); } xml->addparbool("sub_enabled", kit[i].Psubenabled); - if((kit[i].Psubenabled != 0) && (kit[i].subpars != NULL)) { + if(kit[i].Psubenabled && kit[i].subpars) { xml->beginbranch("SUB_SYNTH_PARAMETERS"); kit[i].subpars->add2XML(xml); xml->endbranch(); } xml->addparbool("pad_enabled", kit[i].Ppadenabled); - if((kit[i].Ppadenabled != 0) && (kit[i].padpars != NULL)) { + if(kit[i].Ppadenabled && kit[i].padpars) { xml->beginbranch("PAD_SYNTH_PARAMETERS"); kit[i].padpars->add2XML(xml); xml->endbranch(); @@ -1311,32 +1156,28 @@ void Part::add2XML(XMLwrapper *xml) int Part::saveXML(const char *filename) { - XMLwrapper *xml; - xml = new XMLwrapper(); + XMLwrapper xml; - xml->beginbranch("INSTRUMENT"); - add2XMLinstrument(xml); - xml->endbranch(); + xml.beginbranch("INSTRUMENT"); + add2XMLinstrument(&xml); + xml.endbranch(); - int result = xml->saveXMLfile(filename); - delete (xml); + int result = xml.saveXMLfile(filename); return result; } int Part::loadXMLinstrument(const char *filename) { - XMLwrapper *xml = new XMLwrapper(); - if(xml->loadXMLfile(filename) < 0) { - delete (xml); + XMLwrapper xml; + if(xml.loadXMLfile(filename) < 0) { return -1; } - if(xml->enterbranch("INSTRUMENT") == 0) + if(xml.enterbranch("INSTRUMENT") == 0) return -10; - getfromXMLinstrument(xml); - xml->exitbranch(); + getfromXMLinstrument(&xml); + xml.exitbranch(); - delete (xml); return 0; } @@ -1352,6 +1193,12 @@ void Part::applyparameters(std::function<bool()> do_abort) kit[n].padpars->applyparameters(do_abort); } +void Part::initialize_rt(void) +{ + for(int i=0; i<NUM_PART_EFX; ++i) + partefx[i]->init(); +} + void Part::getfromXMLinstrument(XMLwrapper *xml) { if(xml->enterbranch("INFO")) { @@ -1390,6 +1237,8 @@ void Part::getfromXMLinstrument(XMLwrapper *xml) kit[i].Padenabled = xml->getparbool("add_enabled", kit[i].Padenabled); if(xml->enterbranch("ADD_SYNTH_PARAMETERS")) { + if(!kit[i].adpars) + kit[i].adpars = new ADnoteParameters(fft); kit[i].adpars->getfromXML(xml); xml->exitbranch(); } @@ -1397,6 +1246,8 @@ void Part::getfromXMLinstrument(XMLwrapper *xml) kit[i].Psubenabled = xml->getparbool("sub_enabled", kit[i].Psubenabled); if(xml->enterbranch("SUB_SYNTH_PARAMETERS")) { + if(!kit[i].subpars) + kit[i].subpars = new SUBnoteParameters(); kit[i].subpars->getfromXML(xml); xml->exitbranch(); } @@ -1404,6 +1255,8 @@ void Part::getfromXMLinstrument(XMLwrapper *xml) kit[i].Ppadenabled = xml->getparbool("pad_enabled", kit[i].Ppadenabled); if(xml->enterbranch("PAD_SYNTH_PARAMETERS")) { + if(!kit[i].padpars) + kit[i].padpars = new PADnoteParameters(fft); kit[i].padpars->getfromXML(xml); xml->exitbranch(); } diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -40,6 +40,7 @@ class PADnoteParameters; class SynthNote; class XMLWrapper; class FFTwrapper; +class Allocator; /** Part implementation*/ class Part @@ -48,7 +49,7 @@ class Part /**Constructor * @param microtonal_ Pointer to the microtonal object * @param fft_ Pointer to the FFTwrapper*/ - Part(Microtonal *microtonal_, FFTwrapper *fft_); + Part(Allocator &alloc, Microtonal *microtonal_, FFTwrapper *fft_); /**Destructor*/ ~Part(); @@ -83,8 +84,10 @@ class Part void defaults(); void defaultsinstrument(); - void applyparameters(void); - void applyparameters(std::function<bool()> do_abort); + void applyparameters(void) NONREALTIME; + void applyparameters(std::function<bool()> do_abort) NONREALTIME; + + void initialize_rt(void) REALTIME; void getfromXML(XMLwrapper *xml); void getfromXMLinstrument(XMLwrapper *xml); @@ -93,9 +96,10 @@ class Part //the part's kit struct Kit { - unsigned char Penabled, Pmuted, Pminkey, Pmaxkey; + bool Penabled, Pmuted; + unsigned char Pminkey, Pmaxkey; char *Pname; - unsigned char Padenabled, Psubenabled, Ppadenabled; + bool Padenabled, Psubenabled, Ppadenabled; unsigned char Psendtoparteffect; ADnoteParameters *adpars; SUBnoteParameters *subpars; @@ -109,7 +113,7 @@ class Part void setkeylimit(unsigned char Pkeylimit); void setkititemstatus(unsigned kititem, bool Penabled_); - unsigned char Penabled; /**<if the part is enabled*/ + bool Penabled; /**<if the part is enabled*/ unsigned char Pvolume; /**<part volume*/ unsigned char Pminkey; /**<the minimum key that the part receives noteon messages*/ unsigned char Pmaxkey; //the maximum key that the part receives noteon messages @@ -120,12 +124,12 @@ class Part void setPpanning(char Ppanning); unsigned char Pvelsns; //velocity sensing (amplitude velocity scale) unsigned char Pveloffs; //velocity offset - unsigned char Pnoteon; //if the part receives NoteOn messages - unsigned char Pkitmode; //if the kitmode is enabled - unsigned char Pdrummode; //if all keys are mapped and the system is 12tET (used for drums) + bool Pnoteon; //if the part receives NoteOn messages + int Pkitmode; //if the kitmode is enabled + bool Pdrummode; //if all keys are mapped and the system is 12tET (used for drums) - unsigned char Ppolymode; //Part mode - 0=monophonic , 1=polyphonic - unsigned char Plegatomode; // 0=normal, 1=legato + bool Ppolymode; //Part mode - 0=monophonic , 1=polyphonic + bool Plegatomode; // 0=normal, 1=legato unsigned char Pkeylimit; //how many keys are alowed to be played same time (0=off), the older will be relased char *Pname; //name of the instrument @@ -172,9 +176,7 @@ class Part int note; //if there is no note playing, the "note"=-1 int itemsplaying; struct { - SynthNote *adnote, - *subnote, - *padnote; + SynthNote *adnote, *subnote, *padnote; int sendtoparteffect; } kititem[NUM_KIT_ITEMS]; int time; @@ -199,6 +201,7 @@ class Part float oldfreq; //this is used for portamento Microtonal *microtonal; FFTwrapper *fft; + Allocator &memory; }; #endif diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -89,6 +89,12 @@ T limit(T val, T min, T max) } template<class T> +bool inRange(T val, T min, T max) +{ + return val >= min && val <= max; +} + +template<class T> T array_max(const T *data, size_t len) { T max = 0; diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -28,34 +28,27 @@ #include "../globals.h" #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "../DSP/Filter.h" #include "OscilGen.h" #include "ADnote.h" -ADnote::ADnote(ADnoteParameters *pars, - Controller *ctl_, - float freq, - float velocity, - int portamento_, - int midinote_, - bool besilent) - :SynthNote(freq, velocity, portamento_, midinote_, besilent) +ADnote::ADnote(ADnoteParameters *pars, SynthParams &spars) + :SynthNote(spars) { - tmpwavel = new float [synth->buffersize]; - tmpwaver = new float [synth->buffersize]; - bypassl = new float [synth->buffersize]; - bypassr = new float [synth->buffersize]; + tmpwavel = memory.valloc<float>(synth->buffersize); + tmpwaver = memory.valloc<float>(synth->buffersize); + bypassl = memory.valloc<float>(synth->buffersize); + bypassr = memory.valloc<float>(synth->buffersize); partparams = pars; - ctl = ctl_; - portamento = portamento_; - midinote = midinote_; + ctl = &spars.ctl; + portamento = spars.portamento; + midinote = spars.note; NoteEnabled = ON; - basefreq = freq; - if(velocity > 1.0f) - velocity = 1.0f; - this->velocity = velocity; + basefreq = spars.frequency; + velocity = spars.velocity; time = 0.0f; stereo = pars->GlobalPar.PStereo; @@ -86,7 +79,7 @@ ADnote::ADnote(ADnoteParameters *pars, pars->GlobalPar.PPunchVelocitySensing)); float time = powf(10, 3.0f * pars->GlobalPar.PPunchTime / 127.0f) / 10000.0f; //0.1f .. 100 ms - float stretch = powf(440.0f / freq, + float stretch = powf(440.0f / spars.frequency, pars->GlobalPar.PPunchStretch / 64.0f); NoteGlobalPar.Punch.dt = 1.0f / (time * synth->samplerate_f * stretch); } @@ -116,9 +109,9 @@ ADnote::ADnote(ADnoteParameters *pars, //compute unison unison_size[nvoice] = unison; - unison_base_freq_rap[nvoice] = new float[unison]; - unison_freq_rap[nvoice] = new float[unison]; - unison_invert_phase[nvoice] = new bool[unison]; + unison_base_freq_rap[nvoice] = memory.valloc<float>(unison); + unison_freq_rap[nvoice] = memory.valloc<float>(unison); + unison_invert_phase[nvoice] = memory.valloc<bool>(unison); float unison_spread = pars->getUnisonFrequencySpreadCents( nvoice); float unison_real_spread = powf(2.0f, (unison_spread * 0.5f) / 1200.0f); @@ -166,8 +159,8 @@ ADnote::ADnote(ADnoteParameters *pars, + (unison_base_freq_rap[ nvoice][k] - 1.0f) * (1.0f - unison_vibratto_a); - unison_vibratto[nvoice].step = new float[unison]; - unison_vibratto[nvoice].position = new float[unison]; + unison_vibratto[nvoice].step = memory.valloc<float>(unison); + unison_vibratto[nvoice].position = memory.valloc<float>(unison); unison_vibratto[nvoice].amplitude = (unison_real_spread - 1.0f) * unison_vibratto_a; @@ -216,14 +209,14 @@ ADnote::ADnote(ADnoteParameters *pars, } - oscfreqhi[nvoice] = new int[unison]; - oscfreqlo[nvoice] = new float[unison]; - oscfreqhiFM[nvoice] = new unsigned int[unison]; - oscfreqloFM[nvoice] = new float[unison]; - oscposhi[nvoice] = new int[unison]; - oscposlo[nvoice] = new float[unison]; - oscposhiFM[nvoice] = new unsigned int[unison]; - oscposloFM[nvoice] = new float[unison]; + oscfreqhi[nvoice] = memory.valloc<int>(unison); + oscfreqlo[nvoice] = memory.valloc<float>(unison); + oscfreqhiFM[nvoice] = memory.valloc<unsigned int>(unison); + oscfreqloFM[nvoice] = memory.valloc<float>(unison); + oscposhi[nvoice] = memory.valloc<int>(unison); + oscposlo[nvoice] = memory.valloc<float>(unison); + oscposhiFM[nvoice] = memory.valloc<unsigned int>(unison); + oscposloFM[nvoice] = memory.valloc<float>(unison); NoteVoicePar[nvoice].Enabled = ON; NoteVoicePar[nvoice].fixedfreq = pars->VoicePar[nvoice].Pfixedfreq; @@ -276,7 +269,7 @@ ADnote::ADnote(ADnoteParameters *pars, //the extra points contains the first point NoteVoicePar[nvoice].OscilSmp = - new float[synth->oscilsize + OSCIL_SMP_EXTRA_SAMPLES]; + memory.valloc<float>(synth->oscilsize + OSCIL_SMP_EXTRA_SAMPLES); //Get the voice's oscil or external's voice oscil int vc = nvoice; @@ -383,7 +376,7 @@ ADnote::ADnote(ADnoteParameters *pars, VelF(velocity, partparams->VoicePar[nvoice].PFMVelocityScaleFunction); - FMoldsmp[nvoice] = new float [unison]; + FMoldsmp[nvoice] = memory.valloc<float>(unison); for(int k = 0; k < unison; ++k) FMoldsmp[nvoice][k] = 0.0f; //this is for FM (integration) @@ -400,9 +393,9 @@ ADnote::ADnote(ADnoteParameters *pars, max_unison = unison_size[nvoice]; - tmpwave_unison = new float *[max_unison]; + tmpwave_unison = memory.valloc<float*>(max_unison); for(int k = 0; k < max_unison; ++k) { - tmpwave_unison[k] = new float[synth->buffersize]; + tmpwave_unison[k] = memory.valloc<float>(synth->buffersize); memset(tmpwave_unison[k], 0, synth->bufferbytes); } @@ -413,22 +406,21 @@ ADnote::ADnote(ADnoteParameters *pars, // initparameters() stuck together with some lines removed so that it // only alter the already playing note (to perform legato). It is // possible I left stuff that is not required for this. -void ADnote::legatonote(float freq, float velocity, int portamento_, - int midinote_, bool externcall) +void ADnote::legatonote(LegatoParams lpars) { ADnoteParameters *pars = partparams; // Manage legato stuff - if(legato.update(freq, velocity, portamento_, midinote_, externcall)) + if(legato.update(lpars)) return; - portamento = portamento_; - midinote = midinote_; - basefreq = freq; + portamento = lpars.portamento; + midinote = lpars.midinote; + basefreq = lpars.frequency; if(velocity > 1.0f) velocity = 1.0f; - this->velocity = velocity; + velocity = lpars.velocity; NoteGlobalPar.Detune = getdetune(pars->GlobalPar.PDetuneType, pars->GlobalPar.PCoarseDetune, @@ -665,23 +657,23 @@ void ADnote::legatonote(float freq, float velocity, int portamento_, */ void ADnote::KillVoice(int nvoice) { - delete [] oscfreqhi[nvoice]; - delete [] oscfreqlo[nvoice]; - delete [] oscfreqhiFM[nvoice]; - delete [] oscfreqloFM[nvoice]; - delete [] oscposhi[nvoice]; - delete [] oscposlo[nvoice]; - delete [] oscposhiFM[nvoice]; - delete [] oscposloFM[nvoice]; - - delete [] unison_base_freq_rap[nvoice]; - delete [] unison_freq_rap[nvoice]; - delete [] unison_invert_phase[nvoice]; - delete [] FMoldsmp[nvoice]; - delete [] unison_vibratto[nvoice].step; - delete [] unison_vibratto[nvoice].position; - - NoteVoicePar[nvoice].kill(); + memory.devalloc(oscfreqhi[nvoice]); + memory.devalloc(oscfreqlo[nvoice]); + memory.devalloc(oscfreqhiFM[nvoice]); + memory.devalloc(oscfreqloFM[nvoice]); + memory.devalloc(oscposhi[nvoice]); + memory.devalloc(oscposlo[nvoice]); + memory.devalloc(oscposhiFM[nvoice]); + memory.devalloc(oscposloFM[nvoice]); + + memory.devalloc(unison_base_freq_rap[nvoice]); + memory.devalloc(unison_freq_rap[nvoice]); + memory.devalloc(unison_invert_phase[nvoice]); + memory.devalloc(FMoldsmp[nvoice]); + memory.devalloc(unison_vibratto[nvoice].step); + memory.devalloc(unison_vibratto[nvoice].position); + + NoteVoicePar[nvoice].kill(memory); } /* @@ -694,11 +686,10 @@ void ADnote::KillNote() KillVoice(nvoice); if(NoteVoicePar[nvoice].VoiceOut) - delete NoteVoicePar[nvoice].VoiceOut; - NoteVoicePar[nvoice].VoiceOut = NULL; + memory.dealloc(NoteVoicePar[nvoice].VoiceOut); } - NoteGlobalPar.kill(); + NoteGlobalPar.kill(memory); NoteEnabled = OFF; } @@ -707,13 +698,13 @@ ADnote::~ADnote() { if(NoteEnabled == ON) KillNote(); - delete [] tmpwavel; - delete [] tmpwaver; - delete [] bypassl; - delete [] bypassr; + memory.devalloc(tmpwavel); + memory.devalloc(tmpwaver); + memory.devalloc(bypassl); + memory.devalloc(bypassr); for(int k = 0; k < max_unison; ++k) - delete[] tmpwave_unison[k]; - delete[] tmpwave_unison; + memory.devalloc(tmpwave_unison[k]); + memory.devalloc(tmpwave_unison); } @@ -725,7 +716,8 @@ void ADnote::initparameters() int tmp[NUM_VOICES]; // Global Parameters - NoteGlobalPar.initparameters(partparams->GlobalPar, basefreq, velocity, + NoteGlobalPar.initparameters(partparams->GlobalPar, + memory, basefreq, velocity, stereo); NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output @@ -761,34 +753,34 @@ void ADnote::initparameters() newamplitude[nvoice] = 1.0f; if(param.PAmpEnvelopeEnabled) { - vce.AmpEnvelope = new Envelope(param.AmpEnvelope, basefreq); + vce.AmpEnvelope = memory.alloc<Envelope>(param.AmpEnvelope, basefreq); vce.AmpEnvelope->envout_dB(); //discard the first envelope sample newamplitude[nvoice] *= vce.AmpEnvelope->envout_dB(); } if(param.PAmpLfoEnabled) { - vce.AmpLfo = new LFO(param.AmpLfo, basefreq); + vce.AmpLfo = memory.alloc<LFO>(param.AmpLfo, basefreq); newamplitude[nvoice] *= vce.AmpLfo->amplfoout(); } /* Voice Frequency Parameters Init */ - if(param.PFreqEnvelopeEnabled != 0) - vce.FreqEnvelope = new Envelope(param.FreqEnvelope, basefreq); + if(param.PFreqEnvelopeEnabled) + vce.FreqEnvelope = memory.alloc<Envelope>(param.FreqEnvelope, basefreq); - if(param.PFreqLfoEnabled != 0) - vce.FreqLfo = new LFO(param.FreqLfo, basefreq); + if(param.PFreqLfoEnabled) + vce.FreqLfo = memory.alloc<LFO>(param.FreqLfo, basefreq); /* Voice Filter Parameters Init */ if(param.PFilterEnabled != 0) { - vce.VoiceFilterL = Filter::generate(param.VoiceFilter); - vce.VoiceFilterR = Filter::generate(param.VoiceFilter); + vce.VoiceFilterL = Filter::generate(memory, param.VoiceFilter); + vce.VoiceFilterR = Filter::generate(memory, param.VoiceFilter); } - if(param.PFilterEnvelopeEnabled != 0) - vce.FilterEnvelope = new Envelope(param.FilterEnvelope, basefreq); + if(param.PFilterEnvelopeEnabled) + vce.FilterEnvelope = memory.alloc<Envelope>(param.FilterEnvelope, basefreq); - if(param.PFilterLfoEnabled != 0) - vce.FilterLfo = new LFO(param.FilterLfo, basefreq); + if(param.PFilterLfoEnabled) + vce.FilterLfo = memory.alloc<LFO>(param.FilterLfo, basefreq); vce.FilterFreqTracking = param.VoiceFilter->getfreqtracking(basefreq); @@ -796,7 +788,7 @@ void ADnote::initparameters() /* Voice Modulation Parameters Init */ if((vce.FMEnabled != NONE) && (vce.FMVoice < 0)) { param.FMSmp->newrandseed(prng()); - vce.FMSmp = new float[synth->oscilsize + OSCIL_SMP_EXTRA_SAMPLES]; + vce.FMSmp = memory.valloc<float>(synth->oscilsize + OSCIL_SMP_EXTRA_SAMPLES); //Perform Anti-aliasing only on MORPH or RING MODULATION @@ -832,13 +824,13 @@ void ADnote::initparameters() } if(param.PFMFreqEnvelopeEnabled != 0) - vce.FMFreqEnvelope = new Envelope(param.FMFreqEnvelope, basefreq); + vce.FMFreqEnvelope = memory.alloc<Envelope>(param.FMFreqEnvelope, basefreq); FMnewamplitude[nvoice] = vce.FMVolume * ctl->fmamp.relamp; if(param.PFMAmpEnvelopeEnabled != 0) { - vce.FMAmpEnvelope = new Envelope(param.FMAmpEnvelope, - basefreq); + vce.FMAmpEnvelope = + memory.alloc<Envelope>(param.FMAmpEnvelope, basefreq); FMnewamplitude[nvoice] *= vce.FMAmpEnvelope->envout_dB(); } } @@ -848,7 +840,8 @@ void ADnote::initparameters() tmp[i] = 0; for(int i = nvoice + 1; i < NUM_VOICES; ++i) if((NoteVoicePar[i].FMVoice == nvoice) && (tmp[i] == 0)) { - NoteVoicePar[nvoice].VoiceOut = new float[synth->buffersize]; + NoteVoicePar[nvoice].VoiceOut = + memory.valloc<float>(synth->buffersize); tmp[i] = 1; } @@ -1753,29 +1746,22 @@ void ADnote::Voice::releasekey() FMAmpEnvelope->relasekey(); } -template<class T> -static inline void nullify(T &t) {delete t; t = NULL; } -template<class T> -static inline void arrayNullify(T &t) {delete [] t; t = NULL; } - -void ADnote::Voice::kill() +void ADnote::Voice::kill(Allocator &memory) { - arrayNullify(OscilSmp); - nullify(FreqEnvelope); - nullify(FreqLfo); - nullify(AmpEnvelope); - nullify(AmpLfo); - nullify(VoiceFilterL); - nullify(VoiceFilterR); - nullify(FilterEnvelope); - nullify(FilterLfo); - nullify(FMFreqEnvelope); - nullify(FMAmpEnvelope); - - if((FMEnabled != NONE) && (FMVoice < 0)) { - delete[] FMSmp; - FMSmp = NULL; - } + memory.devalloc(OscilSmp); + memory.dealloc(FreqEnvelope); + memory.dealloc(FreqLfo); + memory.dealloc(AmpEnvelope); + memory.dealloc(AmpLfo); + memory.dealloc(VoiceFilterL); + memory.dealloc(VoiceFilterR); + memory.dealloc(FilterEnvelope); + memory.dealloc(FilterLfo); + memory.dealloc(FMFreqEnvelope); + memory.dealloc(FMAmpEnvelope); + + if((FMEnabled != NONE) && (FMVoice < 0)) + memory.devalloc(FMSmp); if(VoiceOut) memset(VoiceOut, 0, synth->bufferbytes); @@ -1784,39 +1770,40 @@ void ADnote::Voice::kill() Enabled = OFF; } -void ADnote::Global::kill() +void ADnote::Global::kill(Allocator &memory) { - nullify(FreqEnvelope); - nullify(FreqLfo); - nullify(AmpEnvelope); - nullify(AmpLfo); - nullify(GlobalFilterL); - nullify(GlobalFilterR); - nullify(FilterEnvelope); - nullify(FilterLfo); + memory.dealloc(FreqEnvelope); + memory.dealloc(FreqLfo); + memory.dealloc(AmpEnvelope); + memory.dealloc(AmpLfo); + memory.dealloc(GlobalFilterL); + memory.dealloc(GlobalFilterR); + memory.dealloc(FilterEnvelope); + memory.dealloc(FilterLfo); } void ADnote::Global::initparameters(const ADnoteGlobalParam &param, + class Allocator &memory, float basefreq, float velocity, bool stereo) { - FreqEnvelope = new Envelope(param.FreqEnvelope, basefreq); - FreqLfo = new LFO(param.FreqLfo, basefreq); + FreqEnvelope = memory.alloc<Envelope>(param.FreqEnvelope, basefreq); + FreqLfo = memory.alloc<LFO>(param.FreqLfo, basefreq); - AmpEnvelope = new Envelope(param.AmpEnvelope, basefreq); - AmpLfo = new LFO(param.AmpLfo, basefreq); + AmpEnvelope = memory.alloc<Envelope>(param.AmpEnvelope, basefreq); + AmpLfo = memory.alloc<LFO>(param.AmpLfo, basefreq); Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - param.PVolume / 96.0f)) //-60 dB .. 0 dB * VelF(velocity, param.PAmpVelocityScaleFunction); //sensing - GlobalFilterL = Filter::generate(param.GlobalFilter); + GlobalFilterL = Filter::generate(memory, param.GlobalFilter); if(stereo) - GlobalFilterR = Filter::generate(param.GlobalFilter); + GlobalFilterR = Filter::generate(memory, param.GlobalFilter); else GlobalFilterR = NULL; - FilterEnvelope = new Envelope(param.FilterEnvelope, basefreq); - FilterLfo = new LFO(param.FilterLfo, basefreq); + FilterEnvelope = memory.alloc<Envelope>(param.FilterEnvelope, basefreq); + FilterLfo = memory.alloc<LFO>(param.FilterLfo, basefreq); FilterQ = param.GlobalFilter->getq(); FilterFreqTracking = param.GlobalFilter->getfreqtracking(basefreq); } diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h @@ -42,21 +42,13 @@ class ADnote:public SynthNote public: /**Constructor. * @param pars Note Parameters - * @param ctl_ Pointer to system Controller - * @param freq Base frequency for note - * @param velocity Velocity of note - * @param portamento_ 1 if the note has portamento - * @param midinote_ The midi number of the note - * @param besilent Start silent note if true*/ - ADnote(ADnoteParameters *pars, Controller *ctl_, float freq, - float velocity, int portamento_, int midinote_, - bool besilent); + * @param spars Synth Engine Agnostic Parameters*/ + ADnote(ADnoteParameters *pars, SynthParams &spars); /**Destructor*/ ~ADnote(); /**Alters the playing note for legato effect*/ - void legatonote(float freq, float velocity, int portamento_, - int midinote_, bool externcall); + void legatonote(LegatoParams pars); int noteout(float *outl, float *outr); void relasekey(); @@ -125,8 +117,9 @@ class ADnote:public SynthNote /*****************************************************************/ struct Global { - void kill(); + void kill(Allocator &memory); void initparameters(const ADnoteGlobalParam &param, + class Allocator &memory, float basefreq, float velocity, bool stereo); /****************************************** @@ -173,7 +166,7 @@ class ADnote:public SynthNote /***********************************************************/ struct Voice { void releasekey(); - void kill(); + void kill(Allocator &memory); /* If the voice is enabled */ ONOFFTYPE Enabled; diff --git a/src/Synth/Envelope.cpp b/src/Synth/Envelope.cpp @@ -26,7 +26,6 @@ Envelope::Envelope(EnvelopeParams *envpars, float basefreq) { - int i; envpoints = envpars->Penvpoints; if(envpoints > MAX_ENVELOPE_POINTS) envpoints = MAX_ENVELOPE_POINTS; @@ -48,7 +47,7 @@ Envelope::Envelope(EnvelopeParams *envpars, float basefreq) if((mode == 2) && (linearenvelope != 0)) mode = 1; //change to linear - for(i = 0; i < MAX_ENVELOPE_POINTS; ++i) { + for(int i = 0; i < MAX_ENVELOPE_POINTS; ++i) { float tmp = envpars->getdt(i) / 1000.0f * envstretch; if(tmp > bufferdt) envdt[i] = bufferdt / tmp; diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -36,18 +36,6 @@ int main_thread = 0; #include <rtosc/ports.h> #include <rtosc/port-sugar.h> -//template<int i> -//void simpleset(const char *m, rtosc::RtData &d) -//{ -// unsigned char *addr = ((unsigned char*) d.obj)+i; -// if(!rtosc_narguments(m)) -// d.reply(d.loc, "c", *addr); -// else -// *addr = rtosc_argument(m, 0).i; -//} -//#undef PARAMC -//#define PARAMC(x) rtosc::Port{#x "::c", "::", NULL, \ -// simpleset<__builtin_offsetof(class OscilGen, P##x)>} #define PC(x) rParam(P##x, "undocumented oscilgen parameter") #define rObject OscilGen @@ -81,7 +69,8 @@ static rtosc::Ports localPorts = { PC(adaptiveharmonicspower), PC(adaptiveharmonicspar), - {"phase#128::c", "::Sets harmonic phase", + //TODO update to rArray and test + {"phase#128::c", rDoc("Sets harmonic phase"), NULL, [](const char *m, rtosc::RtData &d) { const char *mm = m; while(*mm && !isdigit(*mm)) ++mm; @@ -91,7 +80,8 @@ static rtosc::Ports localPorts = { else phase = rtosc_argument(m,0).i; }}, - {"magnitude#128::c", "::Sets harmonic magnitude", + //TODO update to rArray and test + {"magnitude#128::c", rDoc("Sets harmonic magnitude"), NULL, [](const char *m, rtosc::RtData &d) { //printf("I'm at '%s'\n", d.loc); const char *mm = m; @@ -102,7 +92,7 @@ static rtosc::Ports localPorts = { else mag = rtosc_argument(m,0).i; }}, - {"base-spectrum:", "::Returns spectrum of base waveshape", + {"base-spectrum:", rDoc("Returns spectrum of base waveshape"), NULL, [](const char *m, rtosc::RtData &d) { const unsigned n = synth->oscilsize / 2; float *spc = new float[n]; @@ -111,7 +101,7 @@ static rtosc::Ports localPorts = { d.reply(d.loc, "b", n*sizeof(float), spc); delete[] spc; }}, - {"base-waveform:", "::Returns base waveshape points", + {"base-waveform:", rDoc("Returns base waveshape points"), NULL, [](const char *m, rtosc::RtData &d) { const unsigned n = synth->oscilsize; float *smps = new float[n]; @@ -120,7 +110,7 @@ static rtosc::Ports localPorts = { d.reply(d.loc, "b", n*sizeof(float), smps); delete[] smps; }}, - {"spectrum:", "::Returns spectrum of waveform", + {"spectrum:", rDoc("Returns spectrum of waveform"), NULL, [](const char *m, rtosc::RtData &d) { const unsigned n = synth->oscilsize / 2; float *spc = new float[n]; @@ -129,7 +119,7 @@ static rtosc::Ports localPorts = { d.reply(d.loc, "b", n*sizeof(float), spc); delete[] spc; }}, - {"waveform:", "::Returns waveform points", + {"waveform:", rDoc("Returns waveform points"), NULL, [](const char *m, rtosc::RtData &d) { const unsigned n = synth->oscilsize; float *smps = new float[n]; @@ -141,7 +131,7 @@ static rtosc::Ports localPorts = { d.reply(d.loc, "b", n*sizeof(float), smps); delete[] smps; }}, - {"prepare:", "::Performs setup operation to oscillator", + {"prepare:", rDoc("Performs setup operation to oscillator"), NULL, [](const char *m, rtosc::RtData &d) { //fprintf(stderr, "prepare: got a message from '%s'\n", m); OscilGen &o = *(OscilGen*)d.obj; @@ -151,11 +141,11 @@ static rtosc::Ports localPorts = { d.reply("/forward", "sb", d.loc, sizeof(fft_t*), &data); o.pendingfreqs = data; }}, - {"convert2sine:", "::Translates waveform into FS", + {"convert2sine:", rDoc("Translates waveform into FS"), NULL, [](const char *m, rtosc::RtData &d) { ((OscilGen*)d.obj)->convert2sine(); }}, - {"prepare:b", ":'pointer','realtime':Sets prepared fft data", + {"prepare:b", rProp(internal) rProp(pointer) rDoc("Sets prepared fft data"), NULL, [](const char *m, rtosc::RtData &d) { //fprintf(stderr, "prepare:b got a message from '%s'\n", m); OscilGen &o = *(OscilGen*)d.obj; diff --git a/src/Synth/PADnote.cpp b/src/Synth/PADnote.cpp @@ -21,22 +21,17 @@ #include <math.h> #include "PADnote.h" #include "../Misc/Config.h" +#include "../Misc/Allocator.h" #include "../DSP/Filter.h" PADnote::PADnote(PADnoteParameters *parameters, - Controller *ctl_, - float freq, - float velocity, - int portamento_, - int midinote, - bool besilent) - :SynthNote(freq, velocity, portamento_, midinote, besilent) + SynthParams pars) + :SynthNote(pars), ctl(pars.ctl) { - pars = parameters; + this->pars = parameters; - ctl = ctl_; firsttime = true; - setup(freq, velocity, portamento_, midinote); + setup(pars.frequency, pars.velocity, pars.portamento, pars.note); } @@ -135,11 +130,11 @@ void PADnote::setup(float freq, else NoteGlobalPar.Punch.Enabled = 0; - NoteGlobalPar.FreqEnvelope = new Envelope(pars->FreqEnvelope, basefreq); - NoteGlobalPar.FreqLfo = new LFO(pars->FreqLfo, basefreq); + NoteGlobalPar.FreqEnvelope = memory.alloc<Envelope>(pars->FreqEnvelope, basefreq); + NoteGlobalPar.FreqLfo = memory.alloc<LFO>(pars->FreqLfo, basefreq); - NoteGlobalPar.AmpEnvelope = new Envelope(pars->AmpEnvelope, basefreq); - NoteGlobalPar.AmpLfo = new LFO(pars->AmpLfo, basefreq); + NoteGlobalPar.AmpEnvelope = memory.alloc<Envelope>(pars->AmpEnvelope, basefreq); + NoteGlobalPar.AmpLfo = memory.alloc<LFO>(pars->AmpLfo, basefreq); } NoteGlobalPar.Volume = 4.0f @@ -153,47 +148,42 @@ void PADnote::setup(float freq, * NoteGlobalPar.AmpLfo->amplfoout(); if(!legato) { - NoteGlobalPar.GlobalFilterL = Filter::generate(pars->GlobalFilter); - NoteGlobalPar.GlobalFilterR = Filter::generate(pars->GlobalFilter); + NoteGlobalPar.GlobalFilterL = Filter::generate(memory, pars->GlobalFilter); + NoteGlobalPar.GlobalFilterR = Filter::generate(memory, pars->GlobalFilter); - NoteGlobalPar.FilterEnvelope = new Envelope(pars->FilterEnvelope, - basefreq); - NoteGlobalPar.FilterLfo = new LFO(pars->FilterLfo, basefreq); + NoteGlobalPar.FilterEnvelope = memory.alloc<Envelope>(pars->FilterEnvelope, basefreq); + NoteGlobalPar.FilterLfo = memory.alloc<LFO>(pars->FilterLfo, basefreq); } NoteGlobalPar.FilterQ = pars->GlobalFilter->getq(); NoteGlobalPar.FilterFreqTracking = pars->GlobalFilter->getfreqtracking( basefreq); - if(pars->sample[nsample].smp == NULL) { + if(!pars->sample[nsample].smp) { finished_ = true; return; } } -void PADnote::legatonote(float freq, - float velocity, - int portamento_, - int midinote, - bool externcall) +void PADnote::legatonote(LegatoParams pars) { // Manage legato stuff - if(legato.update(freq, velocity, portamento_, midinote, externcall)) + if(legato.update(pars)) return; - setup(freq, velocity, portamento_, midinote, true); + setup(pars.frequency, pars.velocity, pars.portamento, pars.midinote, true); } PADnote::~PADnote() { - delete (NoteGlobalPar.FreqEnvelope); - delete (NoteGlobalPar.FreqLfo); - delete (NoteGlobalPar.AmpEnvelope); - delete (NoteGlobalPar.AmpLfo); - delete (NoteGlobalPar.GlobalFilterL); - delete (NoteGlobalPar.GlobalFilterR); - delete (NoteGlobalPar.FilterEnvelope); - delete (NoteGlobalPar.FilterLfo); + memory.dealloc(NoteGlobalPar.FreqEnvelope); + memory.dealloc(NoteGlobalPar.FreqLfo); + memory.dealloc(NoteGlobalPar.AmpEnvelope); + memory.dealloc(NoteGlobalPar.AmpLfo); + memory.dealloc(NoteGlobalPar.GlobalFilterL); + memory.dealloc(NoteGlobalPar.GlobalFilterR); + memory.dealloc(NoteGlobalPar.FilterEnvelope); + memory.dealloc(NoteGlobalPar.FilterLfo); } @@ -224,7 +214,7 @@ void PADnote::computecurrentparameters() float globalpitch, globalfilterpitch; globalpitch = 0.01f * (NoteGlobalPar.FreqEnvelope->envout() + NoteGlobalPar.FreqLfo->lfoout() - * ctl->modwheel.relmod + NoteGlobalPar.Detune); + * ctl.modwheel.relmod + NoteGlobalPar.Detune); globaloldamplitude = globalnewamplitude; globalnewamplitude = NoteGlobalPar.Volume * NoteGlobalPar.AmpEnvelope->envout_dB() @@ -234,26 +224,25 @@ void PADnote::computecurrentparameters() + NoteGlobalPar.FilterLfo->lfoout() + NoteGlobalPar.FilterCenterPitch; - float tmpfilterfreq = globalfilterpitch + ctl->filtercutoff.relfreq + float tmpfilterfreq = globalfilterpitch + ctl.filtercutoff.relfreq + NoteGlobalPar.FilterFreqTracking; tmpfilterfreq = Filter::getrealfreq(tmpfilterfreq); - float globalfilterq = NoteGlobalPar.FilterQ * ctl->filterq.relq; + float globalfilterq = NoteGlobalPar.FilterQ * ctl.filterq.relq; NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq, globalfilterq); NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq, globalfilterq); //compute the portamento, if it is used by this note float portamentofreqrap = 1.0f; - if(portamento != 0) { //this voice use portamento - portamentofreqrap = ctl->portamento.freqrap; - if(ctl->portamento.used == 0) //the portamento has finished + if(portamento) { //this voice use portamento + portamentofreqrap = ctl.portamento.freqrap; + if(ctl.portamento.used == 0) //the portamento has finished portamento = 0; //this note is no longer "portamented" - ; } realfreq = basefreq * portamentofreqrap - * powf(2.0f, globalpitch / 12.0f) * ctl->pitchwheel.relfreq; + * powf(2.0f, globalpitch / 12.0f) * ctl.pitchwheel.relfreq; } diff --git a/src/Synth/PADnote.h b/src/Synth/PADnote.h @@ -33,17 +33,10 @@ class PADnote:public SynthNote { public: - PADnote(PADnoteParameters *parameters, - Controller *ctl_, - float freq, - float velocity, - int portamento_, - int midinote, - bool besilent); + PADnote(PADnoteParameters *parameters, SynthParams pars); ~PADnote(); - void legatonote(float freq, float velocity, int portamento_, - int midinote, bool externcall); + void legatonote(LegatoParams pars); int noteout(float *outl, float *outr); int finished() const; @@ -114,7 +107,7 @@ class PADnote:public SynthNote float globaloldamplitude, globalnewamplitude, velocity, realfreq; - Controller *ctl; + Controller &ctl; }; diff --git a/src/Synth/SUBnote.cpp b/src/Synth/SUBnote.cpp @@ -27,20 +27,15 @@ #include "../globals.h" #include "SUBnote.h" #include "../Misc/Util.h" +#include "../Misc/Allocator.h" -SUBnote::SUBnote(SUBnoteParameters *parameters, - Controller *ctl_, - float freq, - float velocity, - int portamento_, - int midinote, - bool besilent) - :SynthNote(freq, velocity, portamento_, midinote, besilent) +SUBnote::SUBnote(SUBnoteParameters *parameters, SynthParams spars) + :SynthNote(spars) { pars = parameters; - ctl = ctl_; + ctl = &spars.ctl; NoteEnabled = ON; - setup(freq, velocity, portamento_, midinote); + setup(spars.frequency, spars.velocity, spars.portamento, spars.note); } void SUBnote::setup(float freq, @@ -70,7 +65,7 @@ void SUBnote::setup(float freq, else { basefreq = 440.0f; int fixedfreqET = pars->PfixedfreqET; - if(fixedfreqET != 0) { //if the frequency varies according the keyboard note + if(fixedfreqET) { //if the frequency varies according the keyboard note float tmp = (midinote - 69.0f) / 12.0f @@ -126,9 +121,9 @@ void SUBnote::setup(float freq, if(!legato) { - lfilter = new bpfilter[numstages * numharmonics]; - if(stereo != 0) - rfilter = new bpfilter[numstages * numharmonics]; + lfilter = memory.valloc<bpfilter>(numstages * numharmonics); + if(stereo) + rfilter = memory.valloc<bpfilter>(numstages * numharmonics); } //how much the amplitude is normalised (because the harmonics) @@ -205,7 +200,7 @@ void SUBnote::setup(float freq, else freq *= basefreq / 440.0f; - if(pars->PGlobalFilterEnabled != 0) { + if(pars->PGlobalFilterEnabled) { globalfiltercenterq = pars->GlobalFilter->getq(); GlobalFilterFreqTracking = pars->GlobalFilter->getfreqtracking( basefreq); @@ -215,14 +210,14 @@ void SUBnote::setup(float freq, oldamplitude = newamplitude; } -void SUBnote::legatonote(float freq, float velocity, int portamento_, - int midinote, bool externcall) +void SUBnote::legatonote(LegatoParams pars) { // Manage legato stuff - if(legato.update(freq, velocity, portamento_, midinote, externcall)) + if(legato.update(pars)) return; - setup(freq, velocity, portamento_, midinote, true); + setup(pars.frequency, pars.velocity, pars.portamento, pars.midinote, + true); } SUBnote::~SUBnote() @@ -237,17 +232,15 @@ SUBnote::~SUBnote() void SUBnote::KillNote() { if(NoteEnabled != OFF) { - delete [] lfilter; - lfilter = NULL; - if(stereo != 0) - delete [] rfilter; - rfilter = NULL; - delete AmpEnvelope; - delete FreqEnvelope; - delete BandWidthEnvelope; - delete GlobalFilterL; - delete GlobalFilterR; - delete GlobalFilterEnvelope; + memory.devalloc(numstages * numharmonics, lfilter); + if(stereo) + memory.devalloc(numstages * numharmonics, rfilter); + memory.dealloc(AmpEnvelope); + memory.dealloc(FreqEnvelope); + memory.dealloc(BandWidthEnvelope); + memory.dealloc(GlobalFilterL); + memory.dealloc(GlobalFilterR); + memory.dealloc(GlobalFilterEnvelope); NoteEnabled = OFF; } } @@ -367,22 +360,21 @@ void SUBnote::filter(bpfilter &filter, float *smps) */ void SUBnote::initparameters(float freq) { - AmpEnvelope = new Envelope(pars->AmpEnvelope, freq); - if(pars->PFreqEnvelopeEnabled != 0) - FreqEnvelope = new Envelope(pars->FreqEnvelope, freq); + AmpEnvelope = memory.alloc<Envelope>(pars->AmpEnvelope, freq); + if(pars->PFreqEnvelopeEnabled) + FreqEnvelope = memory.alloc<Envelope>(pars->FreqEnvelope, freq); else FreqEnvelope = NULL; - if(pars->PBandWidthEnvelopeEnabled != 0) - BandWidthEnvelope = new Envelope(pars->BandWidthEnvelope, freq); + if(pars->PBandWidthEnvelopeEnabled) + BandWidthEnvelope = memory.alloc<Envelope>(pars->BandWidthEnvelope, freq); else BandWidthEnvelope = NULL; - if(pars->PGlobalFilterEnabled != 0) { + if(pars->PGlobalFilterEnabled) { globalfiltercenterq = pars->GlobalFilter->getq(); - GlobalFilterL = Filter::generate(pars->GlobalFilter); + GlobalFilterL = Filter::generate(memory, pars->GlobalFilter); if(stereo) - GlobalFilterR = Filter::generate(pars->GlobalFilter); - GlobalFilterEnvelope = new Envelope(pars->GlobalFilterEnvelope, - freq); + GlobalFilterR = Filter::generate(memory, pars->GlobalFilter); + GlobalFilterEnvelope = memory.alloc<Envelope>(pars->GlobalFilterEnvelope, freq); GlobalFilterFreqTracking = pars->GlobalFilter->getfreqtracking(basefreq); } computecurrentparameters(); diff --git a/src/Synth/SUBnote.h b/src/Synth/SUBnote.h @@ -33,12 +33,10 @@ class SUBnote:public SynthNote { public: - SUBnote(SUBnoteParameters *parameters, Controller *ctl_, float freq, - float velocity, int portamento_, int midinote, bool besilent); + SUBnote(SUBnoteParameters *parameters, SynthParams pars); ~SUBnote(); - void legatonote(float freq, float velocity, int portamento_, - int midinote, bool externcall); + void legatonote(LegatoParams pars); int noteout(float *outl, float *outr); //note output,return 0 if the note is finished void relasekey(); @@ -57,7 +55,7 @@ class SUBnote:public SynthNote SUBnoteParameters *pars; //parameters - int stereo; + bool stereo; int numstages; //number of stages of filters int numharmonics; //number of harmonics (after the too higher hamonics are removed) int firstnumharmonics; //To keep track of the first note's numharmonics value, useful in legato mode. diff --git a/src/Synth/SynthNote.cpp b/src/Synth/SynthNote.cpp @@ -2,8 +2,10 @@ #include "../globals.h" #include <cstring> -SynthNote::SynthNote(float freq, float vel, int port, int note, bool quiet) - :legato(freq, vel, port, note, quiet) +SynthNote::SynthNote(SynthParams &pars) + :legato(pars.frequency, pars.velocity, pars.portamento, + pars.note, pars.quiet), + memory(pars.memory) {} SynthNote::Legato::Legato(float freq, float vel, int port, @@ -24,17 +26,16 @@ SynthNote::Legato::Legato(float freq, float vel, int port, silent = quiet; } -int SynthNote::Legato::update(float freq, float velocity, int portamento_, - int midinote_, bool externcall) +int SynthNote::Legato::update(LegatoParams pars) { - if(externcall) + if(pars.externcall) msg = LM_Norm; if(msg != LM_CatchUp) { lastfreq = param.freq; - param.freq = freq; - param.vel = velocity; - param.portamento = portamento_; - param.midinote = midinote_; + param.freq = pars.frequency; + param.vel = pars.velocity; + param.portamento = pars.portamento; + param.midinote = pars.midinote; if(msg == LM_Norm) { if(silent) { fade.m = 0.0f; @@ -71,8 +72,9 @@ void SynthNote::Legato::apply(SynthNote &note, float *outl, float *outr) // the note to the actual parameters. decounter = -10; msg = LM_ToNorm; - note.legatonote(param.freq, param.vel, param.portamento, - param.midinote, false); + LegatoParams pars{param.freq, param.vel, param.portamento, + param.midinote, false}; + note.legatonote(pars); break; } } @@ -112,8 +114,9 @@ void SynthNote::Legato::apply(SynthNote &note, float *outl, float *outr) //with the heard note for the same length it stayed at the //previous freq during the fadeout. float catchupfreq = param.freq * (param.freq / lastfreq); - note.legatonote(catchupfreq, param.vel, param.portamento, - param.midinote, false); + LegatoParams pars{catchupfreq, param.vel, param.portamento, + param.midinote, false}; + note.legatonote(pars); break; } fade.m -= fade.step; @@ -128,7 +131,8 @@ void SynthNote::Legato::apply(SynthNote &note, float *outl, float *outr) void SynthNote::setVelocity(float velocity_) { legato.setSilent(true); //Let legato.update(...) returns 0. - legatonote(legato.getFreq(), velocity_, - legato.getPortamento(), legato.getMidinote(), true); + LegatoParams pars{legato.getFreq(), velocity_, + legato.getPortamento(), legato.getMidinote(), true}; + legatonote(pars); legato.setDecounter(0); //avoid chopping sound due fade-in } diff --git a/src/Synth/SynthNote.h b/src/Synth/SynthNote.h @@ -24,10 +24,32 @@ #include "../globals.h" #include "../Params/FilterParams.h" +class Allocator; +class Controller; +struct SynthParams +{ + Allocator &memory; //Memory Allocator for the Note to use + Controller &ctl; + float frequency; //Note base frequency + float velocity; //Velocity of the Note + bool portamento;//True if portamento is used for this note + int note; //Integer value of the note + bool quiet; //Initial output condition for legato notes +}; + +struct LegatoParams +{ + float frequency; + float velocity; + bool portamento; + int midinote; + bool externcall; +}; + class SynthNote { public: - SynthNote(float freq, float vel, int port, int note, bool quiet); + SynthNote(SynthParams &pars); virtual ~SynthNote() {} /**Compute Output Samples @@ -42,9 +64,7 @@ class SynthNote * @return finished=1 unfinished=0*/ virtual int finished() const = 0; - virtual void legatonote(float freq, float velocity, - int portamento_, int midinote_, - bool externcall) = 0; + virtual void legatonote(LegatoParams pars) = 0; /* For polyphonic aftertouch needed */ void setVelocity(float velocity_); protected: @@ -56,8 +76,7 @@ class SynthNote int note, bool quiet); void apply(SynthNote &note, float *outl, float *outr); - int update(float freq, float velocity, int portamento_, - int midinote_, bool externalcall); + int update(LegatoParams pars); private: bool silent; @@ -70,17 +89,21 @@ class SynthNote } fade; struct { // Note parameters float freq, vel; - int portamento, midinote; + bool portamento; + int midinote; } param; public: /* Some get routines for legatonote calls (aftertouch feature)*/ float getFreq() {return param.freq; } float getVelocity() {return param.vel; } - int getPortamento() {return param.portamento; } + bool getPortamento() {return param.portamento; } int getMidinote() {return param.midinote; } void setSilent(bool silent_) {silent = silent_; } void setDecounter(int decounter_) {decounter = decounter_; } } legato; + + //Realtime Safe Memory Allocator For notes + class Allocator &memory; }; #endif diff --git a/src/Tests/AdNoteTest.h b/src/Tests/AdNoteTest.h @@ -29,6 +29,7 @@ #include <string> #include "../Misc/Master.h" #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "../Synth/ADnote.h" #include "../Params/Presets.h" #include "../DSP/FFTwrapper.h" @@ -46,6 +47,7 @@ class AdNoteTest:public CxxTest::TestSuite Master *master; FFTwrapper *fft; Controller *controller; + Allocator memory; unsigned char testnote; @@ -102,14 +104,9 @@ class AdNoteTest:public CxxTest::TestSuite //lets go with.... 50! as a nice note testnote = 50; float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); + SynthParams pars{memory, *controller, freq, 120, 0, testnote, false}; - note = new ADnote(defaultPreset, - controller, - freq, - 120, - 0, - testnote, - false); + note = new ADnote(defaultPreset, pars); delete defaultPreset; delete wrap; diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt @@ -12,7 +12,7 @@ CXXTEST_ADD_TEST(SUBnoteTest SubNoteTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SubNote CXXTEST_ADD_TEST(OscilGenTest OscilGenTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/OscilGenTest.h) CXXTEST_ADD_TEST(RandTest RandTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RandTest.h) CXXTEST_ADD_TEST(PADnoteTest PadNoteTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PadNoteTest.h) -#CXXTEST_ADD_TEST(PluginTest PluginTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PluginTest.h) +CXXTEST_ADD_TEST(PluginTest PluginTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PluginTest.h) CXXTEST_ADD_TEST(UnisonTest UnisonTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UnisonTest.h) CXXTEST_ADD_TEST(RtAllocTest RtAllocTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RtAllocTest.h) @@ -30,8 +30,8 @@ target_link_libraries(OscilGenTest ${test_lib}) target_link_libraries(XMLwrapperTest ${test_lib}) target_link_libraries(RandTest ${test_lib}) target_link_libraries(PADnoteTest ${test_lib}) -#target_link_libraries(PluginTest zynaddsubfx_core zynaddsubfx_nio -# ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) +target_link_libraries(PluginTest zynaddsubfx_core zynaddsubfx_nio + ${GUI_LIBRARIES} ${NIO_LIBRARIES} ${AUDIO_LIBRARIES}) target_link_libraries(UnisonTest ${test_lib}) target_link_libraries(RtAllocTest ${test_lib}) diff --git a/src/Tests/EchoTest.h b/src/Tests/EchoTest.h @@ -25,6 +25,7 @@ #include <cstdlib> #include <iostream> #include "../Effects/Echo.h" +#include "../Misc/Allocator.h" #include "../globals.h" SYNTH_T *synth; @@ -45,7 +46,8 @@ class EchoTest:public CxxTest::TestSuite new float[synth->buffersize]); for(int i = 0; i < synth->buffersize; ++i) input->l[i] = input->r[i] = 0.0f; - testFX = new Echo(true, outL, outR, 44100, 256); + EffectParams pars{alloc,true, outL, outR, 0, 44100, 256, nullptr}; + testFX = new Echo(pars); } void tearDown() { @@ -123,4 +125,5 @@ class EchoTest:public CxxTest::TestSuite Stereo<float *> *input; float *outR, *outL; Echo *testFX; + Allocator alloc; }; diff --git a/src/Tests/PadNoteTest.h b/src/Tests/PadNoteTest.h @@ -29,6 +29,7 @@ #include <string> #include "../Misc/Master.h" #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "../Synth/PADnote.h" #include "../Params/Presets.h" #include "../DSP/FFTwrapper.h" @@ -45,6 +46,7 @@ class PadNoteTest:public CxxTest::TestSuite FFTwrapper *fft; Controller *controller; unsigned char testnote; + Allocator memory; float *outR, *outL; @@ -104,14 +106,9 @@ class PadNoteTest:public CxxTest::TestSuite //lets go with.... 50! as a nice note testnote = 50; float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); + SynthParams pars{memory, *controller, freq, 120, 0, testnote, false}; - note = new PADnote(defaultPreset, - controller, - freq, - 120, - 0, - testnote, - false); + note = new PADnote(defaultPreset, pars); //delete defaultPreset; delete wrap; diff --git a/src/Tests/RtAllocTest.h b/src/Tests/RtAllocTest.h @@ -25,6 +25,7 @@ #include <malloc.h> #include "../Misc/Part.h" #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "../Params/Presets.h" #include "../DSP/FFTwrapper.h" #include "../globals.h" @@ -54,6 +55,7 @@ class RtAllocTest:public CxxTest::TestSuite Part *part; Microtonal *micro; FFTwrapper *fft; + Allocator memory; float *outR, *outL; void setUp() { @@ -68,7 +70,7 @@ class RtAllocTest:public CxxTest::TestSuite //phew, glad to get thouse out of my way. took me a lot of sweat and gdb to get this far... fft = new FFTwrapper(synth->oscilsize); micro = new Microtonal(); - part = new Part(micro, fft); + part = new Part(memory, micro, fft); part->partoutl = new float[synth->buffersize]; part->partoutr = new float[synth->buffersize]; //prepare the default settings diff --git a/src/Tests/SubNoteTest.h b/src/Tests/SubNoteTest.h @@ -27,6 +27,7 @@ #include <ctime> #include <string> #include "../Misc/Master.h" +#include "../Misc/Allocator.h" #include "../Misc/Util.h" #include "../Synth/SUBnote.h" #include "../Params/Presets.h" @@ -43,6 +44,7 @@ class SubNoteTest:public CxxTest::TestSuite Master *master; Controller *controller; unsigned char testnote; + Allocator memory; float *outR, *outL; @@ -84,13 +86,8 @@ class SubNoteTest:public CxxTest::TestSuite testnote = 50; float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f); - note = new SUBnote(defaultPreset, - controller, - freq, - 120, - 0, - testnote, - false); + SynthParams pars{memory, *controller, freq, 120, 0, testnote, false}; + note = new SUBnote(defaultPreset, pars); delete wrap; delete defaultPreset; } diff --git a/src/Tests/UnisonTest.h b/src/Tests/UnisonTest.h @@ -28,6 +28,7 @@ #include <ctime> #include <string> #include "../Misc/Util.h" +#include "../Misc/Allocator.h" #include "../Synth/ADnote.h" #include "../Synth/OscilGen.h" #include "../Params/Presets.h" @@ -48,6 +49,7 @@ class AdNoteTest:public CxxTest::TestSuite Controller *controller; unsigned char testnote; ADnoteParameters *params; + Allocator memory; float freq; @@ -101,7 +103,8 @@ class AdNoteTest:public CxxTest::TestSuite params->VoicePar[0].Unison_vibratto_speed = e; params->VoicePar[0].Unison_invert_phase = f; - note = new ADnote(params, controller, freq, 120, 0, testnote, false); + SynthParams pars{memory, *controller, freq, 120, 0, testnote, false}; + note = new ADnote(params, pars); note->noteout(outL, outR); TS_ASSERT_DELTA(outL[80], values[0], 1e-5); //printf("{%f,", outL[80]); diff --git a/tlsf/tlsf.h b/tlsf/tlsf.h @@ -61,6 +61,11 @@ void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user); int tlsf_check(tlsf_t tlsf); int tlsf_check_pool(pool_t pool); +/* TODO add utilities for + * - Find Unused Pool Chunks + * - Define if the pool is running low + */ + #if defined(__cplusplus) }; #endif