|
- /*
- ZynAddSubFX - a software synthesizer
-
- Echo.cpp - Echo effect
- Copyright (C) 2002-2005 Nasca Octavian Paul
- Copyright (C) 2009-2010 Mark McCurry
- Author: Nasca Octavian Paul
- Mark McCurry
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include <cmath>
- #include <rtosc/ports.h>
- #include <rtosc/port-sugar.h>
- #include "../Misc/Allocator.h"
- #include "Echo.h"
-
- #define MAX_DELAY 2
-
- namespace zyncarla {
-
- #define rObject Echo
- #define rBegin [](const char *msg, rtosc::RtData &d) {
- #define rEnd }
-
- rtosc::Ports Echo::ports = {
- {"preset::i", rOptions(Echo 1, Echo 2, Echo 3, Simple Echo, Canyon, Panning Echo 1,
- Panning Echo 2, Panning Echo 3, Feedback Echo)
- rProp(parameter)
- rDoc("Instrument Presets"), 0,
- rBegin;
- rObject *o = (rObject*)d.obj;
- if(rtosc_narguments(msg))
- o->setpreset(rtosc_argument(msg, 0).i);
- else
- d.reply(d.loc, "i", o->Ppreset);
- rEnd},
- rEffParVol(rDefault(67), rPresetsAt(6, 81, 81, 62)),
- rEffParPan(rPresetsAt(2, 75, 60, 60, 64, 60, 60, 64)),
- rEffPar(Pdelay, 2, rShort("delay"),
- rPresets(35, 21, 60, 44, 102, 44, 46, 26, 28),
- "Length of Echo"),
- rEffPar(Plrdelay, 3, rShort("lr delay"),
- rPresetsAt(4, 50, 17, 118, 100, 64), rDefault(64),
- "Difference In Left/Right Delay"),
- rEffPar(Plrcross, 4, rShort("cross"),
- rPresetsAt(5, 0, 100, 127, 100), rDefault(30),
- "Left/Right Crossover"),
- rEffPar(Pfb, 5, rShort("feedback"),
- rPresets(59, 59, 59, 0, 82, 82, 68, 67, 90),
- "Echo Feedback"),
- rEffPar(Phidamp, 6, rShort("damp"),
- rPresets(0, 0, 10, 0, 48, 24, 18, 36, 55),
- "Dampen High Frequencies"),
- };
- #undef rBegin
- #undef rEnd
- #undef rObject
-
- Echo::Echo(EffectParams pars)
- :Effect(pars),
- Pvolume(50),
- Pdelay(60),
- Plrdelay(100),
- Pfb(40),
- Phidamp(60),
- delayTime(1),
- lrdelay(0),
- avgDelay(0),
- delay(memory.valloc<float>(MAX_DELAY * pars.srate),
- memory.valloc<float>(MAX_DELAY * pars.srate)),
- old(0.0f),
- pos(0),
- delta(1),
- ndelta(1)
- {
- initdelays();
- setpreset(Ppreset);
- }
-
- Echo::~Echo()
- {
- memory.devalloc(delay.l);
- memory.devalloc(delay.r);
- }
-
- //Cleanup the effect
- void Echo::cleanup(void)
- {
- memset(delay.l, 0, MAX_DELAY * samplerate * sizeof(float));
- memset(delay.r, 0, MAX_DELAY * samplerate * sizeof(float));
- old = Stereo<float>(0.0f);
- }
-
- inline int max(int a, int b)
- {
- return a > b ? a : b;
- }
-
- //Initialize the delays
- void Echo::initdelays(void)
- {
- cleanup();
- //number of seconds to delay left chan
- float dl = avgDelay - lrdelay;
-
- //number of seconds to delay right chan
- float dr = avgDelay + lrdelay;
-
- ndelta.l = max(1, (int) (dl * samplerate));
- ndelta.r = max(1, (int) (dr * samplerate));
- delta = ndelta;
- }
-
- //Effect output
- void Echo::out(const Stereo<float *> &input)
- {
- for(int i = 0; i < buffersize; ++i) {
- float ldl = delay.l[pos.l];
- float rdl = delay.r[pos.r];
- ldl = ldl * (1.0f - lrcross) + rdl * lrcross;
- rdl = rdl * (1.0f - lrcross) + ldl * lrcross;
-
- efxoutl[i] = ldl * 2.0f;
- efxoutr[i] = rdl * 2.0f;
-
- ldl = input.l[i] * pangainL - ldl * fb;
- rdl = input.r[i] * pangainR - rdl * fb;
-
- //LowPass Filter
- old.l = delay.l[(pos.l + delta.l) % (MAX_DELAY * samplerate)] =
- ldl * hidamp + old.l * (1.0f - hidamp);
- old.r = delay.r[(pos.r + delta.r) % (MAX_DELAY * samplerate)] =
- rdl * hidamp + old.r * (1.0f - hidamp);
-
- //increment
- ++pos.l; // += delta.l;
- ++pos.r; // += delta.r;
-
- //ensure that pos is still in bounds
- pos.l %= MAX_DELAY * samplerate;
- pos.r %= MAX_DELAY * samplerate;
-
- //adjust delay if needed
- delta.l = (15 * delta.l + ndelta.l) / 16;
- delta.r = (15 * delta.r + ndelta.r) / 16;
- }
- }
-
-
- //Parameter control
- void Echo::setvolume(unsigned char _Pvolume)
- {
- Pvolume = _Pvolume;
-
- if(insertion == 0) {
- if (Pvolume == 0) {
- outvolume = 0.0f;
- } else {
- outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f;
- }
- volume = 1.0f;
- }
- else
- volume = outvolume = Pvolume / 127.0f;
- if(Pvolume == 0)
- cleanup();
- }
-
- void Echo::setdelay(unsigned char _Pdelay)
- {
- Pdelay = _Pdelay;
- avgDelay = (Pdelay / 127.0f * 1.5f); //0 .. 1.5 sec
- initdelays();
- }
-
- void Echo::setlrdelay(unsigned char _Plrdelay)
- {
- float tmp;
- Plrdelay = _Plrdelay;
- tmp =
- (powf(2.0f, fabsf(Plrdelay - 64.0f) / 64.0f * 9.0f) - 1.0f) / 1000.0f;
- if(Plrdelay < 64.0f)
- tmp = -tmp;
- lrdelay = tmp;
- initdelays();
- }
-
- void Echo::setfb(unsigned char _Pfb)
- {
- Pfb = _Pfb;
- fb = Pfb / 128.0f;
- }
-
- void Echo::sethidamp(unsigned char _Phidamp)
- {
- Phidamp = _Phidamp;
- hidamp = 1.0f - Phidamp / 127.0f;
- }
-
- void Echo::setpreset(unsigned char npreset)
- {
- const int PRESET_SIZE = 7;
- const int NUM_PRESETS = 9;
- unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
- {67, 64, 35, 64, 30, 59, 0 }, //Echo 1
- {67, 64, 21, 64, 30, 59, 0 }, //Echo 2
- {67, 75, 60, 64, 30, 59, 10}, //Echo 3
- {67, 60, 44, 64, 30, 0, 0 }, //Simple Echo
- {67, 60, 102, 50, 30, 82, 48}, //Canyon
- {67, 64, 44, 17, 0, 82, 24}, //Panning Echo 1
- {81, 60, 46, 118, 100, 68, 18}, //Panning Echo 2
- {81, 60, 26, 100, 127, 67, 36}, //Panning Echo 3
- {62, 64, 28, 64, 100, 90, 55} //Feedback Echo
- };
-
- if(npreset >= NUM_PRESETS)
- npreset = NUM_PRESETS - 1;
- for(int n = 0; n < PRESET_SIZE; ++n)
- changepar(n, presets[npreset][n]);
- if(insertion)
- setvolume(presets[npreset][0] / 2); //lower the volume if this is insertion effect
- Ppreset = npreset;
- }
-
-
- void Echo::changepar(int npar, unsigned char value)
- {
- switch(npar) {
- case 0:
- setvolume(value);
- break;
- case 1:
- setpanning(value);
- break;
- case 2:
- setdelay(value);
- break;
- case 3:
- setlrdelay(value);
- break;
- case 4:
- setlrcross(value);
- break;
- case 5:
- setfb(value);
- break;
- case 6:
- sethidamp(value);
- break;
- }
- }
-
- unsigned char Echo::getpar(int npar) const
- {
- switch(npar) {
- case 0: return Pvolume;
- case 1: return Ppanning;
- case 2: return Pdelay;
- case 3: return Plrdelay;
- case 4: return Plrcross;
- case 5: return Pfb;
- case 6: return Phidamp;
- default: return 0; // in case of bogus parameter number
- }
- }
-
- }
|