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.

905 lines
23KB

  1. #include "global_pre.hpp"
  2. #include "global_ui.hpp"
  3. #include <stdio.h>
  4. #include <string>
  5. #include <vector>
  6. #include <cstddef>
  7. #include <array>
  8. #include <map>
  9. #include <math.h>
  10. #include <float.h>
  11. #ifdef WIN32
  12. #include <windows.h>
  13. #else
  14. #include <sys/time.h>
  15. #endif
  16. #include "window.hpp"
  17. // // #include <GLFW/glfw3.h>
  18. #include "alikins.hpp"
  19. #include "ui.hpp"
  20. #include "enharmonic.hpp"
  21. #include "cv_utils.hpp"
  22. #include "specificValueWidgets.hpp"
  23. namespace rack_plugin_Alikins {
  24. #define DOUBLE_CLICK_SECS 0.5
  25. #ifdef WIN32
  26. static inline
  27. double curtime(void)
  28. {
  29. DWORD ticks = ::GetTickCount();
  30. return ticks / 1000.0;
  31. }
  32. #else
  33. // From KISS FFT,
  34. // https://github.com/mborgerding/kissfft/blob/master/test/testcpp.cc
  35. // BSD-3-Clause
  36. static inline
  37. double curtime(void)
  38. {
  39. struct timeval tv;
  40. gettimeofday(&tv, NULL);
  41. return (double)tv.tv_sec + (double)tv.tv_usec*.000001;
  42. }
  43. #endif
  44. struct SpecificValue : Module
  45. {
  46. enum ParamIds
  47. {
  48. VALUE1_PARAM,
  49. OCTAVE_PARAM,
  50. NUM_PARAMS
  51. };
  52. enum InputIds
  53. {
  54. VALUE1_INPUT,
  55. NUM_INPUTS
  56. };
  57. enum OutputIds
  58. {
  59. VALUE1_OUTPUT,
  60. NUM_OUTPUTS
  61. };
  62. enum LightIds
  63. {
  64. NUM_LIGHTS
  65. };
  66. SpecificValue() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  67. void step() override;
  68. float volt_value;
  69. float hz_value;
  70. float lfo_hz_value;
  71. float cents_value;
  72. float lfo_bpm_value;
  73. };
  74. void SpecificValue::step()
  75. {
  76. if (inputs[VALUE1_INPUT].active) {
  77. params[VALUE1_PARAM].value = inputs[VALUE1_INPUT].value;
  78. }
  79. volt_value = params[VALUE1_PARAM].value;
  80. outputs[VALUE1_OUTPUT].value = volt_value;
  81. }
  82. enum AdjustKey
  83. {
  84. UP,
  85. DOWN,
  86. INITIAL
  87. };
  88. struct FloatField : TextField
  89. {
  90. SpecificValue *module;
  91. FloatField(SpecificValue *module);
  92. void onAction(EventAction &e) override;
  93. void onChange(EventChange &e) override;
  94. void onKey(EventKey &e) override;
  95. void onMouseMove(EventMouseMove &e) override;
  96. void onMouseUp(EventMouseUp &e) override;
  97. void onDragMove(EventDragMove &e) override;
  98. void onDragEnd(EventDragEnd &e) override;
  99. void onFocus(EventFocus &e) override;
  100. virtual void handleKey(AdjustKey key, bool shift_pressed, bool mod_pressed);
  101. virtual void increment(float delta);
  102. float textToVolts(std::string field_text);
  103. std::string voltsToText(float param_volts);
  104. float minValue = -10.0f;
  105. float maxValue = 10.0f;
  106. double prev_mouse_up_time = 0.0;
  107. std::string orig_string;
  108. bool y_dragging = false;
  109. float INC = 1.0f;
  110. float SHIFT_INC = 10.1f;
  111. float MOD_INC = 0.1f;
  112. };
  113. FloatField::FloatField(SpecificValue *_module)
  114. {
  115. module = _module;
  116. INC = 0.01f;
  117. SHIFT_INC = 0.1f;
  118. MOD_INC = 0.001f;
  119. }
  120. float FloatField::textToVolts(std::string field_text) {
  121. return atof(field_text.c_str());
  122. }
  123. std::string FloatField::voltsToText(float param_volts){
  124. return stringf("%#.4g", param_volts);
  125. }
  126. void FloatField::onChange(EventChange &e) {
  127. // debug("FloatField onChange text=%s param=%f", text.c_str(),
  128. // module->params[SpecificValue::VALUE1_PARAM].value);
  129. std::string new_text = voltsToText(module->params[SpecificValue::VALUE1_PARAM].value);
  130. setText(new_text);
  131. }
  132. void FloatField::onAction(EventAction &e)
  133. {
  134. TextField::onAction(e);
  135. float volts = textToVolts(text);
  136. module->params[SpecificValue::VALUE1_PARAM].value = volts;
  137. }
  138. void FloatField::onFocus(EventFocus &e) {
  139. orig_string = text;
  140. TextField::onFocus(e);
  141. }
  142. void FloatField::onMouseUp(EventMouseUp &e) {
  143. double new_mouse_up_time = curtime();
  144. double delta = new_mouse_up_time - prev_mouse_up_time;
  145. prev_mouse_up_time = new_mouse_up_time;
  146. if (delta <= DOUBLE_CLICK_SECS) {
  147. // Select 'all' text in the field
  148. selection = 0;
  149. cursor = text.size();
  150. }
  151. }
  152. void FloatField::onMouseMove(EventMouseMove &e) {
  153. if (this == RACK_PLUGIN_UI_DRAGGED_WIDGET) {
  154. // debug("FloatField::onMouseMove y_dragging: %d", y_dragging);
  155. if (e.mouseRel.x != 0.0f && !y_dragging) {
  156. TextField::onMouseMove(e);
  157. return;
  158. }
  159. }
  160. }
  161. void FloatField::onDragMove(EventDragMove &e)
  162. {
  163. // wait until we are moving and can tell if up/down or left/right before locking the cursor
  164. // no vertical cursor movement, dont do anything. In particular, not
  165. // locking the cursor so text selection keeps working.
  166. if (e.mouseRel.y == 0.0f || fabs(e.mouseRel.x) >= 1.0f) {
  167. if (this == RACK_PLUGIN_UI_DRAGGED_WIDGET) {
  168. return;
  169. }
  170. }
  171. // debug("FloatField::onDragMove doing SOMETHING, start y_dragging");
  172. y_dragging = true;
  173. // lock the
  174. windowCursorLock();
  175. bool shift_pressed = windowIsShiftPressed();
  176. bool mod_pressed = windowIsModPressed();
  177. float inc = shift_pressed ? SHIFT_INC : INC;
  178. // mod "wins" if shift and mod pressed
  179. inc = mod_pressed ? MOD_INC : inc;
  180. float delta = inc * -e.mouseRel.y;
  181. increment(delta);
  182. // we change the text in the field, trigger onAction to update the param
  183. EventAction ae;
  184. onAction(ae);
  185. }
  186. void FloatField::onDragEnd(EventDragEnd &e) {
  187. // mouse key released, stop dragging and release the cursor lock
  188. y_dragging = false;
  189. windowCursorUnlock();
  190. }
  191. void FloatField::increment(float delta) {
  192. float field_value = atof(text.c_str());
  193. field_value += delta;
  194. field_value = clamp2(field_value, minValue, maxValue);
  195. text = voltsToText(field_value);
  196. // debug("orig_string: %s text: %s", orig_string.c_str(), text.c_str());
  197. }
  198. void FloatField::handleKey(AdjustKey adjustKey, bool shift_pressed, bool mod_pressed) {
  199. float inc = shift_pressed ? SHIFT_INC : INC;
  200. // mod "wins" if shift and mod pressed
  201. inc = mod_pressed ? MOD_INC : inc;
  202. inc = adjustKey == AdjustKey::UP ? inc : -inc;
  203. increment(inc);
  204. EventAction e;
  205. onAction(e);
  206. }
  207. void FloatField::onKey(EventKey &e) {
  208. // debug("e.key: %d", e.key);
  209. bool shift_pressed = windowIsShiftPressed();
  210. bool mod_pressed = windowIsModPressed();
  211. switch (e.key) {
  212. case LGLW_VKEY_UP: {
  213. e.consumed = true;
  214. handleKey(AdjustKey::UP, shift_pressed, mod_pressed);
  215. } break;
  216. case LGLW_VKEY_DOWN: {
  217. e.consumed = true;
  218. handleKey(AdjustKey::DOWN, shift_pressed, mod_pressed);
  219. } break;
  220. case LGLW_VKEY_ESCAPE: {
  221. e.consumed = true;
  222. // debug("escape key pressed, orig_string: %s", orig_string.c_str());
  223. text = orig_string;
  224. EventAction ea;
  225. onAction(ea);
  226. } break;
  227. }
  228. if (!e.consumed) {
  229. TextField::onKey(e);
  230. }
  231. }
  232. struct HZFloatField : FloatField
  233. {
  234. SpecificValue *module;
  235. HZFloatField(SpecificValue *_module) ;
  236. void onChange(EventChange &e) override;
  237. void onAction(EventAction &e) override;
  238. void increment(float delta) override;
  239. float textToVolts(std::string field_text);
  240. std::string voltsToText(float param_volts);
  241. };
  242. HZFloatField::HZFloatField(SpecificValue *_module) : FloatField(_module)
  243. {
  244. module = _module;
  245. INC = 1.0f;
  246. SHIFT_INC = 10.0f;
  247. MOD_INC = 0.1f;
  248. minValue = cv_to_freq(-10.0f);
  249. maxValue = cv_to_freq(10.0f);
  250. }
  251. float HZFloatField::textToVolts(std::string field_text) {
  252. float freq = strtof(text.c_str(), NULL);
  253. return freq_to_cv(freq);
  254. }
  255. std::string HZFloatField::voltsToText(float param_volts){
  256. float freq = cv_to_freq(param_volts);
  257. // std::string new_text = stringf("%0.*g", freq < 100 ? 3 : 2, freq);
  258. std::string new_text = stringf("%#.*g", freq < 100 ? 6: 7, freq);
  259. return new_text;
  260. }
  261. void HZFloatField::increment(float delta){
  262. float field_value = atof(text.c_str());
  263. field_value += delta;
  264. field_value = clamp2(field_value, minValue, maxValue);
  265. text = stringf("%#.*g", field_value < 100 ? 6: 7, field_value);
  266. }
  267. void HZFloatField::onChange(EventChange &e) {
  268. if (this != RACK_PLUGIN_UI_FOCUSED_WIDGET)
  269. {
  270. std::string new_text = voltsToText(module->params[SpecificValue::VALUE1_PARAM].value);
  271. setText(new_text);
  272. }
  273. }
  274. void HZFloatField::onAction(EventAction &e) {
  275. TextField::onAction(e);
  276. float volts = textToVolts(text);
  277. module->params[SpecificValue::VALUE1_PARAM].value = volts;
  278. }
  279. struct LFOHzFloatField : FloatField {
  280. SpecificValue *module;
  281. LFOHzFloatField(SpecificValue *_module);
  282. void onAction(EventAction &e) override;
  283. void onChange(EventChange &e) override;
  284. void increment(float delta) override;
  285. float textToVolts(std::string field_text);
  286. std::string voltsToText(float param_volts);
  287. };
  288. LFOHzFloatField::LFOHzFloatField(SpecificValue *_module) : FloatField(_module)
  289. {
  290. module = _module;
  291. INC = 0.01f;
  292. SHIFT_INC = 0.1f;
  293. MOD_INC = 0.001f;
  294. minValue = lfo_cv_to_freq(-10.0f);
  295. maxValue = lfo_cv_to_freq(10.0f);
  296. }
  297. float LFOHzFloatField::textToVolts(std::string field_text) {
  298. float freq_hz = strtof(text.c_str(), NULL);
  299. return lfo_freq_to_cv(freq_hz);
  300. }
  301. std::string LFOHzFloatField::voltsToText(float param_volts) {
  302. float lfo_freq_hz = lfo_cv_to_freq(param_volts);
  303. // std::string new_text = stringf("%0.*f", lfo_freq_hz < 100 ? 4 : 3, lfo_freq_hz);
  304. std::string new_text = stringf("%#0.*g", lfo_freq_hz < 100 ? 5 : 6, lfo_freq_hz);
  305. return new_text;
  306. }
  307. void LFOHzFloatField::increment(float delta) {
  308. float field_value = atof(text.c_str());
  309. field_value += delta;
  310. field_value = clamp2(field_value, minValue, maxValue);
  311. text = stringf("%#0.*g", 6, field_value);
  312. }
  313. void LFOHzFloatField::onChange(EventChange &e) {
  314. if (this != RACK_PLUGIN_UI_FOCUSED_WIDGET)
  315. {
  316. std::string new_text = voltsToText(module->params[SpecificValue::VALUE1_PARAM].value);
  317. setText(new_text);
  318. }
  319. }
  320. void LFOHzFloatField::onAction(EventAction &e)
  321. {
  322. TextField::onAction(e);
  323. float volts = textToVolts(text);
  324. module->params[SpecificValue::VALUE1_PARAM].value = volts;
  325. }
  326. struct LFOBpmFloatField : FloatField {
  327. SpecificValue *module;
  328. LFOBpmFloatField(SpecificValue *_module);
  329. void onAction(EventAction &e) override;
  330. void onChange(EventChange &e) override;
  331. void increment(float delta) override;
  332. float textToVolts(std::string field_text);
  333. std::string voltsToText(float param_volts);
  334. };
  335. LFOBpmFloatField::LFOBpmFloatField(SpecificValue *_module) : FloatField(_module)
  336. {
  337. module = _module;
  338. INC = 1.0f;
  339. SHIFT_INC = 10.0f;
  340. MOD_INC = 0.1f;
  341. minValue = lfo_cv_to_freq(-10.0f)* 60.0f;
  342. maxValue = lfo_cv_to_freq(10.0f) * 60.0f;
  343. }
  344. float LFOBpmFloatField::textToVolts(std::string field_text) {
  345. float lfo_bpm = strtof(text.c_str(), NULL);
  346. float lfo_hz = lfo_bpm / 60.0f;
  347. return lfo_freq_to_cv(lfo_hz);
  348. }
  349. std::string LFOBpmFloatField::voltsToText(float param_volts){
  350. float lfo_freq_hz = lfo_cv_to_freq(param_volts);
  351. float lfo_bpm = lfo_freq_hz * 60.0f;
  352. std::string new_text = stringf("%.6g", lfo_bpm);
  353. return new_text;
  354. }
  355. void LFOBpmFloatField::increment(float delta) {
  356. float field_value = atof(text.c_str());
  357. field_value += delta;
  358. field_value = clamp2(field_value, minValue, maxValue);
  359. text = stringf("%.6g", field_value);
  360. }
  361. void LFOBpmFloatField::onChange(EventChange &e) {
  362. if (this != RACK_PLUGIN_UI_FOCUSED_WIDGET)
  363. {
  364. std::string new_text = voltsToText(module->params[SpecificValue::VALUE1_PARAM].value);
  365. setText(new_text);
  366. }
  367. }
  368. void LFOBpmFloatField::onAction(EventAction &e)
  369. {
  370. TextField::onAction(e);
  371. float volts = textToVolts(text);
  372. module->params[SpecificValue::VALUE1_PARAM].value = volts;
  373. }
  374. struct CentsField : FloatField {
  375. SpecificValue *module;
  376. CentsField(SpecificValue *_module);
  377. void onChange(EventChange &e) override;
  378. void onAction(EventAction &e) override;
  379. void increment(float delta) override;
  380. };
  381. CentsField::CentsField(SpecificValue *_module) : FloatField(_module) {
  382. module = _module;
  383. INC = 1.0f;
  384. SHIFT_INC = 10.0f;
  385. MOD_INC = 0.1f;
  386. minValue = -50.0f;
  387. maxValue = 50.0f;
  388. }
  389. void CentsField::increment(float delta) {
  390. float field_value = atof(text.c_str());
  391. field_value += delta;
  392. field_value = clamp2(field_value, minValue, maxValue);
  393. // debug("field_value1: %f", field_value);
  394. field_value = chop(field_value, 0.01f);
  395. // debug("field_value2: %f", field_value);
  396. text = stringf("%0.2f", field_value);
  397. }
  398. void CentsField::onChange(EventChange &e) {
  399. float cents = volts_to_note_cents(module->params[SpecificValue::VALUE1_PARAM].value);
  400. cents = chop(cents, 0.01f);
  401. std::string new_text = stringf("%0.2f", cents);
  402. setText(new_text);
  403. }
  404. void CentsField::onAction(EventAction &e) {
  405. TextField::onAction(e);
  406. double cents = strtod(text.c_str(), NULL);
  407. // figure what to tweak the current volts
  408. double cent_volt = 1.0 / 12.0 / 100.0;
  409. double delta_volt = cents * cent_volt;
  410. double nearest_note_voltage = volts_of_nearest_note(module->params[SpecificValue::VALUE1_PARAM].value);
  411. module->params[SpecificValue::VALUE1_PARAM].value = (float) (nearest_note_voltage + delta_volt);
  412. }
  413. struct NoteNameField : TextField {
  414. SpecificValue *module;
  415. NoteNameField(SpecificValue *_module);
  416. float minValue = -10.0f;
  417. float maxValue = 10.0f;
  418. float orig_value;
  419. void onChange(EventChange &e) override;
  420. void onAction(EventAction &e) override;
  421. void onKey(EventKey &e) override;
  422. void onMouseMove(EventMouseMove &e) override;
  423. void onMouseUp(EventMouseUp &e) override;
  424. void onDragMove(EventDragMove &e) override;
  425. void onDragEnd(EventDragEnd &e) override;
  426. void onFocus(EventFocus &e) override;
  427. void increment(float delta);
  428. void handleKey(AdjustKey key, bool shift_pressed, bool mod_pressed);
  429. bool y_dragging = false;
  430. double prev_mouse_up_time = 0.0;
  431. float INC = 1.0f;
  432. float SHIFT_INC = 12.0f;
  433. float MOD_INC = 0.01f;
  434. };
  435. NoteNameField::NoteNameField(SpecificValue *_module)
  436. {
  437. module = _module;
  438. }
  439. void NoteNameField::increment(float delta) {
  440. float field_value = module->params[SpecificValue::VALUE1_PARAM].value;
  441. field_value += (float) delta * 1.0 / 12.0;
  442. field_value = clamp2(field_value, minValue, maxValue);
  443. field_value = chop(field_value, 0.001f);
  444. module->params[SpecificValue::VALUE1_PARAM].value = field_value;
  445. }
  446. void NoteNameField::handleKey(AdjustKey adjustKey, bool shift_pressed, bool mod_pressed) {
  447. //inc by oct for shift, and 1 cent for mod
  448. float inc = shift_pressed ? SHIFT_INC : INC;
  449. inc = mod_pressed ? MOD_INC : inc;
  450. inc = adjustKey == AdjustKey::UP ? inc : -inc;
  451. increment(inc);
  452. EventChange e;
  453. onChange(e);
  454. }
  455. void NoteNameField::onKey(EventKey &e) {
  456. bool shift_pressed = windowIsShiftPressed();
  457. bool mod_pressed = windowIsModPressed();
  458. switch (e.key) {
  459. case LGLW_VKEY_UP: {
  460. e.consumed = true;
  461. handleKey(AdjustKey::UP, shift_pressed, mod_pressed );
  462. } break;
  463. case LGLW_VKEY_DOWN: {
  464. e.consumed = true;
  465. handleKey(AdjustKey::DOWN, shift_pressed, mod_pressed);
  466. } break;
  467. case LGLW_VKEY_ESCAPE: {
  468. e.consumed = true;
  469. // debug("escape key pressed, orig_value: %0.5f", orig_value);
  470. module->params[SpecificValue::VALUE1_PARAM].value = orig_value;
  471. EventChange ec;
  472. onChange(ec);
  473. } break;
  474. }
  475. if (!e.consumed) {
  476. TextField::onKey(e);
  477. }
  478. }
  479. void NoteNameField::onFocus(EventFocus &e) {
  480. orig_value = module->params[SpecificValue::VALUE1_PARAM].value;
  481. // debug("onFocus orig_value: %0.5f", orig_value);
  482. TextField::onFocus(e);
  483. }
  484. void NoteNameField::onChange(EventChange &e) {
  485. float cv_volts = module->params[SpecificValue::VALUE1_PARAM].value;
  486. int octave = volts_to_octave(cv_volts);
  487. int note_number = volts_to_note(cv_volts);
  488. /* debug("cv_volts: %f, octave: %d, note_number: %d, can: %s",
  489. cv_volts, octave, note_number, note_name_vec[note_number].c_str()); */
  490. std::string new_text = stringf("%s%d", note_name_vec[note_number].c_str(), octave);
  491. setText(new_text);
  492. }
  493. void NoteNameField::onAction(EventAction &e) {
  494. TextField::onAction(e);
  495. // canoicalize the entered note name into a canonical note id
  496. // (ie, c4 -> C4, Db3 -> C#3, etc)
  497. // then look that up in enharmonic_name_map to voltage
  498. NoteOct *noteOct = parseNote(text);
  499. auto enharm_search = enharmonic_name_map.find(noteOct->name);
  500. if (enharm_search == enharmonic_name_map.end())
  501. {
  502. debug("%s was NOT A VALID note name", noteOct->name.c_str());
  503. return;
  504. }
  505. std::string can_note_name = enharmonic_name_map[noteOct->name];
  506. std::string can_note_id = stringf("%s%s", can_note_name.c_str(), noteOct->octave.c_str());
  507. /*
  508. debug("text: %s", text.c_str());
  509. debug("note_name: %s", noteOct->name.c_str());
  510. debug("can_note_name: %s", can_note_name.c_str());
  511. debug("note_name_flag: %s", noteOct->flag.c_str());
  512. debug("note_oct: %s", noteOct->octave.c_str());
  513. debug("can_note_id: %s", can_note_id.c_str());
  514. */
  515. // search for can_note_id in map to find volts value
  516. auto search = note_name_to_volts_map.find(can_note_id);
  517. if(search != note_name_to_volts_map.end()) {
  518. // float f = (float) orig;
  519. // module->params[SpecificValue::VALUE1_PARAM].value = note_name_to_volts_map[can_note_id];
  520. module->params[SpecificValue::VALUE1_PARAM].value = (float) note_name_to_volts_map[can_note_id];
  521. return;
  522. }
  523. else {
  524. // TODO: change the text color to indicate bogus name?
  525. debug("%s was NOT A VALID CANONICAL NOTE ID", can_note_id.c_str());
  526. return;
  527. }
  528. }
  529. void NoteNameField::onMouseMove(EventMouseMove &e) {
  530. if (this == RACK_PLUGIN_UI_DRAGGED_WIDGET) {
  531. if (e.mouseRel.x != 0.0f && !y_dragging) {
  532. TextField::onMouseMove(e);
  533. return;
  534. }
  535. }
  536. }
  537. // FIXME: refactor to share this and other bits better
  538. // with FloatField and friends
  539. void NoteNameField::onMouseUp(EventMouseUp &e) {
  540. double new_mouse_up_time = curtime();
  541. double delta = new_mouse_up_time - prev_mouse_up_time;
  542. prev_mouse_up_time = new_mouse_up_time;
  543. if (delta <= DOUBLE_CLICK_SECS) {
  544. // Select 'all' text in the field
  545. selection = 0;
  546. cursor = text.size();
  547. }
  548. }
  549. void NoteNameField::onDragMove(EventDragMove &e)
  550. {
  551. // TextField::onDragMove(e);
  552. if (e.mouseRel.y == 0.0f || fabs(e.mouseRel.x) >= 1.0f) {
  553. if (this == RACK_PLUGIN_UI_DRAGGED_WIDGET) {
  554. return;
  555. }
  556. }
  557. y_dragging = true;
  558. windowCursorLock();
  559. bool shift_pressed = windowIsShiftPressed();
  560. bool mod_pressed = windowIsModPressed();
  561. float inc = shift_pressed ? SHIFT_INC : INC;
  562. inc = mod_pressed ? MOD_INC : inc;
  563. float delta = inc * -e.mouseRel.y;
  564. /*
  565. debug("v: %0.5f, dy: %0.5f, delta: %0.5f",
  566. module->params[SpecificValue::VALUE1_PARAM].value,
  567. e.mouseRel.y,
  568. delta);
  569. */
  570. increment(delta);
  571. EventChange ce;
  572. onChange(ce);
  573. }
  574. void NoteNameField::onDragEnd(EventDragEnd &e) {
  575. windowCursorUnlock();
  576. y_dragging = false;
  577. }
  578. struct SpecificValueWidget : ModuleWidget
  579. {
  580. SpecificValueWidget(SpecificValue *module);
  581. void step() override;
  582. void onChange(EventChange &e) override;
  583. float prev_volts = 0.0f;
  584. float prev_input = 0.0f;
  585. FloatField *volts_field;
  586. HZFloatField *hz_field;
  587. LFOHzFloatField *lfo_hz_field;
  588. NoteNameField *note_name_field;
  589. CentsField *cents_field;
  590. LFOBpmFloatField *lfo_bpm_field;
  591. };
  592. SpecificValueWidget::SpecificValueWidget(SpecificValue *module) : ModuleWidget(module)
  593. {
  594. setPanel(SVG::load(assetPlugin(plugin, "res/SpecificValue.svg")));
  595. // TODO: widget with these children?
  596. float y_baseline = 45.0f;
  597. Vec volt_field_size = Vec(70.0f, 22.0f);
  598. Vec hz_field_size = Vec(70.0f, 22.0f);
  599. Vec lfo_hz_field_size = Vec(70.0f, 22.0f);
  600. float x_pos = 10.0f;
  601. y_baseline = 38.0f;
  602. volts_field = new FloatField(module);
  603. volts_field->box.pos = Vec(x_pos, y_baseline);
  604. volts_field->box.size = volt_field_size;
  605. addChild(volts_field);
  606. y_baseline = 78.0f;
  607. float h_pos = x_pos;
  608. hz_field = new HZFloatField(module);
  609. hz_field->box.pos = Vec(x_pos, y_baseline);
  610. hz_field->box.size = hz_field_size;
  611. addChild(hz_field);
  612. y_baseline = 120.0f;
  613. lfo_hz_field = new LFOHzFloatField(module);
  614. lfo_hz_field->box.pos = Vec(h_pos, y_baseline);
  615. lfo_hz_field->box.size = lfo_hz_field_size;
  616. addChild(lfo_hz_field);
  617. y_baseline += lfo_hz_field->box.size.y;
  618. y_baseline += 5.0f;
  619. y_baseline += 12.0f;
  620. lfo_bpm_field = new LFOBpmFloatField(module);
  621. lfo_bpm_field->box.pos = Vec(x_pos, y_baseline);
  622. lfo_bpm_field->box.size = Vec(70.0f, 22.0f);
  623. addChild(lfo_bpm_field);
  624. y_baseline += lfo_bpm_field->box.size.y;
  625. y_baseline += 20.0f;
  626. note_name_field = new NoteNameField(module);
  627. note_name_field->box.pos = Vec(x_pos, y_baseline);
  628. note_name_field->box.size = Vec(70.0f, 22.0f);
  629. addChild(note_name_field);
  630. y_baseline += note_name_field->box.size.y;
  631. y_baseline += 5.0f;
  632. cents_field = new CentsField(module);
  633. cents_field->box.pos = Vec(x_pos, y_baseline);
  634. cents_field->box.size = Vec(55.0f, 22.0f);
  635. addChild(cents_field);
  636. y_baseline += cents_field->box.size.y;
  637. y_baseline += 5.0f;
  638. float middle = box.size.x / 2.0f;
  639. float in_port_x = 15.0f;
  640. y_baseline += 12.0f;
  641. Port *value_in_port = Port::create<PJ301MPort>(
  642. Vec(in_port_x, y_baseline),
  643. Port::INPUT,
  644. module,
  645. SpecificValue::VALUE1_INPUT);
  646. value_in_port->box.pos = Vec(2.0f, y_baseline);
  647. inputs.push_back(value_in_port);
  648. addChild(value_in_port);
  649. float out_port_x = middle + 24.0f;
  650. Port *value_out_port = Port::create<PJ301MPort>(
  651. Vec(out_port_x, y_baseline),
  652. Port::OUTPUT,
  653. module,
  654. SpecificValue::VALUE1_OUTPUT);
  655. outputs.push_back(value_out_port);
  656. value_out_port->box.pos = Vec(box.size.x - value_out_port->box.size.x - 2.0f, y_baseline);
  657. addChild(value_out_port);
  658. y_baseline += value_out_port->box.size.y;
  659. y_baseline += 16.0f;
  660. PurpleTrimpot *trimpot = ParamWidget::create<PurpleTrimpot>(
  661. Vec(middle - 24.0f, y_baseline + 4.5f),
  662. module,
  663. SpecificValue::VALUE1_PARAM,
  664. -10.0f, 10.0f, 0.0f);
  665. params.push_back(trimpot);
  666. addChild(trimpot);
  667. // fire off an event to refresh all the widgets
  668. EventChange e;
  669. onChange(e);
  670. }
  671. void SpecificValueWidget::step() {
  672. ModuleWidget::step();
  673. if (prev_volts != module->params[SpecificValue::VALUE1_PARAM].value ||
  674. prev_input != module->params[SpecificValue::VALUE1_INPUT].value) {
  675. // debug("SpVWidget step - emitting EventChange / onChange prev_volts=%f param=%f",
  676. // prev_volts, module->params[SpecificValue::VALUE1_PARAM].value);
  677. prev_volts = module->params[SpecificValue::VALUE1_PARAM].value;
  678. prev_input = module->params[SpecificValue::VALUE1_INPUT].value;
  679. EventChange e;
  680. onChange(e);
  681. }
  682. }
  683. void SpecificValueWidget::onChange(EventChange &e) {
  684. ModuleWidget::onChange(e);
  685. volts_field->onChange(e);
  686. hz_field->onChange(e);
  687. lfo_hz_field->onChange(e);
  688. note_name_field->onChange(e);
  689. cents_field->onChange(e);
  690. lfo_bpm_field->onChange(e);
  691. }
  692. } // namespace rack_plugin_Alikins
  693. using namespace rack_plugin_Alikins;
  694. RACK_PLUGIN_MODEL_INIT(Alikins, SpecificValue) {
  695. Model *modelSpecificValue = Model::create<SpecificValue, SpecificValueWidget>(
  696. "Alikins", "SpecificValue", "Specific Values", UTILITY_TAG);
  697. return modelSpecificValue;
  698. }