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.

188 lines
6.4KB

  1. #include "LFO.hpp"
  2. #include "dsp/pitch.hpp"
  3. void LFO::onReset() {
  4. _resetTrigger.reset();
  5. _modulationStep = modulationSteps;
  6. _sampleStep = _phasor._sampleRate;
  7. }
  8. void LFO::onSampleRateChange() {
  9. _phasor.setSampleRate(engineGetSampleRate());
  10. _modulationStep = modulationSteps;
  11. _sampleStep = _phasor._sampleRate;
  12. }
  13. void LFO::step() {
  14. lights[SLOW_LIGHT].value = _slowMode = params[SLOW_PARAM].value > 0.5f;
  15. if (!(
  16. outputs[SINE_OUTPUT].active ||
  17. outputs[TRIANGLE_OUTPUT].active ||
  18. outputs[RAMP_UP_OUTPUT].active ||
  19. outputs[RAMP_DOWN_OUTPUT].active ||
  20. outputs[SQUARE_OUTPUT].active
  21. )) {
  22. return;
  23. }
  24. ++_modulationStep;
  25. if (_modulationStep >= modulationSteps) {
  26. _modulationStep = 0;
  27. float frequency = params[FREQUENCY_PARAM].value;
  28. if (inputs[PITCH_INPUT].active) {
  29. frequency += inputs[PITCH_INPUT].value;
  30. }
  31. if (_slowMode) {
  32. frequency -= 8.0f;
  33. }
  34. else {
  35. frequency -= 4.0f;
  36. }
  37. frequency = cvToFrequency(frequency);
  38. if (frequency > 2000.0f) {
  39. frequency = 2000.0f;
  40. }
  41. _phasor.setFrequency(frequency);
  42. float pw = params[PW_PARAM].value;
  43. if (inputs[PW_INPUT].active) {
  44. pw *= clamp(inputs[PW_INPUT].value / 5.0f, -1.0f, 1.0f);
  45. }
  46. pw *= 1.0f - 2.0f * _square.minPulseWidth;
  47. pw *= 0.5f;
  48. pw += 0.5f;
  49. _square.setPulseWidth(pw);
  50. float sample = params[SAMPLE_PARAM].value;
  51. if (inputs[SAMPLE_INPUT].active) {
  52. sample *= clamp(inputs[SAMPLE_INPUT].value / 10.0f, 0.0f, 1.0f);
  53. }
  54. float maxSampleSteps = (_phasor._sampleRate / _phasor._frequency) / 4.0f;
  55. _sampleSteps = clamp((int)(sample * maxSampleSteps), 1, (int)maxSampleSteps);
  56. _offset = params[OFFSET_PARAM].value;
  57. if (inputs[OFFSET_INPUT].active) {
  58. _offset *= clamp(inputs[OFFSET_INPUT].value / 5.0f, -1.0f, 1.0f);
  59. }
  60. _offset *= 5.0f;
  61. _scale = params[SCALE_PARAM].value;
  62. if (inputs[SCALE_INPUT].active) {
  63. _scale *= clamp(inputs[SCALE_INPUT].value / 10.0f, 0.0f, 1.0f);
  64. }
  65. }
  66. if (_resetTrigger.next(inputs[RESET_INPUT].value)) {
  67. _phasor.resetPhase();
  68. }
  69. _phasor.advancePhase();
  70. bool useSample = false;
  71. if (_sampleSteps > 1) {
  72. ++_sampleStep;
  73. if (_sampleStep >= _sampleSteps) {
  74. _sampleStep = 0;
  75. }
  76. else {
  77. useSample = true;
  78. }
  79. }
  80. updateOutput(_sine, useSample, false, outputs[SINE_OUTPUT], _sineSample, _sineActive);
  81. updateOutput(_triangle, useSample, false, outputs[TRIANGLE_OUTPUT], _triangleSample, _triangleActive);
  82. updateOutput(_ramp, useSample, false, outputs[RAMP_UP_OUTPUT], _rampUpSample, _rampUpActive);
  83. updateOutput(_ramp, useSample, true, outputs[RAMP_DOWN_OUTPUT], _rampDownSample, _rampDownActive);
  84. updateOutput(_square, false, false, outputs[SQUARE_OUTPUT], _squareSample, _squareActive);
  85. }
  86. void LFO::updateOutput(Phasor& wave, bool useSample, bool invert, Output& output, float& sample, bool& active) {
  87. if (output.active) {
  88. if (useSample && active) {
  89. output.value = sample;
  90. }
  91. else {
  92. sample = wave.nextFromPhasor(_phasor) * amplitude * _scale + (invert ? -_offset : _offset);
  93. if (invert) {
  94. sample = -sample;
  95. }
  96. output.value = sample;
  97. }
  98. active = true;
  99. }
  100. else {
  101. active = false;
  102. }
  103. }
  104. struct LFOWidget : ModuleWidget {
  105. static constexpr int hp = 10;
  106. LFOWidget(LFO* module) : ModuleWidget(module) {
  107. box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
  108. {
  109. SVGPanel *panel = new SVGPanel();
  110. panel->box.size = box.size;
  111. panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO.svg")));
  112. addChild(panel);
  113. }
  114. addChild(Widget::create<ScrewSilver>(Vec(0, 0)));
  115. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 0)));
  116. addChild(Widget::create<ScrewSilver>(Vec(0, 365)));
  117. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15, 365)));
  118. // generated by svg_widgets.rb
  119. auto frequencyParamPosition = Vec(41.0, 45.0);
  120. auto slowParamPosition = Vec(120.0, 249.0);
  121. auto sampleParamPosition = Vec(37.0, 150.0);
  122. auto pwParamPosition = Vec(102.0, 150.0);
  123. auto offsetParamPosition = Vec(42.0, 196.0);
  124. auto scaleParamPosition = Vec(107.0, 196.0);
  125. auto sampleInputPosition = Vec(15.0, 230.0);
  126. auto pwInputPosition = Vec(47.0, 230.0);
  127. auto offsetInputPosition = Vec(15.0, 274.0);
  128. auto scaleInputPosition = Vec(47.0, 274.0);
  129. auto pitchInputPosition = Vec(15.0, 318.0);
  130. auto resetInputPosition = Vec(47.0, 318.0);
  131. auto rampDownOutputPosition = Vec(79.0, 230.0);
  132. auto rampUpOutputPosition = Vec(79.0, 274.0);
  133. auto squareOutputPosition = Vec(111.0, 274.0);
  134. auto triangleOutputPosition = Vec(79.0, 318.0);
  135. auto sineOutputPosition = Vec(111.0, 318.0);
  136. auto slowLightPosition = Vec(111.0, 240.0);
  137. // end generated by svg_widgets.rb
  138. addParam(ParamWidget::create<Knob68>(frequencyParamPosition, module, LFO::FREQUENCY_PARAM, -8.0, 5.0, 0.0));
  139. addParam(ParamWidget::create<StatefulButton9>(slowParamPosition, module, LFO::SLOW_PARAM, 0.0, 1.0, 0.0));
  140. addParam(ParamWidget::create<Knob26>(sampleParamPosition, module, LFO::SAMPLE_PARAM, 0.0, 1.0, 0.0));
  141. addParam(ParamWidget::create<Knob26>(pwParamPosition, module, LFO::PW_PARAM, -1.0, 1.0, 0.0));
  142. addParam(ParamWidget::create<Knob16>(offsetParamPosition, module, LFO::OFFSET_PARAM, -1.0, 1.0, 0.0));
  143. addParam(ParamWidget::create<Knob16>(scaleParamPosition, module, LFO::SCALE_PARAM, 0.0, 1.0, 1.0));
  144. addInput(Port::create<Port24>(sampleInputPosition, Port::INPUT, module, LFO::SAMPLE_INPUT));
  145. addInput(Port::create<Port24>(pwInputPosition, Port::INPUT, module, LFO::PW_INPUT));
  146. addInput(Port::create<Port24>(offsetInputPosition, Port::INPUT, module, LFO::OFFSET_INPUT));
  147. addInput(Port::create<Port24>(scaleInputPosition, Port::INPUT, module, LFO::SCALE_INPUT));
  148. addInput(Port::create<Port24>(pitchInputPosition, Port::INPUT, module, LFO::PITCH_INPUT));
  149. addInput(Port::create<Port24>(resetInputPosition, Port::INPUT, module, LFO::RESET_INPUT));
  150. addOutput(Port::create<Port24>(rampUpOutputPosition, Port::OUTPUT, module, LFO::RAMP_UP_OUTPUT));
  151. addOutput(Port::create<Port24>(rampDownOutputPosition, Port::OUTPUT, module, LFO::RAMP_DOWN_OUTPUT));
  152. addOutput(Port::create<Port24>(squareOutputPosition, Port::OUTPUT, module, LFO::SQUARE_OUTPUT));
  153. addOutput(Port::create<Port24>(triangleOutputPosition, Port::OUTPUT, module, LFO::TRIANGLE_OUTPUT));
  154. addOutput(Port::create<Port24>(sineOutputPosition, Port::OUTPUT, module, LFO::SINE_OUTPUT));
  155. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(slowLightPosition, module, LFO::SLOW_LIGHT));
  156. }
  157. };
  158. RACK_PLUGIN_MODEL_INIT(Bogaudio, LFO) {
  159. Model *modelLFO = createModel<LFO, LFOWidget>("Bogaudio-LFO", "LFO", "low-frequency oscillator", LFO_TAG);
  160. return modelLFO;
  161. }