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.1KB

  1. #include "dsp/Oscillator.hpp"
  2. #include "LindenbergResearch.hpp"
  3. namespace rack_plugin_LindenbergResearch {
  4. using namespace lrt;
  5. struct VCO : LRModule {
  6. enum ParamIds {
  7. FREQUENCY_PARAM,
  8. OCTAVE_PARAM,
  9. FM_CV_PARAM,
  10. PW_CV_PARAM,
  11. SAW_PARAM,
  12. PULSE_PARAM,
  13. SINE_PARAM,
  14. TRI_PARAM,
  15. NUM_PARAMS
  16. };
  17. enum InputIds {
  18. VOCT1_INPUT,
  19. FM_CV_INPUT,
  20. PW_CV_INPUT,
  21. VOCT2_INPUT,
  22. NUM_INPUTS
  23. };
  24. enum OutputIds {
  25. SAW_OUTPUT,
  26. PULSE_OUTPUT,
  27. SINE_OUTPUT,
  28. TRI_OUTPUT,
  29. NOISE_OUTPUT,
  30. MIX_OUTPUT,
  31. NUM_OUTPUTS
  32. };
  33. enum LightIds {
  34. LFO_LIGHT,
  35. NUM_LIGHTS
  36. };
  37. dsp::DSPBLOscillator *osc = new dsp::DSPBLOscillator(engineGetSampleRate());
  38. LRLCDWidget *lcd = new LRLCDWidget(nvgRGBAf(0.9, 0.2, 0.1, 1.0), 9, "%00004.3f Hz", LRLCDWidget::NUMERIC);
  39. LRBigKnob *frqKnob = NULL;
  40. VCO() : LRModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  41. void step() override;
  42. void onSampleRateChange() override;
  43. };
  44. void VCO::step() {
  45. LRModule::step();
  46. float fm = clamp(inputs[FM_CV_INPUT].value, -CV_BOUNDS, CV_BOUNDS) * 0.4f * quadraticBipolar(params[FM_CV_PARAM].value);
  47. float tune = params[FREQUENCY_PARAM].value;
  48. float pw;
  49. if (inputs[PW_CV_INPUT].active) {
  50. pw = clamp(inputs[PW_CV_INPUT].value, -CV_BOUNDS, CV_BOUNDS) * 0.6f * quadraticBipolar(params[PW_CV_PARAM].value / 2.f) + 1;
  51. pw = clamp(pw, 0.01, 1.99);
  52. } else {
  53. pw = params[PW_CV_PARAM].value * 0.99f + 1;
  54. }
  55. if (frqKnob != NULL) {
  56. frqKnob->setIndicatorActive(inputs[FM_CV_INPUT].active);
  57. frqKnob->setIndicatorValue((params[FREQUENCY_PARAM].value + 1) / 2 + (fm / 2));
  58. }
  59. osc->setInputs(inputs[VOCT1_INPUT].value, inputs[VOCT2_INPUT].value, fm, tune, params[OCTAVE_PARAM].value);
  60. osc->setPulseWidth(pw);
  61. osc->process();
  62. outputs[SAW_OUTPUT].value = osc->getSawWave();
  63. outputs[PULSE_OUTPUT].value = osc->getPulseWave();
  64. outputs[SINE_OUTPUT].value = osc->getSineWave();
  65. outputs[TRI_OUTPUT].value = osc->getTriWave();
  66. outputs[NOISE_OUTPUT].value = osc->getNoise();
  67. if (outputs[MIX_OUTPUT].active) {
  68. float mix = 0.f;
  69. mix += osc->getSawWave() * params[SAW_PARAM].value;
  70. mix += osc->getPulseWave() * params[PULSE_PARAM].value;
  71. mix += osc->getSineWave() * params[SINE_PARAM].value;
  72. mix += osc->getTriWave() * params[TRI_PARAM].value;
  73. outputs[MIX_OUTPUT].value = mix;
  74. }
  75. /* for LFO mode */
  76. if (osc->isLFO())
  77. lights[LFO_LIGHT].setBrightnessSmooth(osc->getSineWave() / 10.f + 0.3f);
  78. else lights[LFO_LIGHT].value = 0.f;
  79. lcd->active = osc->isLFO();
  80. lcd->value = osc->getFrequency();
  81. }
  82. void VCO::onSampleRateChange() {
  83. Module::onSampleRateChange();
  84. osc->updateSampleRate(engineGetSampleRate());
  85. }
  86. /**
  87. * @brief Woldemar VCO Widget
  88. */
  89. struct VCOWidget : LRModuleWidget {
  90. VCOWidget(VCO *module);
  91. };
  92. VCOWidget::VCOWidget(VCO *module) : LRModuleWidget(module) {
  93. panel = new LRPanel(20, 40);
  94. panel->setBackground(SVG::load(assetPlugin(plugin, "res/VCO.svg")));
  95. addChild(panel);
  96. box.size = panel->box.size;
  97. // **** SETUP LCD ********
  98. module->lcd->box.pos = Vec(24, 239);
  99. module->lcd->format = "%00004.3f Hz";
  100. addChild(module->lcd);
  101. // **** SETUP LCD ********
  102. // ***** SCREWS **********
  103. addChild(Widget::create<ScrewDarkA>(Vec(15, 1)));
  104. addChild(Widget::create<ScrewDarkA>(Vec(box.size.x - 30, 1)));
  105. addChild(Widget::create<ScrewDarkA>(Vec(15, 366)));
  106. addChild(Widget::create<ScrewDarkA>(Vec(box.size.x - 30, 366)));
  107. // ***** SCREWS **********
  108. // ***** MAIN KNOBS ******
  109. module->frqKnob = LRKnob::create<LRBigKnob>(Vec(126.0, 64.7), module, VCO::FREQUENCY_PARAM, -1.f, 1.f, 0.f);
  110. addParam(module->frqKnob);
  111. addParam(ParamWidget::create<LRToggleKnob>(Vec(134.6, 171.9), module, VCO::OCTAVE_PARAM, -4.f, 3.f, 0.f));
  112. addParam(ParamWidget::create<LRSmallKnob>(Vec(69.5, 121.5), module, VCO::FM_CV_PARAM, -1.f, 1.f, 0.f));
  113. addParam(ParamWidget::create<LRSmallKnob>(Vec(69.5, 174.8), module, VCO::PW_CV_PARAM, -1, 1, 0.f));
  114. addParam(ParamWidget::create<LRSmallKnob>(Vec(22.8, 270.1), module, VCO::SAW_PARAM, -1.f, 1.f, 0.f));
  115. addParam(ParamWidget::create<LRSmallKnob>(Vec(58.3, 270.1), module, VCO::PULSE_PARAM, -1.f, 1.f, 0.f));
  116. addParam(ParamWidget::create<LRSmallKnob>(Vec(93.1, 270.1), module, VCO::SINE_PARAM, -1.f, 1.f, 0.f));
  117. addParam(ParamWidget::create<LRSmallKnob>(Vec(128.1, 270.1), module, VCO::TRI_PARAM, -1.f, 1.f, 0.f));
  118. // ***** MAIN KNOBS ******
  119. // ***** INPUTS **********
  120. addInput(Port::create<LRIOPort>(Vec(20.8, 67.9), Port::INPUT, module, VCO::VOCT1_INPUT));
  121. addInput(Port::create<LRIOPort>(Vec(68.0, 67.9), Port::INPUT, module, VCO::VOCT2_INPUT));
  122. addInput(Port::create<LRIOPort>(Vec(20.8, 121.5), Port::INPUT, module, VCO::FM_CV_INPUT));
  123. addInput(Port::create<LRIOPort>(Vec(20.8, 174.8), Port::INPUT, module, VCO::PW_CV_INPUT));
  124. // ***** INPUTS **********
  125. // ***** OUTPUTS *********
  126. addOutput(Port::create<LRIOPort>(Vec(21, 305.8), Port::OUTPUT, module, VCO::SAW_OUTPUT));
  127. addOutput(Port::create<LRIOPort>(Vec(56.8, 305.8), Port::OUTPUT, module, VCO::PULSE_OUTPUT));
  128. addOutput(Port::create<LRIOPort>(Vec(91.6, 305.8), Port::OUTPUT, module, VCO::SINE_OUTPUT));
  129. addOutput(Port::create<LRIOPort>(Vec(126.6, 305.8), Port::OUTPUT, module, VCO::TRI_OUTPUT));
  130. addOutput(Port::create<LRIOPort>(Vec(162.0, 305.8), Port::OUTPUT, module, VCO::NOISE_OUTPUT));
  131. addOutput(Port::create<LRIOPort>(Vec(162.0, 269.1), Port::OUTPUT, module, VCO::MIX_OUTPUT));
  132. // ***** OUTPUTS *********
  133. // ***** LIGHTS **********
  134. addChild(ModuleLightWidget::create<LRLight>(Vec(181.8, 210), module, VCO::LFO_LIGHT));
  135. }
  136. } // namespace rack_plugin_LindenbergResearch
  137. using namespace rack_plugin_LindenbergResearch;
  138. RACK_PLUGIN_MODEL_INIT(LindenbergResearch, VCO) {
  139. Model *modelVCO = Model::create<VCO, VCOWidget>("Lindenberg Research", "VCO", "Woldemar VCO", OSCILLATOR_TAG);
  140. return modelVCO;
  141. }