diff --git a/src/Makefile b/src/Makefile index 8804682..fc914ad 100644 --- a/src/Makefile +++ b/src/Makefile @@ -22,6 +22,9 @@ OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ effect_audio/moddistortion/Distortion_BigMuff.o \ effect_audio/moddistortion/HyperbolicTables.o \ effect_audio/moddistortion/OverSample.o \ + effect_audio/rkrlv2/EffectLFO.o \ + effect_audio/rkrlv2/Phaser.o \ + effect_audio/rkrlv2/APhaser.o \ effect_midi/midi_arp.o \ effect_midi/modarpeggiator/common/clock.o \ effect_midi/modarpeggiator/common/midiHandler.o \ @@ -34,4 +37,9 @@ OPTIMIZE = -O3 include ./Synth_Dexed.mk include ./Rules.mk -EXTRACLEAN += effect_audio/moddistortion/*.[od] effect_midi/modarpeggiator/*.[od] effect_midi/modarpeggiator/common/*.[od] \ No newline at end of file +EXTRACLEAN += effect_audio/*.[od] \ + effect_audio/moddistortion/*.[od] \ + effect_audio/rkrlv2/*.[od] \ + effect_midi/*.[od] \ + effect_midi/modarpeggiator/*.[od] \ + effect_midi/modarpeggiator/common/*.[od] diff --git a/src/effect_audio/effect_aphaser.h b/src/effect_audio/effect_aphaser.h new file mode 100644 index 0000000..9a7be20 --- /dev/null +++ b/src/effect_audio/effect_aphaser.h @@ -0,0 +1,179 @@ +/* + * Phaser Port + * Ported from https://github.com/ssj71/rkrlv2 + * + * Javier Nonis (https://github.com/jnonis) - 2024 + */ +#ifndef _EFFECT_APHASER_H +#define _EFFECT_APHASER_H + +#include "effect_base.h" +#include "rkrlv2/APhaser.h" + +class AudioEffectAPhaser : public AudioEffect +{ +public: + enum Param + { + BYPASS, + WETDRY, + PAN, + PH_FREQ, + PH_RND, + TYPE, + STDL, + PH_DEPTH, + FB, + STAGES, + LRCR, + SUB, + PHASE, + UNKNOWN + }; + + AudioEffectAPhaser(float32_t samplerate) : AudioEffect(samplerate) + { + this->phaser = new Analog_Phaser(0, 0, (double) samplerate); + this->init_params = true; + + this->phaser->setpreset(0); + /* + this->setParameter(AudioEffectAPhaser::Param::WETDRY, 64); + this->setParameter(AudioEffectAPhaser::Param::PAN, 64); + this->setParameter(AudioEffectAPhaser::Param::PH_FREQ, 11); + this->setParameter(AudioEffectAPhaser::Param::PH_RND, 0); + this->setParameter(AudioEffectAPhaser::Param::TYPE, 0); + this->setParameter(AudioEffectAPhaser::Param::STDL, 64); + this->setParameter(AudioEffectAPhaser::Param::PH_DEPTH, 110); + this->setParameter(AudioEffectAPhaser::Param::FB, 64); + this->setParameter(AudioEffectAPhaser::Param::STAGES, 4); + this->setParameter(AudioEffectAPhaser::Param::LRCR, 0); + this->setParameter(AudioEffectAPhaser::Param::SUB, 0); + this->setParameter(AudioEffectAPhaser::Param::PHASE, 20); + */ + } + + virtual ~AudioEffectAPhaser() + { + delete this->phaser; + } + + virtual unsigned getId() + { + return EFFECT_APHASER; + } + + virtual void setParameter(unsigned param, unsigned value) + { + switch (param) + { + case AudioEffectAPhaser::Param::BYPASS: + this->setBypass(value == 1); + this->phaser->cleanup(); + break; + case AudioEffectAPhaser::Param::WETDRY: + this->phaser->changepar(0, value); + break; + case AudioEffectAPhaser::Param::PAN: + this->phaser->changepar(1, value); + break; + case AudioEffectAPhaser::Param::PH_FREQ: + this->phaser->changepar(2, value); + break; + case AudioEffectAPhaser::Param::PH_RND: + this->phaser->changepar(3, value); + break; + case AudioEffectAPhaser::Param::TYPE: + this->phaser->changepar(4, value); + break; + case AudioEffectAPhaser::Param::STDL: + this->phaser->changepar(5, value); + break; + case AudioEffectAPhaser::Param::PH_DEPTH: + this->phaser->changepar(6, value); + break; + case AudioEffectAPhaser::Param::FB: + this->phaser->changepar(7, value); + break; + case AudioEffectAPhaser::Param::STAGES: + this->phaser->changepar(8, value); + break; + case AudioEffectAPhaser::Param::LRCR: + this->phaser->changepar(9, value); + break; + case AudioEffectAPhaser::Param::SUB: + this->phaser->changepar(10, value); + break; + case AudioEffectAPhaser::Param::PHASE: + this->phaser->changepar(11, value); + break; + default: + break; + } + } + + virtual unsigned getParameter(unsigned param) + { + switch (param) + { + case AudioEffectAPhaser::Param::BYPASS: + return this->getBypass() ? 1 : 0; + case AudioEffectAPhaser::Param::WETDRY: + return this->phaser->getpar(0); + case AudioEffectAPhaser::Param::PAN: + return this->phaser->getpar(1); + case AudioEffectAPhaser::Param::PH_FREQ: + return this->phaser->getpar(2); + case AudioEffectAPhaser::Param::PH_RND: + return this->phaser->getpar(3); + case AudioEffectAPhaser::Param::TYPE: + return this->phaser->getpar(4); + case AudioEffectAPhaser::Param::STDL: + return this->phaser->getpar(5); + case AudioEffectAPhaser::Param::PH_DEPTH: + return this->phaser->getpar(6); + case AudioEffectAPhaser::Param::FB: + return this->phaser->getpar(7); + case AudioEffectAPhaser::Param::STAGES: + return this->phaser->getpar(8); + case AudioEffectAPhaser::Param::LRCR: + return this->phaser->getpar(9); + case AudioEffectAPhaser::Param::SUB: + return this->phaser->getpar(10); + case AudioEffectAPhaser::Param::PHASE: + return this->phaser->getpar(11); + default: + return 0; + } + } + +protected: + virtual size_t getParametersSize() + { + return AudioEffectAPhaser::Param::UNKNOWN; + } + + virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len) + { + // LFO effects require period be set before setting other params + if(this->init_params) + { + this->phaser->PERIOD = len; + this->phaser->lfo->updateparams(len); + this->init_params = false; // so we only do this once + } + + // now set out ports and global period size + this->phaser->efxoutl = outblockL; + this->phaser->efxoutr = outblockR; + + //now run + this->phaser->out((float*) inblockL, (float*) inblockR, len); + } + +private: + Analog_Phaser* phaser; + bool init_params; +}; + +#endif // _EFFECT_PHASER_H \ No newline at end of file diff --git a/src/effect_audio/effect_base.h b/src/effect_audio/effect_base.h index 303f37c..d92cce3 100644 --- a/src/effect_audio/effect_base.h +++ b/src/effect_audio/effect_base.h @@ -18,6 +18,8 @@ #define EFFECT_REVERB 7 #define EFFECT_MVERB 8 #define EFFECT_3BANDEQ 9 +#define EFFECT_PHASER 10 +#define EFFECT_APHASER 11 class AudioEffect { diff --git a/src/effect_audio/effect_phaser.h b/src/effect_audio/effect_phaser.h new file mode 100644 index 0000000..e9e2160 --- /dev/null +++ b/src/effect_audio/effect_phaser.h @@ -0,0 +1,179 @@ +/* + * Phaser Port + * Ported from https://github.com/ssj71/rkrlv2 + * + * Javier Nonis (https://github.com/jnonis) - 2024 + */ +#ifndef _EFFECT_PHASER_H +#define _EFFECT_PHASER_H + +#include "effect_base.h" +#include "rkrlv2/Phaser.h" + +class AudioEffectPhaser : public AudioEffect +{ +public: + enum Param + { + BYPASS, + WETDRY, + PAN, + PH_FREQ, + PH_RND, + TYPE, + STDL, + PH_DEPTH, + FB, + STAGES, + LRCR, + SUB, + PHASE, + UNKNOWN + }; + + AudioEffectPhaser(float32_t samplerate) : AudioEffect(samplerate) + { + this->phaser = new Phaser(0, 0, (double) samplerate); + this->init_params = true; + + this->phaser->setpreset(0); + /* + this->setParameter(AudioEffectPhaser::Param::WETDRY, 64); + this->setParameter(AudioEffectPhaser::Param::PAN, 64); + this->setParameter(AudioEffectPhaser::Param::PH_FREQ, 11); + this->setParameter(AudioEffectPhaser::Param::PH_RND, 0); + this->setParameter(AudioEffectPhaser::Param::TYPE, 0); + this->setParameter(AudioEffectPhaser::Param::STDL, 64); + this->setParameter(AudioEffectPhaser::Param::PH_DEPTH, 110); + this->setParameter(AudioEffectPhaser::Param::FB, 64); + this->setParameter(AudioEffectPhaser::Param::STAGES, 4); + this->setParameter(AudioEffectPhaser::Param::LRCR, 0); + this->setParameter(AudioEffectPhaser::Param::SUB, 0); + this->setParameter(AudioEffectPhaser::Param::PHASE, 20); + */ + } + + virtual ~AudioEffectPhaser() + { + delete this->phaser; + } + + virtual unsigned getId() + { + return EFFECT_PHASER; + } + + virtual void setParameter(unsigned param, unsigned value) + { + switch (param) + { + case AudioEffectPhaser::Param::BYPASS: + this->setBypass(value == 1); + this->phaser->cleanup(); + break; + case AudioEffectPhaser::Param::WETDRY: + this->phaser->changepar(0, value); + break; + case AudioEffectPhaser::Param::PAN: + this->phaser->changepar(1, value); + break; + case AudioEffectPhaser::Param::PH_FREQ: + this->phaser->changepar(2, value); + break; + case AudioEffectPhaser::Param::PH_RND: + this->phaser->changepar(3, value); + break; + case AudioEffectPhaser::Param::TYPE: + this->phaser->changepar(4, value); + break; + case AudioEffectPhaser::Param::STDL: + this->phaser->changepar(5, value); + break; + case AudioEffectPhaser::Param::PH_DEPTH: + this->phaser->changepar(6, value); + break; + case AudioEffectPhaser::Param::FB: + this->phaser->changepar(7, value); + break; + case AudioEffectPhaser::Param::STAGES: + this->phaser->changepar(8, value); + break; + case AudioEffectPhaser::Param::LRCR: + this->phaser->changepar(9, value); + break; + case AudioEffectPhaser::Param::SUB: + this->phaser->changepar(10, value); + break; + case AudioEffectPhaser::Param::PHASE: + this->phaser->changepar(11, value); + break; + default: + break; + } + } + + virtual unsigned getParameter(unsigned param) + { + switch (param) + { + case AudioEffectPhaser::Param::BYPASS: + return this->getBypass() ? 1 : 0; + case AudioEffectPhaser::Param::WETDRY: + return this->phaser->getpar(0); + case AudioEffectPhaser::Param::PAN: + return this->phaser->getpar(1); + case AudioEffectPhaser::Param::PH_FREQ: + return this->phaser->getpar(2); + case AudioEffectPhaser::Param::PH_RND: + return this->phaser->getpar(3); + case AudioEffectPhaser::Param::TYPE: + return this->phaser->getpar(4); + case AudioEffectPhaser::Param::STDL: + return this->phaser->getpar(5); + case AudioEffectPhaser::Param::PH_DEPTH: + return this->phaser->getpar(6); + case AudioEffectPhaser::Param::FB: + return this->phaser->getpar(7); + case AudioEffectPhaser::Param::STAGES: + return this->phaser->getpar(8); + case AudioEffectPhaser::Param::LRCR: + return this->phaser->getpar(9); + case AudioEffectPhaser::Param::SUB: + return this->phaser->getpar(10); + case AudioEffectPhaser::Param::PHASE: + return this->phaser->getpar(11); + default: + return 0; + } + } + +protected: + virtual size_t getParametersSize() + { + return AudioEffectPhaser::Param::UNKNOWN; + } + + virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len) + { + // LFO effects require period be set before setting other params + if(this->init_params) + { + this->phaser->PERIOD = len; + this->phaser->lfo->updateparams(len); + this->init_params = false; // so we only do this once + } + + // now set out ports and global period size + this->phaser->efxoutl = outblockL; + this->phaser->efxoutr = outblockR; + + //now run + this->phaser->out((float*) inblockL, (float*) inblockR, len); + } + +private: + Phaser* phaser; + bool init_params; +}; + +#endif // _EFFECT_PHASER_H \ No newline at end of file diff --git a/src/effect_audio/rkrlv2/APhaser.cpp b/src/effect_audio/rkrlv2/APhaser.cpp new file mode 100644 index 0000000..0ad6bac --- /dev/null +++ b/src/effect_audio/rkrlv2/APhaser.cpp @@ -0,0 +1,440 @@ +/* + APhaser.C - Approximate digital model of an analog JFET phaser. + Analog modeling implemented by Ryan Billing aka Transmogrifox. + November, 2009 + + Credit to: + /////////////////// + ZynAddSubFX - a software synthesizer + + Phaser.C - Phaser effect + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu + + DSP analog modeling theory & practice largely influenced by various CCRMA publications, particularly works by Julius O. Smith. + //////////////////// + + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#include +#include "APhaser.h" +#include +//#include "FPreset.h" +#define PHASER_LFO_SHAPE 2 +#define ONE_ 0.99999f // To prevent LFO ever reaching 1.0 for filter stability purposes +#define ZERO_ 0.00001f // Same idea as above. + +Analog_Phaser::Analog_Phaser (float * efxoutl_, float * efxoutr_, double sample_rate) +{ + float fSAMPLE_RATE = sample_rate; + + efxoutl = efxoutl_; + efxoutr = efxoutr_; + + lxn1 = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES); + + lyn1 = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES); + + rxn1 = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES); + + ryn1 = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES); + + offset = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES); //model mismatch between JFET devices + offset[0] = -0.2509303f; + offset[1] = 0.9408924f; + offset[2] = 0.998f; + offset[3] = -0.3486182f; + offset[4] = -0.2762545f; + offset[5] = -0.5215785f; + offset[6] = 0.2509303f; + offset[7] = -0.9408924f; + offset[8] = -0.998f; + offset[9] = 0.3486182f; + offset[10] = 0.2762545f; + offset[11] = 0.5215785f; + + barber = 0; //Deactivate barber pole phasing by default + + mis = 1.0f; + Rmin = 625.0f; // 2N5457 typical on resistance at Vgs = 0 + Rmax = 22000.0f; // Resistor parallel to FET + Rmx = Rmin/Rmax; + Rconst = 1.0f + Rmx; // Handle parallel resistor relationship + C = 0.00000005f; // 50 nF + CFs = 2.0f*fSAMPLE_RATE*C; + + lfo = new EffectLFO(sample_rate); + + Ppreset = 0; + PERIOD = 255; //make best guess for init; + setpreset (Ppreset);//this will get done before out is run + cleanup (); +}; + +Analog_Phaser::~Analog_Phaser () +{ + free(lxn1); + free(lyn1); + free(rxn1); + free(ryn1); + free(offset); + delete lfo; +}; + + +/* + * Effect output + */ +void +Analog_Phaser::out (float * smpsl, float * smpsr, uint32_t period) +{ + unsigned int i; + int j; + float lfol, lfor, lgain, rgain, bl, br, gl, gr, rmod, lmod, d, hpfr, hpfl; + invperiod = 1.0f / (float)PERIOD;//had to move this to run + lgain = 0.0; + rgain = 0.0; + + //initialize hpf + hpfl = 0.0; + hpfr = 0.0; + + lfo->effectlfoout (&lfol, &lfor); + lmod = lfol*width + depth; + rmod = lfor*width + depth; + + if (lmod > ONE_) + lmod = ONE_; + else if (lmod < ZERO_) + lmod = ZERO_; + if (rmod > ONE_) + rmod = ONE_; + else if (rmod < ZERO_) + rmod = ZERO_; + + if (Phyper != 0) { + lmod *= lmod; //Triangle wave squared is approximately sin on bottom, tri on top + rmod *= rmod; //Result is exponential sweep more akin to filter in synth with exponential generator circuitry. + }; + + lmod = sqrtf(1.0f - lmod); //gl,gr is Vp - Vgs. Typical FET drain-source resistance follows constant/[1-sqrt(Vp - Vgs)] + rmod = sqrtf(1.0f - rmod); + + rdiff = (rmod - oldrgain) * invperiod; + ldiff = (lmod - oldlgain) * invperiod; + + gl = oldlgain; + gr = oldrgain; + + oldlgain = lmod; + oldrgain = rmod; + + float v1, v2; + if (outvolume < 0.5f) + { + v1 = 1.0f; + v2 = outvolume * 2.0f; + } + else + { + v1 = (1.0f - outvolume) * 2.0f; + v2 = 1.0f; + } + + for (i = 0; i < period; i++) { + + gl += ldiff; // Linear interpolation between LFO samples + gr += rdiff; + + float lxn = smpsl[i]; + float rxn = smpsr[i]; + + + if (barber) { + gl = fmodf((gl + 0.25f) , ONE_); + gr = fmodf((gr + 0.25f) , ONE_); + }; + + + //Left channel + for (j = 0; j < Pstages; j++) { + //Phasing routine + mis = 1.0f + offsetpct*offset[j]; + d = (1.0f + 2.0f*(0.25f + gl)*hpfl*hpfl*distortion) * mis; //This is symmetrical. FET is not, so this deviates slightly, however sym dist. is better sounding than a real FET. + Rconst = 1.0f + mis*Rmx; + bl = (Rconst - gl )/ (d*Rmin); // This is 1/R. R is being modulated to control filter fc. + lgain = (CFs - bl)/(CFs + bl); + + lyn1[j] = lgain * (lxn + lyn1[j]) - lxn1[j]; + lyn1[j] += DENORMAL_GUARD; + hpfl = lyn1[j] + (1.0f-lgain)*lxn1[j]; //high pass filter -- Distortion depends on the high-pass part of the AP stage. + + lxn1[j] = lxn; + lxn = lyn1[j]; + if (j==1) lxn += fbl; //Insert feedback after first phase stage + }; + + //Right channel + for (j = 0; j < Pstages; j++) { + //Phasing routine + mis = 1.0f + offsetpct*offset[j]; + d = (1.0f + 2.0f*(0.25f + gr)*hpfr*hpfr*distortion) * mis; // distortion + Rconst = 1.0f + mis*Rmx; + br = (Rconst - gr )/ (d*Rmin); + rgain = (CFs - br)/(CFs + br); + + ryn1[j] = rgain * (rxn + ryn1[j]) - rxn1[j]; + ryn1[j] += DENORMAL_GUARD; + hpfr = ryn1[j] + (1.0f-rgain)*rxn1[j]; //high pass filter + + rxn1[j] = rxn; + rxn = ryn1[j]; + if (j==1) rxn += fbr; //Insert feedback after first phase stage + }; + + fbl = lxn * fb; + fbr = rxn * fb; + + if (Poutsub != 0) { + lxn *= -1.0f; + rxn *= -1.0f; + } + + efxoutl[i] = smpsl[i] * v1 + lxn * v2; + efxoutr[i] = smpsr[i] * v1 + rxn * v2; + }; +}; + +/* + * Cleanup the effect + */ +void +Analog_Phaser::cleanup () +{ + fbl = 0.0; + fbr = 0.0; + oldlgain = 0.0; + oldrgain = 0.0; + for (int i = 0; i < Pstages; i++) { + lxn1[i] = 0.0; + + lyn1[i] = 0.0; + + rxn1[i] = 0.0; + + ryn1[i] = 0.0; + + }; +}; + +/* + * Parameter control + */ +void +Analog_Phaser::setwidth (int Pwidth) +{ + this->Pwidth = Pwidth; + width = ((float)Pwidth / 127.0f); +}; + + +void +Analog_Phaser::setfb (int Pfb) +{ + this->Pfb = Pfb; + fb = (float) (Pfb - 64) / 64.2f; +}; + +void +Analog_Phaser::setvolume (int Pvolume) +{ + this->Pvolume = Pvolume; + // outvolume is needed in calling program + outvolume = (float)Pvolume / 127.0f; +}; + +void +Analog_Phaser::setdistortion (int Pdistortion) +{ + this->Pdistortion = Pdistortion; + distortion = (float)Pdistortion / 127.0f; +}; + +void +Analog_Phaser::setoffset (int Poffset) +{ + this->Poffset = Poffset; + offsetpct = (float)Poffset / 127.0f; +}; + +void +Analog_Phaser::setstages (int Pstages) +{ + + if (Pstages >= MAX_PHASER_STAGES) + Pstages = MAX_PHASER_STAGES ; + this->Pstages = Pstages; + + cleanup (); +}; + +void +Analog_Phaser::setdepth (int Pdepth) +{ + this->Pdepth = Pdepth; + depth = (float)(Pdepth - 64) / 127.0f; //Pdepth input should be 0-127. depth shall range 0-0.5 since we don't need to shift the full spectrum. +}; + + +void +Analog_Phaser::setpreset (int npreset) +{ + const int PRESET_SIZE = 13; + const int NUM_PRESETS = 6; + int presets[NUM_PRESETS][PRESET_SIZE] = { + //Phaser1 + {64, 20, 14, 0, 1, 64, 110, 40, 4, 10, 0, 64, 1}, + //Phaser2 + {64, 20, 14, 5, 1, 64, 110, 40, 6, 10, 0, 70, 1}, + //Phaser3 + {64, 20, 9, 0, 0, 64, 40, 40, 8, 10, 0, 60, 0}, + //Phaser4 + {64, 20, 14, 10, 0, 64, 110, 80, 7, 10, 1, 45, 1}, + //Phaser5 + {25, 20, 240, 10, 0, 64, 25, 16, 8, 100, 0, 25, 0}, + //Phaser6 + {64, 20, 1, 10, 1, 64, 110, 40, 12, 10, 0, 70, 1} + }; + + if(npreset>NUM_PRESETS-1) { + + } else { + + for (int n = 0; n < PRESET_SIZE; n++) + changepar (n, presets[npreset][n]); + } + + Ppreset = npreset; +}; + + +void +Analog_Phaser::changepar (int npar, int value) +{ + switch (npar) { + case 0: + setvolume (value); + break; + case 1: + setdistortion (value); + break; + case 2: + lfo->Pfreq = value; + lfo->updateparams (PERIOD); + break; + case 3: + lfo->Prandomness = value; + lfo->updateparams (PERIOD); + break; + case 4: + lfo->PLFOtype = value; + lfo->updateparams (PERIOD); + barber = 0; + if (value == 2) barber = 1; + break; + case 5: + lfo->Pstereo = value; + lfo->updateparams (PERIOD); + break; + case 6: + setwidth (value); + break; + case 7: + setfb (value); + break; + case 8: + setstages (value); + break; + case 9: + setoffset (value); + break; + case 10: + if (value > 1) + value = 1; + Poutsub = value; + break; + case 11: + setdepth (value); + break; + case 12: + if (value > 1) + value = 1; + Phyper = value; + break; + }; +}; + +int +Analog_Phaser::getpar (int npar) +{ + switch (npar) { + case 0: + return (Pvolume); + break; + case 1: + return (Pdistortion); + break; + case 2: + return (lfo->Pfreq); + break; + case 3: + return (lfo->Prandomness); + break; + case 4: + return (lfo->PLFOtype); + break; + case 5: + return (lfo->Pstereo); + break; + case 6: + return (Pwidth); + break; + case 7: + return (Pfb); + break; + case 8: + return (Pstages); + break; + case 9: + return (Poffset); + break; + case 10: + return (Poutsub); + break; + case 11: + return (Pdepth); + break; + case 12: + return (Phyper); + break; + + default: + return (0); + }; + +}; diff --git a/src/effect_audio/rkrlv2/APhaser.h b/src/effect_audio/rkrlv2/APhaser.h new file mode 100644 index 0000000..cf3ce04 --- /dev/null +++ b/src/effect_audio/rkrlv2/APhaser.h @@ -0,0 +1,91 @@ +/* + ZynAddSubFX - a software synthesizer + + APhaser.h - Phaser effect + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu and Ryan Billing + + Further modified for rakarrack by Ryan Billing (Transmogrifox) to model Analog Phaser behavior 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef APHASER_H +#define APHASER_H +#include "global.h" +#include "EffectLFO.h" + + +class Analog_Phaser +{ +public: + Analog_Phaser (float * efxoutl_, float * efxoutr_, double sample_rate); + ~Analog_Phaser (); + void out (float * smpsl, float * smpsr, uint32_t period); + void setpreset (int npreset); + void changepar (int npar, int value); + int getpar (int npar); + void cleanup (); + int Ppreset; + float *efxoutl; + float *efxoutr; + float outvolume; + + uint32_t PERIOD; + EffectLFO *lfo; //Phaser modulator + +private: + //Phaser parameters + int Pvolume; //Used in Process.C to set wet/dry mix + int Pdistortion; //Model distortion added by FET element + int Pwidth; //Phaser width (LFO amplitude) + int Pfb; //feedback + int Poffset; //Model mismatch between variable resistors + int Pstages; //Number of first-order All-Pass stages + int Poutsub; //if I wish to subtract the output instead of the adding it + int Phyper; //lfo^2 -- converts tri into hyper-sine + int Pdepth; //Depth of phaser sweep + int Pbarber; //Enable barber pole phasing + + //Control parameters + void setvolume (int Pvolume); + void setdistortion (int Pdistortion); + void setwidth (int Pwidth); + void setfb (int Pfb); + void setoffset (int Poffset); + void setstages (int Pstages); + void setdepth (int Pdepth); + + //Internal Variables + bool barber; //Barber pole phasing flag + float distortion, fb, width, offsetpct, fbl, fbr, depth; + float *lxn1, *lyn1,*rxn1, *ryn1, *offset; + float oldlgain, oldrgain, rdiff, ldiff, invperiod; + + float mis; + float Rmin; // 2N5457 typical on resistance at Vgs = 0 + float Rmax; // Resistor parallel to FET + float Rmx; // Rmin/Rmax to avoid division in loop + float Rconst; // Handle parallel resistor relationship + float C; // Capacitor + float CFs; // A constant derived from capacitor and resistor relationships + float fPERIOD; + + class FPreset *Fpre; + +}; + +#endif \ No newline at end of file diff --git a/src/effect_audio/rkrlv2/EffectLFO.cpp b/src/effect_audio/rkrlv2/EffectLFO.cpp new file mode 100644 index 0000000..4303ddf --- /dev/null +++ b/src/effect_audio/rkrlv2/EffectLFO.cpp @@ -0,0 +1,256 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectLFO.C - Stereo LFO used by some effects + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu 6 Ryan Billing + + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include +#include +#include + +#include "global.h" +#include "EffectLFO.h" +#include "f_sin.h" + +EffectLFO::EffectLFO (double sample_rate) +{ + float fPERIOD = 256;//this is our best guess at what it will be, later we'll correct it when we actually know fPERIOD + fSAMPLE_RATE = sample_rate; + xl = 0.0; + xr = 0.0; + Pfreq = 40; + Prandomness = 0; + PLFOtype = 0; + Pstereo = 96; + + iperiod = fPERIOD/fSAMPLE_RATE; + h = iperiod; + a = 10.0f; + b = 28.0f; + c = 8.0f / 5.0f; + scale = 1.0f/36.0f; + ratediv = 0.1f; + holdflag = 0; + tca = iperiod/(iperiod + 0.02); //20ms default + tcb = 1.0f - tca; + rreg = lreg = oldrreg = oldlreg = 0.0f; + updateparams ((uint32_t)fPERIOD); + + ampl1 = (1.0f - lfornd) + lfornd * (float)RND; + ampl2 = (1.0f - lfornd) + lfornd * (float)RND; + ampr1 = (1.0f - lfornd) + lfornd * (float)RND; + ampr2 = (1.0f - lfornd) + lfornd * (float)RND; + + +}; + +EffectLFO::~EffectLFO () +{ +}; + + +/* + * Update the changed parameters + */ +void +EffectLFO::updateparams (uint32_t period) +{ + float fPERIOD = period; + //must update several parameters once we actually know the period + iperiod = fPERIOD/fSAMPLE_RATE; + h = iperiod; + tca = iperiod/(iperiod + 0.02); //20ms default + tcb = 1.0f - tca; + + + incx = (float)Pfreq * fPERIOD / (fSAMPLE_RATE * 60.0f); + + if (incx > 0.49999999) + incx = 0.499999999f; //Limit the Frequency + + lfornd = (float)Prandomness / 127.0f; + if (lfornd < 0.0) + lfornd = 0.0; + else if (lfornd > 1.0) + lfornd = 1.0; + + if (PLFOtype > 11) //this has to be updated if more lfo's are added + PLFOtype = 0; + lfotype = PLFOtype; + + xr = fmodf (xl + ((float)Pstereo - 64.0f) / 127.0f + 1.0f, 1.0f); + + if ((h = incx*ratediv) > 0.02) h = 0.02; //keeps it stable + + a = 10.0f + (((float) RND) - 0.5f)*8.0f; + b = 28.0f + (((float) RND) - 0.5f)*12.0f; + c = 1.25f + 3.0f * ((float) RND); + +// printf("incx %f x0 %f y0 %f z0 %f out %f c %f b %f a %f\n",incx,x0,y0,z0, (2.0f * radius - 1.0f), c, b, a); + x0 = 0.1f + 0.1f * ((float) RND); + y0 = 0.0f; + z0 = 0.2f; + x1 = y1 = z1 = radius = 0.0f; + + float tmp = 6.0f/((float) Pfreq); //S/H time attack 0.2*60=12.0 + tca = iperiod/(iperiod + tmp); // + tcb = 1.0f - tca; + maxrate = 4.0f*iperiod; +}; + + +/* + * Compute the shape of the LFO + */ +float EffectLFO::getlfoshape (float x) +{ + float tmpv; + float out=0.0; + int iterations = 1; //make fractal go faster + switch (lfotype) { + case 1: //EffectLFO_TRIANGLE + if ((x > 0.0) && (x < 0.25)) + out = 4.0f * x; + else if ((x > 0.25) && (x < 0.75)) + out = 2.0f - 4.0f * x; + else + out = 4.0f * x - 4.0f; + break; + case 2: //EffectLFO_RAMP Ramp+ + out = 2.0f * x - 1.0f; + break; + case 3: //EffectLFO_RAMP Ramp- + out = - 2.0f * x + 1.0f; + break; + case 4: //ZigZag + x = x * 2.0f - 1.0f; + tmpv = 0.33f * f_sin(x); + out = f_sin(f_sin(x*D_PI)*x/tmpv); + break; + case 5: //Modulated Square ?? ;-) + tmpv = x * D_PI; + out=f_sin(tmpv+f_sin(2.0f*tmpv)); + break; + case 6: // Modulated Saw + tmpv = x * D_PI; + out=f_sin(tmpv+f_sin(tmpv)); + break; + case 8: //Lorenz Fractal, faster, using X,Y outputs + iterations = 4; + case 7: // Lorenz Fractal + for(int j=0; j 1.0f) radius = 1.0f; + if(radius < 0.0) radius = 0.0; + out = 2.0f * radius - 1.0f; + } + + break; + case 9: //Sample/Hold Random + if(fmod(x,0.5f)<=(2.0f*incx)) { //this function is called by left, then right...so must toggle each time called + rreg = lreg; + lreg = RND1; + + } + + if(xlreg 0.5f) && (x < 0.75f)) + out = 6 * (x-0.5); + else + out = 1.5 - 6.0f *( x - 0.75f); + out-=0.25f; + out*=0.88888889f; + break; + case 11: //Tri-Bottom + if(x<=0.5f) out = -f_sin(x*D_PI); + else if ((x > 0.5f) && (x < 0.75f)) + out = 6 * (x-0.5); + else + out = 1.5 - 6.0f *( x - 0.75f); + out-=0.25f; + out*=-0.88888889f; + break; + //more to be added here; also ::updateparams() need to be updated (to allow more lfotypes) + default: + out = f_cos (x * D_PI); //EffectLFO_SINE + }; + return (out); +}; + +/* + * LFO output + */ +void +EffectLFO::effectlfoout (float * outl, float * outr) +{ + float out; + + out = getlfoshape (xl); + //if ((lfotype == 0) || (lfotype == 1)) //What was that for? + out *= (ampl1 + xl * (ampl2 - ampl1)); + xl += incx; + if (xl > 1.0) { + xl -= 1.0f; + ampl1 = ampl2; + ampl2 = (1.0f - lfornd) + lfornd * (float)RND; + }; + if(lfotype==8) out = scale*x0; //fractal parameter + *outl = (out + 1.0f) * 0.5f; + + + if(lfotype==8) out = scale*y0; //fractal parameter + else out = getlfoshape (xr); + + //if ((lfotype == 0) || (lfotype == 1)) + out *= (ampr1 + xr * (ampr2 - ampr1)); + xr += incx; + if (xr > 1.0) { + xr -= 1.0f; + ampr1 = ampr2; + ampr2 = (1.0f - lfornd) + lfornd * (float)RND; + }; + *outr = (out + 1.0f) * 0.5f; +}; diff --git a/src/effect_audio/rkrlv2/EffectLFO.h b/src/effect_audio/rkrlv2/EffectLFO.h new file mode 100644 index 0000000..1b56576 --- /dev/null +++ b/src/effect_audio/rkrlv2/EffectLFO.h @@ -0,0 +1,72 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectLFO.h - Stereo LFO used by some effects + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu & Ryan Billing + + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef EFFECT_LFO_H +#define EFFECT_LFO_H + +#include "global.h" +#include + +class EffectLFO +{ +public: + EffectLFO (double sample_rate); + ~EffectLFO (); + void effectlfoout (float * outl, float * outr); + void updateparams (uint32_t period); + int Pfreq; + int Prandomness; + int PLFOtype; + int Pstereo; //"64"=0 +private: + float getlfoshape (float x); + + float xl, xr; + float incx; + float ampl1, ampl2, ampr1, ampr2; //necesar pentru "randomness" + float lfointensity; + float lfornd; + int lfotype; + + //Lorenz Fractal parameters + float x0,y0,z0,x1,y1,z1,radius; + float h; + float a; + float b; + float c; + float scale; + float iperiod; + float ratediv; + + //Sample/Hold + int holdflag; //toggle left/right channel changes + float tca, tcb, maxrate; + float rreg, lreg, xlreg,xrreg, oldrreg, oldlreg; + + float fSAMPLE_RATE; +}; + + +#endif diff --git a/src/effect_audio/rkrlv2/Phaser.cpp b/src/effect_audio/rkrlv2/Phaser.cpp new file mode 100644 index 0000000..6638831 --- /dev/null +++ b/src/effect_audio/rkrlv2/Phaser.cpp @@ -0,0 +1,337 @@ +/* + ZynAddSubFX - a software synthesizer + + Phaser.C - Phaser effect + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#include +#include "Phaser.h" +#include +//#include "FPreset.h" +#define PHASER_LFO_SHAPE 2 + +Phaser::Phaser (float * efxoutl_, float * efxoutr_, double sample_rate) +{ + efxoutl = efxoutl_; + efxoutr = efxoutr_; + + oldl = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES * 2); + oldr = (float *) malloc(sizeof(float)* MAX_PHASER_STAGES * 2); + + lfo = new EffectLFO(sample_rate); + + Ppreset = 0; + PERIOD = 256; //best guess until the effect starts running; + setpreset (Ppreset); + cleanup (); +}; + +Phaser::~Phaser () +{ + free(oldl); + free(oldr); + delete lfo; +}; + + +/* + * Effect output + */ +void +Phaser::out (float * smpsl, float * smpsr, uint32_t period) +{ + unsigned int i; + int j; + float lfol, lfor, lgain, rgain, tmp; + + lfo->effectlfoout (&lfol, &lfor); + lgain = lfol; + rgain = lfor; + lgain = + (expf (lgain * PHASER_LFO_SHAPE) - 1.0f) / (expf (PHASER_LFO_SHAPE) - 1.0f); + rgain = + (expf (rgain * PHASER_LFO_SHAPE) - 1.0f) / (expf (PHASER_LFO_SHAPE) - 1.0f); + + + lgain = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * lgain * depth; + rgain = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * rgain * depth; + + if (lgain > 1.0) + lgain = 1.0f; + else if (lgain < 0.0) + lgain = 0.0f; + if (rgain > 1.0) + rgain = 1.0f; + else if (rgain < 0.0) + rgain = 0.0f; + + float v1, v2; + if (outvolume < 0.5f) + { + v1 = 1.0f; + v2 = outvolume * 2.0f; + } + else + { + v1 = (1.0f - outvolume) * 2.0f; + v2 = 1.0f; + } + + + for (i = 0; i < period; i++) { + float x = (float) i / ((float)period); + float x1 = 1.0f - x; + float gl = lgain * x + oldlgain * x1; + float gr = rgain * x + oldrgain * x1; + float inl = smpsl[i] * panning + fbl; + float inr = smpsr[i] * (1.0f - panning) + fbr; + + //Left channel + for (j = 0; j < Pstages * 2; j++) { + //Phasing routine + tmp = oldl[j] + DENORMAL_GUARD; + oldl[j] = gl * tmp + inl; + inl = tmp - gl * oldl[j]; + }; + //Right channel + for (j = 0; j < Pstages * 2; j++) { + //Phasing routine + tmp = oldr[j] + DENORMAL_GUARD; + oldr[j] = (gr * tmp) + inr; + inr = tmp - (gr * oldr[j]); + }; + //Left/Right crossing + float l = inl; + float r = inr; + inl = l * (1.0f - lrcross) + r * lrcross; + inr = r * (1.0f - lrcross) + l * lrcross; + + fbl = inl * fb; + fbr = inr * fb; + + if (Poutsub != 0) { + inl *= -1.0f; + inr *= -1.0f; + } + + efxoutl[i] = smpsl[i] * v1 + inl * v2; + efxoutr[i] = smpsr[i] * v1 + inr * v2; + + }; + + oldlgain = lgain; + oldrgain = rgain; +}; + +/* + * Cleanup the effect + */ +void +Phaser::cleanup () +{ + fbl = 0.0; + fbr = 0.0; + oldlgain = 0.0; + oldrgain = 0.0; + for (int i = 0; i < Pstages * 2; i++) { + oldl[i] = 0.0; + oldr[i] = 0.0; + }; +}; + +/* + * Parameter control + */ +void +Phaser::setdepth (int Pdepth) +{ + this->Pdepth = Pdepth; + depth = ((float)Pdepth / 127.0f); +}; + + +void +Phaser::setfb (int Pfb) +{ + this->Pfb = Pfb; + fb = ((float)Pfb - 64.0f) / 64.1f; +}; + +void +Phaser::setvolume (int Pvolume) +{ + this->Pvolume = Pvolume; + outvolume = (float)Pvolume / 127.0f; +}; + +void +Phaser::setpanning (int Ppanning) +{ + this->Ppanning = Ppanning; + panning = ((float)Ppanning + .5f)/ 127.0f; +}; + +void +Phaser::setlrcross (int Plrcross) +{ + this->Plrcross = Plrcross; + lrcross = (float)Plrcross / 127.0f; +}; + +void +Phaser::setstages (int Pstages) +{ + if (Pstages > MAX_PHASER_STAGES) + Pstages = MAX_PHASER_STAGES; + this->Pstages = Pstages; + cleanup (); +}; + +void +Phaser::setphase (int Pphase) +{ + this->Pphase = Pphase; + phase = ((float)Pphase / 127.0f); +}; + + +void +Phaser::setpreset (int npreset) +{ + const int PRESET_SIZE = 12; + const int NUM_PRESETS = 6; + int presets[NUM_PRESETS][PRESET_SIZE] = { + //Phaser1 + {64, 64, 11, 0, 0, 64, 110, 64, 1, 0, 0, 20}, + //Phaser2 + {64, 64, 10, 0, 0, 88, 40, 64, 3, 0, 0, 20}, + //Phaser3 + {64, 64, 8, 0, 0, 66, 68, 107, 2, 0, 0, 20}, + //Phaser4 + {39, 64, 1, 0, 0, 66, 67, 10, 5, 0, 1, 20}, + //Phaser5 + {64, 64, 1, 0, 1, 110, 67, 78, 10, 0, 0, 20}, + //Phaser6 + {64, 64, 31, 100, 0, 58, 37, 78, 3, 0, 0, 20} + }; + + if(npreset>NUM_PRESETS-1) { + + } else { + for (int n = 0; n < PRESET_SIZE; n++) + changepar (n, presets[npreset][n]); + } + Ppreset = npreset; +}; + + +void +Phaser::changepar (int npar, int value) +{ + switch (npar) { + case 0: + setvolume (value); + break; + case 1: + setpanning (value); + break; + case 2: + lfo->Pfreq = value; + lfo->updateparams (PERIOD); + break; + case 3: + lfo->Prandomness = value; + lfo->updateparams (PERIOD); + break; + case 4: + lfo->PLFOtype = value; + lfo->updateparams (PERIOD); + break; + case 5: + lfo->Pstereo = value; + lfo->updateparams (PERIOD); + break; + case 6: + setdepth (value); + break; + case 7: + setfb (value); + break; + case 8: + setstages (value); + break; + case 9: + setlrcross (value); + break; + case 10: + if (value > 1) + value = 1; + Poutsub = value; + break; + case 11: + setphase (value); + break; + } +}; + +int +Phaser::getpar (int npar) +{ + switch (npar) { + case 0: + return (Pvolume); + break; + case 1: + return (Ppanning); + break; + case 2: + return (lfo->Pfreq); // tempo + break; + case 3: + return (lfo->Prandomness); + break; + case 4: + return (lfo->PLFOtype); + break; + case 5: + return (lfo->Pstereo); // STDL + break; + case 6: + return (Pdepth); + break; + case 7: + return (Pfb); // pfb feedback + break; + case 8: + return (Pstages); + break; + case 9: + return (Plrcross); + break; + case 10: + return (Poutsub); + break; + case 11: + return (Pphase); + break; + default: + return (0); + } +}; diff --git a/src/effect_audio/rkrlv2/Phaser.h b/src/effect_audio/rkrlv2/Phaser.h new file mode 100644 index 0000000..64f77f9 --- /dev/null +++ b/src/effect_audio/rkrlv2/Phaser.h @@ -0,0 +1,77 @@ +/* + ZynAddSubFX - a software synthesizer + + Phaser.h - Phaser effect + Copyright (C) 2002-2005 Nasca Octavian Paul + Author: Nasca Octavian Paul + + Modified for rakarrack by Josep Andreu + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef PHASER_H +#define PHASER_H +#include "global.h" +#include "EffectLFO.h" + +class Phaser +{ +public: + Phaser (float * efxoutl_, float * efxoutr_, double sample_rate); + ~Phaser (); + void out (float * smpsl, float * smpsr, uint32_t period); + void setpreset (int npreset); + void changepar (int npar, int value); + int getpar (int npar); + void cleanup (); + int Ppreset; + float outvolume; + + float *efxoutl; + float *efxoutr; + + uint32_t PERIOD; + EffectLFO *lfo; //Phaser modulator + +private: + void setvolume (int Pvolume); + void setpanning (int Ppanning); + void setdepth (int Pdepth); + void setfb (int Pfb); + void setlrcross (int Plrcross); + void setstages (int Pstages); + void setphase (int Pphase); + + + //Parametrii Phaser + int Pvolume; + int Ppanning; + int Pdepth; //the depth of the Phaser + int Pfb; //feedback + int Plrcross; //feedback + int Pstages; + int Poutsub; //if I wish to substract the output instead of the adding it + int Pphase; + + //Control Parametrii + + //Valorile interne + float panning, fb, depth, lrcross, fbl, fbr, phase; + float *oldl, *oldr; + float oldlgain, oldrgain; + +}; + +#endif diff --git a/src/effect_audio/rkrlv2/f_sin.h b/src/effect_audio/rkrlv2/f_sin.h new file mode 100644 index 0000000..aa75262 --- /dev/null +++ b/src/effect_audio/rkrlv2/f_sin.h @@ -0,0 +1,50 @@ +/* +Cubic Sine Approximation based upon a modified Taylor Series Expansion +Author: Ryan Billing (C) 2010 + +This is unlicensed. Do whatever you want with but use at your own disgression. +The author makes no guarantee of its suitability for any purpose. +*/ +#ifndef FSIN_H +#define FSIN_H + +#include +#include "global.h" + +//globals +static const float p2 = PI/2.0f; +static const float fact3 = 0.148148148148148f; //can multiply by 1/fact3 + +static inline float +f_sin(float x) +{ + + float y; //function output + float tmp; + bool sign; + if ((x>D_PI) || (x<-D_PI)) x = fmod(x,D_PI); + if (x < 0.0f) x+=D_PI; + sign = 0; + if(x>PI) { + x = D_PI - x; + sign = 1; + } + + if (x <= p2) y = x - x*x*x*fact3; + else { + tmp = x - PI; + y = -tmp + tmp*tmp*tmp*fact3; + } + + if (sign) y = -y; + + return y; +} + +static inline float +f_cos(float x_) +{ + return f_sin(p2 + x_); +} + +#endif diff --git a/src/effect_audio/rkrlv2/global.h b/src/effect_audio/rkrlv2/global.h new file mode 100644 index 0000000..6016064 --- /dev/null +++ b/src/effect_audio/rkrlv2/global.h @@ -0,0 +1,181 @@ +/* + rakarrack - a guitar efects software + + global.h - Variable Definitions and functions + Copyright (C) 2008-2010 Josep Andreu + Author: Josep Andreu & Ryan Billing + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License + (version2) along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + +#ifndef DXEMU_H +#define DXEMU_H + +#include + +#define D_PI 6.283185f +//#define PI 3.141598f +#define LOG_10 2.302585f +#define LOG_2 0.693147f +#define LN2R 1.442695041f +#define CNST_E 2.71828182845905f +#define AMPLITUDE_INTERPOLATION_THRESHOLD 0.0001f +#define FF_MAX_VOWELS 6 +#define FF_MAX_FORMANTS 12 +#define FF_MAX_SEQUENCE 8 +#define MAX_FILTER_STAGES 5 +#define RND (rand()/(RAND_MAX+1.0)) +#define RND1 (((float) rand())/(((float) RAND_MAX)+1.0f)) +#define F2I(f,i) (i)=((f>0) ? ( (int)(f) ) :( (int)(f-1.0f) )) +#define dB2rap(dB) (float)((expf((dB)*LOG_10/20.0f))) +#define rap2dB(rap) (float)((20*log(rap)/LOG_10)) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define INTERPOLATE_AMPLITUDE(a,b,x,size) ( (a) + ( (b) - (a) ) * (float)(x) / (float) (size) ) +#define ABOVE_AMPLITUDE_THRESHOLD(a,b) ( ( 2.0f*fabs( (b) - (a) ) / ( fabs( (b) + (a) + 0.0000000001f) ) ) > AMPLITUDE_INTERPOLATION_THRESHOLD ) +#define POLY 8 +#define DENORMAL_GUARD 1e-18f // Make it smaller until CPU problem re-appears +#define SwapFourBytes(data) ( (((data) >> 24) & 0x000000ff) | (((data) >> 8) & 0x0000ff00) | (((data) << 8) & 0x00ff0000) | (((data) << 24) & 0xff000000) ) +#define D_NOTE 1.059463f +#define LOG_D_NOTE 0.057762f +#define D_NOTE_SQRT 1.029302f +#define MAX_PEAKS 8 +#define MAX_ALIENWAH_DELAY 100 +#define ATTACK 0.175f //crossover time for reverse delay +#define MAX_DELAY 2 // Number of Seconds +#define MAXHARMS 8 // max number of harmonics available +#define MAX_PHASER_STAGES 12 +#define MAX_CHORUS_DELAY 250.0f //ms +#define LN2 (1.0f) //Uncomment for att/rel to behave more like a capacitor. +#define MUG_CORR_FACT 0.4f +//Crunch waveshaping constants +#define Thi 0.67f //High threshold for limiting onset +#define Tlo -0.65f //Low threshold for limiting onset +#define Tlc -0.6139445f //Tlo + sqrt(Tlo/500) +#define Thc 0.6365834f //Thi - sqrt(Thi/600) +#define CRUNCH_GAIN 100.0f //Typical voltage gain for most OD stompboxes +#define DIV_TLC_CONST 0.002f // 1/300 +#define DIV_THC_CONST 0.0016666f // 1/600 (approximately) +//End waveshaping constants +#define D_FLANGE_MAX_DELAY 0.055f // Number of Seconds - 50ms corresponds to fdepth = 20 (Hz). Added some extra for padding +#define LFO_CONSTANT 9.765625e-04 // 1/(2^LOG_FMAX - 1) +#define LOG_FMAX 10.0f // -- This optimizes LFO sweep for useful range. +#define MINDEPTH 20.0f // won't allow filter lower than 20Hz +#define MAXDEPTH 15000.0f // Keeps delay greater than 2 samples at 44kHz SR +#define MAX_EQ_BANDS 16 +#define CLOSED 1 +#define OPENING 2 +#define OPEN 3 +#define CLOSING 4 +#define ENV_TR 0.0001f +#define HARMONICS 11 +#define REV_COMBS 8 +#define REV_APS 4 +#define MAX_SFILTER_STAGES 12 + +#define TEMPBUFSIZE 1024 + +typedef union { + float f; + long i; +} ls_pcast32; + +/* +static inline float f_pow2(float x) +{ + ls_pcast32 *px, tx, lx; + float dx; + + px = (ls_pcast32 *)&x; // store address of float as long pointer + tx.f = (x-0.5f) + (3<<22); // temporary value for truncation + lx.i = tx.i - 0x4b400000; // integer power of 2 + dx = x - (float)lx.i; // float remainder of power of 2 + + x = 1.0f + dx * (0.6960656421638072f + // cubic apporoximation of 2^x + dx * (0.224494337302845f + // for x in the range [0, 1] + dx * (0.07944023841053369f))); + (*px).i += (lx.i << 23); // add integer power of 2 to exponent + + return (*px).f; +} +*/ +/* +#define P2a0 1.00000534060469 +#define P2a1 0.693057900547259 +#define P2a2 0.239411678986933 +#define P2a3 0.0532229404911678 +#define P2a4 0.00686649174914722 +#include +static inline float f_pow2(float x) +{ +float y,xx, intpow; +long xint = (int) fabs(ceil(x)); +xx = x - ceil(x); +xint = xint<0) intpow = (float) xint; +else intpow = 1.0f; + +y = intpow*(xx*(xx*(xx*(xx*P2a4 + P2a3) + P2a2) + P2a1) + P2a0); + +return y; + +} +*/ + +//The below pow function really works & is good to 16 bits, but is it faster than math lib powf()??? +//globals +#include +static const float a[5] = { 1.00000534060469, 0.693057900547259, 0.239411678986933, 0.0532229404911678, 0.00686649174914722 }; +//lookup for positive powers of 2 +static const float pw2[25] = {1.0f, 2.0f, 4.0f, 8.0f, 16.0f, 32.0f, 64.0f, 128.0f, 256.0f, 512.0f, 1024.0f, 2048.0f, 4096.0f, 8192.0f, 16384.0f, 32768.0f, 65536.0f, 131072.0f, 262144.0f, 524288.0f, 1048576.0f, 2097152.0f, 4194304.0f, 8388608.0f, 16777216.0f}; +//negative powers of 2, notice ipw2[0] will never be indexed. +static const float ipw2[25] = {1.0, 5.0e-01, 2.5e-01, 1.25e-01, 6.25e-02, 3.125e-02, 1.5625e-02, 7.8125e-03, 3.90625e-03, 1.953125e-03, 9.765625e-04, 4.8828125e-04, 2.44140625e-04, 1.220703125e-04, 6.103515625e-05, 3.0517578125e-05, 1.52587890625e-05, 7.62939453125e-06, 3.814697265625e-06, 1.9073486328125e-06, 9.5367431640625e-07, 4.76837158203125e-07, 2.38418579101562e-07, 1.19209289550781e-07, 5.96046447753906e-08}; + +static inline float f_pow2(float x) +{ + float y = 0.0f; + + if(x >=24) return pw2[24]; + else if (x <= -24.0f) return ipw2[24]; + else { + float whole = ceilf(x); + int xint = (int) whole; + x = x - whole; + + if (xint>=0) { + y = pw2[xint]*(x*(x*(x*(x*a[4] + a[3]) + a[2]) + a[1]) + a[0]); + + } else { + + y = ipw2[-xint]*(x*(x*(x*(x*a[4] + a[3]) + a[2]) + a[1]) + a[0]); + + } + + return y; + } + +} + +#define f_exp(x) f_pow2(x * LN2R) + +//#include "config.h" +#include +#include +#include +#include +#include +//#include "FPreset.h" + +#endif \ No newline at end of file diff --git a/src/effects.h b/src/effects.h index 2152898..223a2bb 100644 --- a/src/effects.h +++ b/src/effects.h @@ -16,6 +16,8 @@ #include "effect_audio/effect_platervbstereo.h" #include "effect_audio/effect_mverb.h" #include "effect_audio/effect_3bandeq.h" +#include "effect_audio/effect_phaser.h" +#include "effect_audio/effect_aphaser.h" inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate) { @@ -39,6 +41,10 @@ inline AudioEffect* newAudioEffect(unsigned type, float32_t samplerate) return new AudioEffectMVerb(samplerate); case EFFECT_3BANDEQ: return new AudioEffect3BandEQ(samplerate); + case EFFECT_PHASER: + return new AudioEffectPhaser(samplerate); + case EFFECT_APHASER: + return new AudioEffectAPhaser(samplerate); case EFFECT_NONE: default: return new AudioEffectNone(samplerate); @@ -58,6 +64,8 @@ inline std::string getFXTypeName(int nValue) case EFFECT_REVERB: return "Reverb"; case EFFECT_MVERB: return "MVerb"; case EFFECT_3BANDEQ: return "3Band EQ"; + case EFFECT_PHASER: return "Phaser"; + case EFFECT_APHASER: return "A Phaser"; case EFFECT_NONE: default: return "None"; } diff --git a/src/uimenu.cpp b/src/uimenu.cpp index d54dd93..a88c6b7 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -264,6 +264,42 @@ CUIMenu::TMenuItem CUIMenu::s_FX3BandEQ[] = {0} }; +CUIMenu::TMenuItem CUIMenu::s_FXPhaser[] = +{ + {"Bypass", EditTGFXParameter, 0, AudioEffectPhaser::Param::BYPASS}, + {"Mix", EditTGFXParameter, 0, AudioEffectPhaser::Param::WETDRY}, + {"Pan", EditTGFXParameter, 0, AudioEffectPhaser::Param::PAN}, + {"Freq", EditTGFXParameter, 0, AudioEffectPhaser::Param::PH_FREQ}, + {"Random", EditTGFXParameter, 0, AudioEffectPhaser::Param::PH_RND}, + {"Type", EditTGFXParameter, 0, AudioEffectPhaser::Param::TYPE}, + {"Stereo", EditTGFXParameter, 0, AudioEffectPhaser::Param::STDL}, + {"Depth", EditTGFXParameter, 0, AudioEffectPhaser::Param::PH_DEPTH}, + {"Feedback", EditTGFXParameter, 0, AudioEffectPhaser::Param::FB}, + {"Stages", EditTGFXParameter, 0, AudioEffectPhaser::Param::STAGES}, + {"L/R Cross", EditTGFXParameter, 0, AudioEffectPhaser::Param::LRCR}, + {"Sub", EditTGFXParameter, 0, AudioEffectPhaser::Param::SUB}, + {"Phase", EditTGFXParameter, 0, AudioEffectPhaser::Param::PHASE}, + {0} +}; + +CUIMenu::TMenuItem CUIMenu::s_FXAPhaser[] = +{ + {"Bypass", EditTGFXParameter, 0, AudioEffectAPhaser::Param::BYPASS}, + {"Mix", EditTGFXParameter, 0, AudioEffectAPhaser::Param::WETDRY}, + {"Pan", EditTGFXParameter, 0, AudioEffectAPhaser::Param::PAN}, + {"Freq", EditTGFXParameter, 0, AudioEffectAPhaser::Param::PH_FREQ}, + {"Random", EditTGFXParameter, 0, AudioEffectAPhaser::Param::PH_RND}, + {"Type", EditTGFXParameter, 0, AudioEffectAPhaser::Param::TYPE}, + {"Stereo", EditTGFXParameter, 0, AudioEffectAPhaser::Param::STDL}, + {"Depth", EditTGFXParameter, 0, AudioEffectAPhaser::Param::PH_DEPTH}, + {"Feedback", EditTGFXParameter, 0, AudioEffectAPhaser::Param::FB}, + {"Stages", EditTGFXParameter, 0, AudioEffectAPhaser::Param::STAGES}, + {"L/R Cross", EditTGFXParameter, 0, AudioEffectAPhaser::Param::LRCR}, + {"Sub", EditTGFXParameter, 0, AudioEffectAPhaser::Param::SUB}, + {"Phase", EditTGFXParameter, 0, AudioEffectAPhaser::Param::PHASE}, + {0} +}; + const CUIMenu::TMenuItem CUIMenu::s_MidiFX[] = { {"Type:", EditTGParameter2, 0, CMiniDexed::TGParameterMidiFXType}, @@ -363,7 +399,7 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = { {0, 1, 1, ToOnOff}, // ParameterCompressorEnable - {0, 9, 1, ToFXType}, // ParameterSendFXType + {0, 11, 1, ToFXType}, // ParameterSendFXType {0, 100, 1}, // ParameterSendFXLevel {0, 1, 1, ToOnOff}, // ParameterReverbEnable {0, 99, 1}, // ParameterReverbSize @@ -386,7 +422,7 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] {0, CSysExFileLoader::VoicesPerBank-1, 1}, // TGParameterProgram {0, 127, 8, ToVolume}, // TGParameterVolume {0, 127, 8, ToPan}, // TGParameterPan - {0, 9, 1, ToFXType}, // TGParameterInsertFXType + {0, 11, 1, ToFXType}, // TGParameterInsertFXType {0, 1, 1, ToMidiFXType}, // TGParameterMidiFXType {-99, 99, 1}, // TGParameterMasterTune {0, 99, 1}, // TGParameterCutoff @@ -520,6 +556,42 @@ const CUIMenu::TParameter CUIMenu::s_TGFX3BandEQParam[AudioEffect3BandEQ::Param: {1000, 20000, 10}, // MID_HIGH_FQ }; +// must match AudioEffectPhaser::Param +const CUIMenu::TParameter CUIMenu::s_TGFXPhaserParam[AudioEffectPhaser::Param::UNKNOWN] = +{ + {0, 1, 1, ToOnOff}, // BYPASS + {0, 127, 1}, // WETDRY + {0, 127, 1}, // PAN + {1, 600, 1}, // PH_FREQ + {0, 127, 1}, // PH_RND + {0, 11, 1}, // TYPE + {0, 127, 1}, // STDL + {0, 127, 1}, // PH_DEPTH + {0, 127, 1}, // FB + {0, 12, 1}, // STAGES + {0, 127, 1}, // LRCR + {0, 1, 1, ToOnOff}, // SUB + {0, 127, 1}, // PHASE +}; + +// must match AudioEffectAPhaser::Param +const CUIMenu::TParameter CUIMenu::s_TGFXAPhaserParam[AudioEffectPhaser::Param::UNKNOWN] = +{ + {0, 1, 1, ToOnOff}, // BYPASS + {0, 127, 1}, // WETDRY + {0, 127, 1}, // PAN + {1, 600, 1}, // PH_FREQ + {0, 127, 1}, // PH_RND + {0, 11, 1}, // TYPE + {0, 127, 1}, // STDL + {0, 127, 1}, // PH_DEPTH + {0, 127, 1}, // FB + {0, 12, 1}, // STAGES + {0, 127, 1}, // LRCR + {0, 1, 1, ToOnOff}, // SUB + {0, 127, 1}, // PHASE +}; + // must match MidiArp::Param const CUIMenu::TParameter CUIMenu::s_TGMidiFXArpParam[MidiArp::Param::UNKNOWN] = { @@ -2965,6 +3037,12 @@ CUIMenu::TMenuItem* CUIMenu::getFXMenuItem(unsigned type) case EFFECT_3BANDEQ: menu = s_FX3BandEQ; break; + case EFFECT_PHASER: + menu = s_FXPhaser; + break; + case EFFECT_APHASER: + menu = s_FXAPhaser; + break; case EFFECT_NONE: default: menu = s_FXNone; @@ -3029,6 +3107,12 @@ CUIMenu::TParameter CUIMenu::getFXParameter(unsigned type, unsigned nParam) case EFFECT_3BANDEQ: pParam = s_TGFX3BandEQParam[nParam]; break; + case EFFECT_PHASER: + pParam = s_TGFXPhaserParam[nParam]; + break; + case EFFECT_APHASER: + pParam = s_TGFXAPhaserParam[nParam]; + break; default: break; } diff --git a/src/uimenu.h b/src/uimenu.h index 7b9490a..c210f92 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -184,6 +184,8 @@ private: static TMenuItem s_FXReverb[]; static TMenuItem s_FXMVerb[]; static TMenuItem s_FX3BandEQ[]; + static TMenuItem s_FXPhaser[]; + static TMenuItem s_FXAPhaser[]; static TMenuItem s_MidiFXNone[]; static TMenuItem s_MidiFXArp[]; @@ -209,6 +211,8 @@ private: static const TParameter s_TGFXReverbParam[]; static const TParameter s_TGFXMVerbParam[]; static const TParameter s_TGFX3BandEQParam[]; + static const TParameter s_TGFXPhaserParam[]; + static const TParameter s_TGFXAPhaserParam[]; static const TParameter s_TGMidiFXArpParam[]; static const TParameter s_VoiceParameter[]; static const TParameter s_OPParameter[];