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.

268 lines
7.8KB

  1. #include "../dsp/Oscillator.hpp"
  2. #include "../LindenbergResearch.hpp"
  3. #include "../LRModel.hpp"
  4. namespace rack_plugin_LindenbergResearch {
  5. using namespace lrt;
  6. using dsp::DSPBLOscillator;
  7. struct VCO : LRModule {
  8. enum ParamIds {
  9. FREQUENCY_PARAM,
  10. OCTAVE_PARAM,
  11. FM_CV_PARAM,
  12. PW_CV_PARAM,
  13. SAW_PARAM,
  14. PULSE_PARAM,
  15. SINE_PARAM,
  16. TRI_PARAM,
  17. NUM_PARAMS
  18. };
  19. enum InputIds {
  20. VOCT1_INPUT,
  21. FM_CV_INPUT,
  22. PW_CV_INPUT,
  23. VOCT2_INPUT,
  24. NUM_INPUTS
  25. };
  26. enum OutputIds {
  27. SAW_OUTPUT,
  28. PULSE_OUTPUT,
  29. SINE_OUTPUT,
  30. TRI_OUTPUT,
  31. NOISE_OUTPUT,
  32. MIX_OUTPUT,
  33. NUM_OUTPUTS
  34. };
  35. enum LightIds {
  36. LFO_LIGHT,
  37. NUM_LIGHTS
  38. };
  39. dsp::DSPBLOscillator *osc = new dsp::DSPBLOscillator(engineGetSampleRate());
  40. LRLCDWidget *lcd = new LRLCDWidget(10, "%00004.3f Hz", LRLCDWidget::NUMERIC, LCD_FONTSIZE);
  41. LRBigKnob *frqKnob = NULL;
  42. VCO() : LRModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  43. frqKnob = LRKnob::create<LRBigKnob>(Vec(126.0, 64.7), this, VCO::FREQUENCY_PARAM, -1.f, 1.f, 0.f);
  44. }
  45. /*
  46. json_t *toJson() override {
  47. json_t *rootJ = LRModule::toJson();
  48. json_object_set_new(rootJ, "AGED", json_boolean(AGED));
  49. return rootJ;
  50. }
  51. void fromJson(json_t *rootJ) override {
  52. LRModule::fromJson(rootJ);
  53. json_t *agedJ = json_object_get(rootJ, "AGED");
  54. if (agedJ)
  55. AGED = json_boolean_value(agedJ);
  56. updateComponents();
  57. }*/
  58. void onRandomize() override;
  59. void step() override;
  60. void onSampleRateChange() override;
  61. };
  62. void VCO::step() {
  63. Module::step();
  64. float fm = clamp(inputs[FM_CV_INPUT].value, -CV_BOUNDS, CV_BOUNDS) * 0.4f * quadraticBipolar(params[FM_CV_PARAM].value);
  65. float tune = params[FREQUENCY_PARAM].value;
  66. float pw;
  67. if (inputs[PW_CV_INPUT].active) {
  68. pw = clamp(inputs[PW_CV_INPUT].value, -CV_BOUNDS, CV_BOUNDS) * 0.6f * quadraticBipolar(params[PW_CV_PARAM].value / 2.f) + 1;
  69. pw = clamp(pw, 0.01, 1.99);
  70. } else {
  71. pw = params[PW_CV_PARAM].value * 0.99f + 1;
  72. }
  73. if (frqKnob != NULL) {
  74. frqKnob->setIndicatorActive(inputs[FM_CV_INPUT].active);
  75. frqKnob->setIndicatorValue((params[FREQUENCY_PARAM].value + 1) / 2 + (fm / 2));
  76. }
  77. osc->setInputs(inputs[VOCT1_INPUT].value, inputs[VOCT2_INPUT].value, fm, tune, params[OCTAVE_PARAM].value);
  78. osc->setPulseWidth(pw);
  79. osc->process();
  80. outputs[SAW_OUTPUT].value = osc->getSawWave();
  81. outputs[PULSE_OUTPUT].value = osc->getPulseWave();
  82. outputs[SINE_OUTPUT].value = osc->getSineWave();
  83. outputs[TRI_OUTPUT].value = osc->getTriWave();
  84. outputs[NOISE_OUTPUT].value = osc->getNoise();
  85. if (outputs[MIX_OUTPUT].active) {
  86. float mix = 0.f;
  87. mix += osc->getSawWave() * params[SAW_PARAM].value;
  88. mix += osc->getPulseWave() * params[PULSE_PARAM].value;
  89. mix += osc->getSineWave() * params[SINE_PARAM].value;
  90. mix += osc->getTriWave() * params[TRI_PARAM].value;
  91. outputs[MIX_OUTPUT].value = mix;
  92. }
  93. /* for LFO mode */
  94. if (osc->isLFO())
  95. lights[LFO_LIGHT].setBrightnessSmooth(osc->getSineWave() / 10.f + 0.3f);
  96. else lights[LFO_LIGHT].value = 0.f;
  97. lcd->active = osc->isLFO();
  98. lcd->value = osc->getFrequency();
  99. }
  100. void VCO::onSampleRateChange() {
  101. Module::onSampleRateChange();
  102. osc->updateSampleRate(engineGetSampleRate());
  103. }
  104. void VCO::onRandomize() {
  105. Module::randomize();
  106. }
  107. /**
  108. * @brief Woldemar VCO Widget
  109. */
  110. struct VCOWidget : LRModuleWidget {
  111. VCOWidget(VCO *module);
  112. };
  113. VCOWidget::VCOWidget(VCO *module) : LRModuleWidget(module) {
  114. panel->addSVGVariant(LRGestalt::DARK, SVG::load(assetPlugin(plugin, "res/panels/VCO.svg")));
  115. panel->addSVGVariant(LRGestalt::LIGHT, SVG::load(assetPlugin(plugin, "res/panels/Woldemar.svg")));
  116. panel->addSVGVariant(LRGestalt::AGED, SVG::load(assetPlugin(plugin, "res/panels/WoldemarAged.svg")));
  117. panel->init();
  118. box.size = panel->box.size;
  119. addChild(panel);
  120. panel->visible = true;
  121. panel->dirty = true;
  122. /* panel->setInner(nvgRGBAf(0.3, 0.3, 0.f, 0.09f));
  123. panel->setOuter(nvgRGBAf(0.f, 0.f, 0.f, 0.7f));
  124. module->panelAged->setInner(nvgRGBAf(0.5, 0.5, 0.f, 0.1f));
  125. module->panelAged->setOuter(nvgRGBAf(0.f, 0.f, 0.f, 0.73f));*/
  126. // **** SETUP LCD ********
  127. module->lcd->box.pos = Vec(22, 222);
  128. module->lcd->format = "%00004.3f Hz";
  129. addChild(module->lcd);
  130. // **** SETUP LCD ********
  131. // ***** SCREWS **********
  132. addChild(Widget::create<ScrewLight>(Vec(15, 1)));
  133. addChild(Widget::create<ScrewLight>(Vec(box.size.x - 30, 1)));
  134. addChild(Widget::create<ScrewLight>(Vec(15, 366)));
  135. addChild(Widget::create<ScrewLight>(Vec(box.size.x - 30, 366)));
  136. // ***** SCREWS **********
  137. // ***** MAIN KNOBS ******
  138. addParam(module->frqKnob);
  139. addParam(LRKnob::create<LRToggleKnob>(Vec(133, 170.5), module, VCO::OCTAVE_PARAM, -4.f, 3.f, 0.f));
  140. addParam(LRKnob::create<LRSmallKnob>(Vec(69.5, 122), module, VCO::FM_CV_PARAM, -1.f, 1.f, 0.f));
  141. addParam(LRKnob::create<LRSmallKnob>(Vec(69.5, 175), module, VCO::PW_CV_PARAM, -1, 1, 0.f));
  142. addParam(LRKnob::create<LRSmallKnob>(Vec(22.8, 270.1), module, VCO::SAW_PARAM, -1.f, 1.f, 0.f));
  143. addParam(LRKnob::create<LRSmallKnob>(Vec(58.3, 270.1), module, VCO::PULSE_PARAM, -1.f, 1.f, 0.f));
  144. addParam(LRKnob::create<LRSmallKnob>(Vec(93.1, 270.1), module, VCO::SINE_PARAM, -1.f, 1.f, 0.f));
  145. addParam(LRKnob::create<LRSmallKnob>(Vec(128.1, 270.1), module, VCO::TRI_PARAM, -1.f, 1.f, 0.f));
  146. // ***** MAIN KNOBS ******
  147. // ***** INPUTS **********
  148. addInput(Port::create<LRIOPortCV>(Vec(20.8, 67.9), Port::INPUT, module, VCO::VOCT1_INPUT));
  149. addInput(Port::create<LRIOPortCV>(Vec(68.0, 67.9), Port::INPUT, module, VCO::VOCT2_INPUT));
  150. addInput(Port::create<LRIOPortCV>(Vec(20.8, 121.5), Port::INPUT, module, VCO::FM_CV_INPUT));
  151. addInput(Port::create<LRIOPortCV>(Vec(20.8, 174.8), Port::INPUT, module, VCO::PW_CV_INPUT));
  152. // ***** INPUTS **********
  153. // ***** OUTPUTS *********
  154. addOutput(Port::create<LRIOPortAudio>(Vec(21, 305.8), Port::OUTPUT, module, VCO::SAW_OUTPUT));
  155. addOutput(Port::create<LRIOPortAudio>(Vec(56.8, 305.8), Port::OUTPUT, module, VCO::PULSE_OUTPUT));
  156. addOutput(Port::create<LRIOPortAudio>(Vec(91.6, 305.8), Port::OUTPUT, module, VCO::SINE_OUTPUT));
  157. addOutput(Port::create<LRIOPortAudio>(Vec(126.6, 305.8), Port::OUTPUT, module, VCO::TRI_OUTPUT));
  158. addOutput(Port::create<LRIOPortAudio>(Vec(162.0, 305.8), Port::OUTPUT, module, VCO::NOISE_OUTPUT));
  159. addOutput(Port::create<LRIOPortAudio>(Vec(162.0, 269.1), Port::OUTPUT, module, VCO::MIX_OUTPUT));
  160. // ***** OUTPUTS *********
  161. // ***** LIGHTS **********
  162. addChild(ModuleLightWidget::create<LRLight>(Vec(181.8, 210), module, VCO::LFO_LIGHT));
  163. // ***** LIGHTS **********
  164. }
  165. /*
  166. struct VCOAged : MenuItem {
  167. VCO *vco;
  168. void onAction(EventAction &e) override {
  169. if (vco->AGED) {
  170. vco->AGED = false;
  171. } else {
  172. vco->AGED = true;
  173. }
  174. vco->updateComponents();
  175. }
  176. void step() override {
  177. rightText = CHECKMARK(vco->AGED);
  178. }
  179. };
  180. void VCOWidget::appendContextMenu(Menu *menu) {
  181. menu->addChild(MenuEntry::create());
  182. VCO *vco = dynamic_cast<VCO *>(module);
  183. assert(vco);
  184. VCOAged *mergeItemAged = MenuItem::create<VCOAged>("Use AGED look");
  185. mergeItemAged->vco = vco;
  186. menu->addChild(mergeItemAged);
  187. }*/
  188. } // namespace rack_plugin_LindenbergResearch
  189. using namespace rack_plugin_LindenbergResearch;
  190. RACK_PLUGIN_MODEL_INIT(LindenbergResearch, VCO) {
  191. Model *modelVCO = Model::create<VCO, VCOWidget>("Lindenberg Research", "VCO", "Woldemar VCO", OSCILLATOR_TAG);
  192. return modelVCO;
  193. }