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.

408 lines
13KB

  1. #pragma once
  2. #include <rack.hpp>
  3. using namespace rack;
  4. extern Plugin* pluginInstance;
  5. extern Model* modelEvenVCO;
  6. extern Model* modelEvenVCO2;
  7. extern Model* modelRampage;
  8. extern Model* modelABC;
  9. extern Model* modelSpringReverb;
  10. extern Model* modelMixer;
  11. extern Model* modelSlewLimiter;
  12. extern Model* modelDualAtenuverter;
  13. extern Model* modelPercall;
  14. extern Model* modelHexmixVCA;
  15. extern Model* modelChoppingKinky;
  16. extern Model* modelKickall;
  17. extern Model* modelSamplingModulator;
  18. extern Model* modelMorphader;
  19. extern Model* modelADSR;
  20. extern Model* modelSTMix;
  21. extern Model* modelMuxlicer;
  22. extern Model* modelMex;
  23. extern Model* modelNoisePlethora;
  24. extern Model* modelChannelStrip;
  25. extern Model* modelPonyVCO;
  26. extern Model* modelMotionMTR;
  27. extern Model* modelBurst;
  28. extern Model* modelMidiThing;
  29. extern Model* modelVoltio;
  30. extern Model* modelOctaves;
  31. struct Knurlie : SvgScrew {
  32. Knurlie() {
  33. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Knurlie.svg")));
  34. }
  35. };
  36. struct BefacoTinyKnobWhite : BefacoTinyKnob {
  37. BefacoTinyKnobWhite() {}
  38. };
  39. struct BefacoTinyKnobRed : BefacoTinyKnob {
  40. BefacoTinyKnobRed() {
  41. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyPointWhite.svg")));
  42. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyKnobRed_bg.svg")));
  43. }
  44. };
  45. struct BefacoTinyKnobDarkGrey : BefacoTinyKnob {
  46. BefacoTinyKnobDarkGrey() {
  47. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyPointWhite.svg")));
  48. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyKnobDarkGrey_bg.svg")));
  49. }
  50. };
  51. struct BefacoTinyKnobLightGrey : BefacoTinyKnob {
  52. BefacoTinyKnobLightGrey() {
  53. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyKnobLightGrey_bg.svg")));
  54. }
  55. };
  56. struct BefacoTinyKnobBlack : BefacoTinyKnob {
  57. BefacoTinyKnobBlack() {
  58. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyPointWhite.svg")));
  59. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoTinyKnobBlack_bg.svg")));
  60. }
  61. };
  62. struct Davies1900hLargeGreyKnob : Davies1900hKnob {
  63. Davies1900hLargeGreyKnob() {
  64. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLargeGrey.svg")));
  65. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLargeGrey_bg.svg")));
  66. }
  67. };
  68. struct Davies1900hLightGreyKnob : Davies1900hKnob {
  69. Davies1900hLightGreyKnob() {
  70. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLightGrey.svg")));
  71. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLightGrey_bg.svg")));
  72. }
  73. };
  74. struct Davies1900hDarkGreyKnob : Davies1900hKnob {
  75. Davies1900hDarkGreyKnob() {
  76. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hDarkGrey.svg")));
  77. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hDarkGrey_bg.svg")));
  78. }
  79. };
  80. /** Deprecated alias */
  81. using Davies1900hDarkBlackAlt = Davies1900hBlackKnob;
  82. struct BananutRed : app::SvgPort {
  83. BananutRed() {
  84. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BananutRed.svg")));
  85. }
  86. };
  87. /** Deprecated alias */
  88. using BefacoOutputPort = BananutRed;
  89. struct BananutBlack : app::SvgPort {
  90. BananutBlack() {
  91. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BananutBlack.svg")));
  92. }
  93. };
  94. /** Deprecated alias */
  95. using BefacoInputPort = BananutBlack;
  96. struct CKSSNarrow : app::SvgSwitch {
  97. CKSSNarrow() {
  98. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_0.svg")));
  99. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_2.svg")));
  100. }
  101. };
  102. struct Crossfader : app::SvgSlider {
  103. Crossfader() {
  104. setBackgroundSvg(Svg::load(asset::plugin(pluginInstance, "res/components/CrossfaderBackground.svg")));
  105. setHandleSvg(Svg::load(asset::plugin(pluginInstance, "res/components/CrossfaderHandle.svg")));
  106. minHandlePos = mm2px(Vec(4.5f, -0.8f));
  107. maxHandlePos = mm2px(Vec(34.5, -0.8f));
  108. horizontal = true;
  109. math::Vec margin = math::Vec(15, 5);
  110. background->box.pos = margin;
  111. box.size = background->box.size.plus(margin.mult(2));
  112. }
  113. };
  114. struct BefacoSwitchHorizontal : app::SvgSwitch {
  115. BefacoSwitchHorizontal() {
  116. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoSwitchHoriz_0.svg")));
  117. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoSwitchHoriz_1.svg")));
  118. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoSwitchHoriz_2.svg")));
  119. }
  120. };
  121. struct CKSSHoriz2 : app::SvgSwitch {
  122. CKSSHoriz2() {
  123. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrowHoriz_0.svg")));
  124. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrowHoriz_1.svg")));
  125. }
  126. };
  127. struct CKSSVert7 : app::SvgSlider {
  128. CKSSVert7() {
  129. math::Vec margin = math::Vec(3.5, 3.5);
  130. maxHandlePos = math::Vec(1, 1).plus(margin);
  131. minHandlePos = math::Vec(1, 45).plus(margin);
  132. setBackgroundSvg(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchTallVert_bg.svg")));
  133. setHandleSvg(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchTallVert_fg.svg")));
  134. background->box.pos = margin;
  135. box.size = background->box.size.plus(margin.mult(2));
  136. }
  137. // disable double click as this messes with click to advance
  138. void onDoubleClick(const event::DoubleClick& e) override { }
  139. // cycle through the values (with reset) on click only (not drag)
  140. void onAction(const ActionEvent& e) override {
  141. ParamQuantity* paramQuantity = getParamQuantity();
  142. float range = paramQuantity->maxValue - paramQuantity->minValue;
  143. float newValue = paramQuantity->getValue() + 1.f;
  144. if (newValue > paramQuantity->maxValue) {
  145. newValue -= range + 1.f;
  146. }
  147. paramQuantity->setValue(newValue);
  148. }
  149. };
  150. struct CKSSHoriz4 : app::SvgSlider {
  151. CKSSHoriz4() {
  152. setBackgroundSvg(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchWideHoriz_bg.svg")));
  153. setHandleSvg(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchWideHoriz_fg.svg")));
  154. minHandlePos = mm2px(Vec(0.3f, 0.3f));
  155. maxHandlePos = mm2px(Vec(6.3f, 0.3f));
  156. horizontal = true;
  157. math::Vec margin = math::Vec(0, 0);
  158. background->box.pos = margin;
  159. box.size = background->box.size.plus(margin.mult(2));
  160. }
  161. // disable double click as this messes with click to advance
  162. void onDoubleClick(const event::DoubleClick& e) override { }
  163. // cycle through the values (with reset) on click only (not drag)
  164. void onAction(const ActionEvent& e) override {
  165. ParamQuantity* paramQuantity = getParamQuantity();
  166. float range = paramQuantity->maxValue - paramQuantity->minValue;
  167. float newValue = paramQuantity->getValue() + 1.f;
  168. if (newValue > paramQuantity->maxValue) {
  169. newValue -= range + 1.f;
  170. }
  171. paramQuantity->setValue(newValue);
  172. }
  173. };
  174. struct CKSSNarrow3 : app::SvgSwitch {
  175. CKSSNarrow3() {
  176. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_0.svg")));
  177. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_1.svg")));
  178. addFrame(Svg::load(asset::plugin(pluginInstance, "res/components/SwitchNarrow_2.svg")));
  179. }
  180. };
  181. struct Davies1900hLargeLightGreyKnob : Davies1900hKnob {
  182. Davies1900hLargeLightGreyKnob() {
  183. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLargeLightGrey.svg")));
  184. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hLargeLightGrey_bg.svg")));
  185. }
  186. };
  187. struct BefacoSlidePotSmall : app::SvgSlider {
  188. BefacoSlidePotSmall() {
  189. math::Vec margin = math::Vec(3.5, 3.5);
  190. maxHandlePos = math::Vec(-2, -2).plus(margin);
  191. minHandlePos = math::Vec(-2, 60).plus(margin);
  192. setBackgroundSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoSlidePotSmall.svg")));
  193. setHandleSvg(Svg::load(asset::plugin(pluginInstance, "res/components/BefacoSlidePotHandleSmall.svg")));
  194. background->box.pos = margin;
  195. box.size = background->box.size.plus(margin.mult(2));
  196. }
  197. };
  198. struct BefacoButton : app::SvgSwitch {
  199. BefacoButton() {
  200. momentary = true;
  201. addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/BefacoButton_0.svg")));
  202. addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/BefacoButton_1.svg")));
  203. }
  204. };
  205. struct Davies1900hWhiteKnobEndless : Davies1900hKnob {
  206. Davies1900hWhiteKnobEndless() {
  207. setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hWhiteEndless.svg")));
  208. bg->setSvg(Svg::load(asset::plugin(pluginInstance, "res/components/Davies1900hWhiteEndless_bg.svg")));
  209. }
  210. };
  211. inline int unsigned_modulo(int a, int b) {
  212. return ((a % b) + b) % b;
  213. }
  214. template <typename T>
  215. T sin2pi_pade_05_5_4(T x) {
  216. x -= 0.5f;
  217. return (T(-6.283185307) * x + T(33.19863968) * simd::pow(x, 3) - T(32.44191367) * simd::pow(x, 5))
  218. / (1 + T(1.296008659) * simd::pow(x, 2) + T(0.7028072946) * simd::pow(x, 4));
  219. }
  220. template <typename T>
  221. T tanh_pade(T x) {
  222. T x2 = x * x;
  223. T q = 12.f + x2;
  224. return 12.f * x * q / (36.f * x2 + q * q);
  225. }
  226. template <typename T>
  227. T exponentialBipolar80Pade_5_4(T x) {
  228. return (T(0.109568) * x + T(0.281588) * simd::pow(x, 3) + T(0.133841) * simd::pow(x, 5))
  229. / (T(1.) - T(0.630374) * simd::pow(x, 2) + T(0.166271) * simd::pow(x, 4));
  230. }
  231. struct ADEnvelope {
  232. enum Stage {
  233. STAGE_OFF,
  234. STAGE_ATTACK,
  235. STAGE_DECAY
  236. };
  237. Stage stage = STAGE_OFF;
  238. float env = 0.f;
  239. float attackTime = 0.1, decayTime = 0.1;
  240. float attackShape = 1.0, decayShape = 1.0;
  241. ADEnvelope() { };
  242. void process(const float& sampleTime) {
  243. if (stage == STAGE_OFF) {
  244. env = envLinear = 0.0f;
  245. }
  246. else if (stage == STAGE_ATTACK) {
  247. envLinear += sampleTime / attackTime;
  248. env = std::pow(envLinear, attackShape);
  249. }
  250. else if (stage == STAGE_DECAY) {
  251. envLinear -= sampleTime / decayTime;
  252. env = std::pow(envLinear, decayShape);
  253. }
  254. if (envLinear >= 1.0f) {
  255. stage = STAGE_DECAY;
  256. env = envLinear = 1.0f;
  257. }
  258. else if (envLinear <= 0.0f) {
  259. stage = STAGE_OFF;
  260. env = envLinear = 0.0f;
  261. }
  262. }
  263. void trigger() {
  264. stage = ADEnvelope::STAGE_ATTACK;
  265. // non-linear envelopes won't retrigger at the correct starting point if
  266. // attackShape != decayShape, so we advance the linear envelope
  267. envLinear = std::pow(env, 1.0f / attackShape);
  268. }
  269. private:
  270. float envLinear = 0.f;
  271. };
  272. // Creates a Butterworth 2*Nth order highpass filter for blocking DC
  273. template<int N>
  274. struct DCBlockerT {
  275. DCBlockerT() {
  276. setFrequency(0.1f);
  277. }
  278. // set frequency (in normalised units, 0 < fc < 1)
  279. void setFrequency(float fc) {
  280. fc_ = fc;
  281. recalculateCoefficients();
  282. }
  283. float process(float x) {
  284. for (int idx = 0; idx < N; idx++) {
  285. x = blockDCFilter[idx].process(x);
  286. }
  287. return x;
  288. }
  289. private:
  290. // https://www.earlevel.com/main/2016/09/29/cascading-filters/
  291. void recalculateCoefficients() {
  292. float poleInc = M_PI / order;
  293. float firstAngle = poleInc / 2;
  294. for (int idx = 0; idx < N; idx++) {
  295. float Q = 1.0f / (2.0f * std::cos(firstAngle + idx * poleInc));
  296. blockDCFilter[idx].setParameters(dsp::BiquadFilter::HIGHPASS, fc_, Q, 1.0f);
  297. }
  298. }
  299. float fc_;
  300. static const int order = 2 * N;
  301. dsp::BiquadFilter blockDCFilter[N];
  302. };
  303. typedef DCBlockerT<2> DCBlocker;
  304. /** When triggered, holds a high value for a specified time before going low again */
  305. struct PulseGenerator_4 {
  306. simd::float_4 remaining = 0.f;
  307. /** Immediately disables the pulse */
  308. void reset() {
  309. remaining = 0.f;
  310. }
  311. /** Advances the state by `deltaTime`. Returns whether the pulse is in the HIGH state. */
  312. simd::float_4 process(float deltaTime) {
  313. simd::float_4 mask = (remaining > 0.f);
  314. remaining -= ifelse(mask, deltaTime, 0.f);
  315. return ifelse(mask, simd::float_4::mask(), 0.f);
  316. }
  317. /** Begins a trigger with the given `duration`. */
  318. void trigger(simd::float_4 mask, float duration = 1e-3f) {
  319. // Keep the previous pulse if the existing pulse will be held longer than the currently requested one.
  320. remaining = ifelse(mask & (duration > remaining), duration, remaining);
  321. }
  322. };
  323. // Zavalishin 2018, "The Art of VA Filter Design", http://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_2.0.0a.pdf
  324. // Section 6.7, adopted from BogAudio Saturator https://github.com/bogaudio/BogaudioModules/blob/master/src/dsp/signal.cpp
  325. template <class T>
  326. struct Saturator {
  327. // saturate input at around ~[-1, +1] V with soft clipping
  328. static T process(T sample) {
  329. return simd::ifelse(sample < 0.f, -saturation(-sample), saturation(sample));
  330. }
  331. private:
  332. static T saturation(T sample) {
  333. const float limit = 1.05f;
  334. const float y1 = 0.98765f; // (2*x - 1)/x**2 where x is 0.9.
  335. // correction so that saturation(0) = 0
  336. const float offset = 0.0062522; // -0.5f + sqrtf(0.5f * 0.5f) / y1;
  337. T x = sample / limit;
  338. T x1 = (x + 1.0f) * 0.5f;
  339. return limit * (offset + x1 - simd::sqrt(x1 * x1 - y1 * x) * (1.0f / y1));
  340. }
  341. };