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.

164 lines
5.1KB

  1. #include "Bidoo.hpp"
  2. #include "BidooComponents.hpp"
  3. #include "dsp/decimator.hpp"
  4. #include "dep/filters/biquad.h"
  5. using namespace std;
  6. namespace rack_plugin_Bidoo {
  7. #define BANDS 16
  8. struct ZINC : Module {
  9. enum ParamIds {
  10. BG_PARAM,
  11. ATTACK_PARAM = BG_PARAM + BANDS,
  12. DECAY_PARAM,
  13. Q_PARAM,
  14. GMOD_PARAM,
  15. GCARR_PARAM,
  16. G_PARAM,
  17. SHAPE_PARAM,
  18. NUM_PARAMS
  19. };
  20. enum InputIds {
  21. IN_MOD,
  22. IN_CARR,
  23. NUM_INPUTS
  24. };
  25. enum OutputIds {
  26. OUT,
  27. NUM_OUTPUTS
  28. };
  29. enum LightIds {
  30. LEARN_LIGHT,
  31. NUM_LIGHTS
  32. };
  33. Biquad* iFilter[2*BANDS];
  34. Biquad* cFilter[2*BANDS];
  35. float mem[BANDS] = {0.0f};
  36. float freq[BANDS] = {125.0f,185.0f,270.0f,350.0f,430.0f,530.0f,630.0f,780.0f,950.0f,1150.0f,1380.0f,1680.0f,2070.0f,2780.0f,3800.0f,6400.0f};
  37. float peaks[BANDS] = {0.0f};
  38. ZINC() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  39. for(int i=0; i<2*BANDS; i++) {
  40. iFilter[i] = new Biquad(bq_type_bandpass, freq[i%BANDS] / engineGetSampleRate(), 5.0, 6.0);
  41. cFilter[i] = new Biquad(bq_type_bandpass, freq[i%BANDS] / engineGetSampleRate(), 5.0, 6.0);
  42. }
  43. }
  44. void step() override;
  45. };
  46. void ZINC::step() {
  47. float inM = inputs[IN_MOD].value/5.0f;
  48. float inC = inputs[IN_CARR].value/5.0f;
  49. const float slewMin = 0.001f;
  50. const float slewMax = 500.0f;
  51. const float shapeScale = 1.0f/10.0f;
  52. float attack = params[ATTACK_PARAM].value;
  53. float decay = params[DECAY_PARAM].value;
  54. float slewAttack = slewMax * powf(slewMin / slewMax, attack);
  55. float slewDecay = slewMax * powf(slewMin / slewMax, decay);
  56. float out = 0.0f;
  57. for(int i=0; i<BANDS; i++) {
  58. float coeff = mem[i];
  59. float peak = abs(iFilter[i+BANDS]->process(iFilter[i]->process(inM*params[GMOD_PARAM].value)));
  60. if (peak>coeff) {
  61. coeff += slewAttack * shapeScale * (peak - coeff) / engineGetSampleRate();
  62. if (coeff > peak)
  63. coeff = peak;
  64. }
  65. else if (peak < coeff) {
  66. coeff -= slewDecay * shapeScale * (coeff - peak) / engineGetSampleRate();
  67. if (coeff < peak)
  68. coeff = peak;
  69. }
  70. peaks[i]=peak;
  71. mem[i]=coeff;
  72. out += cFilter[i+BANDS]->process(cFilter[i]->process(inC*params[GCARR_PARAM].value)) * coeff * params[BG_PARAM+i].value;
  73. }
  74. outputs[OUT].value = out * 5.0f * params[G_PARAM].value;
  75. }
  76. struct ZINCDisplay : TransparentWidget {
  77. ZINC *module;
  78. std::shared_ptr<Font> font;
  79. ZINCDisplay() {
  80. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  81. }
  82. void draw(NVGcontext *vg) override {
  83. nvgFontSize(vg, 12);
  84. nvgFontFaceId(vg, font->handle);
  85. nvgStrokeWidth(vg, 2);
  86. nvgTextLetterSpacing(vg, -2);
  87. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  88. static const int portX0[4] = {20, 63, 106, 149};
  89. for (int i=0; i<BANDS; i++) {
  90. char fVal[10];
  91. snprintf(fVal, sizeof(fVal), "%1i", (int)module->freq[i]);
  92. nvgFillColor(vg,nvgRGBA(0, 0, 0, 255));
  93. nvgText(vg, portX0[i%(BANDS/4)]+1, 35+43*(int)(i/4), fVal, NULL);
  94. }
  95. }
  96. };
  97. struct ZINCWidget : ModuleWidget {
  98. ParamWidget *controls[16];
  99. void step() override;
  100. ZINCWidget(ZINC *module) : ModuleWidget(module) {
  101. setPanel(SVG::load(assetPlugin(plugin, "res/ZINC.svg")));
  102. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  103. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  104. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  105. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  106. ZINCDisplay *display = new ZINCDisplay();
  107. display->module = module;
  108. display->box.pos = Vec(12, 12);
  109. display->box.size = Vec(110, 70);
  110. addChild(display);
  111. static const float portX0[4] = {20, 63, 106, 149};
  112. for (int i = 0; i < BANDS; i++) {
  113. controls[i]=ParamWidget::create<BidooziNCColoredKnob>(Vec(portX0[i%(BANDS/4)]+2, 50+43*(int)(i/4)+2), module, ZINC::BG_PARAM + i, 0, 2, 1);
  114. BidooziNCColoredKnob *control = dynamic_cast<BidooziNCColoredKnob*>(controls[i]);
  115. control->coeff=module->peaks+i;
  116. addParam(controls[i]);
  117. }
  118. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(portX0[1]+4, 230), module, ZINC::ATTACK_PARAM, 0.0, 0.25, 0.0));
  119. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(portX0[2]+4, 230), module, ZINC::DECAY_PARAM, 0.0, 0.25, 0.0));
  120. addParam(ParamWidget::create<BidooBlueKnob>(Vec(portX0[0]+20, 268), module, ZINC::GMOD_PARAM, 1, 10, 1));
  121. addParam(ParamWidget::create<BidooBlueKnob>(Vec(portX0[1]+20, 268), module, ZINC::GCARR_PARAM, 1, 10, 1));
  122. addParam(ParamWidget::create<BidooBlueKnob>(Vec(portX0[2]+20, 268), module, ZINC::G_PARAM, 1, 10, 1));
  123. addInput(Port::create<PJ301MPort>(Vec(portX0[0]+27.5, 320), Port::INPUT, module, ZINC::IN_MOD));
  124. addInput(Port::create<PJ301MPort>(Vec(portX0[1]+22.5, 320), Port::INPUT, module, ZINC::IN_CARR));
  125. addOutput(Port::create<PJ301MPort>(Vec(portX0[2]+16.5, 320), Port::OUTPUT, module, ZINC::OUT));
  126. }
  127. };
  128. void ZINCWidget::step() {
  129. for (int i = 0; i < BANDS; i++) {
  130. BidooziNCColoredKnob* knob = dynamic_cast<BidooziNCColoredKnob*>(controls[i]);
  131. knob->dirty = true;
  132. }
  133. ModuleWidget::step();
  134. }
  135. } // namespace rack_plugin_Bidoo
  136. using namespace rack_plugin_Bidoo;
  137. RACK_PLUGIN_MODEL_INIT(Bidoo, ZINC) {
  138. Model *modelZINC = Model::create<ZINC, ZINCWidget>("Bidoo", "ziNC", "ziNC vocoder", EFFECT_TAG, VOCODER_TAG);
  139. return modelZINC;
  140. }