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.

367 lines
11KB

  1. //**************************************************************************************
  2. //16-Steps Sequencer Module for VCV Rack by Autodafe http://www.autodafe.net
  3. //
  4. //Based on code taken from the Fundamentals plugins by Andrew Belt http://www.vcvrack.com
  5. //**************************************************************************************
  6. #include "Autodafe.hpp"
  7. #include "dsp/digital.hpp"
  8. namespace rack_plugin_Autodafe {
  9. struct SEQ16 : Module {
  10. enum ParamIds {
  11. CLOCK_PARAM,
  12. RUN_PARAM,
  13. RESET_PARAM,
  14. STEPS_PARAM,
  15. ROW1_PARAM,
  16. ROW2_PARAM = ROW1_PARAM + 16,
  17. ROW3_PARAM = ROW2_PARAM + 16,
  18. GATE_PARAM = ROW3_PARAM + 16,
  19. NUM_PARAMS = GATE_PARAM + 16
  20. };
  21. enum InputIds {
  22. CLOCK_INPUT,
  23. EXT_CLOCK_INPUT,
  24. START_INPUT,
  25. STOP_INPUT,
  26. RESET_INPUT,
  27. STEPS_INPUT,
  28. NUM_INPUTS
  29. };
  30. enum OutputIds {
  31. CLOCK_OUT,
  32. CLOCK_GATE_OUT,
  33. GATES_OUTPUT,
  34. ROW1_OUTPUT,
  35. ROW2_OUTPUT,
  36. ROW3_OUTPUT,
  37. GATE_OUTPUT,
  38. NUM_OUTPUTS = GATE_OUTPUT + 16
  39. };
  40. enum LightIds {
  41. RUNNING_LIGHT,
  42. RESET_LIGHT,
  43. GATES_LIGHT,
  44. ROW_LIGHTS,
  45. GATE_LIGHTS = ROW_LIGHTS + 3,
  46. NUM_LIGHTS = GATE_LIGHTS + 16
  47. };
  48. bool running = true;
  49. SchmittTrigger clockTrigger; // for external clock
  50. // For buttons
  51. SchmittTrigger runningTrigger;
  52. SchmittTrigger resetTrigger;
  53. SchmittTrigger gateTriggers[16];
  54. float phase = 0.0;
  55. int index = 0;
  56. bool gateState[16] = {};
  57. float resetLight = 0.0;
  58. float stepLights[16] = {};
  59. enum GateMode {
  60. TRIGGER,
  61. RETRIGGER,
  62. CONTINUOUS,
  63. };
  64. GateMode gateMode = TRIGGER;
  65. PulseGenerator gatePulse;
  66. SEQ16() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  67. void step() override;
  68. json_t *toJson() override {
  69. json_t *rootJ = json_object();
  70. // running
  71. json_object_set_new(rootJ, "running", json_boolean(running));
  72. // gates
  73. json_t *gatesJ = json_array();
  74. for (int i = 0; i < 16; i++) {
  75. json_t *gateJ = json_integer((int) gateState[i]);
  76. json_array_append_new(gatesJ, gateJ);
  77. }
  78. json_object_set_new(rootJ, "gates", gatesJ);
  79. // gateMode
  80. json_t *gateModeJ = json_integer((int) gateMode);
  81. json_object_set_new(rootJ, "gateMode", gateModeJ);
  82. return rootJ;
  83. }
  84. void fromJson(json_t *rootJ) override {
  85. // running
  86. json_t *runningJ = json_object_get(rootJ, "running");
  87. if (runningJ)
  88. running = json_is_true(runningJ);
  89. // gates
  90. json_t *gatesJ = json_object_get(rootJ, "gates");
  91. if (gatesJ) {
  92. for (int i = 0; i < 16; i++) {
  93. json_t *gateJ = json_array_get(gatesJ, i);
  94. if (gateJ)
  95. gateState[i] = !!json_integer_value(gateJ);
  96. }
  97. }
  98. // gateMode
  99. json_t *gateModeJ = json_object_get(rootJ, "gateMode");
  100. if (gateModeJ)
  101. gateMode = (GateMode)json_integer_value(gateModeJ);
  102. }
  103. void reset() override {
  104. for (int i = 0; i < 16; i++) {
  105. gateState[i] = false;
  106. }
  107. }
  108. void randomize() override {
  109. for (int i = 0; i < 16; i++) {
  110. gateState[i] = (randomf() > 0.5);
  111. }
  112. }
  113. };
  114. void SEQ16::step() {
  115. const float lightLambda = 0.075;
  116. outputs[CLOCK_OUT].value=0;
  117. outputs[CLOCK_GATE_OUT].value=0;
  118. // Run
  119. if (runningTrigger.process(params[RUN_PARAM].value)) {
  120. running = !running;
  121. }
  122. if(inputs[START_INPUT].value>0){running=true;}
  123. if(inputs[STOP_INPUT].value>0){running=false;}
  124. lights[RUNNING_LIGHT].value = running ? 1.0 : 0.0;
  125. bool nextStep = false;
  126. if (running) {
  127. if (inputs[EXT_CLOCK_INPUT].active) {
  128. // External clock
  129. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) {
  130. phase = 0.0;
  131. nextStep = true;
  132. outputs[CLOCK_OUT].value=1;
  133. }
  134. }
  135. else {
  136. // Internal clock
  137. float clockTime = powf(2.0, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  138. phase += clockTime / engineGetSampleRate();
  139. if (phase >= 1.0) {
  140. phase -= 1.0;
  141. nextStep = true;
  142. outputs[CLOCK_OUT].value=1;
  143. }
  144. }
  145. }
  146. // Reset
  147. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
  148. phase = 0.0;
  149. index = 16;
  150. nextStep = true;
  151. resetLight = 1.0;
  152. }
  153. if (nextStep) {
  154. // Advance step
  155. int numSteps = clampi(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1, 16);
  156. index += 1;
  157. if (index >= numSteps) {
  158. index = 0;
  159. }
  160. stepLights[index] = 1.0;
  161. gatePulse.trigger(1e-3);
  162. }
  163. resetLight -= resetLight / lightLambda / engineGetSampleRate();
  164. bool pulse = gatePulse.process(1.0 / engineGetSampleRate());
  165. // Gate buttons
  166. for (int i = 0; i < 16; i++) {
  167. if (gateTriggers[i].process(params[GATE_PARAM + i].value)) {
  168. gateState[i] = !gateState[i];
  169. }
  170. bool gateOn = (running && i == index && gateState[i]);
  171. if (gateMode == TRIGGER)
  172. gateOn = gateOn && pulse;
  173. else if (gateMode == RETRIGGER)
  174. gateOn = gateOn && !pulse;
  175. outputs[GATE_OUTPUT + i].value = gateOn ? 10.0 : 0.0;
  176. if (outputs[GATE_OUTPUT + i].value!=0)
  177. {
  178. outputs[CLOCK_GATE_OUT].value=gateOn ? 1.0 : 0.0;
  179. }
  180. stepLights[i] -= stepLights[i] / lightLambda / engineGetSampleRate();
  181. lights[GATE_LIGHTS + i].value = gateState[i] ? 1.0 - stepLights[i] : stepLights[i];
  182. }
  183. // Rows
  184. float row1 = params[ROW1_PARAM + index].value;
  185. float row2 = params[ROW2_PARAM + index].value;
  186. float row3 = params[ROW3_PARAM + index].value;
  187. bool gatesOn = (running && gateState[index]);
  188. if (gateMode == TRIGGER)
  189. gatesOn = gatesOn && pulse;
  190. else if (gateMode == RETRIGGER)
  191. gatesOn = gatesOn && !pulse;
  192. outputs[ROW1_OUTPUT].value = row1;
  193. outputs[ROW2_OUTPUT].value = row2;
  194. outputs[ROW3_OUTPUT].value = row3;
  195. outputs[GATES_OUTPUT].value = gatesOn ? 10.0 : 0.0;
  196. lights[RESET_LIGHT].value = resetLight;
  197. lights[GATES_LIGHT].value = gatesOn ? 1.0 : 0.0;
  198. lights[ROW_LIGHTS].value = row1 / 10.0;
  199. lights[ROW_LIGHTS + 1].value = row2 / 10.0;
  200. lights[ROW_LIGHTS + 2].value = row3 / 10.0;
  201. }
  202. struct AutodafePurpleLight : ModuleLightWidget {
  203. AutodafePurpleLight() {
  204. addBaseColor(nvgRGB(0x89, 0x13, 0xC4));
  205. }
  206. };
  207. struct SEQ16Widget : ModuleWidget{
  208. SEQ16Widget(SEQ16 *module);
  209. Menu *createContextMenu() override;
  210. };
  211. SEQ16Widget::SEQ16Widget(SEQ16 *module) : ModuleWidget(module) {
  212. box.size = Vec(15*42, 380);
  213. {
  214. SVGPanel *panel = new SVGPanel();
  215. panel->box.size = box.size;
  216. panel->setBackground(SVG::load(assetPlugin(plugin, "res/SEQ16.svg")));
  217. addChild(panel);
  218. }
  219. addChild(createScrew<ScrewSilver>(Vec(5, 0)));
  220. addChild(createScrew<ScrewSilver>(Vec(box.size.x-20, 0)));
  221. addChild(createScrew<ScrewSilver>(Vec(5, 365)));
  222. addChild(createScrew<ScrewSilver>(Vec(box.size.x-20, 365)));
  223. addParam(createParam<AutodafeKnobPurpleSmall>(Vec(18, 56), module, SEQ16::CLOCK_PARAM, -2.0, 6.0, 2.0));
  224. addParam(createParam<LEDButton>(Vec(60, 61-1), module, SEQ16::RUN_PARAM, 0.0, 1.0, 0.0));
  225. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(64.4, 64.4), module, SEQ16::RUNNING_LIGHT));
  226. addParam(createParam<LEDButton>(Vec(98, 61-1), module, SEQ16::RESET_PARAM, 0.0, 1.0, 0.0));
  227. addOutput(createOutput<PJ301MPort>(Vec(403, 98), module, SEQ16::CLOCK_OUT));
  228. addOutput(createOutput<PJ301MPort>(Vec(442, 98), module, SEQ16::CLOCK_GATE_OUT));
  229. addInput(createInput<PJ301MPort>(Vec(327, 98), module, SEQ16::START_INPUT));
  230. addInput(createInput<PJ301MPort>(Vec(365, 98), module, SEQ16::STOP_INPUT));
  231. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(103.4, 64.4), module, SEQ16::RESET_LIGHT));
  232. addParam(createParam<AutodafeKnobPurple>(Vec(128, 52), module, SEQ16::STEPS_PARAM, 1.0, 16.0, 16.0));
  233. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(179.4, 64.4), module, SEQ16::GATES_LIGHT));
  234. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(218.4, 64.4), module, SEQ16::ROW_LIGHTS));
  235. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(256.4, 64.4), module, SEQ16::ROW_LIGHTS + 1));
  236. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(295.4, 64.4), module, SEQ16::ROW_LIGHTS + 2));
  237. static const float portX[16] = {19,57,96,134,173,211,250,288,326,364,402,440,478,516,554,592};
  238. addInput(createInput<PJ301MPort>(Vec(portX[0]-1, 99-1), module, SEQ16::CLOCK_INPUT));
  239. addInput(createInput<PJ301MPort>(Vec(portX[1]-1, 99-1), module, SEQ16::EXT_CLOCK_INPUT));
  240. addInput(createInput<PJ301MPort>(Vec(portX[2]-1, 99-1), module, SEQ16::RESET_INPUT));
  241. addInput(createInput<PJ301MPort>(Vec(portX[3]-1, 99-1), module, SEQ16::STEPS_INPUT));
  242. addOutput(createOutput<PJ301MPort>(Vec(portX[4]-1, 99-1), module, SEQ16::GATES_OUTPUT));
  243. addOutput(createOutput<PJ301MPort>(Vec(portX[5]-1, 99-1), module, SEQ16::ROW1_OUTPUT));
  244. addOutput(createOutput<PJ301MPort>(Vec(portX[6]-1, 99-1), module, SEQ16::ROW2_OUTPUT));
  245. addOutput(createOutput<PJ301MPort>(Vec(portX[7]-1, 99-1), module, SEQ16::ROW3_OUTPUT));
  246. for (int i = 0; i < 16; i++) {
  247. addParam(createParam<AutodafeKnobPurpleSmall>(Vec(portX[i] - 2, 157), module, SEQ16::ROW1_PARAM + i, 0.0, 6.0, 0.0));
  248. addParam(createParam<AutodafeKnobPurpleSmall>(Vec(portX[i] - 2, 198), module, SEQ16::ROW2_PARAM + i, 0.0, 6.0, 0.0));
  249. addParam(createParam<AutodafeKnobPurpleSmall>(Vec(portX[i] - 2, 240), module, SEQ16::ROW3_PARAM + i, 0.0, 6.0, 0.0));
  250. addParam(createParam<LEDButton>(Vec(portX[i] + 2, 278 - 1), module, SEQ16::GATE_PARAM + i, 0.0, 1.0, 0.0));
  251. addChild(createLight<MediumLight<AutodafePurpleLight>>(Vec(portX[i]+6.4, 281.4), module, SEQ16::GATE_LIGHTS + i));
  252. addOutput(createOutput<PJ301MPort>(Vec(portX[i] - 1, 308 - 1), module, SEQ16::GATE_OUTPUT + i));
  253. }
  254. }
  255. struct SEQ16GateModeItem : MenuItem {
  256. struct SEQ16 *SEQ16;
  257. SEQ16::GateMode gateMode;
  258. void onAction(EventAction &e) override {
  259. SEQ16->gateMode = gateMode;
  260. }
  261. void step() override {
  262. rightText = (SEQ16->gateMode == gateMode) ? "✔" : "";
  263. }
  264. };
  265. Menu *SEQ16Widget::createContextMenu() {
  266. Menu *menu = ModuleWidget::createContextMenu();
  267. MenuLabel *spacerLabel = new MenuLabel();
  268. menu->pushChild(spacerLabel);
  269. SEQ16 *SEQ16 = dynamic_cast<struct SEQ16*>(module);
  270. assert(SEQ16);
  271. MenuLabel *modeLabel = new MenuLabel();
  272. modeLabel->text = "Gate Mode";
  273. menu->pushChild(modeLabel);
  274. SEQ16GateModeItem *triggerItem = new SEQ16GateModeItem();
  275. triggerItem->text = "Trigger";
  276. triggerItem->SEQ16 = SEQ16;
  277. triggerItem->gateMode = SEQ16::TRIGGER;
  278. menu->pushChild(triggerItem);
  279. SEQ16GateModeItem *retriggerItem = new SEQ16GateModeItem();
  280. retriggerItem->text = "Retrigger";
  281. retriggerItem->SEQ16 = SEQ16;
  282. retriggerItem->gateMode = SEQ16::RETRIGGER;
  283. menu->pushChild(retriggerItem);
  284. SEQ16GateModeItem *continuousItem = new SEQ16GateModeItem();
  285. continuousItem->text = "Continuous";
  286. continuousItem->SEQ16 = SEQ16;
  287. continuousItem->gateMode = SEQ16::CONTINUOUS;
  288. menu->pushChild(continuousItem);
  289. return menu;
  290. }
  291. } // namespace rack_plugin_Autodafe
  292. using namespace rack_plugin_Autodafe;
  293. RACK_PLUGIN_MODEL_INIT(Autodafe, SEQ16) {
  294. return Model::create<SEQ16, SEQ16Widget>("Autodafe", "16-Step Sequencer", "16-Step Sequencer", SEQUENCER_TAG);
  295. }