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.

128 line
3.8KB

  1. /* Audio Library for Teensy, Ladder Filter
  2. * Copyright (c) 2021, Richard van Hoesel
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice, development funding notice, and this permission
  12. * notice shall be included in all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. //-----------------------------------------------------------
  23. // Huovilainen New Moog (HNM) model as per CMJ jun 2006
  24. // Implemented as Teensy Audio Library compatible object
  25. // Richard van Hoesel, Feb. 9 2021
  26. // v.1.01 now includes FC "CV" modulation input
  27. // please retain this header if you use this code.
  28. //-----------------------------------------------------------
  29. // https://forum.pjrc.com/threads/60488?p=269609&viewfull=1#post269609
  30. #include <Arduino.h>
  31. #include "filter_ladder.h"
  32. #include <math.h>
  33. #include <stdint.h>
  34. #define MOOG_PI ((float)3.14159265358979323846264338327950288)
  35. float AudioFilterLadder::LPF(float s, int i)
  36. {
  37. float ft = s * (1.0f/1.3f) + (0.3f/1.3f) * z0[i] - z1[i];
  38. ft = ft * alpha + z1[i];
  39. z1[i] = ft;
  40. z0[i] = s;
  41. return ft;
  42. }
  43. void AudioFilterLadder::resonance(float res)
  44. {
  45. // maps resonance = 0->1 to K = 0 -> 4
  46. if (res > 1) {
  47. res = 1;
  48. } else if (res < 0) {
  49. res = 0;
  50. }
  51. K = 4.0 * res;
  52. }
  53. void AudioFilterLadder::frequency(float c)
  54. {
  55. Fbase = c;
  56. compute_coeffs(c);
  57. }
  58. void AudioFilterLadder::compute_coeffs(float c)
  59. {
  60. if (c > 0.49f * AUDIO_SAMPLE_RATE_EXACT)
  61. c = 0.49f * AUDIO_SAMPLE_RATE_EXACT;
  62. else if (c < 1)
  63. c = 1;
  64. float wc = c * (float)(2.0f * MOOG_PI / AUDIO_SAMPLE_RATE_EXACT);
  65. float wc2 = wc * wc;
  66. alpha = 0.9892f * wc - 0.4324f * wc2 + 0.1381f * wc * wc2 - 0.0202f * wc2 * wc2;
  67. }
  68. static inline float fast_tanh(float x)
  69. {
  70. float x2 = x * x;
  71. return x * (27.0f + x2) / (27.0f + 9.0f * x2);
  72. }
  73. void AudioFilterLadder::update(void)
  74. {
  75. audio_block_t *blocka, *blockb;
  76. float ftot, FCmod;
  77. bool FCmodActive = true;
  78. blocka = receiveWritable(0);
  79. blockb = receiveReadOnly(1);
  80. if (!blocka) {
  81. blocka = allocate();
  82. if (!blocka) {
  83. if (blockb) release(blockb);
  84. return;
  85. }
  86. // When no data arrives, we must treat it as if zeros had
  87. // arrived. Because of resonance, we need to keep computing
  88. // output. Perhaps we could examine the filter state here
  89. // and just return without any work when it's below some
  90. // threshold we know produces no more sound/resonance?
  91. for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
  92. blocka->data[i] = 0;
  93. }
  94. }
  95. if (!blockb) FCmodActive = false;
  96. for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
  97. float input = blocka->data[i] * (1.0f/32768.0f);
  98. ftot = Fbase;
  99. if (FCmodActive) {
  100. FCmod = blockb->data[i] * (1.0f/32768.0f);
  101. ftot += Fbase * FCmod;
  102. if (FCmod != 0) compute_coeffs(ftot);
  103. }
  104. float u = input - (z1[3] - 0.5f * input) * K;
  105. u = fast_tanh(u);
  106. float stage1 = LPF(u, 0);
  107. float stage2 = LPF(stage1, 1);
  108. float stage3 = LPF(stage2, 2);
  109. float stage4 = LPF(stage3, 3);
  110. blocka->data[i] = stage4 * 32767.0f;
  111. }
  112. transmit(blocka);
  113. release(blocka);
  114. if (blockb) release(blockb);
  115. }