Echo.cpp (7660B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 Echo.cpp - Echo effect 5 Copyright (C) 2002-2005 Nasca Octavian Paul 6 Copyright (C) 2009-2010 Mark McCurry 7 Author: Nasca Octavian Paul 8 Mark McCurry 9 10 This program is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License 12 as published by the Free Software Foundation; either version 2 13 of the License, or (at your option) any later version. 14 */ 15 16 #include <cmath> 17 #include <rtosc/ports.h> 18 #include <rtosc/port-sugar.h> 19 #include "../Misc/Allocator.h" 20 #include "Echo.h" 21 22 #define MAX_DELAY 2 23 24 namespace zyn { 25 26 #define rObject Echo 27 #define rBegin [](const char *msg, rtosc::RtData &d) { 28 #define rEnd } 29 30 rtosc::Ports Echo::ports = { 31 {"preset::i", rOptions(Echo 1, Echo 2, Echo 3, Simple Echo, Canyon, Panning Echo 1, 32 Panning Echo 2, Panning Echo 3, Feedback Echo) 33 rDefault(0) 34 rProp(alias) 35 rProp(parameter) 36 rDoc("Instrument Presets"), 0, 37 rBegin; 38 rObject *o = (rObject*)d.obj; 39 if(rtosc_narguments(msg)) 40 o->setpreset(rtosc_argument(msg, 0).i); 41 else 42 d.reply(d.loc, "i", o->Ppreset); 43 rEnd}, 44 rPresetForVolume, 45 rEffParVol(rDefaultDepends(presetOfVolume), rDefault(67), 46 rPresetsAt(6, 81, 81, 62), 47 rPresetsAt(16, 33, 33, 33, 33, 33, 33, 40, 40, 31)), 48 rEffParPan(rDefaultDepends(preset), rPresetsAt(2, 75, 60, 60, 64, 60, 60)), 49 rEffPar(Pdelay, 2, rShort("delay"), rLinear(0, 127), 50 rPresets(35, 21, 60, 44, 102, 44, 46, 26, 28), 51 "Length of Echo"), 52 rEffPar(Plrdelay, 3, rShort("lr delay"), 53 rPresetsAt(4, 50, 17, 118, 100, 64), rDefault(64), 54 "Difference In Left/Right Delay"), 55 rEffPar(Plrcross, 4, rShort("cross"), 56 rPresetsAt(5, 0, 100, 127, 100), rDefault(30), 57 "Left/Right Crossover"), 58 rEffPar(Pfb, 5, rShort("feedback"), 59 rPresets(59, 59, 59, 0, 82, 82, 68, 67, 90), 60 "Echo Feedback"), 61 rEffPar(Phidamp, 6, rShort("damp"), 62 rPresets(0, 0, 10, 0, 48, 24, 18, 36, 55), 63 "Dampen High Frequencies"), 64 }; 65 #undef rBegin 66 #undef rEnd 67 #undef rObject 68 69 Echo::Echo(EffectParams pars) 70 :Effect(pars), 71 Pvolume(50), 72 Pdelay(60), 73 Plrdelay(100), 74 Pfb(40), 75 Phidamp(60), 76 delayTime(1), 77 lrdelay(0), 78 avgDelay(0), 79 delay(memory.valloc<float>(MAX_DELAY * pars.srate), 80 memory.valloc<float>(MAX_DELAY * pars.srate)), 81 old(0.0f), 82 pos(0), 83 delta(1), 84 ndelta(1) 85 { 86 initdelays(); 87 setpreset(Ppreset); 88 } 89 90 Echo::~Echo() 91 { 92 memory.devalloc(delay.l); 93 memory.devalloc(delay.r); 94 } 95 96 //Cleanup the effect 97 void Echo::cleanup(void) 98 { 99 memset(delay.l, 0, MAX_DELAY * samplerate * sizeof(float)); 100 memset(delay.r, 0, MAX_DELAY * samplerate * sizeof(float)); 101 old = Stereo<float>(0.0f); 102 } 103 104 inline int max(int a, int b) 105 { 106 return a > b ? a : b; 107 } 108 109 //Initialize the delays 110 void Echo::initdelays(void) 111 { 112 cleanup(); 113 //number of seconds to delay left chan 114 float dl = avgDelay - lrdelay; 115 116 //number of seconds to delay right chan 117 float dr = avgDelay + lrdelay; 118 119 ndelta.l = max(1, (int) (dl * samplerate)); 120 ndelta.r = max(1, (int) (dr * samplerate)); 121 delta = ndelta; 122 } 123 124 //Effect output 125 void Echo::out(const Stereo<float *> &input) 126 { 127 for(int i = 0; i < buffersize; ++i) { 128 float ldl = delay.l[pos.l]; 129 float rdl = delay.r[pos.r]; 130 ldl = ldl * (1.0f - lrcross) + rdl * lrcross; 131 rdl = rdl * (1.0f - lrcross) + ldl * lrcross; 132 133 efxoutl[i] = ldl * 2.0f; 134 efxoutr[i] = rdl * 2.0f; 135 136 ldl = input.l[i] * pangainL - ldl * fb; 137 rdl = input.r[i] * pangainR - rdl * fb; 138 139 //LowPass Filter 140 old.l = delay.l[(pos.l + delta.l) % (MAX_DELAY * samplerate)] = 141 ldl * hidamp + old.l * (1.0f - hidamp); 142 old.r = delay.r[(pos.r + delta.r) % (MAX_DELAY * samplerate)] = 143 rdl * hidamp + old.r * (1.0f - hidamp); 144 145 //increment 146 ++pos.l; // += delta.l; 147 ++pos.r; // += delta.r; 148 149 //ensure that pos is still in bounds 150 pos.l %= MAX_DELAY * samplerate; 151 pos.r %= MAX_DELAY * samplerate; 152 153 //adjust delay if needed 154 delta.l = (15 * delta.l + ndelta.l) / 16; 155 delta.r = (15 * delta.r + ndelta.r) / 16; 156 } 157 } 158 159 160 //Parameter control 161 void Echo::setvolume(unsigned char _Pvolume) 162 { 163 Pvolume = _Pvolume; 164 165 if(insertion == 0) { 166 if (Pvolume == 0) { 167 outvolume = 0.0f; 168 } else { 169 outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f; 170 } 171 volume = 1.0f; 172 } 173 else 174 volume = outvolume = Pvolume / 127.0f; 175 if(Pvolume == 0) 176 cleanup(); 177 } 178 179 void Echo::setdelay(unsigned char _Pdelay) 180 { 181 Pdelay = _Pdelay; 182 avgDelay = (Pdelay / 127.0f * 1.5f); //0 .. 1.5 sec 183 initdelays(); 184 } 185 186 void Echo::setlrdelay(unsigned char _Plrdelay) 187 { 188 float tmp; 189 Plrdelay = _Plrdelay; 190 tmp = 191 (powf(2.0f, fabsf(Plrdelay - 64.0f) / 64.0f * 9.0f) - 1.0f) / 1000.0f; 192 if(Plrdelay < 64.0f) 193 tmp = -tmp; 194 lrdelay = tmp; 195 initdelays(); 196 } 197 198 void Echo::setfb(unsigned char _Pfb) 199 { 200 Pfb = _Pfb; 201 fb = Pfb / 128.0f; 202 } 203 204 void Echo::sethidamp(unsigned char _Phidamp) 205 { 206 Phidamp = _Phidamp; 207 hidamp = 1.0f - Phidamp / 127.0f; 208 } 209 210 unsigned char Echo::getpresetpar(unsigned char npreset, unsigned int npar) 211 { 212 #define PRESET_SIZE 7 213 #define NUM_PRESETS 9 214 static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { 215 {67, 64, 35, 64, 30, 59, 0 }, //Echo 1 216 {67, 64, 21, 64, 30, 59, 0 }, //Echo 2 217 {67, 75, 60, 64, 30, 59, 10}, //Echo 3 218 {67, 60, 44, 64, 30, 0, 0 }, //Simple Echo 219 {67, 60, 102, 50, 30, 82, 48}, //Canyon 220 {67, 64, 44, 17, 0, 82, 24}, //Panning Echo 1 221 {81, 60, 46, 118, 100, 68, 18}, //Panning Echo 2 222 {81, 60, 26, 100, 127, 67, 36}, //Panning Echo 3 223 {62, 64, 28, 64, 100, 90, 55} //Feedback Echo 224 }; 225 if(npreset < NUM_PRESETS && npar < PRESET_SIZE) { 226 if(npar == 0 && insertion != 0) { 227 /* lower the volume if this is insertion effect */ 228 return presets[npreset][npar] / 2; 229 } 230 return presets[npreset][npar]; 231 } 232 return 0; 233 } 234 235 void Echo::setpreset(unsigned char npreset) 236 { 237 if(npreset >= NUM_PRESETS) 238 npreset = NUM_PRESETS - 1; 239 for(int n = 0; n != 128; n++) 240 changepar(n, getpresetpar(npreset, n)); 241 Ppreset = npreset; 242 } 243 244 void Echo::changepar(int npar, unsigned char value) 245 { 246 switch(npar) { 247 case 0: 248 setvolume(value); 249 break; 250 case 1: 251 setpanning(value); 252 break; 253 case 2: 254 setdelay(value); 255 break; 256 case 3: 257 setlrdelay(value); 258 break; 259 case 4: 260 setlrcross(value); 261 break; 262 case 5: 263 setfb(value); 264 break; 265 case 6: 266 sethidamp(value); 267 break; 268 } 269 } 270 271 unsigned char Echo::getpar(int npar) const 272 { 273 switch(npar) { 274 case 0: return Pvolume; 275 case 1: return Ppanning; 276 case 2: return Pdelay; 277 case 3: return Plrdelay; 278 case 4: return Plrcross; 279 case 5: return Pfb; 280 case 6: return Phidamp; 281 default: return 0; // in case of bogus parameter number 282 } 283 } 284 285 }