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.

235 lines
9.1KB

  1. #include "Bidoo.hpp"
  2. #include "BidooComponents.hpp"
  3. #include "dsp/samplerate.hpp"
  4. using namespace std;
  5. namespace rack_plugin_Bidoo {
  6. //Approximates cos(pi*x) for x in [-1,1].
  7. inline float fast_cos(const float x)
  8. {
  9. float x2=x*x;
  10. return 1.0f+x2*(-4.0f+2.0f*x2);
  11. }
  12. //Length of the table
  13. #define L_TABLE (256+1) //The last entry of the table equals the first (to avoid a modulo)
  14. //Maximal formant width
  15. #define I_MAX 64
  16. //Table of formants
  17. float TF[L_TABLE*I_MAX];
  18. //Formantic function of width I (used to fill the table of formants)
  19. float fonc_formant(float p,const float I)
  20. {
  21. float a=0.5f;
  22. int hmax=int(10*I)>L_TABLE/2?L_TABLE/2:int(10*I);
  23. float phi=0.0f;
  24. for(int h=1;h<hmax;h++)
  25. {
  26. phi+=3.14159265359f*p;
  27. float hann=0.5f+0.5f*fast_cos(h*(1.0f/hmax));
  28. float gaussienne=0.85f*exp(-h*h/(I*I));
  29. float jupe=0.15f;
  30. float harmonique=cosf(phi);
  31. a+=hann*(gaussienne+jupe)*harmonique;
  32. }
  33. return a;
  34. }
  35. //Initialisation of the table TF with the fonction fonc_formant.
  36. void init_formant(void)
  37. { float coef=2.0f/(L_TABLE-1);
  38. for(int I=0;I<I_MAX;I++)
  39. for(int P=0;P<L_TABLE;P++)
  40. TF[P+I*L_TABLE]=fonc_formant(-1+P*coef,float(I));
  41. }
  42. //This function emulates the function fonc_formant
  43. // thanks to the table TF. A bilinear interpolation is
  44. // performed
  45. float formant(float p,float i)
  46. {
  47. i=i<0?0:i>I_MAX-2?I_MAX-2:i; // width limitation
  48. float P=(L_TABLE-1)*(p+1)*0.5f; // phase normalisation
  49. int P0=(int)P; float fP=P-P0; // Integer and fractional
  50. int I0=(int)i; float fI=i-I0; // parts of the phase (p) and width (i).
  51. int i00=P0+L_TABLE*I0; int i10=i00+L_TABLE;
  52. //bilinear interpolation.
  53. return (1-fI)*(TF[i00] + fP*(TF[i00+1]-TF[i00]))
  54. + fI*(TF[i10] + fP*(TF[i10+1]-TF[i10]));
  55. }
  56. // Double carrier.
  57. // h : position (float harmonic number)
  58. // p : phase
  59. float porteuse(const float h,const float p)
  60. {
  61. float h0=floor(h); //integer and
  62. float hf=h-h0; //decimal part of harmonic number.
  63. // modulos pour ramener p*h0 et p*(h0+1) dans [-1,1]
  64. float phi0=fmodf(p* h0 +1+1000,2.0f)-1.0f;
  65. float phi1=fmodf(p*(h0+1)+1+1000,2.0f)-1.0f;
  66. // two carriers.
  67. float Porteuse0=fast_cos(phi0); float Porteuse1=fast_cos(phi1);
  68. // crossfade between the two carriers.
  69. return Porteuse0+hf*(Porteuse1-Porteuse0);
  70. }
  71. struct FORK : Module {
  72. enum ParamIds {
  73. FORMANT_TYPE_PARAM,
  74. PITCH_PARAM,
  75. PRESET_PARAM,
  76. F_PARAM,
  77. A_PARAM = F_PARAM + 4,
  78. NUM_PARAMS = A_PARAM + 4
  79. };
  80. enum InputIds {
  81. FORMANT_TYPE_INPUT,
  82. PITCH_INPUT,
  83. F_INPUT,
  84. A_INPUT = F_INPUT + 4,
  85. NUM_INPUTS = A_INPUT + 4
  86. };
  87. enum OutputIds {
  88. SIGNAL_OUTPUT,
  89. NUM_OUTPUTS
  90. };
  91. enum LightIds {
  92. NUM_LIGHTS
  93. };
  94. float F1[9]={ 730.0f, 200.0f, 400.0f, 250.0f, 190.0f, 350.0f, 550.0f, 550.0f, 450.0f};
  95. float A1[9]={ 1.0f, 0.5f, 1.0f, 1.0f, 0.7f, 1.0f, 1.0f, 0.3f, 1.0f};
  96. float F2[9]={ 1090.0f, 2100.0f, 900.0f, 1700.0f, 800.0f, 1900.0f, 1600.0f, 850.0f, 1100.0f};
  97. float A2[9]={ 2.0f, 0.5f, 0.7f, 0.7f,0.35f, 0.3f, 0.5f, 1.0f, 0.7f};
  98. float F3[9]={ 2440.0f, 3100.0f, 2300.0f, 2100.0f, 2000.0f, 2500.0f, 2250.0f, 1900.0f, 1500.0f};
  99. float A3[9]={ 0.3f,0.15f, 0.2f, 0.4f, 0.1f, 0.3f, 0.7f, 0.2f, 0.2f};
  100. float F4[9]={ 3400.0f, 4700.0f, 3000.0f, 3300.0f, 3400.0f, 3700.0f, 3200.0f, 3000.0f, 3000.0f};
  101. float A4[9]={ 0.2f, 0.1f, 0.2f, 0.3f, 0.1f, 0.1f, 0.3f, 0.2f, 0.3f};
  102. int preset=0;
  103. float f0,dp0,p0=0.0f;
  104. float f1,f2,f3,f4,a1,a2,a3,a4;
  105. FORK() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  106. init_formant();
  107. f1=f2=f3=f4=100.0f;a1=a2=a3=a4=0.0f;
  108. }
  109. void step() override;
  110. };
  111. void FORK::step() {
  112. f0=261.626f * powf(2.0f, clamp(params[PITCH_PARAM].value + 12.0f * inputs[PITCH_INPUT].value,-54.0f,54.0f) / 12.0f);
  113. dp0=f0*(2/engineGetSampleRate());
  114. float un_f0=1.0f/f0;
  115. p0+=dp0;
  116. p0-=2.0f*(p0>1.0f);
  117. {
  118. float r=0.001f;
  119. f1+=r*(clamp(params[F_PARAM].value + rescale(inputs[F_INPUT].value,0.0f,10.0f,190.0f,730.0f),190.0f,730.0f)-f1);
  120. f2+=r*(clamp(params[F_PARAM+1].value + rescale(inputs[F_INPUT+1].value,0.0f,10.0f,800.0f,2100.0f),800.0f,2100.0f)-f2);
  121. f3+=r*(clamp(params[F_PARAM+2].value + rescale(inputs[F_INPUT+2].value,0.0f,10.0f,1500.0f,3100.0f),1500.0f,3100.0f)-f3);
  122. f4+=r*(clamp(params[F_PARAM+3].value + rescale(inputs[F_INPUT+3].value,0.0f,10.0f,3000.0f,4700.0f),3000.0f,4700.0f)-f4);
  123. a1+=r*(clamp(params[A_PARAM].value + rescale(inputs[A_INPUT].value,0.0f,10.0f,0.0f,1.0f),0.0f,1.0f)-a1);
  124. a2+=r*(clamp(params[A_PARAM+1].value + rescale(inputs[A_INPUT+1].value,0.0f,10.0f,0.0f,2.0f),0.0f,2.0f)-a2);
  125. a3+=r*(clamp(params[A_PARAM+2].value + rescale(inputs[A_INPUT+2].value,0.0f,10.0f,0.0f,0.7f),0.0f,0.7f)-a3);
  126. a4+=r*(clamp(params[A_PARAM+3].value + rescale(inputs[A_INPUT+3].value,0.0f,10.0f,0.0f,0.3f),0.0f,0.3f)-a4);
  127. }
  128. float out=
  129. a1*(f0/f1)*formant(p0,100.0f*un_f0)*porteuse(f1*un_f0,p0)
  130. +0.7f*a2*(f0/f2)*formant(p0,120.0f*un_f0)*porteuse(f2*un_f0,p0)
  131. + a3*(f0/f3)*formant(p0,150.0f*un_f0)*porteuse(f3*un_f0,p0)
  132. + a4*(f0/f4)*formant(p0,300.0f*un_f0)*porteuse(f4*un_f0,p0);
  133. outputs[SIGNAL_OUTPUT].value =10.0f*out;
  134. }
  135. struct FORKWidget : ModuleWidget {
  136. ParamWidget *F1;
  137. ParamWidget *F2;
  138. ParamWidget *F3;
  139. ParamWidget *F4;
  140. ParamWidget *A1;
  141. ParamWidget *A2;
  142. ParamWidget *A3;
  143. ParamWidget *A4;
  144. FORKWidget(FORK *module);
  145. };
  146. struct FORKCKD6 : BlueCKD6 {
  147. void onMouseDown(EventMouseDown &e) override {
  148. FORKWidget *parent = dynamic_cast<FORKWidget*>(this->parent);
  149. FORK *module = dynamic_cast<FORK*>(this->module);
  150. if (parent && module) {
  151. module->preset = (module->preset + 1)%8;
  152. parent->F1->setValue(module->F1[module->preset]);
  153. parent->F2->setValue(module->F2[module->preset]);
  154. parent->F3->setValue(module->F3[module->preset]);
  155. parent->F4->setValue(module->F4[module->preset]);
  156. parent->A1->setValue(module->A1[module->preset]);
  157. parent->A2->setValue(module->A2[module->preset]);
  158. parent->A3->setValue(module->A3[module->preset]);
  159. parent->A4->setValue(module->A4[module->preset]);
  160. }
  161. BlueCKD6::onMouseDown(e);
  162. }
  163. };
  164. FORKWidget::FORKWidget(FORK *module) : ModuleWidget(module) {
  165. setPanel(SVG::load(assetPlugin(plugin, "res/FORK.svg")));
  166. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  167. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  168. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  169. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  170. addParam(ParamWidget::create<BidooLargeBlueKnob>(Vec(26.0f,40.0f), module, FORK::PITCH_PARAM, -54.0f, 54.0f, 0));
  171. addParam(ParamWidget::create<FORKCKD6>(Vec(30.0f,274.0f), module, FORK::PRESET_PARAM, 0.0f, 8.0f, 0.0f));
  172. int xtpots = 32;
  173. int xtinyports = 67;
  174. F1 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35.0f + 25.0f * 2.0f), module, FORK::F_PARAM, 190.0f, 730.0f, 190.0f);
  175. addParam(F1);
  176. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35.0f + 25.0f * 2.0f + 2.0f), Port::INPUT, module, FORK::F_INPUT));
  177. A1 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35.0f + 25.0f * 2.0f + 20.0f), module, FORK::A_PARAM, 0.0f, 1.0f, 1.0f);
  178. addParam(A1);
  179. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35.0f + 25.0f * 2.0f + 20.0f + 2.0f), Port::INPUT, module, FORK::A_INPUT));
  180. F2 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35.0f - 2.0f + 25.0f * 4.0f), module, FORK::F_PARAM + 1.0f, 800.0f, 2100.0f, 1090.0f);
  181. addParam(F2);
  182. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35 - 2.0f + 25.0f * 4.0f + 2.0f), Port::INPUT, module, FORK::F_INPUT + 1));
  183. A2 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35.0f - 2.0f + 25.0f * 4.0f + 20.0f), module, FORK::A_PARAM + 1, 0.0f, 2.0f, 1.0f);
  184. addParam(A2);
  185. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35 - 2 + 25 * 4 + 20 + 2), Port::INPUT, module, FORK::A_INPUT + 1));
  186. F3 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35.0f - 4.0f + 25.0f * 6.0f), module, FORK::F_PARAM + 2, 1500.0f, 3100.0f, 2440.0f);
  187. addParam(F3);
  188. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35 - 4 + 25 * 6 + 2), Port::INPUT, module, FORK::F_INPUT + 2));
  189. A3 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35 - 4 + 25 * 6 + 20), module, FORK::A_PARAM + 2, 0.0f, 0.7f, 0.3f);
  190. addParam(A3);
  191. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35 - 4 + 25 * 6 + 20 + 2), Port::INPUT, module, FORK::A_INPUT + 2));
  192. F4 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35 - 6 + 25 * 8), module, FORK::F_PARAM + 3, 3000.0f, 4700.0f, 3400.0f);
  193. addParam(F4);
  194. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35 - 6 + 25 * 8 + 2), Port::INPUT, module, FORK::F_INPUT + 3));
  195. A4 = ParamWidget::create<BidooBlueTrimpot>(Vec(xtpots,35 - 6 + 25 * 8 + 20), module, FORK::A_PARAM + 3, 0.0f, 0.3f, 0.2f);
  196. addParam(A4);
  197. addInput(Port::create<TinyPJ301MPort>(Vec(xtinyports,35 - 6 + 25 * 8 + 20 + 2), Port::INPUT, module, FORK::A_INPUT + 3));
  198. addInput(Port::create<PJ301MPort>(Vec(15,320), Port::INPUT, module, FORK::PITCH_INPUT));
  199. addOutput(Port::create<PJ301MPort>(Vec(50,320), Port::OUTPUT, module, FORK::SIGNAL_OUTPUT));
  200. }
  201. } // namespace rack_plugin_Bidoo
  202. using namespace rack_plugin_Bidoo;
  203. RACK_PLUGIN_MODEL_INIT(Bidoo, FORK) {
  204. Model *modelFORK= Model::create<FORK, FORKWidget>("Bidoo", "ForK", "ForK oscillator", OSCILLATOR_TAG);
  205. return modelFORK;
  206. }