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.

209 lines
7.0KB

  1. #include "Fundamental.hpp"
  2. #include "dsp/digital.hpp"
  3. struct SEQ3 : Module {
  4. enum ParamIds {
  5. CLOCK_PARAM,
  6. RUN_PARAM,
  7. RESET_PARAM,
  8. STEPS_PARAM,
  9. ENUMS(ROW1_PARAM, 8),
  10. ENUMS(ROW2_PARAM, 8),
  11. ENUMS(ROW3_PARAM, 8),
  12. ENUMS(GATE_PARAM, 8),
  13. NUM_PARAMS
  14. };
  15. enum InputIds {
  16. CLOCK_INPUT,
  17. EXT_CLOCK_INPUT,
  18. RESET_INPUT,
  19. STEPS_INPUT,
  20. NUM_INPUTS
  21. };
  22. enum OutputIds {
  23. GATES_OUTPUT,
  24. ROW1_OUTPUT,
  25. ROW2_OUTPUT,
  26. ROW3_OUTPUT,
  27. ENUMS(GATE_OUTPUT, 8),
  28. NUM_OUTPUTS
  29. };
  30. enum LightIds {
  31. RUNNING_LIGHT,
  32. RESET_LIGHT,
  33. GATES_LIGHT,
  34. ENUMS(ROW_LIGHTS, 3),
  35. ENUMS(GATE_LIGHTS, 8),
  36. NUM_LIGHTS
  37. };
  38. bool running = true;
  39. SchmittTrigger clockTrigger;
  40. SchmittTrigger runningTrigger;
  41. SchmittTrigger resetTrigger;
  42. SchmittTrigger gateTriggers[8];
  43. /** Phase of internal LFO */
  44. float phase = 0.f;
  45. int index = 0;
  46. bool gates[8] = {};
  47. SEQ3() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  48. onReset();
  49. }
  50. void onReset() override {
  51. for (int i = 0; i < 8; i++) {
  52. gates[i] = true;
  53. }
  54. }
  55. void onRandomize() override {
  56. for (int i = 0; i < 8; i++) {
  57. gates[i] = (randomUniform() > 0.5f);
  58. }
  59. }
  60. json_t *toJson() override {
  61. json_t *rootJ = json_object();
  62. // running
  63. json_object_set_new(rootJ, "running", json_boolean(running));
  64. // gates
  65. json_t *gatesJ = json_array();
  66. for (int i = 0; i < 8; i++) {
  67. json_array_insert_new(gatesJ, i, json_integer((int) gates[i]));
  68. }
  69. json_object_set_new(rootJ, "gates", gatesJ);
  70. return rootJ;
  71. }
  72. void fromJson(json_t *rootJ) override {
  73. // running
  74. json_t *runningJ = json_object_get(rootJ, "running");
  75. if (runningJ)
  76. running = json_is_true(runningJ);
  77. // gates
  78. json_t *gatesJ = json_object_get(rootJ, "gates");
  79. if (gatesJ) {
  80. for (int i = 0; i < 8; i++) {
  81. json_t *gateJ = json_array_get(gatesJ, i);
  82. if (gateJ)
  83. gates[i] = !!json_integer_value(gateJ);
  84. }
  85. }
  86. }
  87. void setIndex(int index) {
  88. int numSteps = (int) clamp(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 8.0f);
  89. phase = 0.f;
  90. this->index = index;
  91. if (this->index >= numSteps)
  92. this->index = 0;
  93. }
  94. void step() override {
  95. // Run
  96. if (runningTrigger.process(params[RUN_PARAM].value)) {
  97. running = !running;
  98. }
  99. bool gateIn = false;
  100. if (running) {
  101. if (inputs[EXT_CLOCK_INPUT].active) {
  102. // External clock
  103. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) {
  104. setIndex(index + 1);
  105. }
  106. gateIn = clockTrigger.isHigh();
  107. }
  108. else {
  109. // Internal clock
  110. float clockTime = powf(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  111. phase += clockTime * engineGetSampleTime();
  112. if (phase >= 1.0f) {
  113. setIndex(index + 1);
  114. }
  115. gateIn = (phase < 0.5f);
  116. }
  117. }
  118. // Reset
  119. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
  120. setIndex(0);
  121. }
  122. // Gate buttons
  123. for (int i = 0; i < 8; i++) {
  124. if (gateTriggers[i].process(params[GATE_PARAM + i].value)) {
  125. gates[i] = !gates[i];
  126. }
  127. outputs[GATE_OUTPUT + i].value = (running && gateIn && i == index && gates[i]) ? 10.0f : 0.0f;
  128. lights[GATE_LIGHTS + i].setBrightnessSmooth((gateIn && i == index) ? (gates[i] ? 1.f : 0.33) : (gates[i] ? 0.66 : 0.0));
  129. }
  130. // Outputs
  131. outputs[ROW1_OUTPUT].value = params[ROW1_PARAM + index].value;
  132. outputs[ROW2_OUTPUT].value = params[ROW2_PARAM + index].value;
  133. outputs[ROW3_OUTPUT].value = params[ROW3_PARAM + index].value;
  134. outputs[GATES_OUTPUT].value = (gateIn && gates[index]) ? 10.0f : 0.0f;
  135. lights[RUNNING_LIGHT].value = (running);
  136. lights[RESET_LIGHT].setBrightnessSmooth(resetTrigger.isHigh());
  137. lights[GATES_LIGHT].setBrightnessSmooth(gateIn);
  138. lights[ROW_LIGHTS].value = outputs[ROW1_OUTPUT].value / 10.0f;
  139. lights[ROW_LIGHTS + 1].value = outputs[ROW2_OUTPUT].value / 10.0f;
  140. lights[ROW_LIGHTS + 2].value = outputs[ROW3_OUTPUT].value / 10.0f;
  141. }
  142. };
  143. struct SEQ3Widget : ModuleWidget {
  144. SEQ3Widget(SEQ3 *module) : ModuleWidget(module) {
  145. setPanel(SVG::load(assetPlugin(plugin, "res/SEQ3.svg")));
  146. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  147. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  148. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  149. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  150. addParam(ParamWidget::create<RoundBlackKnob>(Vec(18, 56), module, SEQ3::CLOCK_PARAM, -2.0f, 6.0f, 2.0f));
  151. addParam(ParamWidget::create<LEDButton>(Vec(60, 61-1), module, SEQ3::RUN_PARAM, 0.0f, 1.0f, 0.0f));
  152. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(64.4f, 64.4f), module, SEQ3::RUNNING_LIGHT));
  153. addParam(ParamWidget::create<LEDButton>(Vec(99, 61-1), module, SEQ3::RESET_PARAM, 0.0f, 1.0f, 0.0f));
  154. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(103.4f, 64.4f), module, SEQ3::RESET_LIGHT));
  155. addParam(ParamWidget::create<RoundBlackSnapKnob>(Vec(132, 56), module, SEQ3::STEPS_PARAM, 1.0f, 8.0f, 8.0f));
  156. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(179.4f, 64.4f), module, SEQ3::GATES_LIGHT));
  157. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(218.4f, 64.4f), module, SEQ3::ROW_LIGHTS));
  158. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(256.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 1));
  159. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(295.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 2));
  160. static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289};
  161. addInput(Port::create<PJ301MPort>(Vec(portX[0]-1, 98), Port::INPUT, module, SEQ3::CLOCK_INPUT));
  162. addInput(Port::create<PJ301MPort>(Vec(portX[1]-1, 98), Port::INPUT, module, SEQ3::EXT_CLOCK_INPUT));
  163. addInput(Port::create<PJ301MPort>(Vec(portX[2]-1, 98), Port::INPUT, module, SEQ3::RESET_INPUT));
  164. addInput(Port::create<PJ301MPort>(Vec(portX[3]-1, 98), Port::INPUT, module, SEQ3::STEPS_INPUT));
  165. addOutput(Port::create<PJ301MPort>(Vec(portX[4]-1, 98), Port::OUTPUT, module, SEQ3::GATES_OUTPUT));
  166. addOutput(Port::create<PJ301MPort>(Vec(portX[5]-1, 98), Port::OUTPUT, module, SEQ3::ROW1_OUTPUT));
  167. addOutput(Port::create<PJ301MPort>(Vec(portX[6]-1, 98), Port::OUTPUT, module, SEQ3::ROW2_OUTPUT));
  168. addOutput(Port::create<PJ301MPort>(Vec(portX[7]-1, 98), Port::OUTPUT, module, SEQ3::ROW3_OUTPUT));
  169. for (int i = 0; i < 8; i++) {
  170. addParam(ParamWidget::create<RoundBlackKnob>(Vec(portX[i]-2, 157), module, SEQ3::ROW1_PARAM + i, 0.0f, 10.0f, 0.0f));
  171. addParam(ParamWidget::create<RoundBlackKnob>(Vec(portX[i]-2, 198), module, SEQ3::ROW2_PARAM + i, 0.0f, 10.0f, 0.0f));
  172. addParam(ParamWidget::create<RoundBlackKnob>(Vec(portX[i]-2, 240), module, SEQ3::ROW3_PARAM + i, 0.0f, 10.0f, 0.0f));
  173. addParam(ParamWidget::create<LEDButton>(Vec(portX[i]+2, 278-1), module, SEQ3::GATE_PARAM + i, 0.0f, 1.0f, 0.0f));
  174. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(portX[i]+6.4f, 281.4f), module, SEQ3::GATE_LIGHTS + i));
  175. addOutput(Port::create<PJ301MPort>(Vec(portX[i]-1, 307), Port::OUTPUT, module, SEQ3::GATE_OUTPUT + i));
  176. }
  177. }
  178. };
  179. RACK_PLUGIN_MODEL_INIT(Fundamental, SEQ3) {
  180. Model *modelSEQ3 = Model::create<SEQ3, SEQ3Widget>("Fundamental", "SEQ3", "SEQ-3", SEQUENCER_TAG);
  181. return modelSEQ3;
  182. }