Added RKR / Zynaddsubfx Phasers

pull/764/head
Javier Nonis 6 months ago
parent f0e2593e81
commit aae85e5f85
  1. 10
      src/Makefile
  2. 179
      src/effect_audio/effect_aphaser.h
  3. 2
      src/effect_audio/effect_base.h
  4. 179
      src/effect_audio/effect_phaser.h
  5. 440
      src/effect_audio/rkrlv2/APhaser.cpp
  6. 91
      src/effect_audio/rkrlv2/APhaser.h
  7. 256
      src/effect_audio/rkrlv2/EffectLFO.cpp
  8. 72
      src/effect_audio/rkrlv2/EffectLFO.h
  9. 337
      src/effect_audio/rkrlv2/Phaser.cpp
  10. 77
      src/effect_audio/rkrlv2/Phaser.h
  11. 50
      src/effect_audio/rkrlv2/f_sin.h
  12. 181
      src/effect_audio/rkrlv2/global.h
  13. 8
      src/effects.h
  14. 88
      src/uimenu.cpp
  15. 4
      src/uimenu.h

@ -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]
EXTRACLEAN += effect_audio/*.[od] \
effect_audio/moddistortion/*.[od] \
effect_audio/rkrlv2/*.[od] \
effect_midi/*.[od] \
effect_midi/modarpeggiator/*.[od] \
effect_midi/modarpeggiator/common/*.[od]

@ -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

@ -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
{

@ -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

@ -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 <math.h>
#include "APhaser.h"
#include <stdio.h>
//#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);
};
};

@ -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

@ -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 <stdlib.h>
#include <stdio.h>
#include <arm_math.h>
#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<iterations; j++) {
x1 = x0 + h * a * (y0 - x0);
y1 = y0 + h * (x0 * (b - z0) - y0);
z1 = z0 + h * (x0 * y0 - c * z0);
x0 = x1;
y0 = y1;
z0 = z1;
}
if(lfotype==7) {
if((radius = (sqrtf(x0*x0 + y0*y0 + z0*z0) * scale) - 0.25f) > 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<lreg) xlreg += maxrate;
else xlreg -= maxrate;
if(xrreg<rreg) xrreg += maxrate;
else xrreg -= maxrate;
oldlreg = xlreg*tca + oldlreg*tcb;
oldrreg = xrreg*tca + oldrreg*tcb;
if(holdflag) {
out = 2.0f*oldlreg -1.0f;
holdflag = (1 + holdflag)%2;
} else {
out = 2.0f*oldrreg - 1.0f;
}
break;
case 10: //Tri-top
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;
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;
};

@ -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 <arm_math.h>
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

@ -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 <math.h>
#include "Phaser.h"
#include <stdio.h>
//#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);
}
};

@ -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

@ -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 <arm_math.h>
#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

@ -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 <arm_math.h>
#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 <math.h>
static inline float f_pow2(float x)
{
float y,xx, intpow;
long xint = (int) fabs(ceil(x));
xx = x - ceil(x);
xint = xint<<xint;
if(x>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 <math.h>
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 <sys/time.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
//#include "FPreset.h"
#endif

@ -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";
}

@ -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;
}

@ -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[];

Loading…
Cancel
Save