Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
7.7KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. EQ.cpp - EQ effect
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. */
  11. #include <cmath>
  12. #include <rtosc/ports.h>
  13. #include <rtosc/port-sugar.h>
  14. #include "EQ.h"
  15. #include "../DSP/AnalogFilter.h"
  16. #include "../Misc/Allocator.h"
  17. using rtosc::RtData;
  18. #define rObject EQ
  19. #define rBegin [](const char *msg, RtData &d) {\
  20. rObject *obj = (rObject*)d.obj;
  21. #define rEQ(offset) \
  22. int nfilt = atoi(msg-2); \
  23. int id = 10+nfilt*5+offset; \
  24. if(rtosc_narguments(msg)) \
  25. obj->changepar(id, rtosc_argument(msg,0).i);\
  26. else \
  27. d.reply(d.loc, "i", obj->getpar(id))
  28. #define rEnd }
  29. static rtosc::Ports filterports {
  30. {"Ptype::i", rProp(parameter) rOptions(Off, LP1, HP1, LP2,
  31. HP2, BP, notch, peak, l.shelf, h.shelf)
  32. rShort("type") rDoc("Filter Type"), 0,
  33. rBegin;
  34. rEQ(0);
  35. rEnd},
  36. {"Pfreq::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
  37. rShort("freq"), 0,
  38. rBegin;
  39. rEQ(1);
  40. rEnd},
  41. {"Pgain::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
  42. rShort("gain"), 0,
  43. rBegin;
  44. rEQ(2);
  45. rEnd},
  46. {"Pq::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
  47. rShort("q") rDoc("Resonance/Bandwidth"), 0,
  48. rBegin;
  49. rEQ(3);
  50. rEnd},
  51. {"Pstages::i", rProp(parameter) rMap(min, 0) rMap(max, 4)
  52. rShort("stages") rDoc("Additional filter stages"), 0,
  53. rBegin;
  54. rEQ(4);
  55. rEnd},
  56. };
  57. rtosc::Ports EQ::ports = {
  58. {"filter#8/", 0, &filterports,
  59. rBegin;
  60. (void)obj;
  61. SNIP;
  62. filterports.dispatch(msg, d);
  63. rEnd},
  64. {"coeff:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL,
  65. [](const char *, rtosc::RtData &d)
  66. {
  67. EQ *eq = (EQ*)d.obj;
  68. float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
  69. float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
  70. memset(a, 0, sizeof(a));
  71. memset(b, 0, sizeof(b));
  72. eq->getFilter(a,b);
  73. char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {0};
  74. rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {0};
  75. for(int i=0; i<MAX_EQ_BANDS*MAX_FILTER_STAGES*3; ++i) {
  76. int stride = MAX_EQ_BANDS*MAX_FILTER_STAGES*3;
  77. type[i] = type[i+stride] = 'f';
  78. val[i].f = b[i];
  79. val[i+stride].f = a[i];
  80. }
  81. d.replyArray(d.loc, type, val);
  82. }},
  83. };
  84. #undef rObject
  85. #undef rBegin
  86. #undef rEnd
  87. EQ::EQ(EffectParams pars)
  88. :Effect(pars)
  89. {
  90. for(int i = 0; i < MAX_EQ_BANDS; ++i) {
  91. filter[i].Ptype = 0;
  92. filter[i].Pfreq = 64;
  93. filter[i].Pgain = 64;
  94. filter[i].Pq = 64;
  95. filter[i].Pstages = 0;
  96. filter[i].l = memory.alloc<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize);
  97. filter[i].r = memory.alloc<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize);
  98. }
  99. //default values
  100. Pvolume = 50;
  101. setpreset(Ppreset);
  102. cleanup();
  103. }
  104. EQ::~EQ()
  105. {
  106. for(int i = 0; i < MAX_EQ_BANDS; ++i) {
  107. memory.dealloc(filter[i].l);
  108. memory.dealloc(filter[i].r);
  109. }
  110. }
  111. // Cleanup the effect
  112. void EQ::cleanup(void)
  113. {
  114. for(int i = 0; i < MAX_EQ_BANDS; ++i) {
  115. filter[i].l->cleanup();
  116. filter[i].r->cleanup();
  117. }
  118. }
  119. //Effect output
  120. void EQ::out(const Stereo<float *> &smp)
  121. {
  122. for(int i = 0; i < buffersize; ++i) {
  123. efxoutl[i] = smp.l[i] * volume;
  124. efxoutr[i] = smp.r[i] * volume;
  125. }
  126. for(int i = 0; i < MAX_EQ_BANDS; ++i) {
  127. if(filter[i].Ptype == 0)
  128. continue;
  129. filter[i].l->filterout(efxoutl);
  130. filter[i].r->filterout(efxoutr);
  131. }
  132. }
  133. //Parameter control
  134. void EQ::setvolume(unsigned char _Pvolume)
  135. {
  136. Pvolume = _Pvolume;
  137. outvolume = powf(0.005f, (1.0f - Pvolume / 127.0f)) * 10.0f;
  138. volume = (!insertion) ? 1.0f : outvolume;
  139. }
  140. void EQ::setpreset(unsigned char npreset)
  141. {
  142. const int PRESET_SIZE = 1;
  143. const int NUM_PRESETS = 2;
  144. unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
  145. {67}, //EQ 1
  146. {67} //EQ 2
  147. };
  148. if(npreset >= NUM_PRESETS)
  149. npreset = NUM_PRESETS - 1;
  150. for(int n = 0; n < PRESET_SIZE; ++n)
  151. changepar(n, presets[npreset][n]);
  152. Ppreset = npreset;
  153. }
  154. void EQ::changepar(int npar, unsigned char value)
  155. {
  156. switch(npar) {
  157. case 0:
  158. setvolume(value);
  159. break;
  160. }
  161. if(npar < 10)
  162. return;
  163. int nb = (npar - 10) / 5; //number of the band (filter)
  164. if(nb >= MAX_EQ_BANDS)
  165. return;
  166. int bp = npar % 5; //band paramenter
  167. float tmp;
  168. switch(bp) {
  169. case 0:
  170. filter[nb].Ptype = value;
  171. if(value > 9)
  172. filter[nb].Ptype = 0; //has to be changed if more filters will be added
  173. if(filter[nb].Ptype != 0) {
  174. filter[nb].l->settype(value - 1);
  175. filter[nb].r->settype(value - 1);
  176. }
  177. break;
  178. case 1:
  179. filter[nb].Pfreq = value;
  180. tmp = 600.0f * powf(30.0f, (value - 64.0f) / 64.0f);
  181. filter[nb].l->setfreq(tmp);
  182. filter[nb].r->setfreq(tmp);
  183. break;
  184. case 2:
  185. filter[nb].Pgain = value;
  186. tmp = 30.0f * (value - 64.0f) / 64.0f;
  187. filter[nb].l->setgain(tmp);
  188. filter[nb].r->setgain(tmp);
  189. break;
  190. case 3:
  191. filter[nb].Pq = value;
  192. tmp = powf(30.0f, (value - 64.0f) / 64.0f);
  193. filter[nb].l->setq(tmp);
  194. filter[nb].r->setq(tmp);
  195. break;
  196. case 4:
  197. filter[nb].Pstages = value;
  198. if(value >= MAX_FILTER_STAGES)
  199. filter[nb].Pstages = MAX_FILTER_STAGES - 1;
  200. filter[nb].l->setstages(value);
  201. filter[nb].r->setstages(value);
  202. break;
  203. }
  204. }
  205. unsigned char EQ::getpar(int npar) const
  206. {
  207. switch(npar) {
  208. case 0:
  209. return Pvolume;
  210. break;
  211. }
  212. if(npar < 10)
  213. return 0;
  214. int nb = (npar - 10) / 5; //number of the band (filter)
  215. if(nb >= MAX_EQ_BANDS)
  216. return 0;
  217. int bp = npar % 5; //band paramenter
  218. switch(bp) {
  219. case 0:
  220. return filter[nb].Ptype;
  221. break;
  222. case 1:
  223. return filter[nb].Pfreq;
  224. break;
  225. case 2:
  226. return filter[nb].Pgain;
  227. break;
  228. case 3:
  229. return filter[nb].Pq;
  230. break;
  231. case 4:
  232. return filter[nb].Pstages;
  233. break;
  234. default: return 0; //in case of bogus parameter number
  235. }
  236. }
  237. float EQ::getfreqresponse(float freq)
  238. {
  239. float resp = 1.0f;
  240. for(int i = 0; i < MAX_EQ_BANDS; ++i) {
  241. if(filter[i].Ptype == 0)
  242. continue;
  243. resp *= filter[i].l->H(freq);
  244. }
  245. return rap2dB(resp * outvolume);
  246. }
  247. //Not exactly the most efficient manner to derive the total taps, but it should
  248. //be fast enough in practice
  249. void EQ::getFilter(float *a, float *b) const
  250. {
  251. a[0] = 1;
  252. b[0] = 1;
  253. off_t off=0;
  254. for(int i = 0; i < MAX_EQ_BANDS; ++i) {
  255. auto &F = filter[i];
  256. if(F.Ptype == 0)
  257. continue;
  258. const double Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]};
  259. const double Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]};
  260. for(int j=0; j<F.Pstages+1; ++j) {
  261. for(int k=0; k<3; ++k) {
  262. a[off] = Fa[k];
  263. b[off] = Fb[k];
  264. off++;
  265. }
  266. }
  267. }
  268. }