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.

407 lines
12KB

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