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.

679 lines
14KB

  1. #pragma once
  2. #include "rack.hpp"
  3. #include "asset.hpp"
  4. #include "widgets.hpp"
  5. #define LCD_FONT_DIG7 "res/digital-7.ttf"
  6. #define LCD_FONTSIZE 11
  7. #define LCD_LETTER_SPACING 0
  8. /* show values of all knobs */
  9. #define DEBUG_VALUES false
  10. typedef std::shared_ptr<rack::Font> TrueType;
  11. using namespace rack;
  12. #ifdef USE_VST2
  13. #define plugin "LindenbergResearch"
  14. #else
  15. extern Plugin *plugin;
  16. #endif // USE_VST2
  17. /**
  18. * @brief Standard LRT module
  19. */
  20. struct LRModule : Module {
  21. long cnt = 0;
  22. /**
  23. * @brief Overtake default constructor for module to be compatible
  24. * @param numParams
  25. * @param numInputs
  26. * @param numOutputs
  27. * @param numLights
  28. */
  29. LRModule(int numParams, int numInputs, int numOutputs, int numLights = 0) :
  30. Module(numParams, numInputs, numOutputs, numLights) {}
  31. void step() override {
  32. Module::step();
  33. // increment counter
  34. cnt++;
  35. }
  36. };
  37. /**
  38. * @brief Standard LRT ModuleWidget definition
  39. */
  40. struct LRModuleWidget : ModuleWidget {
  41. explicit LRModuleWidget(Module *module);
  42. };
  43. /**
  44. * @brief Emulation of a LCD monochrome display
  45. */
  46. struct LCDWidget : Label {
  47. enum LCDType {
  48. NUMERIC,
  49. TEXT,
  50. LIST
  51. };
  52. TrueType ttfLCDDig7;
  53. float fontsize;
  54. LCDType type;
  55. NVGcolor fg;
  56. NVGcolor bg;
  57. bool active = true;
  58. float value = 0.0;
  59. unsigned char length = 0;
  60. std::string format;
  61. std::vector<std::string> items;
  62. std::string s1;
  63. std::string s2;
  64. /**
  65. * @brief Constructor
  66. */
  67. LCDWidget(NVGcolor fg, unsigned char length, std::string format, LCDType type, float fontsize = LCD_FONTSIZE);
  68. /**
  69. * @brief Draw LCD display
  70. * @param vg
  71. */
  72. void draw(NVGcontext *vg) override;
  73. inline void addItem(std::string name) {
  74. items.push_back(name);
  75. }
  76. };
  77. /**
  78. * @brief Indicator for control voltages on knobs
  79. */
  80. struct Indicator {
  81. static constexpr float OVERFLOW_THRESHOLD = 0.01f;
  82. /** flag to control drawing */
  83. bool active = false;
  84. /** color of indicator */
  85. NVGcolor normalColor = nvgRGBA(0x00, 0x00, 0x00, 0xBB);
  86. NVGcolor overflowColor = nvgRGBA(0xBB, 0x00, 0x00, 0xBB);
  87. /** radius from middle */
  88. float distance;
  89. /** normalized control voltage. must between [0..1] */
  90. float cv = 0.f;
  91. /** draw angle */
  92. float angle;
  93. float angle2;
  94. /** middle of parent */
  95. Vec middle;
  96. /**
  97. * @brief Init indicator
  98. * @param distance Radius viewed from the middle
  99. * @param angle Angle of active knob area
  100. */
  101. Indicator(float distance, float angle) {
  102. Indicator::distance = distance;
  103. Indicator::angle = angle;
  104. /** for optimization */
  105. angle2 = 2 * angle;
  106. }
  107. /**
  108. * @brief Draw routine for cv indicator
  109. * @param vg
  110. */
  111. void draw(NVGcontext *vg);
  112. };
  113. /**
  114. * @brief Standard LR Shadow
  115. */
  116. struct LRShadow {
  117. private:
  118. Rect box;
  119. float size = 0.65;
  120. float strength = 1.f;
  121. /** shadow shift */
  122. Vec shadowPos = Vec(3, 5);
  123. public:
  124. /**
  125. * @brief Set the new offset of the shadow gradient
  126. * @param x
  127. * @param y
  128. */
  129. void setShadowPosition(float x, float y) {
  130. shadowPos = Vec(x, y);
  131. }
  132. void setBox(const Rect &box);
  133. void setSize(float size);
  134. void setStrength(float strength);
  135. /**
  136. * @brief Draw shadow for circular knobs
  137. * @param vg NVGcontext
  138. * @param strength Alpha value of outside gradient
  139. * @param size Outer size
  140. * @param shift XY Offset shift from middle
  141. */
  142. void drawShadow(NVGcontext *vg, float strength, float size);
  143. void draw(NVGcontext *vg);
  144. };
  145. /**
  146. * @brief The base of all knobs used in LR panels, includes a indicator
  147. */
  148. struct LRKnob : SVGKnob {
  149. private:
  150. static constexpr float ANGLE = 0.83f;
  151. /** setup indicator with default values */
  152. Indicator idc = Indicator(15.f, ANGLE);
  153. bool debug = DEBUG_VALUES;
  154. TrueType font;
  155. /** snap mode */
  156. bool snap = false;
  157. /** position to snap */
  158. float snapAt = 0.0f;
  159. /** snap sensitivity */
  160. float snapSens = 0.1;
  161. protected:
  162. /** shader */
  163. LRShadow shadow = LRShadow();
  164. public:
  165. /**
  166. * @brief Default constructor
  167. */
  168. LRKnob() {
  169. minAngle = -ANGLE * (float) M_PI;
  170. maxAngle = ANGLE * (float) M_PI;
  171. font = Font::load(assetGlobal("res/fonts/ShareTechMono-Regular.ttf"));
  172. }
  173. /**
  174. * @brief Set the value of the indicator
  175. * @param value
  176. */
  177. void setIndicatorValue(float value) {
  178. idc.cv = value;
  179. }
  180. /**
  181. * @brief Switch indicator on/off
  182. * @param active
  183. */
  184. void setIndicatorActive(bool active) {
  185. idc.active = active;
  186. }
  187. /**
  188. * @brief Get indicator state
  189. * @return
  190. */
  191. bool isIndicatorActive() {
  192. return idc.active;
  193. }
  194. /**
  195. * @brief Setup distance of indicator from middle
  196. * @param distance
  197. */
  198. void setIndicatorDistance(float distance) {
  199. idc.distance = distance;
  200. }
  201. /**
  202. * @brief Hook into setSVG() method to setup box dimensions correct for indicator
  203. * @param svg
  204. */
  205. void setSVG(std::shared_ptr<SVG> svg) {
  206. SVGKnob::setSVG(svg);
  207. /** inherit dimensions after loaded svg */
  208. idc.middle = Vec(box.size.x / 2, box.size.y / 2);
  209. shadow.setBox(box);
  210. }
  211. /**
  212. * @brief Creates a new instance of a LRKnob child
  213. * @tparam TParamWidget Subclass of LRKnob
  214. * @param pos Position
  215. * @param module Module pointer
  216. * @param paramId Parameter ID
  217. * @param minValue Min
  218. * @param maxValue Max
  219. * @param defaultValue Default
  220. * @return Pointer to new subclass of LRKnob
  221. */
  222. template<class TParamWidget>
  223. static TParamWidget *create(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) {
  224. auto *param = new TParamWidget();
  225. param->box.pos = pos;
  226. param->module = module;
  227. param->paramId = paramId;
  228. param->setLimits(minValue, maxValue);
  229. param->setDefaultValue(defaultValue);
  230. return param;
  231. }
  232. /**
  233. * @brief Draw knob
  234. * @param vg
  235. */
  236. void draw(NVGcontext *vg) override {
  237. /** shadow */
  238. shadow.draw(vg);
  239. /** component */
  240. FramebufferWidget::draw(vg);
  241. /*
  242. nvgBeginPath(vg);
  243. nvgRect(vg, -30, -30, box.size.x + 60, box.size.y + 60);
  244. NVGcolor icol = nvgRGBAf(0.0f, 0.0f, 0.0f, 0.3f);
  245. NVGcolor ocol = nvgRGBAf(0.0f, 0.0f, 0.0f, 0.0f);;
  246. NVGpaint paint = nvgRadialGradient(vg, box.size.x / 2, box.size.y / 2,
  247. 0.f, box.size.x /2.f * 0.9f, icol, ocol);
  248. nvgFillPaint(vg, paint);
  249. nvgFill(vg);*/
  250. /** indicator */
  251. idc.draw(vg);
  252. if (debug) {
  253. auto text = stringf("%4.2f", value);
  254. nvgFontSize(vg, 15);
  255. nvgFontFaceId(vg, font->handle);
  256. nvgFillColor(vg, nvgRGBAf(1.f, 1.f, 1.0f, 1.0f));
  257. nvgText(vg, box.size.x - 5, box.size.y + 10, text.c_str(), NULL);
  258. }
  259. }
  260. /**
  261. * @brief Setup knob snapping
  262. * @param position
  263. * @param sensitivity
  264. */
  265. void setSnap(float position, float sensitivity) {
  266. snap = true;
  267. snapSens = sensitivity;
  268. snapAt = position;
  269. }
  270. /**
  271. * @brief Remove knob snaping
  272. */
  273. void unsetSnap() {
  274. snap = false;
  275. }
  276. /**
  277. * @brief Snapping mode for knobs
  278. * @param e
  279. */
  280. void onChange(EventChange &e) override {
  281. // if the value still inside snap-tolerance keep the value zero
  282. if (snap && value > -snapSens + snapAt && value < snapSens + snapAt) value = 0;
  283. SVGKnob::onChange(e);
  284. }
  285. };
  286. /**
  287. * @brief Quantize position to odd numbers to simulate a toggle switch
  288. */
  289. struct LRToggleKnob : LRKnob {
  290. LRToggleKnob(float length = 0.5f) {
  291. //TODO: parametrize start and end angle
  292. minAngle = -0.666666f * (float) M_PI;
  293. maxAngle = length * (float) M_PI;
  294. setSVG(SVG::load(assetPlugin(plugin, "res/ToggleKnob.svg")));
  295. shadow.setShadowPosition(3, 4);
  296. shadow.setStrength(1.2f);
  297. shadow.setSize(0.7f);
  298. speed = 2.f;
  299. }
  300. void onChange(EventChange &e) override {
  301. value = round(value);
  302. SVGKnob::onChange(e);
  303. }
  304. };
  305. /**
  306. * @brief Quantize position to odd numbers to simulate a toggle switch
  307. */
  308. struct LRMiddleIncremental : LRKnob {
  309. LRMiddleIncremental(float length = 0.5f) {
  310. minAngle = -length * (float) M_PI;
  311. maxAngle = length * (float) M_PI;
  312. setSVG(SVG::load(assetPlugin(plugin, "res/MiddleIncremental.svg")));
  313. shadow.setShadowPosition(3, 4);
  314. shadow.setStrength(1.2f);
  315. shadow.setSize(0.7f);
  316. speed = 3.f;
  317. }
  318. void onChange(EventChange &e) override {
  319. value = lround(value);
  320. //value = round(value);
  321. SVGKnob::onChange(e);
  322. }
  323. };
  324. /**
  325. * @brief LR Big Knob
  326. */
  327. struct LRBigKnob : LRKnob {
  328. LRBigKnob() {
  329. setSVG(SVG::load(assetPlugin(plugin, "res/BigKnob.svg")));
  330. setIndicatorDistance(15);
  331. shadow.setShadowPosition(5, 6);
  332. }
  333. };
  334. /**
  335. * @brief LR Middle Knob
  336. */
  337. struct LRMiddleKnob : LRKnob {
  338. LRMiddleKnob() {
  339. setSVG(SVG::load(assetPlugin(plugin, "res/MiddleKnob.svg")));
  340. setIndicatorDistance(12);
  341. shadow.setShadowPosition(4, 4);
  342. }
  343. };
  344. /**
  345. * @brief LR Small Knob
  346. */
  347. struct LRSmallKnob : LRKnob {
  348. LRSmallKnob() {
  349. setSVG(SVG::load(assetPlugin(plugin, "res/SmallKnob.svg")));
  350. shadow.setShadowPosition(3, 3);
  351. setSnap(0.0f, 0.03f);
  352. speed = 0.9f;
  353. }
  354. };
  355. /**
  356. * @brief LR Alternate Small Knob
  357. */
  358. struct LRAlternateSmallKnob : LRKnob {
  359. LRAlternateSmallKnob() {
  360. setSVG(SVG::load(assetPlugin(plugin, "res/AlternateSmallKnob.svg")));
  361. shadow.setShadowPosition(3, 3);
  362. setSnap(0.0f, 0.03f);
  363. speed = 0.9f;
  364. }
  365. };
  366. /**
  367. * @brief LR Middle Knob
  368. */
  369. struct LRAlternateMiddleKnob : LRKnob {
  370. LRAlternateMiddleKnob() {
  371. setSVG(SVG::load(assetPlugin(plugin, "res/AlternateMiddleKnob.svg")));
  372. setIndicatorDistance(12);
  373. shadow.setShadowPosition(4, 4);
  374. }
  375. };
  376. /**
  377. * @brief LR Big Knob
  378. */
  379. struct LRAlternateBigKnob : LRKnob {
  380. LRAlternateBigKnob() {
  381. setSVG(SVG::load(assetPlugin(plugin, "res/AlternateBigKnob.svg")));
  382. setIndicatorDistance(15);
  383. shadow.setShadowPosition(5, 6);
  384. }
  385. };
  386. /**
  387. * @brief Alternative IO Port
  388. */
  389. struct LRIOPort : SVGPort {
  390. private:
  391. LRShadow shadow = LRShadow();
  392. public:
  393. LRIOPort() {
  394. background->svg = SVG::load(assetPlugin(plugin, "res/IOPortB.svg"));
  395. background->wrap();
  396. box.size = background->box.size;
  397. /** inherit dimensions */
  398. shadow.setBox(box);
  399. shadow.setSize(0.50);
  400. shadow.setShadowPosition(2, 1);
  401. }
  402. /**
  403. * @brief Hook into draw method
  404. * @param vg
  405. */
  406. void draw(NVGcontext *vg) override {
  407. shadow.draw(vg);
  408. SVGPort::draw(vg);
  409. }
  410. };
  411. /**
  412. * @brief Alternative IO Port
  413. */
  414. struct LRIOPortC : SVGPort {
  415. private:
  416. LRShadow shadow = LRShadow();
  417. public:
  418. LRIOPortC() {
  419. background->svg = SVG::load(assetPlugin(plugin, "res/IOPortC.svg"));
  420. background->wrap();
  421. box.size = background->box.size;
  422. /** inherit dimensions */
  423. shadow.setBox(box);
  424. shadow.setSize(0.50);
  425. shadow.setShadowPosition(2, 1);
  426. }
  427. /**
  428. * @brief Hook into draw method
  429. * @param vg
  430. */
  431. void draw(NVGcontext *vg) override {
  432. shadow.draw(vg);
  433. SVGPort::draw(vg);
  434. }
  435. };
  436. /**
  437. * @brief Alternative screw head A
  438. */
  439. struct ScrewDarkA : SVGScrew {
  440. ScrewDarkA() {
  441. sw->svg = SVG::load(assetPlugin(plugin, "res/ScrewDark.svg"));
  442. sw->wrap();
  443. box.size = sw->box.size;
  444. }
  445. };
  446. /**
  447. * @brief Alternative screw head A
  448. */
  449. struct ScrewLight : SVGScrew {
  450. ScrewLight() {
  451. sw->svg = SVG::load(assetPlugin(plugin, "res/ScrewLight.svg"));
  452. sw->wrap();
  453. box.size = sw->box.size;
  454. }
  455. };
  456. /**
  457. * @brief Custom switch based on original Rack files
  458. */
  459. struct LRSwitch : SVGSwitch, ToggleSwitch {
  460. LRSwitch() {
  461. addFrame(SVG::load(assetPlugin(plugin, "res/Switch0.svg")));
  462. addFrame(SVG::load(assetPlugin(plugin, "res/Switch1.svg")));
  463. }
  464. };
  465. /**
  466. * @brief Standard LED Redlight
  467. */
  468. struct LRLight : SmallLight<ModuleLightWidget> {
  469. LRLight();
  470. void draw(NVGcontext *vg) override;
  471. };
  472. /**
  473. * @brief Standard LR module Panel
  474. */
  475. struct LRPanel : SVGPanel {
  476. private:
  477. /** margin of gradient box */
  478. static constexpr float MARGIN = 10;
  479. /** gradient colors */
  480. NVGcolor inner = nvgRGBAf(1.5f * .369f, 1.5f * 0.357f, 1.5f * 0.3333f, 0.25f);
  481. NVGcolor outer = nvgRGBAf(0.0f, 0.0f, 0.0f, 0.34f);;
  482. /** gradient offset */
  483. Vec offset = Vec(30, -50);
  484. public:
  485. LRPanel();
  486. LRPanel(float x, float y) {
  487. offset.x = x;
  488. offset.y = y;
  489. }
  490. void setInner(const NVGcolor &inner);
  491. void setOuter(const NVGcolor &outer);
  492. const NVGcolor &getInner() const;
  493. const NVGcolor &getOuter() const;
  494. void draw(NVGcontext *vg) override;
  495. };
  496. /**
  497. * @brief Passive rotating SVG image
  498. */
  499. struct SVGRotator : FramebufferWidget {
  500. TransformWidget *tw;
  501. SVGWidget *sw;
  502. /** angle to rotate per step */
  503. float angle = 0;
  504. float inc;
  505. SVGRotator();
  506. /**
  507. * @brief Factory method
  508. * @param pos Position
  509. * @param svg Pointer to SVG image
  510. * @param angle Increment angle per step
  511. */
  512. SVGRotator static *create(Vec pos, std::shared_ptr<SVG> svg, float inc) {
  513. SVGRotator *rotator = FramebufferWidget::create<SVGRotator>(pos);
  514. rotator->setSVG(svg);
  515. rotator->inc = inc;
  516. return rotator;
  517. }
  518. void setSVG(std::shared_ptr<SVG> svg);
  519. void step() override;
  520. };