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.

540 lines
21KB

  1. #include "AudibleInstruments.hpp"
  2. #include "dsp/digital.hpp"
  3. // #include "stages/chain_state.h"
  4. #include "stages/segment_generator.h"
  5. #include "stages/oscillator.h"
  6. // Must match io_buffer.h
  7. static const int NUM_CHANNELS = 6;
  8. static const int BLOCK_SIZE = 8;
  9. static const int MAX_MODULES = 6;
  10. struct SineOscillator {
  11. float phase = 0.f;
  12. float step(float offset) {
  13. // Implement a simple sine oscillator
  14. float deltaTime = engineGetSampleTime();
  15. float freq = 0.5f;
  16. // Accumulate the phase
  17. phase += freq * deltaTime;
  18. if (phase >= 1.0f)
  19. phase -= 1.0f;
  20. // Compute the sine output
  21. float sine = sinf(2.0f * M_PI * (phase + offset));
  22. return sine;
  23. }
  24. };
  25. struct LongPressButton {
  26. enum Events {
  27. NO_PRESS,
  28. SHORT_PRESS,
  29. LONG_PRESS
  30. };
  31. float pressedTime = 0.f;
  32. BooleanTrigger trigger;
  33. Events step(Param& param) {
  34. auto result = NO_PRESS;
  35. bool pressed = param.value > 0.f;
  36. if (pressed && pressedTime >= 0.f) {
  37. pressedTime += engineGetSampleTime();
  38. if (pressedTime >= 1.f) {
  39. pressedTime = -1.f;
  40. result = LONG_PRESS;
  41. }
  42. }
  43. // Check if released
  44. if (trigger.process(!pressed)) {
  45. if (pressedTime >= 0.f) {
  46. result = SHORT_PRESS;
  47. }
  48. pressedTime = 0.f;
  49. }
  50. return result;
  51. }
  52. };
  53. struct GroupBuilder {
  54. GroupBuilder() {
  55. for (size_t i = 0; i < NUM_CHANNELS*MAX_MODULES; i += 1) {
  56. groupSize[i] = 0;
  57. }
  58. }
  59. size_t groupSize[NUM_CHANNELS*MAX_MODULES];
  60. bool isPatched = false;
  61. bool buildGroups(std::vector<Input> *inputs, size_t first, size_t count) {
  62. bool changed = false;
  63. isPatched = false;
  64. size_t activeGroup = 0;
  65. for (int i = count-1; i >= 0; i -= 1) {
  66. auto patched = (*inputs)[first + i].active;
  67. activeGroup += 1;
  68. if (!patched) {
  69. changed = changed || groupSize[i] != 0;
  70. groupSize[i] = 0;
  71. } else if (patched) {
  72. isPatched = true;
  73. changed = changed || groupSize[i] != activeGroup;
  74. groupSize[i] = activeGroup;
  75. activeGroup = 0;
  76. }
  77. }
  78. return changed;
  79. }
  80. int groupForSegment(int segment) {
  81. int group = 0;
  82. int currentGroupSize = 0;
  83. for (int i = 0; i < NUM_CHANNELS * MAX_MODULES; i += 1) {
  84. if (currentGroupSize <= 0) {
  85. currentGroupSize = max(1, groupSize[i]);
  86. group = i;
  87. }
  88. if (segment == i) {
  89. return group;
  90. }
  91. currentGroupSize -= 1;
  92. }
  93. return segment;
  94. }
  95. };
  96. struct Stages : Module {
  97. enum ParamIds {
  98. ENUMS(SHAPE_PARAMS, NUM_CHANNELS*MAX_MODULES),
  99. ENUMS(TYPE_PARAMS, NUM_CHANNELS*MAX_MODULES),
  100. ENUMS(LEVEL_PARAMS, NUM_CHANNELS*MAX_MODULES),
  101. NUM_PARAMS
  102. };
  103. enum InputIds {
  104. ENUMS(LEVEL_INPUTS, NUM_CHANNELS*MAX_MODULES),
  105. ENUMS(GATE_INPUTS, NUM_CHANNELS*MAX_MODULES),
  106. NUM_INPUTS
  107. };
  108. enum OutputIds {
  109. ENUMS(ENVELOPE_OUTPUTS, NUM_CHANNELS*MAX_MODULES),
  110. NUM_OUTPUTS
  111. };
  112. enum LightIds {
  113. ENUMS(TYPE_LIGHTS, NUM_CHANNELS*2*MAX_MODULES),
  114. ENUMS(ENVELOPE_LIGHTS, NUM_CHANNELS*MAX_MODULES),
  115. NUM_LIGHTS
  116. };
  117. int numModules = 1;
  118. stages::segment::Configuration configurations[NUM_CHANNELS*MAX_MODULES];
  119. bool configuration_changed[NUM_CHANNELS*MAX_MODULES];
  120. stages::SegmentGenerator segment_generator[NUM_CHANNELS*MAX_MODULES];
  121. SineOscillator oscillator[NUM_CHANNELS*MAX_MODULES];
  122. bool abloop;
  123. // stages::ChainState chain_state;
  124. // stages::Settings settings;
  125. // Buttons
  126. LongPressButton typeButtons[NUM_CHANNELS*MAX_MODULES];
  127. // Buffers
  128. float envelopeBuffer[NUM_CHANNELS*MAX_MODULES][BLOCK_SIZE] = {};
  129. stmlib::GateFlags last_gate_flags[NUM_CHANNELS*MAX_MODULES] = {};
  130. stmlib::GateFlags gate_flags[NUM_CHANNELS*MAX_MODULES][BLOCK_SIZE] = {};
  131. int blockIndex = 0;
  132. GroupBuilder groupBuilder;
  133. Stages() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  134. // chain_state.Init(NULL, NULL);
  135. onReset();
  136. }
  137. void onReset() override {
  138. stages::kSampleRate = engineGetSampleRate();
  139. abloop = false;
  140. for (size_t i = 0; i < NUM_CHANNELS*MAX_MODULES; ++i) {
  141. segment_generator[i].Init();
  142. configurations[i].type = stages::segment::TYPE_RAMP;
  143. configurations[i].loop = false;
  144. configuration_changed[i] = true;
  145. }
  146. }
  147. json_t *toJson() override {
  148. json_t *rootJ = json_object();
  149. json_object_set_new(rootJ, "numModules", json_integer(numModules));
  150. json_t *configurationsJ = json_array();
  151. for (int i = 0; i < NUM_CHANNELS*MAX_MODULES; i++) {
  152. json_t *configurationJ = json_object();
  153. json_object_set_new(configurationJ, "type", json_integer(configurations[i].type));
  154. json_object_set_new(configurationJ, "loop", json_boolean(configurations[i].loop));
  155. json_array_insert_new(configurationsJ, i, configurationJ);
  156. }
  157. json_object_set_new(rootJ, "configurations", configurationsJ);
  158. return rootJ;
  159. }
  160. void fromJson(json_t *rootJ) override {
  161. json_t *numModulesJ = json_object_get(rootJ, "numModules");
  162. if (numModulesJ)
  163. numModules = json_integer_value(numModulesJ);
  164. json_t *configurationsJ = json_object_get(rootJ, "configurations");
  165. for (int i = 0; i < NUM_CHANNELS*MAX_MODULES; i++) {
  166. json_t *configurationJ = json_array_get(configurationsJ, i);
  167. if (configurationJ) {
  168. json_t *typeJ = json_object_get(configurationJ, "type");
  169. if (typeJ)
  170. configurations[i].type = (stages::segment::Type) json_integer_value(typeJ);
  171. json_t *loopJ = json_object_get(configurationJ, "loop");
  172. if (loopJ)
  173. configurations[i].loop = json_boolean_value(loopJ);
  174. }
  175. }
  176. }
  177. void onSampleRateChange() override {
  178. stages::kSampleRate = engineGetSampleRate();
  179. for (int i = 0; i < NUM_CHANNELS*MAX_MODULES; i++) {
  180. segment_generator[i].InitRamps();
  181. }
  182. }
  183. void stepBlock() {
  184. // Get parameters
  185. float primaries[NUM_CHANNELS*numModules];
  186. float secondaries[NUM_CHANNELS*numModules];
  187. for (int i = 0; i < NUM_CHANNELS*numModules; i++) {
  188. primaries[i] = clamp(params[LEVEL_PARAMS + i].value + inputs[LEVEL_INPUTS + i].value / 8.f, 0.f, 1.f);
  189. secondaries[i] = params[SHAPE_PARAMS + i].value;
  190. }
  191. // See if the group associations have changed since the last group
  192. auto groups_changed = groupBuilder.buildGroups(&inputs, GATE_INPUTS, NUM_CHANNELS * numModules);
  193. // Process block
  194. stages::SegmentGenerator::Output out[BLOCK_SIZE] = {};
  195. for (int i = 0; i < NUM_CHANNELS*numModules;) {
  196. // Check if the config needs applying to the segment generator for this group
  197. bool segment_changed = groups_changed;
  198. int numberOfLoops = 0;
  199. for (int j = 0; j < max(1, groupBuilder.groupSize[i]); j += 1) {
  200. numberOfLoops += configurations[i + j].loop ? 1 : 0;
  201. segment_changed |= configuration_changed[i + j];
  202. configuration_changed[i + j] = false;
  203. }
  204. if (segment_changed) {
  205. if (numberOfLoops > 2) {
  206. for (int j = 0; j < max(1, groupBuilder.groupSize[i]); j += 1) {
  207. configurations[i + j].loop = false;
  208. }
  209. }
  210. segment_generator[i].Configure(groupBuilder.groupSize[i] > 0, &configurations[i], max(1, groupBuilder.groupSize[i]));
  211. }
  212. // Set the segment parameters on the generator we're about to process
  213. for (int j = 0; j < segment_generator[i].num_segments(); j += 1) {
  214. segment_generator[i].set_segment_parameters(j, primaries[i + j], secondaries[i + j]);
  215. }
  216. segment_generator[i].Process(gate_flags[i], out, BLOCK_SIZE);
  217. // Set the outputs for the active segment in each output sample
  218. // All outputs also go to the first segment
  219. for (int j = 0; j < BLOCK_SIZE; j++) {
  220. for (int k = 1; k < segment_generator[i].num_segments(); k += 1) {
  221. envelopeBuffer[i + k][j] = k == out[j].segment ? 1- out[j].phase : 0.f;
  222. }
  223. envelopeBuffer[i][j] = out[j].value;
  224. }
  225. i += segment_generator[i].num_segments();
  226. }
  227. }
  228. void toggleMode(int i) {
  229. configurations[i].type = (stages::segment::Type) ((configurations[i].type + 1) % 3);
  230. configuration_changed[i] = true;
  231. }
  232. void toggleLoop(int i) {
  233. configuration_changed[i] = true;
  234. configurations[i].loop = !configurations[i].loop;
  235. // ensure that we're the only loop item in the group
  236. if (configurations[i].loop) {
  237. int group = groupBuilder.groupForSegment(i);
  238. // See how many loop items we have
  239. int loopitems = 0;
  240. for (size_t j = 0; j < groupBuilder.groupSize[group]; j += 1) {
  241. loopitems += configurations[group + j].loop ? 1 : 0;
  242. }
  243. // If we've got too many loop items, clear down to the one loop
  244. if ((abloop && loopitems > 2) || (!abloop && loopitems > 1)) {
  245. for (size_t j = 0; j < groupBuilder.groupSize[group]; j += 1) {
  246. configurations[group + j].loop = (group + (int)j) == i;
  247. }
  248. loopitems = 1;
  249. }
  250. // Turn abloop off if we've got 2 or more loops
  251. if (loopitems >= 2) {
  252. abloop = false;
  253. }
  254. }
  255. }
  256. void step() override {
  257. // Buttons
  258. for (int i = 0; i < NUM_CHANNELS * numModules; i++) {
  259. switch (typeButtons[i].step(params[TYPE_PARAMS + i])) {
  260. default:
  261. case LongPressButton::NO_PRESS: break;
  262. case LongPressButton::SHORT_PRESS: toggleMode(i); break;
  263. case LongPressButton::LONG_PRESS: toggleLoop(i); break;
  264. }
  265. }
  266. // Input
  267. for (int i = 0; i < NUM_CHANNELS * numModules; i++) {
  268. bool gate = (inputs[GATE_INPUTS + i].value >= 1.7f);
  269. last_gate_flags[i] = stmlib::ExtractGateFlags(last_gate_flags[i], gate);
  270. gate_flags[i][blockIndex] = last_gate_flags[i];
  271. }
  272. // Process block
  273. if (++blockIndex >= BLOCK_SIZE) {
  274. blockIndex = 0;
  275. stepBlock();
  276. }
  277. // Output
  278. int currentGroupSize = 0;
  279. int loopcount = 0;
  280. for (int i = 0; i < NUM_CHANNELS * numModules; i++) {
  281. float envelope = envelopeBuffer[i][blockIndex];
  282. outputs[ENVELOPE_OUTPUTS + i].value = envelope * 8.f;
  283. lights[ENVELOPE_LIGHTS + i].setBrightnessSmooth(envelope);
  284. if (currentGroupSize <= 0) {
  285. currentGroupSize = max(1, groupBuilder.groupSize[i]);
  286. loopcount = 0;
  287. }
  288. currentGroupSize -= 1;
  289. loopcount += configurations[i].loop ? 1 : 0;
  290. auto flashlevel = 1.f;
  291. if (!configurations[i].loop) {
  292. oscillator[i].step(0.f); // move the oscillator on to keep the lights in sync
  293. } else if (configurations[i].loop && loopcount == 1) {
  294. flashlevel = abs(oscillator[i].step(0.f));
  295. } else {
  296. flashlevel = abs(oscillator[i].step(0.25f));
  297. }
  298. lights[TYPE_LIGHTS + i*2 + 0].setBrightness((configurations[i].type == 0 || configurations[i].type == 1) * flashlevel);
  299. lights[TYPE_LIGHTS + i*2 + 1].setBrightness((configurations[i].type == 1 || configurations[i].type == 2) * flashlevel);
  300. }
  301. }
  302. };
  303. struct StagesWidget : ModuleWidget {
  304. Stages* module;
  305. int lastNumModules = 1;
  306. Widget* topLeftScrew;
  307. Widget* topRightScrew;
  308. Widget* bottomLeftScrew;
  309. Widget* bottomRightScrew;
  310. StagesWidget(Stages *module) : ModuleWidget(module) {
  311. this->module = module;
  312. setPanel(SVG::load(assetPlugin(plugin, "res/Stages.svg")));
  313. this->box.size.x = 210 * module->numModules;
  314. this->panel->box.size = this->box.size;
  315. topLeftScrew = Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0));
  316. topRightScrew = Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0));
  317. bottomLeftScrew = Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH));
  318. bottomRightScrew = Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH));
  319. addChild(topLeftScrew);
  320. addChild(topRightScrew);
  321. addChild(bottomLeftScrew);
  322. addChild(bottomRightScrew);
  323. for(auto i = 0; i < MAX_MODULES; i += 1) {
  324. float offset = 71.12 * i;
  325. addParam(ParamWidget::create<Trimpot>(mm2px(Vec(offset + 3.72965, 13.98158)), module, Stages::SHAPE_PARAMS + 0 + (NUM_CHANNELS*i), 0.0, 1.0, 0.5));
  326. addParam(ParamWidget::create<Trimpot>(mm2px(Vec(offset + 15.17012, 13.98158)), module, Stages::SHAPE_PARAMS + 1 + (NUM_CHANNELS*i), 0.0, 1.0, 0.5));
  327. addParam(ParamWidget::create<Trimpot>(mm2px(Vec(offset + 26.6099, 13.98158)), module, Stages::SHAPE_PARAMS + 2 + (NUM_CHANNELS*i), 0.0, 1.0, 0.5));
  328. addParam(ParamWidget::create<Trimpot>(mm2px(Vec(offset + 38.07174, 13.98158)), module, Stages::SHAPE_PARAMS + 3 + (NUM_CHANNELS*i), 0.0, 1.0, 0.5));
  329. addParam(ParamWidget::create<Trimpot>(mm2px(Vec(offset + 49.51152, 13.98158)), module, Stages::SHAPE_PARAMS + 4 + (NUM_CHANNELS*i), 0.0, 1.0, 0.5));
  330. addParam(ParamWidget::create<Trimpot>(mm2px(Vec(offset + 60.95199, 13.98158)), module, Stages::SHAPE_PARAMS + 5 + (NUM_CHANNELS*i), 0.0, 1.0, 0.5));
  331. addParam(ParamWidget::create<TL1105>(mm2px(Vec(offset + 4.17259, 32.37248)), module, Stages::TYPE_PARAMS + 0 + (NUM_CHANNELS*i), 0.0, 1.0, 0.0));
  332. addParam(ParamWidget::create<TL1105>(mm2px(Vec(offset + 15.61237, 32.37248)), module, Stages::TYPE_PARAMS + 1 + (NUM_CHANNELS*i), 0.0, 1.0, 0.0));
  333. addParam(ParamWidget::create<TL1105>(mm2px(Vec(offset + 27.05284, 32.37248)), module, Stages::TYPE_PARAMS + 2 + (NUM_CHANNELS*i), 0.0, 1.0, 0.0));
  334. addParam(ParamWidget::create<TL1105>(mm2px(Vec(offset + 38.51399, 32.37248)), module, Stages::TYPE_PARAMS + 3 + (NUM_CHANNELS*i), 0.0, 1.0, 0.0));
  335. addParam(ParamWidget::create<TL1105>(mm2px(Vec(offset + 49.95446, 32.37248)), module, Stages::TYPE_PARAMS + 4 + (NUM_CHANNELS*i), 0.0, 1.0, 0.0));
  336. addParam(ParamWidget::create<TL1105>(mm2px(Vec(offset + 61.39424, 32.37248)), module, Stages::TYPE_PARAMS + 5 + (NUM_CHANNELS*i), 0.0, 1.0, 0.0));
  337. addParam(ParamWidget::create<LEDSliderGreen>(mm2px(Vec(offset + 3.36193, 43.06508)), module, Stages::LEVEL_PARAMS + 0 + (NUM_CHANNELS*i), 0.0, 1.0, 1.0));
  338. addParam(ParamWidget::create<LEDSliderGreen>(mm2px(Vec(offset + 14.81619, 43.06508)), module, Stages::LEVEL_PARAMS + 1 + (NUM_CHANNELS*i), 0.0, 1.0, 1.0));
  339. addParam(ParamWidget::create<LEDSliderGreen>(mm2px(Vec(offset + 26.26975, 43.06508)), module, Stages::LEVEL_PARAMS + 2 + (NUM_CHANNELS*i), 0.0, 1.0, 1.0));
  340. addParam(ParamWidget::create<LEDSliderGreen>(mm2px(Vec(offset + 37.70265, 43.06508)), module, Stages::LEVEL_PARAMS + 3 + (NUM_CHANNELS*i), 0.0, 1.0, 1.0));
  341. addParam(ParamWidget::create<LEDSliderGreen>(mm2px(Vec(offset + 49.15759, 43.06508)), module, Stages::LEVEL_PARAMS + 4 + (NUM_CHANNELS*i), 0.0, 1.0, 1.0));
  342. addParam(ParamWidget::create<LEDSliderGreen>(mm2px(Vec(offset + 60.61184, 43.06508)), module, Stages::LEVEL_PARAMS + 5 + (NUM_CHANNELS*i), 0.0, 1.0, 1.0));
  343. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 2.70756, 77.75277)), Port::INPUT, module, Stages::LEVEL_INPUTS + 0 + (NUM_CHANNELS*i)));
  344. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 14.14734, 77.75277)), Port::INPUT, module, Stages::LEVEL_INPUTS + 1 + (NUM_CHANNELS*i)));
  345. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 25.58781, 77.75277)), Port::INPUT, module, Stages::LEVEL_INPUTS + 2 + (NUM_CHANNELS*i)));
  346. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 37.04896, 77.75277)), Port::INPUT, module, Stages::LEVEL_INPUTS + 3 + (NUM_CHANNELS*i)));
  347. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 48.48943, 77.75277)), Port::INPUT, module, Stages::LEVEL_INPUTS + 4 + (NUM_CHANNELS*i)));
  348. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 59.92921, 77.75277)), Port::INPUT, module, Stages::LEVEL_INPUTS + 5 + (NUM_CHANNELS*i)));
  349. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 2.70756, 92.35239)), Port::INPUT, module, Stages::GATE_INPUTS + 0 + (NUM_CHANNELS*i)));
  350. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 14.14734, 92.35239)), Port::INPUT, module, Stages::GATE_INPUTS + 1 + (NUM_CHANNELS*i)));
  351. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 25.58781, 92.35239)), Port::INPUT, module, Stages::GATE_INPUTS + 2 + (NUM_CHANNELS*i)));
  352. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 37.04896, 92.35239)), Port::INPUT, module, Stages::GATE_INPUTS + 3 + (NUM_CHANNELS*i)));
  353. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 48.48943, 92.35239)), Port::INPUT, module, Stages::GATE_INPUTS + 4 + (NUM_CHANNELS*i)));
  354. addInput(Port::create<PJ301MPort>(mm2px(Vec(offset + 59.92921, 92.35239)), Port::INPUT, module, Stages::GATE_INPUTS + 5 + (NUM_CHANNELS*i)));
  355. addOutput(Port::create<PJ301MPort>(mm2px(Vec(offset + 2.70756, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 0 + (NUM_CHANNELS*i)));
  356. addOutput(Port::create<PJ301MPort>(mm2px(Vec(offset + 14.14734, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 1 + (NUM_CHANNELS*i)));
  357. addOutput(Port::create<PJ301MPort>(mm2px(Vec(offset + 25.58781, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 2 + (NUM_CHANNELS*i)));
  358. addOutput(Port::create<PJ301MPort>(mm2px(Vec(offset + 37.04896, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 3 + (NUM_CHANNELS*i)));
  359. addOutput(Port::create<PJ301MPort>(mm2px(Vec(offset + 48.48943, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 4 + (NUM_CHANNELS*i)));
  360. addOutput(Port::create<PJ301MPort>(mm2px(Vec(offset + 59.92921, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 5 + (NUM_CHANNELS*i)));
  361. addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(offset + 5.27737, 26.74447)), module, Stages::TYPE_LIGHTS + (0*2) + (NUM_CHANNELS*2*i)));
  362. addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(offset + 16.73784, 26.74447)), module, Stages::TYPE_LIGHTS + (1*2) + (NUM_CHANNELS*2*i)));
  363. addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(offset + 28.1783, 26.74447)), module, Stages::TYPE_LIGHTS + (2*2) + (NUM_CHANNELS*2*i)));
  364. addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(offset + 39.61877, 26.74447)), module, Stages::TYPE_LIGHTS + (3*2) + (NUM_CHANNELS*2*i)));
  365. addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(offset + 51.07923, 26.74447)), module, Stages::TYPE_LIGHTS + (4*2) + (NUM_CHANNELS*2*i)));
  366. addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(offset + 62.51971, 26.74447)), module, Stages::TYPE_LIGHTS + (5*2) + (NUM_CHANNELS*2*i)));
  367. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(offset + 2.29462, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 0 + (NUM_CHANNELS*i)));
  368. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(offset + 13.73509, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 1 + (NUM_CHANNELS*i)));
  369. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(offset + 25.17556, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 2 + (NUM_CHANNELS*i)));
  370. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(offset + 36.63671, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 3 + (NUM_CHANNELS*i)));
  371. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(offset + 48.07649, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 4 + (NUM_CHANNELS*i)));
  372. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(offset + 59.51696, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 5 + (NUM_CHANNELS*i)));
  373. }
  374. }
  375. void step() override {
  376. if (module->numModules != lastNumModules) {
  377. resize(module->numModules);
  378. // Remove wires which no longer have a port
  379. for (int i = 0; i < inputs.size(); i++) {
  380. if (inputs[i]->portId >= Stages::LEVEL_INPUTS + (module->numModules * NUM_CHANNELS) && inputs[i]->portId < Stages::LEVEL_INPUTS + (NUM_CHANNELS * MAX_MODULES)) {
  381. gRackWidget->wireContainer->removeAllWires(inputs[i]);
  382. }
  383. if (inputs[i]->portId >= Stages::GATE_INPUTS + (module->numModules * NUM_CHANNELS) && inputs[i]->portId < Stages::GATE_INPUTS + (NUM_CHANNELS * MAX_MODULES)) {
  384. gRackWidget->wireContainer->removeAllWires(inputs[i]);
  385. }
  386. }
  387. for (int i = 0; i < outputs.size(); i++) {
  388. if (outputs[i]->portId >= Stages::ENVELOPE_OUTPUTS + (module->numModules * NUM_CHANNELS) && outputs[i]->portId < Stages::ENVELOPE_OUTPUTS + (NUM_CHANNELS * MAX_MODULES)) {
  389. gRackWidget->wireContainer->removeAllWires(outputs[i]);
  390. }
  391. }
  392. }
  393. ModuleWidget::step();
  394. }
  395. void resize(int width) {
  396. lastNumModules = width;
  397. this->box.size.x = width * 210;
  398. this->panel->box.size = this->box.size;
  399. topRightScrew->box.pos.x = box.size.x - 2 * RACK_GRID_WIDTH;
  400. bottomRightScrew->box.pos.x = box.size.x - 2 * RACK_GRID_WIDTH;
  401. }
  402. void appendContextMenu(Menu *menu) override {
  403. Stages *module = dynamic_cast<Stages*>(this->module);
  404. struct ABLoopItem : MenuItem {
  405. Stages *module;
  406. void onAction(EventAction &e) override {
  407. module->abloop = true;
  408. }
  409. };
  410. menu->addChild(MenuEntry::create());
  411. ABLoopItem *abloopItem = MenuItem::create<ABLoopItem>("Set A/B Loop", CHECKMARK(module->abloop));
  412. abloopItem->module = module;
  413. menu->addChild(abloopItem);
  414. struct ExpandoItem : MenuItem {
  415. Stages *module;
  416. int width = 1;
  417. void onAction(EventAction &e) override {
  418. module->numModules = width;
  419. }
  420. };
  421. struct ModuleLinkingItem : MenuItem {
  422. Stages* module;
  423. Menu *createChildMenu() override {
  424. Menu *menu = new Menu();
  425. for (auto i = 1; i <= MAX_MODULES; i += 1) {
  426. ExpandoItem *expandoItem = MenuItem::create<ExpandoItem>(stringf("%dx", i), CHECKMARK(module->numModules == i));
  427. expandoItem->module = module;
  428. expandoItem->width = i;
  429. menu->addChild(expandoItem);
  430. }
  431. return menu;
  432. }
  433. };
  434. menu->addChild(MenuEntry::create());
  435. ModuleLinkingItem *moduleLinkingItem = MenuItem::create<ModuleLinkingItem>("Linked Modules");
  436. moduleLinkingItem->module = module;
  437. menu->addChild(moduleLinkingItem);
  438. }
  439. };
  440. Model *modelStages = Model::create<Stages, StagesWidget>("Audible Instruments", "Stages", "Segment Generator", FUNCTION_GENERATOR_TAG, ENVELOPE_GENERATOR_TAG);