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.

461 lines
17KB

  1. #include "plugin.hpp"
  2. #include "stages/segment_generator.h"
  3. #include "stages/oscillator.h"
  4. // Must match io_buffer.h
  5. static const int NUM_CHANNELS = 6;
  6. static const int BLOCK_SIZE = 8;
  7. struct LongPressButton {
  8. enum Events {
  9. NO_PRESS,
  10. SHORT_PRESS,
  11. LONG_PRESS
  12. };
  13. float pressedTime = 0.f;
  14. dsp::BooleanTrigger trigger;
  15. Events step(Param& param) {
  16. Events result = NO_PRESS;
  17. bool pressed = param.value > 0.f;
  18. if (pressed && pressedTime >= 0.f) {
  19. pressedTime += APP->engine->getSampleTime();
  20. if (pressedTime >= 1.f) {
  21. pressedTime = -1.f;
  22. result = LONG_PRESS;
  23. }
  24. }
  25. // Check if released
  26. if (trigger.process(!pressed)) {
  27. if (pressedTime >= 0.f) {
  28. result = SHORT_PRESS;
  29. }
  30. pressedTime = 0.f;
  31. }
  32. return result;
  33. }
  34. };
  35. struct GroupInfo {
  36. int first_segment = 0;
  37. int segment_count = 0;
  38. bool gated = false;
  39. };
  40. struct GroupBuilder {
  41. GroupInfo groups[NUM_CHANNELS];
  42. int groupCount = 0;
  43. bool buildGroups(std::vector<Input>* gateInputs, size_t first, size_t count) {
  44. bool any_gates = false;
  45. GroupInfo nextGroups[NUM_CHANNELS];
  46. int currentGroup = 0;
  47. for (int i = 0; i < NUM_CHANNELS; i++) {
  48. bool gated = (*gateInputs)[first + i].isConnected();
  49. if (!any_gates) {
  50. if (!gated) {
  51. // No gates at all yet, segments are all single segment groups
  52. nextGroups[currentGroup].first_segment = i;
  53. nextGroups[currentGroup].segment_count = 1;
  54. nextGroups[currentGroup].gated = false;
  55. currentGroup++;
  56. }
  57. else {
  58. // first gate, current group is start of a segment group
  59. any_gates = true;
  60. nextGroups[currentGroup].first_segment = i;
  61. nextGroups[currentGroup].segment_count = 1;
  62. nextGroups[currentGroup].gated = true;
  63. currentGroup++;
  64. }
  65. }
  66. else {
  67. if (!gated) {
  68. // We've had a gate, this ungated segment is part of the previous group
  69. nextGroups[currentGroup - 1].segment_count++;
  70. }
  71. else {
  72. // This gated input indicates the start of the next group
  73. nextGroups[currentGroup].first_segment = i;
  74. nextGroups[currentGroup].segment_count = 1;
  75. nextGroups[currentGroup].gated = true;
  76. currentGroup++;
  77. }
  78. }
  79. }
  80. bool changed = false;
  81. if (currentGroup != groupCount) {
  82. changed = true;
  83. groupCount = currentGroup;
  84. }
  85. for (int i = 0; i < groupCount; i++) {
  86. if (nextGroups[i].segment_count != groups[i].segment_count ||
  87. nextGroups[i].gated != groups[i].gated ||
  88. nextGroups[i].first_segment != groups[i].first_segment) {
  89. changed = true;
  90. }
  91. groups[i].first_segment = nextGroups[i].first_segment;
  92. groups[i].segment_count = nextGroups[i].segment_count;
  93. groups[i].gated = nextGroups[i].gated;
  94. }
  95. return changed;
  96. }
  97. };
  98. struct Stages : Module {
  99. enum ParamIds {
  100. ENUMS(SHAPE_PARAMS, NUM_CHANNELS),
  101. ENUMS(TYPE_PARAMS, NUM_CHANNELS),
  102. ENUMS(LEVEL_PARAMS, NUM_CHANNELS),
  103. NUM_PARAMS
  104. };
  105. enum InputIds {
  106. ENUMS(LEVEL_INPUTS, NUM_CHANNELS),
  107. ENUMS(GATE_INPUTS, NUM_CHANNELS),
  108. NUM_INPUTS
  109. };
  110. enum OutputIds {
  111. ENUMS(ENVELOPE_OUTPUTS, NUM_CHANNELS),
  112. NUM_OUTPUTS
  113. };
  114. enum LightIds {
  115. ENUMS(TYPE_LIGHTS, NUM_CHANNELS * 2),
  116. ENUMS(ENVELOPE_LIGHTS, NUM_CHANNELS),
  117. NUM_LIGHTS
  118. };
  119. stages::segment::Configuration configurations[NUM_CHANNELS];
  120. bool configuration_changed[NUM_CHANNELS];
  121. stages::SegmentGenerator segment_generator[NUM_CHANNELS];
  122. float lightOscillatorPhase;
  123. // Buttons
  124. LongPressButton typeButtons[NUM_CHANNELS];
  125. // Buffers
  126. float envelopeBuffer[NUM_CHANNELS][BLOCK_SIZE] = {};
  127. stmlib::GateFlags last_gate_flags[NUM_CHANNELS] = {};
  128. stmlib::GateFlags gate_flags[NUM_CHANNELS][BLOCK_SIZE] = {};
  129. int blockIndex = 0;
  130. GroupBuilder groupBuilder;
  131. Stages() {
  132. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  133. configParam(SHAPE_PARAMS + 0, 0.0, 1.0, 0.5, "Shape 1");
  134. configParam(SHAPE_PARAMS + 1, 0.0, 1.0, 0.5, "Shape 2");
  135. configParam(SHAPE_PARAMS + 2, 0.0, 1.0, 0.5, "Shape 3");
  136. configParam(SHAPE_PARAMS + 3, 0.0, 1.0, 0.5, "Shape 4");
  137. configParam(SHAPE_PARAMS + 4, 0.0, 1.0, 0.5, "Shape 5");
  138. configParam(SHAPE_PARAMS + 5, 0.0, 1.0, 0.5, "Shape 6");
  139. configParam(TYPE_PARAMS + 0, 0.0, 1.0, 0.0, "Type 1");
  140. configParam(TYPE_PARAMS + 1, 0.0, 1.0, 0.0, "Type 2");
  141. configParam(TYPE_PARAMS + 2, 0.0, 1.0, 0.0, "Type 3");
  142. configParam(TYPE_PARAMS + 3, 0.0, 1.0, 0.0, "Type 4");
  143. configParam(TYPE_PARAMS + 4, 0.0, 1.0, 0.0, "Type 5");
  144. configParam(TYPE_PARAMS + 5, 0.0, 1.0, 0.0, "Type 6");
  145. configParam(LEVEL_PARAMS + 0, 0.0, 1.0, 0.5, "Level 1");
  146. configParam(LEVEL_PARAMS + 1, 0.0, 1.0, 0.5, "Level 2");
  147. configParam(LEVEL_PARAMS + 2, 0.0, 1.0, 0.5, "Level 3");
  148. configParam(LEVEL_PARAMS + 3, 0.0, 1.0, 0.5, "Level 4");
  149. configParam(LEVEL_PARAMS + 4, 0.0, 1.0, 0.5, "Level 5");
  150. configParam(LEVEL_PARAMS + 5, 0.0, 1.0, 0.5, "Level 6");
  151. onReset();
  152. }
  153. void onReset() override {
  154. for (size_t i = 0; i < NUM_CHANNELS; ++i) {
  155. segment_generator[i].Init();
  156. configurations[i].type = stages::segment::TYPE_RAMP;
  157. configurations[i].loop = false;
  158. configuration_changed[i] = true;
  159. }
  160. lightOscillatorPhase = 0.f;
  161. onSampleRateChange();
  162. }
  163. json_t* dataToJson() override {
  164. json_t* rootJ = json_object();
  165. json_t* configurationsJ = json_array();
  166. for (int i = 0; i < NUM_CHANNELS; i++) {
  167. json_t* configurationJ = json_object();
  168. json_object_set_new(configurationJ, "type", json_integer(configurations[i].type));
  169. json_object_set_new(configurationJ, "loop", json_boolean(configurations[i].loop));
  170. json_array_insert_new(configurationsJ, i, configurationJ);
  171. }
  172. json_object_set_new(rootJ, "configurations", configurationsJ);
  173. return rootJ;
  174. }
  175. void dataFromJson(json_t* rootJ) override {
  176. json_t* configurationsJ = json_object_get(rootJ, "configurations");
  177. for (int i = 0; i < NUM_CHANNELS; i++) {
  178. json_t* configurationJ = json_array_get(configurationsJ, i);
  179. if (configurationJ) {
  180. json_t* typeJ = json_object_get(configurationJ, "type");
  181. if (typeJ)
  182. configurations[i].type = (stages::segment::Type) json_integer_value(typeJ);
  183. json_t* loopJ = json_object_get(configurationJ, "loop");
  184. if (loopJ)
  185. configurations[i].loop = json_boolean_value(loopJ);
  186. }
  187. }
  188. }
  189. void onSampleRateChange() override {
  190. for (int i = 0; i < NUM_CHANNELS; i++) {
  191. segment_generator[i].SetSampleRate(APP->engine->getSampleRate());
  192. }
  193. }
  194. void stepBlock() {
  195. // Get parameters
  196. float primaries[NUM_CHANNELS];
  197. float secondaries[NUM_CHANNELS];
  198. for (int i = 0; i < NUM_CHANNELS; i++) {
  199. primaries[i] = clamp(params[LEVEL_PARAMS + i].getValue() + inputs[LEVEL_INPUTS + i].getVoltage() / 8.f, 0.f, 1.f);
  200. secondaries[i] = params[SHAPE_PARAMS + i].getValue();
  201. }
  202. // See if the group associations have changed since the last group
  203. bool groups_changed = groupBuilder.buildGroups(&inputs, GATE_INPUTS, NUM_CHANNELS);
  204. // Process block
  205. stages::SegmentGenerator::Output out[BLOCK_SIZE] = {};
  206. for (int i = 0; i < groupBuilder.groupCount; i++) {
  207. GroupInfo& group = groupBuilder.groups[i];
  208. // Check if the config needs applying to the segment generator for this group
  209. bool apply_config = groups_changed;
  210. int numberOfLoopsInGroup = 0;
  211. for (int j = 0; j < group.segment_count; j++) {
  212. int segment = group.first_segment + j;
  213. numberOfLoopsInGroup += configurations[segment].loop ? 1 : 0;
  214. apply_config |= configuration_changed[segment];
  215. configuration_changed[segment] = false;
  216. }
  217. if (numberOfLoopsInGroup > 2) {
  218. // Too many segments are looping, turn them all off
  219. apply_config = true;
  220. for (int j = 0; j < group.segment_count; j++) {
  221. configurations[group.first_segment + j].loop = false;
  222. }
  223. }
  224. if (apply_config) {
  225. segment_generator[i].Configure(group.gated, &configurations[group.first_segment], group.segment_count);
  226. }
  227. // Set the segment parameters on the generator we're about to process
  228. for (int j = 0; j < group.segment_count; j++) {
  229. segment_generator[i].set_segment_parameters(j, primaries[group.first_segment + j], secondaries[group.first_segment + j]);
  230. }
  231. segment_generator[i].Process(gate_flags[group.first_segment], out, BLOCK_SIZE);
  232. for (int j = 0; j < BLOCK_SIZE; j++) {
  233. for (int k = 1; k < group.segment_count; k++) {
  234. int segment = group.first_segment + k;
  235. if (k == out[j].segment) {
  236. // Set the phase output for the active segment
  237. envelopeBuffer[segment][j] = 1.f - out[j].phase;
  238. }
  239. else {
  240. // Non active segments have 0.f output
  241. envelopeBuffer[segment][j] = 0.f;
  242. }
  243. }
  244. // First group segment gets the actual output
  245. envelopeBuffer[group.first_segment][j] = out[j].value;
  246. }
  247. }
  248. }
  249. void toggleMode(int i) {
  250. configurations[i].type = (stages::segment::Type)((configurations[i].type + 1) % 3);
  251. configuration_changed[i] = true;
  252. }
  253. void toggleLoop(int segment) {
  254. configuration_changed[segment] = true;
  255. configurations[segment].loop = !configurations[segment].loop;
  256. // ensure that we don't have too many looping segments in the group
  257. if (configurations[segment].loop) {
  258. int segment_count = 0;
  259. for (int i = 0; i < groupBuilder.groupCount; i++) {
  260. segment_count += groupBuilder.groups[i].segment_count;
  261. if (segment_count > segment) {
  262. GroupInfo& group = groupBuilder.groups[i];
  263. // See how many loop items we have
  264. int numberOfLoopsInGroup = 0;
  265. for (int j = 0; j < group.segment_count; j++) {
  266. numberOfLoopsInGroup += configurations[group.first_segment + j].loop ? 1 : 0;
  267. }
  268. // If we've got too many loop items, clear down to the one looping segment
  269. if (numberOfLoopsInGroup > 2) {
  270. for (int j = 0; j < group.segment_count; j++) {
  271. configurations[group.first_segment + j].loop = (group.first_segment + j) == segment;
  272. }
  273. }
  274. break;
  275. }
  276. }
  277. }
  278. }
  279. void process(const ProcessArgs& args) override {
  280. // Oscillate flashing the type lights
  281. lightOscillatorPhase += 0.5f * args.sampleTime;
  282. if (lightOscillatorPhase >= 1.0f)
  283. lightOscillatorPhase -= 1.0f;
  284. // Buttons
  285. for (int i = 0; i < NUM_CHANNELS; i++) {
  286. switch (typeButtons[i].step(params[TYPE_PARAMS + i])) {
  287. default:
  288. case LongPressButton::NO_PRESS: break;
  289. case LongPressButton::SHORT_PRESS: toggleMode(i); break;
  290. case LongPressButton::LONG_PRESS: toggleLoop(i); break;
  291. }
  292. }
  293. // Input
  294. for (int i = 0; i < NUM_CHANNELS; i++) {
  295. bool gate = (inputs[GATE_INPUTS + i].getVoltage() >= 1.7f);
  296. last_gate_flags[i] = stmlib::ExtractGateFlags(last_gate_flags[i], gate);
  297. gate_flags[i][blockIndex] = last_gate_flags[i];
  298. }
  299. // Process block
  300. if (++blockIndex >= BLOCK_SIZE) {
  301. blockIndex = 0;
  302. stepBlock();
  303. }
  304. // Output
  305. for (int i = 0; i < groupBuilder.groupCount; i++) {
  306. GroupInfo& group = groupBuilder.groups[i];
  307. int numberOfLoopsInGroup = 0;
  308. for (int j = 0; j < group.segment_count; j++) {
  309. int segment = group.first_segment + j;
  310. float envelope = envelopeBuffer[segment][blockIndex];
  311. outputs[ENVELOPE_OUTPUTS + segment].setVoltage(envelope * 8.f);
  312. lights[ENVELOPE_LIGHTS + segment].setSmoothBrightness(envelope, args.sampleTime);
  313. numberOfLoopsInGroup += configurations[segment].loop ? 1 : 0;
  314. float flashlevel = 1.f;
  315. if (configurations[segment].loop && numberOfLoopsInGroup == 1) {
  316. flashlevel = abs(sinf(2.0f * M_PI * lightOscillatorPhase));
  317. }
  318. else if (configurations[segment].loop && numberOfLoopsInGroup > 1) {
  319. float advancedPhase = lightOscillatorPhase + 0.25f;
  320. if (advancedPhase > 1.0f)
  321. advancedPhase -= 1.0f;
  322. flashlevel = abs(sinf(2.0f * M_PI * advancedPhase));
  323. }
  324. lights[TYPE_LIGHTS + segment * 2 + 0].setBrightness((configurations[segment].type == 0 || configurations[segment].type == 1) * flashlevel);
  325. lights[TYPE_LIGHTS + segment * 2 + 1].setBrightness((configurations[segment].type == 1 || configurations[segment].type == 2) * flashlevel);
  326. }
  327. }
  328. }
  329. };
  330. struct StagesWidget : ModuleWidget {
  331. StagesWidget(Stages* module) {
  332. setModule(module);
  333. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Stages.svg")));
  334. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  335. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  336. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  337. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  338. addParam(createParam<Trimpot>(mm2px(Vec(3.72965, 13.98158)), module, Stages::SHAPE_PARAMS + 0));
  339. addParam(createParam<Trimpot>(mm2px(Vec(15.17012, 13.98158)), module, Stages::SHAPE_PARAMS + 1));
  340. addParam(createParam<Trimpot>(mm2px(Vec(26.6099, 13.98158)), module, Stages::SHAPE_PARAMS + 2));
  341. addParam(createParam<Trimpot>(mm2px(Vec(38.07174, 13.98158)), module, Stages::SHAPE_PARAMS + 3));
  342. addParam(createParam<Trimpot>(mm2px(Vec(49.51152, 13.98158)), module, Stages::SHAPE_PARAMS + 4));
  343. addParam(createParam<Trimpot>(mm2px(Vec(60.95199, 13.98158)), module, Stages::SHAPE_PARAMS + 5));
  344. addParam(createParam<TL1105>(mm2px(Vec(4.17259, 32.37248)), module, Stages::TYPE_PARAMS + 0));
  345. addParam(createParam<TL1105>(mm2px(Vec(15.61237, 32.37248)), module, Stages::TYPE_PARAMS + 1));
  346. addParam(createParam<TL1105>(mm2px(Vec(27.05284, 32.37248)), module, Stages::TYPE_PARAMS + 2));
  347. addParam(createParam<TL1105>(mm2px(Vec(38.51399, 32.37248)), module, Stages::TYPE_PARAMS + 3));
  348. addParam(createParam<TL1105>(mm2px(Vec(49.95446, 32.37248)), module, Stages::TYPE_PARAMS + 4));
  349. addParam(createParam<TL1105>(mm2px(Vec(61.39424, 32.37248)), module, Stages::TYPE_PARAMS + 5));
  350. addParam(createParam<LEDSliderGreen>(mm2px(Vec(3.36193, 43.06508)), module, Stages::LEVEL_PARAMS + 0));
  351. addParam(createParam<LEDSliderGreen>(mm2px(Vec(14.81619, 43.06508)), module, Stages::LEVEL_PARAMS + 1));
  352. addParam(createParam<LEDSliderGreen>(mm2px(Vec(26.26975, 43.06508)), module, Stages::LEVEL_PARAMS + 2));
  353. addParam(createParam<LEDSliderGreen>(mm2px(Vec(37.70265, 43.06508)), module, Stages::LEVEL_PARAMS + 3));
  354. addParam(createParam<LEDSliderGreen>(mm2px(Vec(49.15759, 43.06508)), module, Stages::LEVEL_PARAMS + 4));
  355. addParam(createParam<LEDSliderGreen>(mm2px(Vec(60.61184, 43.06508)), module, Stages::LEVEL_PARAMS + 5));
  356. addInput(createInput<PJ301MPort>(mm2px(Vec(2.70756, 77.75277)), module, Stages::LEVEL_INPUTS + 0));
  357. addInput(createInput<PJ301MPort>(mm2px(Vec(14.14734, 77.75277)), module, Stages::LEVEL_INPUTS + 1));
  358. addInput(createInput<PJ301MPort>(mm2px(Vec(25.58781, 77.75277)), module, Stages::LEVEL_INPUTS + 2));
  359. addInput(createInput<PJ301MPort>(mm2px(Vec(37.04896, 77.75277)), module, Stages::LEVEL_INPUTS + 3));
  360. addInput(createInput<PJ301MPort>(mm2px(Vec(48.48943, 77.75277)), module, Stages::LEVEL_INPUTS + 4));
  361. addInput(createInput<PJ301MPort>(mm2px(Vec(59.92921, 77.75277)), module, Stages::LEVEL_INPUTS + 5));
  362. addInput(createInput<PJ301MPort>(mm2px(Vec(2.70756, 92.35239)), module, Stages::GATE_INPUTS + 0));
  363. addInput(createInput<PJ301MPort>(mm2px(Vec(14.14734, 92.35239)), module, Stages::GATE_INPUTS + 1));
  364. addInput(createInput<PJ301MPort>(mm2px(Vec(25.58781, 92.35239)), module, Stages::GATE_INPUTS + 2));
  365. addInput(createInput<PJ301MPort>(mm2px(Vec(37.04896, 92.35239)), module, Stages::GATE_INPUTS + 3));
  366. addInput(createInput<PJ301MPort>(mm2px(Vec(48.48943, 92.35239)), module, Stages::GATE_INPUTS + 4));
  367. addInput(createInput<PJ301MPort>(mm2px(Vec(59.92921, 92.35239)), module, Stages::GATE_INPUTS + 5));
  368. addOutput(createOutput<PJ301MPort>(mm2px(Vec(2.70756, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 0));
  369. addOutput(createOutput<PJ301MPort>(mm2px(Vec(14.14734, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 1));
  370. addOutput(createOutput<PJ301MPort>(mm2px(Vec(25.58781, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 2));
  371. addOutput(createOutput<PJ301MPort>(mm2px(Vec(37.04896, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 3));
  372. addOutput(createOutput<PJ301MPort>(mm2px(Vec(48.48943, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 4));
  373. addOutput(createOutput<PJ301MPort>(mm2px(Vec(59.92921, 106.95203)), module, Stages::ENVELOPE_OUTPUTS + 5));
  374. addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(5.27737, 26.74447)), module, Stages::TYPE_LIGHTS + 0 * 2));
  375. addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(16.73784, 26.74447)), module, Stages::TYPE_LIGHTS + 1 * 2));
  376. addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(28.1783, 26.74447)), module, Stages::TYPE_LIGHTS + 2 * 2));
  377. addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(39.61877, 26.74447)), module, Stages::TYPE_LIGHTS + 3 * 2));
  378. addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(51.07923, 26.74447)), module, Stages::TYPE_LIGHTS + 4 * 2));
  379. addChild(createLight<MediumLight<GreenRedLight>>(mm2px(Vec(62.51971, 26.74447)), module, Stages::TYPE_LIGHTS + 5 * 2));
  380. addChild(createLight<MediumLight<GreenLight>>(mm2px(Vec(2.29462, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 0));
  381. addChild(createLight<MediumLight<GreenLight>>(mm2px(Vec(13.73509, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 1));
  382. addChild(createLight<MediumLight<GreenLight>>(mm2px(Vec(25.17556, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 2));
  383. addChild(createLight<MediumLight<GreenLight>>(mm2px(Vec(36.63671, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 3));
  384. addChild(createLight<MediumLight<GreenLight>>(mm2px(Vec(48.07649, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 4));
  385. addChild(createLight<MediumLight<GreenLight>>(mm2px(Vec(59.51696, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 5));
  386. }
  387. };
  388. Model* modelStages = createModel<Stages, StagesWidget>("Stages");