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.

248 lines
8.0KB

  1. #include "plugin.hpp"
  2. using simd::float_4;
  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_4 phase[4];
  27. float_4 tri[4];
  28. /** The value of the last sync input */
  29. float sync = 0.0;
  30. /** The outputs */
  31. /** Whether we are past the pulse width already */
  32. bool halfPhase[PORT_MAX_CHANNELS];
  33. dsp::MinBlepGenerator<16, 32> triSquareMinBlep[PORT_MAX_CHANNELS];
  34. dsp::MinBlepGenerator<16, 32> triMinBlep[PORT_MAX_CHANNELS];
  35. dsp::MinBlepGenerator<16, 32> sineMinBlep[PORT_MAX_CHANNELS];
  36. dsp::MinBlepGenerator<16, 32> doubleSawMinBlep[PORT_MAX_CHANNELS];
  37. dsp::MinBlepGenerator<16, 32> sawMinBlep[PORT_MAX_CHANNELS];
  38. dsp::MinBlepGenerator<16, 32> squareMinBlep[PORT_MAX_CHANNELS];
  39. dsp::RCFilter triFilter;
  40. EvenVCO() {
  41. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
  42. configParam(OCTAVE_PARAM, -5.0, 4.0, 0.0, "Octave", "'", 0.5);
  43. configParam(TUNE_PARAM, -7.0, 7.0, 0.0, "Tune", " semitones");
  44. configParam(PWM_PARAM, -1.0, 1.0, 0.0, "Pulse width");
  45. for (int i = 0; i < 4; i++) {
  46. phase[i] = 0.f;
  47. tri[i] = 0.f;
  48. }
  49. for (int c = 0; c < PORT_MAX_CHANNELS; c++)
  50. halfPhase[c] = false;
  51. }
  52. void process(const ProcessArgs& args) override {
  53. int channels_pitch1 = inputs[PITCH1_INPUT].getChannels();
  54. int channels_pitch2 = inputs[PITCH2_INPUT].getChannels();
  55. int channels = 1;
  56. channels = std::max(channels, channels_pitch1);
  57. channels = std::max(channels, channels_pitch2);
  58. float pitch_0 = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f;
  59. // Compute frequency, pitch is 1V/oct
  60. float_4 pitch[4];
  61. for (int c = 0; c < channels; c += 4)
  62. pitch[c / 4] = float_4(pitch_0);
  63. if (inputs[PITCH1_INPUT].isConnected()) {
  64. for (int c = 0; c < channels; c += 4)
  65. pitch[c / 4] += inputs[PITCH1_INPUT].getPolyVoltageSimd<float_4>(c);
  66. }
  67. if (inputs[PITCH2_INPUT].isConnected()) {
  68. for (int c = 0; c < channels; c += 4)
  69. pitch[c / 4] += inputs[PITCH2_INPUT].getPolyVoltageSimd<float_4>(c);
  70. }
  71. if (inputs[FM_INPUT].isConnected()) {
  72. for (int c = 0; c < channels; c += 4)
  73. pitch[c / 4] += inputs[FM_INPUT].getPolyVoltageSimd<float_4>(c) / 4.f;
  74. }
  75. float_4 freq[4];
  76. for (int c = 0; c < channels; c += 4) {
  77. freq[c / 4] = dsp::FREQ_C4 * simd::pow(2.f, pitch[c / 4]);
  78. freq[c / 4] = clamp(freq[c / 4], 0.f, 20000.f);
  79. }
  80. // Pulse width
  81. float pw_0 = params[PWM_PARAM].getValue();
  82. float_4 pw[4];
  83. for (int c = 0; c < channels; c += 4)
  84. pw[c / 4] = float_4(pw_0);
  85. if (inputs[PWM_INPUT].isConnected()) {
  86. for (int c = 0; c < channels; c += 4)
  87. pw[c / 4] += inputs[PWM_INPUT].getPolyVoltageSimd<float_4>(c) / 5.f;
  88. }
  89. const float_4 minPw_4 = float_4(0.05f);
  90. const float_4 m_one_4 = float_4(-1.0f);
  91. const float_4 one_4 = float_4(1.0f);
  92. float_4 deltaPhase[4];
  93. float_4 oldPhase[4];
  94. for (int c = 0; c < channels; c += 4) {
  95. pw[c / 4] = rescale(clamp(pw[c / 4], m_one_4, one_4), m_one_4, one_4, minPw_4, one_4 - minPw_4);
  96. // Advance phase
  97. deltaPhase[c / 4] = clamp(freq[c / 4] * args.sampleTime, float_4(1e-6f), float_4(0.5f));
  98. oldPhase[c / 4] = phase[c / 4];
  99. phase[c / 4] += deltaPhase[c / 4];
  100. }
  101. // the next block can't be done with SIMD instructions:
  102. for (int c = 0; c < channels; c++) {
  103. if (oldPhase[c / 4].s[c % 4] < 0.5 && phase[c / 4].s[c % 4] >= 0.5) {
  104. float crossing = -(phase[c / 4].s[c % 4] - 0.5) / deltaPhase[c / 4].s[c % 4];
  105. triSquareMinBlep[c].insertDiscontinuity(crossing, 2.f);
  106. doubleSawMinBlep[c].insertDiscontinuity(crossing, -2.f);
  107. }
  108. if (!halfPhase[c] && phase[c / 4].s[c % 4] >= pw[c / 4].s[c % 4]) {
  109. float crossing = -(phase[c / 4].s[c % 4] - pw[c / 4].s[c % 4]) / deltaPhase[c / 4].s[c % 4];
  110. squareMinBlep[c].insertDiscontinuity(crossing, 2.f);
  111. halfPhase[c] = true;
  112. }
  113. // Reset phase if at end of cycle
  114. if (phase[c / 4].s[c % 4] >= 1.f) {
  115. phase[c / 4].s[c % 4] -= 1.f;
  116. float crossing = -phase[c / 4].s[c % 4] / deltaPhase[c / 4].s[c % 4];
  117. triSquareMinBlep[c].insertDiscontinuity(crossing, -2.f);
  118. doubleSawMinBlep[c].insertDiscontinuity(crossing, -2.f);
  119. squareMinBlep[c].insertDiscontinuity(crossing, -2.f);
  120. sawMinBlep[c].insertDiscontinuity(crossing, -2.f);
  121. halfPhase[c] = false;
  122. }
  123. }
  124. float_4 triSquareMinBlepOut[4];
  125. float_4 doubleSawMinBlepOut[4];
  126. float_4 sawMinBlepOut[4];
  127. float_4 squareMinBlepOut[4];
  128. float_4 triSquare[4];
  129. float_4 sine[4];
  130. float_4 doubleSaw[4];
  131. float_4 even[4];
  132. float_4 saw[4];
  133. float_4 square[4];
  134. float_4 triOut[4];
  135. for (int c = 0; c < channels; c++) {
  136. triSquareMinBlepOut[c / 4].s[c % 4] = triSquareMinBlep[c].process();
  137. doubleSawMinBlepOut[c / 4].s[c % 4] = doubleSawMinBlep[c].process();
  138. sawMinBlepOut[c / 4].s[c % 4] = sawMinBlep[c].process();
  139. squareMinBlepOut[c / 4].s[c % 4] = squareMinBlep[c].process();
  140. }
  141. // Outputs
  142. outputs[TRI_OUTPUT].setChannels(channels);
  143. outputs[SINE_OUTPUT].setChannels(channels);
  144. outputs[EVEN_OUTPUT].setChannels(channels);
  145. outputs[SAW_OUTPUT].setChannels(channels);
  146. outputs[SQUARE_OUTPUT].setChannels(channels);
  147. for (int c = 0; c < channels; c += 4) {
  148. triSquare[c / 4] = simd::ifelse((phase[c / 4] < 0.5f * one_4), m_one_4, one_4);
  149. triSquare[c / 4] += triSquareMinBlepOut[c / 4];
  150. // Integrate square for triangle
  151. tri[c / 4] += (4.f * triSquare[c / 4]) * (freq[c / 4] * args.sampleTime);
  152. tri[c / 4] *= (1.f - 40.f * args.sampleTime);
  153. triOut[c / 4] = 5.f * tri[c / 4];
  154. sine[c / 4] = 5.f * simd::cos(2 * M_PI * phase[c / 4]);
  155. doubleSaw[c / 4] = simd::ifelse((phase[c / 4] < 0.5), (-1.f + 4.f * phase[c / 4]), (-1.f + 4.f * (phase[c / 4] - 0.5f)));
  156. doubleSaw[c / 4] += doubleSawMinBlepOut[c / 4];
  157. doubleSaw[c / 4] *= 5.f;
  158. even[c / 4] = 0.55 * (doubleSaw[c / 4] + 1.27 * sine[c / 4]);
  159. saw[c / 4] = -1.f + 2.f * phase[c / 4];
  160. saw[c / 4] += sawMinBlepOut[c / 4];
  161. saw[c / 4] *= 5.f;
  162. square[c / 4] = simd::ifelse((phase[c / 4] < pw[c / 4]), m_one_4, one_4) ;
  163. square[c / 4] += squareMinBlepOut[c / 4];
  164. square[c / 4] *= 5.f;
  165. // Set outputs
  166. outputs[TRI_OUTPUT].setVoltageSimd(triOut[c / 4], c);
  167. outputs[SINE_OUTPUT].setVoltageSimd(sine[c / 4], c);
  168. outputs[EVEN_OUTPUT].setVoltageSimd(even[c / 4], c);
  169. outputs[SAW_OUTPUT].setVoltageSimd(saw[c / 4], c);
  170. outputs[SQUARE_OUTPUT].setVoltageSimd(square[c / 4], c);
  171. }
  172. }
  173. };
  174. struct EvenVCOWidget : ModuleWidget {
  175. EvenVCOWidget(EvenVCO* module) {
  176. setModule(module);
  177. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/EvenVCO.svg")));
  178. addChild(createWidget<Knurlie>(Vec(15, 0)));
  179. addChild(createWidget<Knurlie>(Vec(15, 365)));
  180. addChild(createWidget<Knurlie>(Vec(15 * 6, 0)));
  181. addChild(createWidget<Knurlie>(Vec(15 * 6, 365)));
  182. addParam(createParam<BefacoBigSnapKnob>(Vec(22, 32), module, EvenVCO::OCTAVE_PARAM));
  183. addParam(createParam<BefacoTinyKnob>(Vec(73, 131), module, EvenVCO::TUNE_PARAM));
  184. addParam(createParam<Davies1900hRedKnob>(Vec(16, 230), module, EvenVCO::PWM_PARAM));
  185. addInput(createInput<BefacoInputPort>(Vec(8, 120), module, EvenVCO::PITCH1_INPUT));
  186. addInput(createInput<BefacoInputPort>(Vec(19, 157), module, EvenVCO::PITCH2_INPUT));
  187. addInput(createInput<BefacoInputPort>(Vec(48, 183), module, EvenVCO::FM_INPUT));
  188. addInput(createInput<BefacoInputPort>(Vec(86, 189), module, EvenVCO::SYNC_INPUT));
  189. addInput(createInput<BefacoInputPort>(Vec(72, 236), module, EvenVCO::PWM_INPUT));
  190. addOutput(createOutput<BefacoOutputPort>(Vec(10, 283), module, EvenVCO::TRI_OUTPUT));
  191. addOutput(createOutput<BefacoOutputPort>(Vec(87, 283), module, EvenVCO::SINE_OUTPUT));
  192. addOutput(createOutput<BefacoOutputPort>(Vec(48, 306), module, EvenVCO::EVEN_OUTPUT));
  193. addOutput(createOutput<BefacoOutputPort>(Vec(10, 327), module, EvenVCO::SAW_OUTPUT));
  194. addOutput(createOutput<BefacoOutputPort>(Vec(87, 327), module, EvenVCO::SQUARE_OUTPUT));
  195. }
  196. };
  197. Model* modelEvenVCO = createModel<EvenVCO, EvenVCOWidget>("EvenVCO");