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.

254 lines
7.8KB

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