MicroDexed is a compatible 6-operator-FM-synth based on the Teensy(-3.6/-4.0) Microcontroller. https://www.parasitstudio.de
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.

217 lines
4.9KB

  1. /**
  2. Copyright (c) 2013-2014 Pascal Gauthier.
  3. Copyright (c) 2013-2014 Filatov Vadim.
  4. Filter taken from the Obxd project :
  5. https://github.com/2DaT/Obxd
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software Foundation,
  16. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #define _USE_MATH_DEFINES
  19. #include <math.h>
  20. #include "PluginFx.h"
  21. const float dc = 1e-18;
  22. inline static float tptpc(float& state, float inp, float cutoff) {
  23. float v = (inp - state) * cutoff / (1 + cutoff);
  24. float res = v + state;
  25. state = res + v;
  26. return res;
  27. }
  28. inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) {
  29. cutoff = (cutoff * srInv) * M_PI;
  30. float v = (inp - state) * cutoff / (1 + cutoff);
  31. float res = v + state;
  32. state = res + v;
  33. return res;
  34. }
  35. //static float linsc(float param,const float min,const float max) {
  36. // return (param) * (max - min) + min;
  37. //}
  38. static float logsc(float param, const float min, const float max, const float rolloff = 19.0f) {
  39. return ((expf(param * logf(rolloff + 1)) - 1.0f) / (rolloff)) * (max - min) + min;
  40. }
  41. PluginFx::PluginFx() {
  42. Cutoff = 1;
  43. Reso = 0;
  44. Gain = 1;
  45. }
  46. void PluginFx::init(int sr) {
  47. mm = 0;
  48. s1 = s2 = s3 = s4 = c = d = 0;
  49. R24 = 0;
  50. mmch = (int)(mm * 3);
  51. mmt = mm * 3 - mmch;
  52. sampleRate = sr;
  53. sampleRateInv = 1 / sampleRate;
  54. float rcrate = sqrt((44000 / sampleRate));
  55. rcor24 = (970.0 / 44000) * rcrate;
  56. rcor24Inv = 1 / rcor24;
  57. bright = tanf((sampleRate * 0.5f - 10) * M_PI * sampleRateInv);
  58. R = 1;
  59. rcor = (480.0 / 44000) * rcrate;
  60. rcorInv = 1 / rcor;
  61. bandPassSw = false;
  62. pCutoff = -1;
  63. pReso = -1;
  64. dc_r = 1.0 - (126.0 / sr);
  65. dc_id = 0;
  66. dc_od = 0;
  67. }
  68. inline float PluginFx::NR24(float sample, float g, float lpc) {
  69. float ml = 1 / (1 + g);
  70. float S = (lpc * (lpc * (lpc * s1 + s2) + s3) + s4) * ml;
  71. float G = lpc * lpc * lpc * lpc;
  72. float y = (sample - R24 * S) / (1 + R24 * G);
  73. return y + 1e-8;
  74. };
  75. inline float PluginFx::NR(float sample, float g) {
  76. float y = ((sample - R * s1 * 2 - g * s1 - s2) / (1 + g * (2 * R + g))) + dc;
  77. return y;
  78. }
  79. void PluginFx::process(float *work, int sampleSize) {
  80. // very basic DC filter
  81. float t_fd = work[0];
  82. work[0] = work[0] - dc_id + dc_r * dc_od;
  83. dc_id = t_fd;
  84. for (int i = 1; i < sampleSize; i++) {
  85. t_fd = work[i];
  86. work[i] = work[i] - dc_id + dc_r * work[i - 1];
  87. dc_id = t_fd;
  88. }
  89. dc_od = work[sampleSize - 1];
  90. if ( Gain != 1 ) {
  91. for (int i = 0; i < sampleSize; i++ )
  92. work[i] *= Gain;
  93. }
  94. // don't apply the LPF if the cutoff is to maximum
  95. if ( Cutoff == 1 )
  96. return;
  97. if ( Cutoff != pCutoff || Reso != pReso ) {
  98. rReso = (0.991 - logsc(1 - Reso, 0, 0.991));
  99. R24 = 3.5 * rReso;
  100. float cutoffNorm = logsc(Cutoff, 60, 19000);
  101. rCutoff = (float)tanf(cutoffNorm * sampleRateInv * M_PI);
  102. pCutoff = Cutoff;
  103. pReso = Reso;
  104. R = 1 - rReso;
  105. }
  106. // THIS IS MY FAVORITE 4POLE OBXd filter
  107. // maybe smooth this value
  108. float g = rCutoff;
  109. float lpc = g / (1 + g);
  110. for (int i = 0; i < sampleSize; i++ ) {
  111. float s = work[i];
  112. s = s - 0.45 * tptlpupw(c, s, 15, sampleRateInv);
  113. s = tptpc(d, s, bright);
  114. float y0 = NR24(s, g, lpc);
  115. //first low pass in cascade
  116. float v = (y0 - s1) * lpc;
  117. float res = v + s1;
  118. s1 = res + v;
  119. //damping
  120. s1 = atanf(s1 * rcor24) * rcor24Inv;
  121. float y1 = res;
  122. float y2 = tptpc(s2, y1, g);
  123. float y3 = tptpc(s3, y2, g);
  124. float y4 = tptpc(s4, y3, g);
  125. float mc = 0.0;
  126. switch (mmch) {
  127. case 0:
  128. mc = ((1 - mmt) * y4 + (mmt) * y3);
  129. break;
  130. case 1:
  131. mc = ((1 - mmt) * y3 + (mmt) * y2);
  132. break;
  133. case 2:
  134. mc = ((1 - mmt) * y2 + (mmt) * y1);
  135. break;
  136. case 3:
  137. mc = y1;
  138. break;
  139. }
  140. //half volume comp
  141. work[i] = mc * (1 + R24 * 0.45);
  142. }
  143. }
  144. /*
  145. // THIS IS THE 2POLE FILTER
  146. for(int i=0; i < sampleSize; i++ ) {
  147. float s = work[i];
  148. s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
  149. s = tptpc(d,s,bright);
  150. //float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2));
  151. float v = NR(s,g);
  152. float y1 = v*g + s1;
  153. //damping
  154. s1 = atanf(s1 * rcor) * rcorInv;
  155. float y2 = y1*g + s2;
  156. s2 = y2 + y1*g;
  157. float mc;
  158. if(!bandPassSw)
  159. mc = (1-mm)*y2 + (mm)*v;
  160. else
  161. {
  162. mc =2 * ( mm < 0.5 ?
  163. ((0.5 - mm) * y2 + (mm) * y1):
  164. ((1-mm) * y1 + (mm-0.5) * v)
  165. );
  166. }
  167. work[i] = mc;
  168. }
  169. */