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.

107 lines
2.6KB

  1. //-----------------------------------------------------------
  2. // Huovilainen New Moog (HNM) model as per CMJ jun 2006
  3. // Implemented as Teensy Audio Library compatible object
  4. // Richard van Hoesel, Feb. 9 2021
  5. // v.1.01 now includes FC "CV" modulation input
  6. // please retain this header if you use this code.
  7. //-----------------------------------------------------------
  8. // https://forum.pjrc.com/threads/60488?p=269609&viewfull=1#post269609
  9. #include <Arduino.h>
  10. #include "filter_ladder.h"
  11. #include <math.h>
  12. #include <stdint.h>
  13. #define MOOG_PI 3.14159265358979323846264338327950288
  14. float HNMoog::LPF(float s, int i)
  15. {
  16. float ft = s * (1/1.3) + (0.3/1.3) * z0[i] - z1[i];
  17. ft = ft * alpha + z1[i];
  18. z1[i] = ft;
  19. z0[i] = s;
  20. return ft;
  21. }
  22. void HNMoog::SetResonance(float res)
  23. {
  24. // maps resonance = 0->1 to K = 0 -> 4
  25. if (res > 1) {
  26. res = 1;
  27. } else if (res < 0) {
  28. res = 0;
  29. }
  30. K = 4.0 * res;
  31. }
  32. void HNMoog::SetCutoff(float c)
  33. {
  34. Fbase = c;
  35. compute_coeffs(c);
  36. }
  37. void HNMoog::compute_coeffs(float c)
  38. {
  39. if (c > 0.49 * AUDIO_SAMPLE_RATE_EXACT)
  40. c = 0.49 * AUDIO_SAMPLE_RATE_EXACT;
  41. else if (c < 1)
  42. c = 1;
  43. float wc = c * (2.0 * MOOG_PI / AUDIO_SAMPLE_RATE_EXACT);
  44. float wc2 = wc * wc;
  45. alpha = 0.9892f * wc - 0.4324f * wc2 + 0.1381f * wc * wc2 - 0.0202f * wc2 * wc2;
  46. }
  47. inline float fast_tanh(float x)
  48. {
  49. float x2 = x * x;
  50. return x * (27.0 + x2) / (27.0 + 9.0 * x2);
  51. }
  52. void HNMoog::update(void)
  53. {
  54. audio_block_t *blocka, *blockb;
  55. float ftot, FCmod;
  56. bool FCmodActive = true;
  57. blocka = receiveWritable(0);
  58. blockb = receiveReadOnly(1);
  59. if (!blocka) {
  60. blocka = allocate();
  61. if (!blocka) {
  62. if (blockb) release(blockb);
  63. return;
  64. }
  65. // When no data arrives, we must treat it as if zeros had
  66. // arrived. Because of resonance, we need to keep computing
  67. // output. Perhaps we could examine the filter state here
  68. // and just return without any work when it's below some
  69. // threshold we know produces no more sound/resonance?
  70. for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
  71. blocka->data[i] = 0;
  72. }
  73. }
  74. if (!blockb) FCmodActive = false;
  75. for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
  76. float input = blocka->data[i] * (1.0/32768);
  77. ftot = Fbase;
  78. if (FCmodActive) {
  79. FCmod = blockb->data[i] * (1.0/32768);
  80. ftot += Fbase * FCmod;
  81. if (FCmod != 0) compute_coeffs(ftot);
  82. }
  83. float u = input - (z1[3] - 0.5 * input) * K;
  84. u = fast_tanh(u);
  85. float stage1 = LPF(u,0);
  86. float stage2 = LPF(stage1,1);
  87. float stage3 = LPF(stage2,2);
  88. float stage4 = LPF(stage3,3);
  89. blocka->data[i] = stage4 * 32767.0;
  90. }
  91. transmit(blocka);
  92. release(blocka);
  93. if (blockb) release(blockb);
  94. }