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.

396 lines
12KB

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