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.

415 lines
13KB

  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. extern Model* modelMidiThing;
  28. extern Model* modelVoltio;
  29. extern Model* modelOctaves;
  30. extern Model* modelBypass;
  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. template <typename TBase = WhiteLight>
  212. struct VeryLargeSimpleLight : TBase {
  213. VeryLargeSimpleLight() {
  214. this->box.size = mm2px(math::Vec(7, 7));
  215. }
  216. };
  217. inline int unsigned_modulo(int a, int b) {
  218. return ((a % b) + b) % b;
  219. }
  220. template <typename T>
  221. T sin2pi_pade_05_5_4(T x) {
  222. x -= 0.5f;
  223. return (T(-6.283185307) * x + T(33.19863968) * simd::pow(x, 3) - T(32.44191367) * simd::pow(x, 5))
  224. / (1 + T(1.296008659) * simd::pow(x, 2) + T(0.7028072946) * simd::pow(x, 4));
  225. }
  226. template <typename T>
  227. T tanh_pade(T x) {
  228. T x2 = x * x;
  229. T q = 12.f + x2;
  230. return 12.f * x * q / (36.f * x2 + q * q);
  231. }
  232. template <typename T>
  233. T exponentialBipolar80Pade_5_4(T x) {
  234. return (T(0.109568) * x + T(0.281588) * simd::pow(x, 3) + T(0.133841) * simd::pow(x, 5))
  235. / (T(1.) - T(0.630374) * simd::pow(x, 2) + T(0.166271) * simd::pow(x, 4));
  236. }
  237. struct ADEnvelope {
  238. enum Stage {
  239. STAGE_OFF,
  240. STAGE_ATTACK,
  241. STAGE_DECAY
  242. };
  243. Stage stage = STAGE_OFF;
  244. float env = 0.f;
  245. float attackTime = 0.1, decayTime = 0.1;
  246. float attackShape = 1.0, decayShape = 1.0;
  247. ADEnvelope() { };
  248. void process(const float& sampleTime) {
  249. if (stage == STAGE_OFF) {
  250. env = envLinear = 0.0f;
  251. }
  252. else if (stage == STAGE_ATTACK) {
  253. envLinear += sampleTime / attackTime;
  254. env = std::pow(envLinear, attackShape);
  255. }
  256. else if (stage == STAGE_DECAY) {
  257. envLinear -= sampleTime / decayTime;
  258. env = std::pow(envLinear, decayShape);
  259. }
  260. if (envLinear >= 1.0f) {
  261. stage = STAGE_DECAY;
  262. env = envLinear = 1.0f;
  263. }
  264. else if (envLinear <= 0.0f) {
  265. stage = STAGE_OFF;
  266. env = envLinear = 0.0f;
  267. }
  268. }
  269. void trigger() {
  270. stage = ADEnvelope::STAGE_ATTACK;
  271. // non-linear envelopes won't retrigger at the correct starting point if
  272. // attackShape != decayShape, so we advance the linear envelope
  273. envLinear = std::pow(env, 1.0f / attackShape);
  274. }
  275. private:
  276. float envLinear = 0.f;
  277. };
  278. // Creates a Butterworth 2*Nth order highpass filter for blocking DC
  279. template<int N, typename T>
  280. struct DCBlockerT {
  281. DCBlockerT() {
  282. setFrequency(0.1f);
  283. }
  284. // set frequency (in normalised units, 0 < fc < 1)
  285. void setFrequency(float fc) {
  286. fc_ = fc;
  287. recalculateCoefficients();
  288. }
  289. T process(T x) {
  290. for (int idx = 0; idx < N; idx++) {
  291. x = blockDCFilter[idx].process(x);
  292. }
  293. return x;
  294. }
  295. private:
  296. // https://www.earlevel.com/main/2016/09/29/cascading-filters/
  297. void recalculateCoefficients() {
  298. float poleInc = M_PI / order;
  299. float firstAngle = poleInc / 2;
  300. for (int idx = 0; idx < N; idx++) {
  301. float Q = 1.0f / (2.0f * std::cos(firstAngle + idx * poleInc));
  302. blockDCFilter[idx].setParameters(dsp::TBiquadFilter<T>::HIGHPASS, fc_, Q, 1.0f);
  303. }
  304. }
  305. float fc_;
  306. static const int order = 2 * N;
  307. dsp::TBiquadFilter<T> blockDCFilter[N];
  308. };
  309. typedef DCBlockerT<2, float> DCBlocker;
  310. /** When triggered, holds a high value for a specified time before going low again */
  311. struct PulseGenerator_4 {
  312. simd::float_4 remaining = 0.f;
  313. /** Immediately disables the pulse */
  314. void reset() {
  315. remaining = 0.f;
  316. }
  317. /** Advances the state by `deltaTime`. Returns whether the pulse is in the HIGH state. */
  318. simd::float_4 process(float deltaTime) {
  319. simd::float_4 mask = (remaining > 0.f);
  320. remaining -= ifelse(mask, deltaTime, 0.f);
  321. return ifelse(mask, simd::float_4::mask(), 0.f);
  322. }
  323. /** Begins a trigger with the given `duration`. */
  324. void trigger(simd::float_4 mask, float duration = 1e-3f) {
  325. // Keep the previous pulse if the existing pulse will be held longer than the currently requested one.
  326. remaining = ifelse(mask & (duration > remaining), duration, remaining);
  327. }
  328. };
  329. // Zavalishin 2018, "The Art of VA Filter Design", http://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_2.0.0a.pdf
  330. // Section 6.7, adopted from BogAudio Saturator https://github.com/bogaudio/BogaudioModules/blob/master/src/dsp/signal.cpp
  331. template <class T>
  332. struct Saturator {
  333. // saturate input at around ~[-1, +1] V with soft clipping
  334. static T process(T sample) {
  335. return simd::ifelse(sample < 0.f, -saturation(-sample), saturation(sample));
  336. }
  337. private:
  338. static T saturation(T sample) {
  339. const float limit = 1.05f;
  340. const float y1 = 0.98765f; // (2*x - 1)/x**2 where x is 0.9.
  341. // correction so that saturation(0) = 0
  342. const float offset = 0.0062522; // -0.5f + sqrtf(0.5f * 0.5f) / y1;
  343. T x = sample / limit;
  344. T x1 = (x + 1.0f) * 0.5f;
  345. return limit * (offset + x1 - simd::sqrt(x1 * x1 - y1 * x) * (1.0f / y1));
  346. }
  347. };