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.

228 lines
6.7KB

  1. #include "dsp/digital.hpp"
  2. #include "alikins.hpp"
  3. #define VALUE_COUNT 4
  4. #define CLOSE_ENOUGH 0.01f
  5. namespace rack_plugin_Alikins {
  6. struct ValueSaver : Module {
  7. enum ParamIds {
  8. ENUMS(VALUE_PARAM, VALUE_COUNT),
  9. NUM_PARAMS
  10. };
  11. enum InputIds {
  12. ENUMS(VALUE_INPUT, VALUE_COUNT),
  13. NUM_INPUTS
  14. };
  15. enum OutputIds {
  16. ENUMS(VALUE_OUTPUT, VALUE_COUNT),
  17. NUM_OUTPUTS
  18. };
  19. enum LightIds {
  20. NUM_LIGHTS
  21. };
  22. ValueSaver() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  23. void step() override;
  24. void onReset() override {
  25. }
  26. json_t *toJson() override;
  27. void fromJson(json_t *rootJ) override;
  28. float values[VALUE_COUNT] = {0.0f};
  29. float prevInputs[VALUE_COUNT] = {0.0f};
  30. bool initialized = false;
  31. bool changingInputs[VALUE_COUNT] = {};
  32. SchmittTrigger valueUpTrigger[VALUE_COUNT];
  33. SchmittTrigger valueDownTrigger[VALUE_COUNT];
  34. };
  35. void ValueSaver::step()
  36. {
  37. // states:
  38. // - active inputs, meaningful current input -> output
  39. // - active inputs,
  40. // - in active inputs, meaningful 'saved' input -> output
  41. // - in active inputs, default/unset value -> output
  42. //
  43. for (int i = 0; i < VALUE_COUNT; i++) {
  44. // Just output the "saved" value if NO ACTIVE input
  45. if (!inputs[VALUE_INPUT + i].active) {
  46. outputs[VALUE_OUTPUT + i].value = prevInputs[i];
  47. continue;
  48. }
  49. // ACTIVE INPUTS
  50. // process(rescale(in, low, high, 0.f, 1.f))
  51. // if we haven't already figured out this is a useful changing input, check
  52. if (!changingInputs[i]) {
  53. float down = rescale(inputs[VALUE_INPUT + i].value, 0.0f, -CLOSE_ENOUGH, 0.f, 1.f);
  54. float up = rescale(inputs[VALUE_INPUT + i].value, 0.0f, CLOSE_ENOUGH, 0.f, 1.f);
  55. // TODO: if input is changing from 0.0f
  56. // if input is 0.0f but that is changing from prevInput (explicitly sent 0.0f)
  57. if (valueUpTrigger[i].process(up) || valueDownTrigger[i].process(down)) {
  58. // debug("value*Trigger[%d] triggered value: %f %f", i, values[i], up);
  59. changingInputs[i] = true;
  60. }
  61. }
  62. if (!changingInputs[i]) {
  63. // active input but it is 0.0f, like a midi-1 on startup that hasn't sent any signal yet
  64. // debug("[%d] ACTIVE but input is ~0.0f, prevInputs[%d]=%f", i, i, prevInputs[i]);
  65. values[i] = prevInputs[i];
  66. outputs[VALUE_OUTPUT + i].value = values[i];
  67. }
  68. else {
  69. // input value copied to output value and stored in values[]
  70. values[i] = inputs[VALUE_INPUT + i].value;
  71. outputs[VALUE_OUTPUT + i].value = values[i];
  72. prevInputs[i] = values[i];
  73. // We are getting meaningful input values (ie, not just 0.0f), we can
  74. // pay attention to the inputs now
  75. changingInputs[i] = true;
  76. continue;
  77. }
  78. }
  79. }
  80. json_t* ValueSaver::toJson() {
  81. json_t *rootJ = json_object();
  82. json_t *valuesJ = json_array();
  83. for (int i = 0; i < VALUE_COUNT; i++)
  84. {
  85. // debug("toJson current values[%d]: %f", i, values[i]);
  86. json_t *valueJ = json_real(values[i]);
  87. json_array_append_new(valuesJ, valueJ);
  88. }
  89. json_object_set_new(rootJ, "values", valuesJ);
  90. return rootJ;
  91. }
  92. void ValueSaver::fromJson(json_t *rootJ) {
  93. json_t *valuesJ = json_object_get(rootJ, "values");
  94. float savedInput;
  95. if (valuesJ) {
  96. for (int i = 0; i < VALUE_COUNT; i++) {
  97. json_t *valueJ = json_array_get(valuesJ, i);
  98. if (valueJ) {
  99. savedInput = json_number_value(valueJ);
  100. prevInputs[i] = savedInput;
  101. values[i] = savedInput;
  102. changingInputs[i] = false;
  103. }
  104. }
  105. }
  106. initialized = true;
  107. }
  108. struct LabelTextField : LedDisplayTextField {
  109. LabelTextField() {
  110. color = COLOR_CYAN;
  111. textOffset = Vec(-2.0f, -3.0f);
  112. multiline = true;
  113. text = "";
  114. }
  115. };
  116. struct ValueSaverWidget : ModuleWidget {
  117. ValueSaverWidget(ValueSaver *module);
  118. LabelTextField *labelTextFields[VALUE_COUNT];
  119. json_t *toJson() override;
  120. void fromJson(json_t *rootJ) override;
  121. };
  122. json_t *ValueSaverWidget::toJson() {
  123. json_t *rootJ = ModuleWidget::toJson();
  124. json_t *labelsJ = json_array();
  125. for (int i = 0; i < VALUE_COUNT; i++) {
  126. json_t *labelJ = json_string(labelTextFields[i]->text.c_str());
  127. json_array_append_new(labelsJ, labelJ);
  128. }
  129. json_object_set_new(rootJ, "labels", labelsJ);
  130. return rootJ;
  131. }
  132. void ValueSaverWidget::fromJson(json_t *rootJ) {
  133. ModuleWidget::fromJson(rootJ);
  134. json_t *labelsJ = json_object_get(rootJ, "labels");
  135. if (labelsJ) {
  136. for (int i = 0; i < VALUE_COUNT; i++) {
  137. json_t *labelJ = json_array_get(labelsJ, i);
  138. if (labelJ) {
  139. labelTextFields[i]->text = json_string_value(labelJ);
  140. }
  141. }
  142. }
  143. }
  144. ValueSaverWidget::ValueSaverWidget(ValueSaver *module) : ModuleWidget(module) {
  145. box.size = Vec(4 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  146. setPanel(SVG::load(assetPlugin(plugin, "res/ValueSaverPanel.svg")));
  147. float y_baseline = 48.0f;
  148. float y_pos = y_baseline;
  149. for (int i = 0; i < VALUE_COUNT; i++) {
  150. float x_pos = 4.0f;
  151. addInput(Port::create<PJ301MPort>(Vec(x_pos, y_pos),
  152. Port::INPUT,
  153. module,
  154. ValueSaver::VALUE_INPUT + i));
  155. x_pos += 30.0f;
  156. addOutput(Port::create<PJ301MPort>(Vec(box.size.x - 30.0f, y_pos),
  157. Port::OUTPUT,
  158. module,
  159. ValueSaver::VALUE_OUTPUT + i));
  160. y_pos += 28.0f;
  161. labelTextFields[i] = new LabelTextField();
  162. labelTextFields[i]->box.pos = (Vec(4.0f, y_pos));
  163. labelTextFields[i]->box.size = Vec(box.size.x - 8.0f, 38.0f);
  164. addChild(labelTextFields[i]);
  165. y_pos += labelTextFields[i]->box.size.y;
  166. y_pos += 14.0f;
  167. }
  168. addChild(Widget::create<ScrewSilver>(Vec(0.0f, 0.0f)));
  169. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15.0f, 0.0f)));
  170. addChild(Widget::create<ScrewSilver>(Vec(0.0f, 365.0f)));
  171. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 15.0f, 365.0f)));
  172. }
  173. } // namespace rack_plugin_Alikins
  174. using namespace rack_plugin_Alikins;
  175. RACK_PLUGIN_MODEL_INIT(Alikins, ValueSaver) {
  176. Model *modelValueSaver = Model::create<ValueSaver, ValueSaverWidget>(
  177. "Alikins", "ValueSaver", "Value Saver", UTILITY_TAG);
  178. return modelValueSaver;
  179. }