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.

167 lines
4.9KB

  1. #include "Befaco.hpp"
  2. #include "dsp.hpp"
  3. struct EvenVCO : Module {
  4. enum ParamIds {
  5. OCTAVE_PARAM,
  6. TUNE_PARAM,
  7. PWM_PARAM,
  8. NUM_PARAMS
  9. };
  10. enum InputIds {
  11. PITCH1_INPUT,
  12. PITCH2_INPUT,
  13. FM_INPUT,
  14. SYNC_INPUT,
  15. PWM_INPUT,
  16. NUM_INPUTS
  17. };
  18. enum OutputIds {
  19. TRI_OUTPUT,
  20. SINE_OUTPUT,
  21. EVEN_OUTPUT,
  22. SAW_OUTPUT,
  23. SQUARE_OUTPUT,
  24. NUM_OUTPUTS
  25. };
  26. float phase = 0.0;
  27. /** The value of the last sync input */
  28. float sync = 0.0;
  29. /** The outputs */
  30. float tri = 0.0;
  31. /** Whether we are past the pulse width already */
  32. bool halfPhase = false;
  33. MinBLEP<16> triSquareMinBLEP;
  34. MinBLEP<16> triMinBLEP;
  35. MinBLEP<16> sineMinBLEP;
  36. MinBLEP<16> doubleSawMinBLEP;
  37. MinBLEP<16> sawMinBLEP;
  38. MinBLEP<16> squareMinBLEP;
  39. RCFilter triFilter;
  40. EvenVCO();
  41. void step();
  42. };
  43. EvenVCO::EvenVCO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  44. triSquareMinBLEP.minblep = minblep_16_32;
  45. triSquareMinBLEP.oversample = 32;
  46. triMinBLEP.minblep = minblep_16_32;
  47. triMinBLEP.oversample = 32;
  48. sineMinBLEP.minblep = minblep_16_32;
  49. sineMinBLEP.oversample = 32;
  50. doubleSawMinBLEP.minblep = minblep_16_32;
  51. doubleSawMinBLEP.oversample = 32;
  52. sawMinBLEP.minblep = minblep_16_32;
  53. sawMinBLEP.oversample = 32;
  54. squareMinBLEP.minblep = minblep_16_32;
  55. squareMinBLEP.oversample = 32;
  56. }
  57. void EvenVCO::step() {
  58. // Compute frequency, pitch is 1V/oct
  59. float pitch = 1.0 + roundf(params[OCTAVE_PARAM].value) + params[TUNE_PARAM].value / 12.0;
  60. pitch += inputs[PITCH1_INPUT].value + inputs[PITCH2_INPUT].value;
  61. pitch += inputs[FM_INPUT].value / 4.0;
  62. float freq = 261.626 * powf(2.0, pitch);
  63. freq = clampf(freq, 0.0, 20000.0);
  64. // Pulse width
  65. float pw = params[PWM_PARAM].value + inputs[PWM_INPUT].value / 5.0;
  66. const float minPw = 0.05;
  67. pw = rescalef(clampf(pw, -1.0, 1.0), -1.0, 1.0, minPw, 1.0-minPw);
  68. // Advance phase
  69. float deltaPhase = clampf(freq / gSampleRate, 1e-6, 0.5);
  70. float oldPhase = phase;
  71. phase += deltaPhase;
  72. if (oldPhase < 0.5 && phase >= 0.5) {
  73. float crossing = -(phase - 0.5) / deltaPhase;
  74. triSquareMinBLEP.jump(crossing, 2.0);
  75. doubleSawMinBLEP.jump(crossing, -2.0);
  76. }
  77. if (!halfPhase && phase >= pw) {
  78. float crossing = -(phase - pw) / deltaPhase;
  79. squareMinBLEP.jump(crossing, 2.0);
  80. halfPhase = true;
  81. }
  82. // Reset phase if at end of cycle
  83. if (phase >= 1.0) {
  84. phase -= 1.0;
  85. float crossing = -phase / deltaPhase;
  86. triSquareMinBLEP.jump(crossing, -2.0);
  87. doubleSawMinBLEP.jump(crossing, -2.0);
  88. squareMinBLEP.jump(crossing, -2.0);
  89. sawMinBLEP.jump(crossing, -2.0);
  90. halfPhase = false;
  91. }
  92. // Outputs
  93. float triSquare = (phase < 0.5) ? -1.0 : 1.0;
  94. triSquare += triSquareMinBLEP.shift();
  95. // Integrate square for triangle
  96. tri += 4.0 * triSquare * freq / gSampleRate;
  97. tri *= (1.0 - 40.0 / gSampleRate);
  98. float sine = -cosf(2*M_PI * phase);
  99. float doubleSaw = (phase < 0.5) ? (-1.0 + 4.0*phase) : (-1.0 + 4.0*(phase - 0.5));
  100. doubleSaw += doubleSawMinBLEP.shift();
  101. float even = 0.55 * (doubleSaw + 1.27 * sine);
  102. float saw = -1.0 + 2.0*phase;
  103. saw += sawMinBLEP.shift();
  104. float square = (phase < pw) ? -1.0 : 1.0;
  105. square += squareMinBLEP.shift();
  106. // Set outputs
  107. outputs[TRI_OUTPUT].value = 5.0*tri;
  108. outputs[SINE_OUTPUT].value = 5.0*sine;
  109. outputs[EVEN_OUTPUT].value = 5.0*even;
  110. outputs[SAW_OUTPUT].value = 5.0*saw;
  111. outputs[SQUARE_OUTPUT].value = 5.0*square;
  112. }
  113. EvenVCOWidget::EvenVCOWidget() {
  114. EvenVCO *module = new EvenVCO();
  115. setModule(module);
  116. box.size = Vec(15*8, 380);
  117. {
  118. SVGPanel *panel = new SVGPanel();
  119. panel->box.size = box.size;
  120. panel->setBackground(SVG::load(assetPlugin(plugin, "res/EvenVCO.svg")));
  121. addChild(panel);
  122. }
  123. addChild(createScrew<ScrewBlack>(Vec(15, 0)));
  124. addChild(createScrew<ScrewBlack>(Vec(15, 365)));
  125. addChild(createScrew<ScrewBlack>(Vec(15*6, 0)));
  126. addChild(createScrew<ScrewBlack>(Vec(15*6, 365)));
  127. addParam(createParam<BefacoBigSnapKnob>(Vec(24-4+2, 35-4+1), module, EvenVCO::OCTAVE_PARAM, -5.0, 4.0, 0.0));
  128. addParam(createParam<BefacoTinyKnob>(Vec(73, 131), module, EvenVCO::TUNE_PARAM, -7.0, 7.0, 0.0));
  129. addParam(createParam<Davies1900hRedKnob>(Vec(16, 230), module, EvenVCO::PWM_PARAM, -1.0, 1.0, 0.0));
  130. addInput(createInput<PJ3410Port>(Vec(13-7-1, 124-7), module, EvenVCO::PITCH1_INPUT));
  131. addInput(createInput<PJ3410Port>(Vec(22-7, 162-7-1), module, EvenVCO::PITCH2_INPUT));
  132. addInput(createInput<PJ3410Port>(Vec(51-7, 188-7-1), module, EvenVCO::FM_INPUT));
  133. addInput(createInput<PJ3410Port>(Vec(88-7, 193-7), module, EvenVCO::SYNC_INPUT));
  134. addInput(createInput<PJ3410Port>(Vec(76-7, 240-7), module, EvenVCO::PWM_INPUT));
  135. addOutput(createOutput<PJ3410Port>(Vec(12-7, 285-7), module, EvenVCO::TRI_OUTPUT));
  136. addOutput(createOutput<PJ3410Port>(Vec(88-7+1, 285-7), module, EvenVCO::SINE_OUTPUT));
  137. addOutput(createOutput<PJ3410Port>(Vec(50-7+1, 308-7), module, EvenVCO::EVEN_OUTPUT));
  138. addOutput(createOutput<PJ3410Port>(Vec(12-7, 329-7), module, EvenVCO::SAW_OUTPUT));
  139. addOutput(createOutput<PJ3410Port>(Vec(88-7+1, 329-7), module, EvenVCO::SQUARE_OUTPUT));
  140. }