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.

608 lines
13KB

  1. #pragma once
  2. #include <cmath>
  3. #include <random>
  4. #include "rack.hpp"
  5. #include "dsp/resampler.hpp"
  6. #include "DSPEffect.hpp"
  7. using namespace rack;
  8. const static float TWOPI = lroundf(M_PI * 2.);
  9. namespace dsp {
  10. /**
  11. * @brief Basic leaky integrator
  12. */
  13. struct Integrator {
  14. float d = 0.25f;
  15. float value = 0.f;
  16. /**
  17. * @brief Add value to integrator
  18. * @param x Input sample
  19. * @param Fn
  20. * @return Current integrator state
  21. */
  22. float add(float x, float Fn);
  23. };
  24. /**
  25. * @brief Filter out DC offset / 1-Pole HP Filter
  26. */
  27. struct DCBlocker {
  28. double r = 0.999;
  29. double xm1 = 0.f, ym1 = 0.f;
  30. DCBlocker(double r);
  31. /**
  32. * @brief Filter signal
  33. * @param x Input sample
  34. * @return Filtered output
  35. */
  36. double filter(double x);
  37. };
  38. /**
  39. * @brief Simple 6dB lowpass filter
  40. */
  41. struct LP6DBFilter {
  42. private:
  43. float RC;
  44. float dt;
  45. float alpha;
  46. float y0;
  47. float fc;
  48. public:
  49. /**
  50. * @brief Create a new filter with a given cutoff frequency
  51. * @param fc cutoff frequency
  52. * @param factor Oversampling factor
  53. */
  54. LP6DBFilter(float fc, int factor) {
  55. updateFrequency(fc, factor);
  56. y0 = 0.f;
  57. }
  58. /**
  59. * @brief Set new cutoff frequency
  60. * @param fc cutoff frequency
  61. */
  62. void updateFrequency(float fc, int factor);
  63. /**
  64. * @brief Filter signal
  65. * @param x Input sample
  66. * @return Filtered output
  67. */
  68. float filter(float x);
  69. };
  70. /**
  71. * @brief Simple noise generator
  72. */
  73. struct Noise {
  74. Noise() {}
  75. float nextFloat(float gain) {
  76. static std::default_random_engine e;
  77. static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
  78. return (float) dis(e) * gain;
  79. }
  80. };
  81. /**
  82. * @brief Simple oversampling class
  83. * @deprecated Use resampler instead
  84. */
  85. template<int OVERSAMPLE, int CHANNELS>
  86. struct OverSampler {
  87. struct Vector {
  88. float y0, y1;
  89. };
  90. Vector y[CHANNELS] = {};
  91. float up[CHANNELS][OVERSAMPLE] = {};
  92. float data[CHANNELS][OVERSAMPLE] = {};
  93. rack::Decimator<OVERSAMPLE, OVERSAMPLE> decimator[CHANNELS];
  94. int factor = OVERSAMPLE;
  95. /**
  96. * @brief Constructor
  97. * @param factor Oversampling factor
  98. */
  99. OverSampler() {}
  100. /**
  101. * @brief Return linear interpolated position
  102. * @param point Point in oversampled data
  103. * @return
  104. */
  105. float interpolate(int channel, int point) {
  106. return y[channel].y0 + (point / factor) * (y[channel].y1 - y[channel].y0);
  107. }
  108. /**
  109. * @brief Create up-sampled data out of two basic values
  110. */
  111. void doUpsample(int channel) {
  112. for (int i = 0; i < factor; i++) {
  113. up[channel][i] = interpolate(channel, i + 1);
  114. }
  115. }
  116. /**
  117. * @brief Downsample data from a given channel
  118. * @param channel Channel to proccess
  119. * @return Downsampled point
  120. */
  121. float getDownsampled(int channel) {
  122. return decimator[channel].process(data[channel]);
  123. }
  124. /**
  125. * @brief Step to next sample point
  126. * @param y Next sample point
  127. */
  128. void next(int channel, float n) {
  129. y[channel].y0 = y[channel].y1;
  130. y[channel].y1 = n;
  131. }
  132. };
  133. /**
  134. * @brief Fast sin approximation
  135. * @param angle Angle
  136. * @return App. value
  137. */
  138. inline float fastSin(float angle) {
  139. float sqr = angle * angle;
  140. float result = -2.39e-08f;
  141. result *= sqr;
  142. result += 2.7526e-06f;
  143. result *= sqr;
  144. result -= 1.98409e-04f;
  145. result *= sqr;
  146. result += 8.3333315e-03f;
  147. result *= sqr;
  148. result -= 1.666666664e-01f;
  149. result *= sqr;
  150. result += 1.0f;
  151. result *= angle;
  152. return result;
  153. }
  154. float wrapTWOPI(float n);
  155. float getPhaseIncrement(float frq);
  156. float clipl(float in, float clip);
  157. float cliph(float in, float clip);
  158. float BLIT(float N, float phase);
  159. float shape1(float a, float x);
  160. double saturate(double x, double a);
  161. double overdrive(double input);
  162. float shape2(float a, float x);
  163. /**
  164. * @brief Double version of clamp
  165. * @param x
  166. * @param min
  167. * @param max
  168. * @return
  169. */
  170. inline double clampd(double x, double min, double max) {
  171. return fmax(fmin(x, max), min);
  172. }
  173. /**
  174. * @brief Soft clipping
  175. * @param x
  176. * @param sat
  177. * @param satinv
  178. * @return
  179. */
  180. inline float clip(float x, float sat, float satinv) {
  181. float v2 = (x * satinv > 1 ? 1 :
  182. (x * satinv < -1 ? -1 :
  183. x * satinv));
  184. return (sat * (v2 - (1.f / 3.f) * v2 * v2 * v2));
  185. }
  186. /**
  187. * @brief Clamp without branching
  188. * @param input Input sample
  189. * @return
  190. */
  191. inline double saturate2(double input) { //clamp without branching
  192. const double _limit = 0.3;
  193. double x1 = fabs(input + _limit);
  194. double x2 = fabs(input - _limit);
  195. return 0.5 * (x1 - x2);
  196. }
  197. /**
  198. * @brief Fast arctan approximation, corresponds to tanhf() but decreases y to infinity
  199. * @param x
  200. * @return
  201. */
  202. inline float fastatan(float x) {
  203. return (x / (1.0f + 0.28f * (x * x)));
  204. }
  205. /**
  206. * @brief Linear fade of two points
  207. * @param a Point 1
  208. * @param b Point 2
  209. * @param n Fade value
  210. * @return
  211. */
  212. inline float fade2(float a, float b, float n) {
  213. return (1 - n) * a + n * b;
  214. }
  215. /**
  216. * @brief Linear fade of five points
  217. * @param a Point 1
  218. * @param b Point 2
  219. * @param c Point 3
  220. * @param d Point 4
  221. * @param e Point 5
  222. * @param n Fade value
  223. * @return
  224. */
  225. inline float fade5(float a, float b, float c, float d, float e, float n) {
  226. if (n >= 0 && n < 1) {
  227. return fade2(a, b, n);
  228. } else if (n >= 1 && n < 2) {
  229. return fade2(b, c, n - 1);
  230. } else if (n >= 2 && n < 3) {
  231. return fade2(c, d, n - 2);
  232. } else if (n >= 3 && n < 4) {
  233. return fade2(d, e, n - 3);
  234. }
  235. return e;
  236. }
  237. /**
  238. * @brief Shapes between 0..1 with a log type courve
  239. * @param x
  240. * @return
  241. */
  242. inline float cubicShape(float x) {
  243. return (x - 1.f) * (x - 1.f) * (x - 1.f) + 1.f;
  244. }
  245. /**
  246. * @brief ArcTan like shaper for foldback distortion
  247. * @param x
  248. * @return
  249. */
  250. inline float atanShaper(float x) {
  251. return x / (1.f + (0.28f * x * x));
  252. }
  253. /** Generate chebyshev polynoms
  254. * @brief
  255. * @param x Input sample
  256. * @param A ?
  257. * @param order Polynom order
  258. * @return
  259. */
  260. inline float chebyshev(float x, float A[], int order) {
  261. // To = 1
  262. // T1 = x
  263. // Tn = 2.x.Tn-1 - Tn-2
  264. // out = sum(Ai*Ti(x)) , i C {1,..,order}
  265. float Tn_2 = 1.0f;
  266. float Tn_1 = x;
  267. float Tn;
  268. float out = A[0] * Tn_1;
  269. for (int n = 2; n <= order; n++) {
  270. Tn = 2.0f * x * Tn_1 - Tn_2;
  271. out += A[n - 1] * Tn;
  272. Tn_2 = Tn_1;
  273. Tn_1 = Tn;
  274. }
  275. return out;
  276. }
  277. /**
  278. * @brief Signum function
  279. * @param x
  280. * @return
  281. */
  282. inline double sign(double x) {
  283. if (x > 0) return 1;
  284. if (x < 0) return -1;
  285. return 0;
  286. }
  287. /**
  288. * @brief Signum function
  289. * @param x
  290. * @return
  291. */
  292. inline float sign(float x) {
  293. if (x > 0) return 1;
  294. if (x < 0) return -1;
  295. return 0;
  296. }
  297. /**
  298. * @brief Lambert-W function using Halley's method
  299. * see: http://smc2017.aalto.fi/media/materials/proceedings/SMC17_p336.pdf
  300. * @param x
  301. * @param ln1
  302. * @return
  303. */
  304. inline double lambert_W_Halley(double x, double ln1) {
  305. double w;
  306. double p, r, s, err;
  307. double expw;
  308. // if (!isnan(ln1) || !isfinite(ln1)) ln1 = 0.;
  309. // initial guess, previous value
  310. w = ln1;
  311. // debug("x: %f ln1: %f", x, ln1);
  312. // Haley's method (Sec. 4.2 of the paper)
  313. for (int i = 0; i < 100; i++) {
  314. expw = pow(M_E, w);
  315. p = w * expw - x;
  316. r = (w + 1.) * expw;
  317. s = (w + 2.) / (2. * (w + 1.));
  318. err = (p / (r - (p * s)));
  319. if (abs(err) < 10e-12) {
  320. break;
  321. }
  322. w = w - err;
  323. }
  324. return w;
  325. }
  326. /**
  327. * @brief
  328. *
  329. * This function evaluates the upper branch of the Lambert-W function for
  330. * real input x.
  331. *
  332. * Function written by F. Esqueda 2/10/17 based on implementation presented
  333. * by Darko Veberic - "Lambert W Function for Applications in Physics"
  334. * Available at https://arxiv.org/pdf/1209.0735.pdf
  335. *
  336. * @param x input
  337. * @return W(x)
  338. */
  339. inline double lambert_W_Fritsch(double x) {
  340. double num, den;
  341. double w, w1, a, b, ia;
  342. double z, q, e;
  343. if (x < 0.14546954290661823) {
  344. num = 1 + 5.931375839364438 * x + 11.39220550532913 * x * x + 7.33888339911111 * x * x * x + 0.653449016991959 * x * x * x * x;
  345. den = 1 + 6.931373689597704 * x + 16.82349461388016 * x * x + 16.43072324143226 * x * x * x + 5.115235195211697 * x * x * x * x;
  346. w = x * num / den;
  347. } else if (x < 8.706658967856612) {
  348. num = 1 + 2.4450530707265568 * x + 1.3436642259582265 * x * x + 0.14844005539759195 * x * x * x +
  349. 0.0008047501729130 * x * x * x * x;
  350. den = 1 + 3.4447089864860025 * x + 3.2924898573719523 * x * x + 0.9164600188031222 * x * x * x +
  351. 0.05306864044833221 * x * x * x * x;
  352. w = x * num / den;
  353. } else {
  354. a = log(x);
  355. b = log(a);
  356. ia = 1. / a;
  357. w = a - b + (b * ia) * 0.5 * b * (b - 2.) * (ia * ia) + (1. / 6.) * (2. * b * b - 9. * b + 6.) * (ia * ia * ia);
  358. }
  359. for (int i = 0; i < 20; i++) {
  360. w1 = w + 1.;
  361. z = log(x) - log(w) - w;
  362. q = 2. * w1 * (w1 + (2. / 3.) * z);
  363. e = (z / w1) * ((q - z) / (q - 2. * z));
  364. if (abs(e) < 10e-12) {
  365. break;
  366. }
  367. }
  368. return w;
  369. }
  370. /**
  371. * @brief Implementation of the error function
  372. * @brief https://www.johndcook.com/blog/cpp_erf/
  373. *
  374. * @param x input
  375. * @return erf(x)
  376. */
  377. inline double erf(const double x) {
  378. double a1 = 0.254829592;
  379. double a2 = -0.284496736;
  380. double a3 = 1.421413741;
  381. double a4 = -1.453152027;
  382. double a5 = 1.061405429;
  383. double p = 0.3275911;
  384. // save sign in coefficent
  385. int sign = (x < 0) ? -1 : 1;
  386. double xa = fabs(x);
  387. // A&S formula 7.1.26
  388. double t = 1.0 / (1.0 + p * xa);
  389. double y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xa * xa);
  390. return sign * y;
  391. }
  392. /**
  393. * @brief Approximates log to the base of 2 with optimized code.
  394. * @brief https://www.ebayinc.com/stories/blogs/tech/fast-approximate-logarithms-part-i-the-basics/
  395. * @param x
  396. * @return
  397. */
  398. inline float fastlog2(float x) // compute log2(x) by reducing x to [0.75, 1.5)
  399. {
  400. // a*(x-1)^2 + b*(x-1) approximates log2(x) when 0.75 <= x < 1.5
  401. const float a = -.6296735;
  402. const float b = 1.466967;
  403. float signif, fexp;
  404. int exp;
  405. float lg2;
  406. union {
  407. float f;
  408. unsigned int i;
  409. } ux1, ux2;
  410. int greater; // really a boolean
  411. /*
  412. * Assume IEEE representation, which is sgn(1):exp(8):frac(23)
  413. * representing (1+frac)*2^(exp-127) Call 1+frac the significand
  414. */
  415. // get exponent
  416. ux1.f = x;
  417. exp = (ux1.i & 0x7F800000) >> 23;
  418. // actual exponent is exp-127, will subtract 127 later
  419. greater = ux1.i & 0x00400000; // true if signif > 1.5
  420. if (greater) {
  421. // signif >= 1.5 so need to divide by 2. Accomplish this by
  422. // stuffing exp = 126 which corresponds to an exponent of -1
  423. ux2.i = (ux1.i & 0x007FFFFF) | 0x3f000000;
  424. signif = ux2.f;
  425. fexp = exp - 126; // 126 instead of 127 compensates for division by 2
  426. signif = signif - 1.0; // <
  427. lg2 = fexp + a * signif * signif + b * signif; // <
  428. } else {
  429. // get signif by stuffing exp = 127 which corresponds to an exponent of 0
  430. ux2.i = (ux1.i & 0x007FFFFF) | 0x3f800000;
  431. signif = ux2.f;
  432. fexp = exp - 127;
  433. signif = signif - 1.0; // <<--
  434. lg2 = fexp + a * signif * signif + b * signif; // <<--
  435. }
  436. // lines marked <<-- are common code, but optimize better
  437. // when duplicated, at least when using gcc
  438. return (lg2);
  439. }
  440. /**
  441. * @brief Fast natural log to the base of e using the optimized approximation of log2.
  442. * @param x
  443. * @return
  444. */
  445. inline float fastlog(float x) {
  446. return 0.6931472f * fastlog2(x);
  447. }
  448. /**
  449. * @brief Fast pow() approximation
  450. * @brief https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
  451. * @param a base
  452. * @param b exponent
  453. * @return
  454. */
  455. inline double fastPow(double a, double b) {
  456. union {
  457. double d;
  458. int x[2];
  459. } u = {a};
  460. u.x[1] = (int) (b * (u.x[1] - 1072632447) + 1072632447);
  461. u.x[0] = 0;
  462. return u.d;
  463. }
  464. // should be much more precise with large b
  465. inline double fastPrecisePow(double a, double b) {
  466. // calculate approximation with fraction of the exponent
  467. int e = (int) b;
  468. union {
  469. double d;
  470. int x[2];
  471. } u = {a};
  472. u.x[1] = (int) ((b - e) * (u.x[1] - 1072632447) + 1072632447);
  473. u.x[0] = 0;
  474. // exponentiation by squaring with the exponent's integer part
  475. // double r = u.d makes everything much slower, not sure why
  476. double r = 1.0;
  477. while (e) {
  478. if (e & 1) {
  479. r *= a;
  480. }
  481. a *= a;
  482. e >>= 1;
  483. }
  484. return r * u.d;
  485. }
  486. /**
  487. * @brief Unaccurate approcimation of the LambertW function for x>0
  488. * @brief usable my waveshaper applications
  489. * @param x
  490. * @return
  491. */
  492. inline double fakedLambertW(double x) {
  493. return log(x + 1);
  494. }
  495. } // namespace dsp