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.

332 lines
12KB

  1. #include "Bidoo.hpp"
  2. #include "BidooComponents.hpp"
  3. #include "dsp/ringbuffer.hpp"
  4. using namespace std;
  5. namespace rack_plugin_Bidoo {
  6. struct BAR : Module {
  7. enum ParamIds {
  8. THRESHOLD_PARAM,
  9. RATIO_PARAM,
  10. ATTACK_PARAM,
  11. RELEASE_PARAM,
  12. KNEE_PARAM,
  13. MAKEUP_PARAM,
  14. MIX_PARAM,
  15. LOOKAHEAD_PARAM,
  16. NUM_PARAMS
  17. };
  18. enum InputIds {
  19. IN_L_INPUT,
  20. IN_R_INPUT,
  21. SC_L_INPUT,
  22. SC_R_INPUT,
  23. NUM_INPUTS
  24. };
  25. enum OutputIds {
  26. OUT_L_OUTPUT,
  27. OUT_R_OUTPUT,
  28. NUM_OUTPUTS
  29. };
  30. enum LightIds {
  31. NUM_LIGHTS
  32. };
  33. DoubleRingBuffer<float,16384> vu_L_Buffer, vu_R_Buffer;
  34. DoubleRingBuffer<float,512> rms_L_Buffer, rms_R_Buffer;
  35. float runningVU_L_Sum = 1e-6f, runningRMS_L_Sum = 1e-6f, rms_L = -96.3f, vu_L = -96.3f, peakL = -96.3f;
  36. float runningVU_R_Sum = 1e-6f, runningRMS_R_Sum = 1e-6f, rms_R = -96.3f, vu_R = -96.3f, peakR = -96.3f;
  37. float in_L_dBFS = 1e-6f;
  38. float in_R_dBFS = 1e-6f;
  39. float dist = 0.0f, gain = 1.0f, gaindB = 1.0f, ratio = 1.0f, threshold = 1.0f, knee = 0.0f;
  40. float attackTime = 0.0f, releaseTime = 0.0f, makeup = 1.0f, previousPostGain = 1.0f, mix = 1.0f;
  41. int indexVU = 0, indexRMS = 0, lookAheadWriteIndex=0;
  42. int maxIndexVU = 0, maxIndexRMS = 0, maxLookAheadWriteIndex=0;
  43. int lookAhead;
  44. float buffL[20000] = {0.0f}, buffR[20000] = {0.0f};
  45. BAR() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  46. }
  47. void step() override;
  48. };
  49. void BAR::step() {
  50. if (indexVU>=16384) {
  51. runningVU_L_Sum -= *vu_L_Buffer.startData();
  52. runningVU_R_Sum -= *vu_R_Buffer.startData();
  53. vu_L_Buffer.startIncr(1);
  54. vu_R_Buffer.startIncr(1);
  55. indexVU--;
  56. }
  57. if (indexRMS>=512) {
  58. runningRMS_L_Sum -= *rms_L_Buffer.startData();
  59. runningRMS_R_Sum -= *rms_R_Buffer.startData();
  60. rms_L_Buffer.startIncr(1);
  61. rms_R_Buffer.startIncr(1);
  62. indexRMS--;
  63. }
  64. indexVU++;
  65. indexRMS++;
  66. buffL[lookAheadWriteIndex]=inputs[IN_L_INPUT].value;
  67. buffR[lookAheadWriteIndex]=inputs[IN_R_INPUT].value;
  68. if (!inputs[SC_L_INPUT].active && inputs[IN_L_INPUT].active)
  69. in_L_dBFS = max(20.0f*log10((abs(inputs[IN_L_INPUT].value)+1e-6f)/5.0f), -96.3f);
  70. else if (inputs[SC_L_INPUT].active)
  71. in_L_dBFS = max(20.0f*log10((abs(inputs[SC_L_INPUT].value)+1e-6f)/5.0f), -96.3f);
  72. else
  73. in_L_dBFS = -96.3f;
  74. if (!inputs[SC_R_INPUT].active && inputs[IN_R_INPUT].active)
  75. in_R_dBFS = max(20.0f*log10((abs(inputs[IN_R_INPUT].value)+1e-6f)/5.0f), -96.3f);
  76. else if (inputs[SC_R_INPUT].active)
  77. in_R_dBFS = max(20.0f*log10((abs(inputs[SC_R_INPUT].value)+1e-6f)/5.0f), -96.3f);
  78. else
  79. in_R_dBFS = -96.3f;
  80. float data_L = in_L_dBFS*in_L_dBFS;
  81. if (!vu_L_Buffer.full()) {
  82. vu_L_Buffer.push(data_L);
  83. }
  84. if (!rms_L_Buffer.full()) {
  85. rms_L_Buffer.push(data_L);
  86. }
  87. float data_R = in_R_dBFS*in_R_dBFS;
  88. if (!vu_R_Buffer.full()) {
  89. vu_R_Buffer.push(data_R);
  90. }
  91. if (!rms_R_Buffer.full()) {
  92. rms_R_Buffer.push(data_R);
  93. }
  94. runningVU_L_Sum += data_L;
  95. runningRMS_L_Sum += data_L;
  96. runningVU_R_Sum += data_R;
  97. runningRMS_R_Sum += data_R;
  98. rms_L = clamp(-1 * sqrtf(runningRMS_L_Sum/512), -96.3f,0.0f);
  99. vu_L = clamp(-1 * sqrtf(runningVU_L_Sum/16384), -96.3f,0.0f);
  100. rms_R = clamp(-1 * sqrtf(runningRMS_R_Sum/512), -96.3f,0.0f);
  101. vu_R = clamp(-1 * sqrtf(runningVU_R_Sum/16384), -96.3f,0.0f);
  102. threshold = params[THRESHOLD_PARAM].value;
  103. attackTime = params[ATTACK_PARAM].value;
  104. releaseTime = params[RELEASE_PARAM].value;
  105. ratio = params[RATIO_PARAM].value;
  106. knee = params[KNEE_PARAM].value;
  107. makeup = params[MAKEUP_PARAM].value;
  108. if (in_L_dBFS>peakL)
  109. peakL=in_L_dBFS;
  110. else
  111. peakL -= 50.0f/engineGetSampleRate();
  112. if (in_R_dBFS>peakR)
  113. peakR=in_R_dBFS;
  114. else
  115. peakR -= 50.0f/engineGetSampleRate();
  116. float slope = 1.0f/ratio-1.0f;
  117. float maxIn = max(in_L_dBFS,in_R_dBFS);
  118. float dist = maxIn-threshold;
  119. float gcurve = 0.0f;
  120. if (dist<-1.0f*knee/2.0f)
  121. gcurve = maxIn;
  122. else if ((dist > -1.0f*knee/2.0f) && (dist < knee/2.0f)) {
  123. gcurve = maxIn + slope * pow(dist + knee/2.0f,2.0f)/(2.0f * knee);
  124. } else {
  125. gcurve = maxIn + slope * dist;
  126. }
  127. float preGain = gcurve - maxIn;
  128. float postGain = 0.0f;
  129. float cAtt = exp(-1.0f/(attackTime*engineGetSampleRate()/1000.0f));
  130. float cRel = exp(-1.0f/(releaseTime*engineGetSampleRate()/1000.0f));
  131. if (preGain>previousPostGain) {
  132. postGain = cAtt * previousPostGain + (1.0f-cAtt) * preGain;
  133. } else {
  134. postGain = cRel * previousPostGain + (1.0f-cRel) * preGain;
  135. }
  136. previousPostGain = postGain;
  137. gaindB = makeup + postGain;
  138. gain = pow(10.0f, gaindB/20.0f);
  139. mix = params[MIX_PARAM].value;
  140. lookAhead = params[LOOKAHEAD_PARAM].value;
  141. int nbSamples = clamp(floor(lookAhead*attackTime*engineGetSampleRate()/100000),0.0f,19999.0f);
  142. int readIndex;
  143. if (lookAheadWriteIndex-nbSamples>=0)
  144. readIndex = (lookAheadWriteIndex-nbSamples)%20000;
  145. else {
  146. readIndex = 20000 - abs(lookAheadWriteIndex-nbSamples);
  147. }
  148. outputs[OUT_L_OUTPUT].value = buffL[readIndex] * (gain*mix + (1.0f-mix));
  149. outputs[OUT_R_OUTPUT].value = buffR[readIndex] * (gain*mix + (1.0f-mix));
  150. lookAheadWriteIndex = (lookAheadWriteIndex+1)%20000;
  151. }
  152. struct BARDisplay : TransparentWidget {
  153. BAR *module;
  154. std::shared_ptr<Font> font;
  155. BARDisplay() {
  156. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  157. }
  158. void draw(NVGcontext *vg) override {
  159. float height = 150.0f;
  160. float width = 15.0f;
  161. float spacer = 3.0f;
  162. float vuL = rescale(module->vu_L,-97.0f,0.0f,0.0f,height);
  163. float rmsL = rescale(module->rms_L,-97.0f,0.0f,0.0f,height);
  164. float vuR = rescale(module->vu_R,-97.0f,0.0f,0.0f,height);
  165. float rmsR = rescale(module->rms_R,-97.0f,0.0f,0.0f,height);
  166. float threshold = rescale(module->threshold,0.0f,-97.0f,0.0f,height);
  167. float gain = rescale(1-(module->gaindB-module->makeup),-97.0f,0.0f,97.0f,0.0f);
  168. float makeup = rescale(module->makeup,0.0f,60.0f,0.0f,60.0f);
  169. float peakL = rescale(module->peakL,0.0f,-97.0f,0.0f,height);
  170. float peakR = rescale(module->peakR,0.0f,-97.0f,0.0f,height);
  171. float inL = rescale(module->in_L_dBFS,-97.0f,0.0f,0.0f,height);
  172. float inR = rescale(module->in_R_dBFS,-97.0f,0.0f,0.0f,height);
  173. nvgStrokeWidth(vg, 0.0f);
  174. nvgBeginPath(vg);
  175. nvgFillColor(vg, BLUE_BIDOO);
  176. nvgRoundedRect(vg,0.0f,height-vuL,width,vuL,0.0f);
  177. nvgRoundedRect(vg,3.0f*(width+spacer),height-vuR,width,vuR,0.0f);
  178. nvgFill(vg);
  179. nvgClosePath(vg);
  180. nvgBeginPath(vg);
  181. nvgFillColor(vg, LIGHTBLUE_BIDOO);
  182. nvgRoundedRect(vg,width+spacer,height-rmsL,width,rmsL,0.0f);
  183. nvgRoundedRect(vg,2.0f*(width+spacer),height-rmsR,width,rmsR,0.0f);
  184. nvgFill(vg);
  185. nvgClosePath(vg);
  186. nvgFillColor(vg, RED_BIDOO);
  187. nvgBeginPath(vg);
  188. nvgRoundedRect(vg,width+spacer,peakL,width,2.0f,0.0f);
  189. nvgRoundedRect(vg,2.0f*(width+spacer),peakR,width,2.0f,0.0f);
  190. nvgFill(vg);
  191. nvgClosePath(vg);
  192. nvgFillColor(vg, ORANGE_BIDOO);
  193. nvgBeginPath(vg);
  194. if (inL>rmsL+3.0f)
  195. nvgRoundedRect(vg,width+spacer,height-inL+1.0f,width,inL-rmsL-2.0f,0.0f);
  196. if (inR>rmsR+3)
  197. nvgRoundedRect(vg,2.0f*(width+spacer),height-inR+1.0f,width,inR-rmsR-2.0f,0.0f);
  198. nvgFill(vg);
  199. nvgClosePath(vg);
  200. nvgStrokeWidth(vg, 0.5f);
  201. nvgFillColor(vg, nvgRGBA(255, 255, 255, 255));
  202. nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 255));
  203. nvgBeginPath(vg);
  204. nvgMoveTo(vg, width+spacer+5.0f, threshold);
  205. nvgLineTo(vg, 3.0f*width+2.0f*spacer-5.0f, threshold);
  206. //nvgRoundedRect(vg,22,threshold+50,22,2,0);
  207. {
  208. nvgMoveTo(vg, width+spacer, threshold-3.0f);
  209. nvgLineTo(vg, width+spacer, threshold+3.0f);
  210. nvgLineTo(vg, width+spacer+5.0f, threshold);
  211. nvgLineTo(vg, width+spacer, threshold-3.0f);
  212. nvgMoveTo(vg, 3.0f*width+2.0f*spacer, threshold-3.0f);
  213. nvgLineTo(vg, 3*width+2*spacer, threshold+3.0f);
  214. nvgLineTo(vg, 3.0f*width+2.0f*spacer-5.0f, threshold);
  215. nvgLineTo(vg, 3.0f*width+2.0f*spacer, threshold-3.0f);
  216. }
  217. nvgClosePath(vg);
  218. nvgStroke(vg);
  219. nvgFill(vg);
  220. float offset = 11.0f;
  221. nvgStrokeWidth(vg, 0.5f);
  222. nvgFillColor(vg, YELLOW_BIDOO);
  223. nvgStrokeColor(vg, YELLOW_BIDOO);
  224. nvgBeginPath(vg);
  225. nvgRoundedRect(vg,4.0f*(width+spacer)+offset,70.0f,width,-gain-makeup,0.0f);
  226. nvgMoveTo(vg, 5.0f*(width+spacer)+7.0f+offset, 70.0f-3.0f);
  227. nvgLineTo(vg, 5.0f*(width+spacer)+7.0f+offset, 70.0f+3.0f);
  228. nvgLineTo(vg, 5.0f*(width+spacer)+2.0f+offset, 70.0f);
  229. nvgLineTo(vg, 5.0f*(width+spacer)+7.0f+offset, 70.0f-3.0f);
  230. nvgClosePath(vg);
  231. nvgStroke(vg);
  232. nvgFill(vg);
  233. char tTresh[128],tRatio[128],tAtt[128],tRel[128],tKnee[128],tMakeUp[128],tMix[128],tLookAhead[128];
  234. snprintf(tTresh, sizeof(tTresh), "%2.1f", module->threshold);
  235. snprintf(tRatio, sizeof(tTresh), "%2.0f:1", module->ratio);
  236. snprintf(tAtt, sizeof(tTresh), "%1.0f/%1.0f", module->attackTime,module->releaseTime);
  237. snprintf(tRel, sizeof(tTresh), "%3.0f", module->releaseTime);
  238. snprintf(tKnee, sizeof(tTresh), "%2.1f", module->knee);
  239. snprintf(tMakeUp, sizeof(tTresh), "%2.1f", module->makeup);
  240. snprintf(tMix, sizeof(tTresh), "%1.0f/%1.0f", (1-module->mix)*100,module->mix*100);
  241. snprintf(tLookAhead, sizeof(tTresh), "%3i", module->lookAhead);
  242. nvgFontSize(vg, 14.0f);
  243. nvgFontFaceId(vg, font->handle);
  244. nvgTextLetterSpacing(vg, -2.0f);
  245. nvgFillColor(vg, YELLOW_BIDOO);
  246. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  247. nvgText(vg, 8.0f, height+31.0f, tTresh, NULL);
  248. nvgText(vg, 50.0f, height+31.0f, tRatio, NULL);
  249. nvgText(vg, 96.0f, height+31.0f, tAtt, NULL);
  250. nvgText(vg, 8.0f, height+63.0f, tKnee, NULL);
  251. nvgText(vg, 40.0f, height+63.0f, tMakeUp, NULL);
  252. nvgText(vg, 75.0f, height+63.0f, tMix, NULL);
  253. nvgText(vg, 107.0f, height+63.0f, tLookAhead, NULL);
  254. }
  255. };
  256. struct BARWidget : ModuleWidget {
  257. BARWidget(BAR *module) : ModuleWidget(module) {
  258. setPanel(SVG::load(assetPlugin(plugin, "res/BAR.svg")));
  259. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  260. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  261. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  262. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  263. BARDisplay *display = new BARDisplay();
  264. display->module = module;
  265. display->box.pos = Vec(12.0f, 40.0f);
  266. display->box.size = Vec(110.0f, 70.0f);
  267. addChild(display);
  268. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(10.0f,265.0f), module, BAR::THRESHOLD_PARAM, -93.6f, 0.0f, 0.0f));
  269. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(42.0f,265.0f), module, BAR::RATIO_PARAM, 1.0f, 20.0f, 0.0f));
  270. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(74.0f,265.0f), module, BAR::ATTACK_PARAM, 1.0f, 100.0f, 10.0f));
  271. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(106.0f,265.0f), module, BAR::RELEASE_PARAM, 1.0f, 300.0f, 10.0f));
  272. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(10.0f,291.0f), module, BAR::KNEE_PARAM, 0.0f, 24.0f, 6.0f));
  273. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(42.0f,291.0f), module, BAR::MAKEUP_PARAM, 0.0f, 60.0f, 0.0f));
  274. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(74.0f,291.0f), module, BAR::MIX_PARAM, 0.0f, 1.0f, 1.0f));
  275. addParam(ParamWidget::create<BidooBlueTrimpot>(Vec(106.0f,291.0f), module, BAR::LOOKAHEAD_PARAM, 0.0f, 200.0f, 0.0f));
  276. //Changed ports opposite way around
  277. addInput(Port::create<TinyPJ301MPort>(Vec(24.0f, 319.0f), Port::INPUT, module, BAR::IN_L_INPUT));
  278. addInput(Port::create<TinyPJ301MPort>(Vec(24.0f, 339.0f), Port::INPUT, module, BAR::IN_R_INPUT));
  279. addInput(Port::create<TinyPJ301MPort>(Vec(66.0f, 319.0f), Port::INPUT, module, BAR::SC_L_INPUT));
  280. addInput(Port::create<TinyPJ301MPort>(Vec(66.0f, 339.0f), Port::INPUT, module, BAR::SC_R_INPUT));
  281. addOutput(Port::create<TinyPJ301MPort>(Vec(109.0f, 319.0f),Port::OUTPUT, module, BAR::OUT_L_OUTPUT));
  282. addOutput(Port::create<TinyPJ301MPort>(Vec(109.0f, 339.0f),Port::OUTPUT, module, BAR::OUT_R_OUTPUT));
  283. }
  284. };
  285. } // namespace rack_plugin_Bidoo
  286. using namespace rack_plugin_Bidoo;
  287. RACK_PLUGIN_MODEL_INIT(Bidoo, BAR) {
  288. Model *modelBAR = Model::create<BAR, BARWidget>("Bidoo", "baR", "bAR compressor", DYNAMICS_TAG);
  289. return modelBAR;
  290. }