commit b2eb72f658c0e942978fee36f9d83305cbc975cb
parent c308840ece9c043c7bd0642e53ab2056c93de572
Author: fundamental <[email protected]>
Date: Wed, 24 Feb 2016 13:05:52 -0500
SUBnote: Add Partial Realtime Automation
Diffstat:
2 files changed, 192 insertions(+), 148 deletions(-)
diff --git a/src/Synth/SUBnote.cpp b/src/Synth/SUBnote.cpp
@@ -43,12 +43,78 @@ SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars)
BandWidthEnvelope(nullptr),
GlobalFilter(nullptr),
GlobalFilterEnvelope(nullptr),
- NoteEnabled(ON),
+ NoteEnabled(true),
lfilter(nullptr), rfilter(nullptr)
{
setup(spars.frequency, spars.velocity, spars.portamento, spars.note);
}
+float SUBnote::setupFilters(int *pos, bool automation)
+{
+ //how much the amplitude is normalised (because the harmonics)
+ float reduceamp = 0.0f;
+
+ for(int n = 0; n < numharmonics; ++n) {
+ float freq = basefreq * pars.POvertoneFreqMult[pos[n]];
+ overtone_freq[n] = freq;
+ overtone_rolloff[n] = computerolloff(freq);
+
+ //the bandwidth is not absolute(Hz); it is relative to frequency
+ float bw =
+ powf(10, (pars.Pbandwidth - 127.0f) / 127.0f * 4) * numstages;
+
+ //Bandwidth Scale
+ bw *= powf(1000 / freq, (pars.Pbwscale - 64.0f) / 64.0f * 3.0f);
+
+ //Relative BandWidth
+ bw *= powf(100, (pars.Phrelbw[pos[n]] - 64.0f) / 64.0f);
+
+ if(bw > 25.0f)
+ bw = 25.0f;
+
+ //try to keep same amplitude on all freqs and bw. (empirically)
+ float gain = sqrt(1500.0f / (bw * freq));
+
+ float hmagnew = 1.0f - pars.Phmag[pos[n]] / 127.0f;
+ float hgain;
+
+ switch(pars.Phmagtype) {
+ case 1:
+ hgain = expf(hmagnew * logf(0.01f));
+ break;
+ case 2:
+ hgain = expf(hmagnew * logf(0.001f));
+ break;
+ case 3:
+ hgain = expf(hmagnew * logf(0.0001f));
+ break;
+ case 4:
+ hgain = expf(hmagnew * logf(0.00001f));
+ break;
+ default:
+ hgain = 1.0f - hmagnew;
+ }
+ gain *= hgain;
+ reduceamp += hgain;
+
+ for(int nph = 0; nph < numstages; ++nph) {
+ float amp = 1.0f;
+ if(nph == 0)
+ amp = gain;
+ initfilter(lfilter[nph + n * numstages], freq + OffsetHz, bw,
+ amp, hgain, automation);
+ if(stereo)
+ initfilter(rfilter[nph + n * numstages], freq + OffsetHz, bw,
+ amp, hgain, automation);
+ }
+ }
+
+ if(reduceamp < 0.001f)
+ reduceamp = 1.0f;
+
+ return reduceamp;
+}
+
void SUBnote::setup(float freq,
float velocity,
int portamento_,
@@ -72,7 +138,6 @@ void SUBnote::setup(float freq,
firsttick = 1;
}
- int pos[MAX_SUB_HARMONICS];
if(pars.Pfixedfreq == 0)
basefreq = freq;
@@ -101,6 +166,7 @@ void SUBnote::setup(float freq,
basefreq *= powf(2.0f, detune / 1200.0f); //detune
// basefreq*=ctl.pitchwheel.relfreq;//pitch wheel
+ int pos[MAX_SUB_HARMONICS];
int harmonics = 0;
//select only harmonics that desire to compute
@@ -120,7 +186,7 @@ void SUBnote::setup(float freq,
if(numharmonics == 0) {
- NoteEnabled = OFF;
+ NoteEnabled = false;
return;
}
@@ -132,65 +198,9 @@ void SUBnote::setup(float freq,
}
//how much the amplitude is normalised (because the harmonics)
- float reduceamp = 0.0f;
-
- for(int n = 0; n < numharmonics; ++n) {
- float freq = basefreq * pars.POvertoneFreqMult[pos[n]];
- overtone_freq[n] = freq;
- overtone_rolloff[n] = computerolloff(freq);
-
- //the bandwidth is not absolute(Hz); it is relative to frequency
- float bw =
- powf(10, (pars.Pbandwidth - 127.0f) / 127.0f * 4) * numstages;
-
- //Bandwidth Scale
- bw *= powf(1000 / freq, (pars.Pbwscale - 64.0f) / 64.0f * 3.0f);
-
- //Relative BandWidth
- bw *= powf(100, (pars.Phrelbw[pos[n]] - 64.0f) / 64.0f);
-
- if(bw > 25.0f)
- bw = 25.0f;
-
- //try to keep same amplitude on all freqs and bw. (empirically)
- float gain = sqrt(1500.0f / (bw * freq));
+ float reduceamp = setupFilters(pos, false);
+ oldreduceamp = reduceamp;
- float hmagnew = 1.0f - pars.Phmag[pos[n]] / 127.0f;
- float hgain;
-
- switch(pars.Phmagtype) {
- case 1:
- hgain = expf(hmagnew * logf(0.01f));
- break;
- case 2:
- hgain = expf(hmagnew * logf(0.001f));
- break;
- case 3:
- hgain = expf(hmagnew * logf(0.0001f));
- break;
- case 4:
- hgain = expf(hmagnew * logf(0.00001f));
- break;
- default:
- hgain = 1.0f - hmagnew;
- }
- gain *= hgain;
- reduceamp += hgain;
-
- for(int nph = 0; nph < numstages; ++nph) {
- float amp = 1.0f;
- if(nph == 0)
- amp = gain;
- initfilter(lfilter[nph + n * numstages], freq + OffsetHz, bw,
- amp, hgain);
- if(stereo)
- initfilter(rfilter[nph + n * numstages], freq + OffsetHz, bw,
- amp, hgain);
- }
- }
-
- if(reduceamp < 0.001f)
- reduceamp = 1.0f;
volume /= reduceamp;
oldpitchwheel = 0;
@@ -216,8 +226,8 @@ void SUBnote::setup(float freq,
SynthNote *SUBnote::cloneLegato(void)
{
- SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
- (bool)portamento, legato.param.midinote, true};
+ SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
+ portamento, legato.param.midinote, true};
return memory.alloc<SUBnote>(&pars, sp);
}
@@ -237,7 +247,7 @@ void SUBnote::legatonote(LegatoParams pars)
SUBnote::~SUBnote()
{
- if(NoteEnabled != OFF)
+ if(NoteEnabled)
KillNote();
}
@@ -246,7 +256,7 @@ SUBnote::~SUBnote()
*/
void SUBnote::KillNote()
{
- if(NoteEnabled != OFF) {
+ if(NoteEnabled) {
memory.devalloc(numstages * numharmonics, lfilter);
if(stereo)
memory.devalloc(numstages * numharmonics, rfilter);
@@ -255,7 +265,7 @@ void SUBnote::KillNote()
memory.dealloc(BandWidthEnvelope);
memory.dealloc(GlobalFilter);
memory.dealloc(GlobalFilterEnvelope);
- NoteEnabled = OFF;
+ NoteEnabled = false;
}
}
@@ -296,29 +306,32 @@ void SUBnote::initfilter(bpfilter &filter,
float freq,
float bw,
float amp,
- float mag)
+ float mag,
+ bool automation)
{
- filter.xn1 = 0.0f;
- filter.xn2 = 0.0f;
+ if(!automation) {
+ filter.xn1 = 0.0f;
+ filter.xn2 = 0.0f;
- if(start == 0) {
- filter.yn1 = 0.0f;
- filter.yn2 = 0.0f;
- }
- else {
- float a = 0.1f * mag; //empirically
- float p = RND * 2.0f * PI;
- if(start == 1)
- a *= RND;
- filter.yn1 = a * cosf(p);
- filter.yn2 = a * cosf(p + freq * 2.0f * PI / synth.samplerate_f);
-
- //correct the error of computation the start amplitude
- //at very high frequencies
- if(freq > synth.samplerate_f * 0.96f) {
+ if(start == 0) {
filter.yn1 = 0.0f;
filter.yn2 = 0.0f;
}
+ else {
+ float a = 0.1f * mag; //empirically
+ float p = RND * 2.0f * PI;
+ if(start == 1)
+ a *= RND;
+ filter.yn1 = a * cosf(p);
+ filter.yn2 = a * cosf(p + freq * 2.0f * PI / synth.samplerate_f);
+
+ //correct the error of computation the start amplitude
+ //at very high frequencies
+ if(freq > synth.samplerate_f * 0.96f) {
+ filter.yn1 = 0.0f;
+ filter.yn2 = 0.0f;
+ }
+ }
}
filter.amp = amp;
@@ -420,61 +433,76 @@ float SUBnote::computerolloff(float freq)
*/
void SUBnote::computecurrentparameters()
{
+ //Recompute parameters for realtime automation
+ if(pars.time && pars.last_update_timestamp == pars.time->time()) {
+ //A little bit of copy/paste for now
+
+ int pos[MAX_SUB_HARMONICS];
+ int harmonics = 0;
+
+ //select only harmonics that desire to compute
+ for(int n = 0; n < MAX_SUB_HARMONICS; ++n) {
+ if(pars.Phmag[n] == 0)
+ continue;
+ pos[harmonics++] = n;
+ }
+
+ bool delta_harmonics = (harmonics != numharmonics);
+ if(delta_harmonics) {
+ memory.devalloc(lfilter);
+ memory.devalloc(rfilter);
+
+ firstnumharmonics = numharmonics = harmonics;
+ lfilter = memory.valloc<bpfilter>(numstages * numharmonics);
+ if(stereo)
+ rfilter = memory.valloc<bpfilter>(numstages * numharmonics);
+ }
+
+ float reduceamp = setupFilters(pos, !delta_harmonics);
+ volume = volume*oldreduceamp/reduceamp;
+ oldreduceamp = reduceamp;
+ }
+
if(FreqEnvelope || BandWidthEnvelope
|| (oldpitchwheel != ctl.pitchwheel.data)
|| (oldbandwidth != ctl.bandwidth.data)
|| portamento) {
float envfreq = 1.0f;
float envbw = 1.0f;
- float gain = 1.0f;
if(FreqEnvelope) {
envfreq = FreqEnvelope->envout() / 1200;
envfreq = powf(2.0f, envfreq);
}
+
envfreq *=
powf(ctl.pitchwheel.relfreq, BendAdjust); //pitch wheel
- if(portamento) { //portamento is used
+
+ //Update frequency while portamento is converging
+ if(portamento) {
envfreq *= ctl.portamento.freqrap;
if(!ctl.portamento.used) //the portamento has finished
- portamento = false; //this note is no longer "portamented"
+ portamento = false;
}
if(BandWidthEnvelope) {
envbw = BandWidthEnvelope->envout();
envbw = powf(2, envbw);
}
+
envbw *= ctl.bandwidth.relbw; //bandwidth controller
- float tmpgain = 1.0f / sqrt(envbw * envfreq);
- for(int n = 0; n < numharmonics; ++n) {
- overtone_rolloff[n] = computerolloff(overtone_freq[n] * envfreq);
- }
+ //Recompute High Frequency Dampening Terms
for(int n = 0; n < numharmonics; ++n)
- for(int nph = 0; nph < numstages; ++nph) {
- if(nph == 0)
- gain = tmpgain;
- else
- gain = 1.0f;
- computefiltercoefs(lfilter[nph + n * numstages],
- lfilter[nph + n * numstages].freq * envfreq,
- lfilter[nph + n * numstages].bw * envbw,
- gain);
- }
+ overtone_rolloff[n] = computerolloff(overtone_freq[n] * envfreq);
+
+
+ //Recompute Filter Coefficients
+ float tmpgain = 1.0f / sqrt(envbw * envfreq);
+ computeallfiltercoefs(lfilter, envfreq, envbw, tmpgain);
if(stereo)
- for(int n = 0; n < numharmonics; ++n)
- for(int nph = 0; nph < numstages; ++nph) {
- if(nph == 0)
- gain = tmpgain;
- else
- gain = 1.0f;
- computefiltercoefs(
- rfilter[nph + n * numstages],
- rfilter[nph + n * numstages].freq * envfreq,
- rfilter[nph + n * numstages].bw * envbw,
- gain);
- }
+ computeallfiltercoefs(rfilter, envfreq, envbw, tmpgain);
oldbandwidth = ctl.bandwidth.data;
@@ -488,55 +516,68 @@ void SUBnote::computecurrentparameters()
ctl.filterq.relq);
}
-/*
- * Note Output
- */
-int SUBnote::noteout(float *outl, float *outr)
+void SUBnote::computeallfiltercoefs(bpfilter *filters, float envfreq,
+ float envbw, float gain)
{
- memcpy(outl, synth.denormalkillbuf, synth.bufferbytes);
- memcpy(outr, synth.denormalkillbuf, synth.bufferbytes);
+ for(int n = 0; n < numharmonics; ++n)
+ for(int nph = 0; nph < numstages; ++nph)
+ computefiltercoefs(filters[nph + n * numstages],
+ filters[nph + n * numstages].freq * envfreq,
+ filters[nph + n * numstages].bw * envbw,
+ nph == 0 ? gain : 1.0);
+}
- if(NoteEnabled == OFF)
- return 0;
+void SUBnote::chanOutput(float *out, bpfilter *bp, int buffer_size)
+{
+ float tmprnd[buffer_size];
+ float tmpsmp[buffer_size];
- float tmprnd[synth.buffersize];
- float tmpsmp[synth.buffersize];
- //left channel
- for(int i = 0; i < synth.buffersize; ++i)
+ //Initialize Random Input
+ for(int i = 0; i < buffer_size; ++i)
tmprnd[i] = RND * 2.0f - 1.0f;
+
+ //For each harmonic apply the filter on the random input stream
+ //Sum the filter outputs to obtain the output signal
for(int n = 0; n < numharmonics; ++n) {
float rolloff = overtone_rolloff[n];
memcpy(tmpsmp, tmprnd, synth.bufferbytes);
+
for(int nph = 0; nph < numstages; ++nph)
- filter(lfilter[nph + n * numstages], tmpsmp);
+ filter(bp[nph + n * numstages], tmpsmp);
+
for(int i = 0; i < synth.buffersize; ++i)
- outl[i] += tmpsmp[i] * rolloff;
+ out[i] += tmpsmp[i] * rolloff;
}
+}
+/*
+ * Note Output
+ */
+int SUBnote::noteout(float *outl, float *outr)
+{
+ memcpy(outl, synth.denormalkillbuf, synth.bufferbytes);
+ memcpy(outr, synth.denormalkillbuf, synth.bufferbytes);
+
+ if(!NoteEnabled)
+ return 0;
- //right channel
if(stereo) {
- for(int i = 0; i < synth.buffersize; ++i)
- tmprnd[i] = RND * 2.0f - 1.0f;
- for(int n = 0; n < numharmonics; ++n) {
- float rolloff = overtone_rolloff[n];
- memcpy(tmpsmp, tmprnd, synth.bufferbytes);
- for(int nph = 0; nph < numstages; ++nph)
- filter(rfilter[nph + n * numstages], tmpsmp);
- for(int i = 0; i < synth.buffersize; ++i)
- outr[i] += tmpsmp[i] * rolloff;
- }
+ chanOutput(outl, lfilter, synth.buffersize);
+ chanOutput(outr, rfilter, synth.buffersize);
+
if(GlobalFilter)
GlobalFilter->filter(outl, outr);
} else {
+ chanOutput(outl, lfilter, synth.buffersize);
+
if(GlobalFilter)
GlobalFilter->filter(outl, 0);
memcpy(outr, outl, synth.bufferbytes);
}
- if(firsttick != 0) {
+ if(firsttick) {
int n = 10;
if(n > synth.buffersize)
n = synth.buffersize;
@@ -546,7 +587,7 @@ int SUBnote::noteout(float *outl, float *outr)
outl[i] *= ampfadein;
outr[i] *= ampfadein;
}
- firsttick = 0;
+ firsttick = false;
}
if(ABOVE_AMPLITUDE_THRESHOLD(oldamplitude, newamplitude))
@@ -602,10 +643,7 @@ void SUBnote::releasekey()
*/
bool SUBnote::finished() const
{
- if(NoteEnabled == OFF)
- return 1;
- else
- return 0;
+ return !NoteEnabled;
}
void SUBnote::entomb(void)
diff --git a/src/Synth/SUBnote.h b/src/Synth/SUBnote.h
@@ -46,6 +46,7 @@ class SUBnote:public SynthNote
int portamento_,
int midinote,
bool legato = false);
+ float setupFilters(int *pos, bool automation);
void computecurrentparameters();
/*
* Initialize envelopes and global filter
@@ -74,9 +75,10 @@ class SUBnote:public SynthNote
Envelope *GlobalFilterEnvelope;
//internal values
- ONOFFTYPE NoteEnabled;
- int firsttick, portamento;
- float volume, oldamplitude, newamplitude;
+ bool NoteEnabled;
+ bool firsttick, portamento;
+ float volume, oldamplitude, newamplitude;
+ float oldreduceamp;
struct bpfilter {
float freq, bw, amp; //filter parameters
@@ -84,12 +86,16 @@ class SUBnote:public SynthNote
float xn1, xn2, yn1, yn2; //filter internal values
};
+ void chanOutput(float *out, bpfilter *bp, int buffer_size);
+
void initfilter(bpfilter &filter,
float freq,
float bw,
float amp,
- float mag);
+ float mag,
+ bool automation);
float computerolloff(float freq);
+ void computeallfiltercoefs(bpfilter *filters, float envfreq, float envbw, float gain);
void computefiltercoefs(bpfilter &filter,
float freq,
float bw,