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.

314 lines
9.2KB

  1. #include "LFSR.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_alto777_LFSR {
  4. /* at x1 works good except switching noise */
  5. /* at x2 noise gone, but we get the tail end effect, a wee bit of f0 */
  6. /* at 4. total rewrite ARGH! works good except I still get the tail effect */
  7. //# define FADE_STEPS 20000 /* whoa! */
  8. #define FADE_STEPS 2000
  9. struct cheapFX : Module {
  10. enum ParamIds {
  11. ENUMS(FREQUENCY_PARAM, 2),
  12. ENUMS(SHAPE_PARAM, 2),
  13. NUM_PARAMS
  14. };
  15. enum InputIds {
  16. ENUMS(FREQUENCY_CV_INPUT, 2),
  17. ENUMS(SHAPE_CV_INPUT, 2),
  18. ENUMS(TRIGGER_INPUT, 2),
  19. NUM_INPUTS
  20. };
  21. enum OutputIds {
  22. ENUMS(TRIANGLE_OUTPUT, 2),
  23. ENUMS(RECTANGLE_OUTPUT, 2),
  24. ENUMS(GATE_OUTPUT, 2),
  25. NUM_OUTPUTS
  26. };
  27. enum LightIds {
  28. NUM_LIGHTS
  29. };
  30. enum fadeFSMStates {
  31. OFF, START, COMING, ON, STOP, GOING
  32. };
  33. enum tweedFSMStates {
  34. NOT, INIT, TWEEDLE, FINI, BUSY
  35. };
  36. float phase[2] = {0.0f, 0.0f};
  37. // float previousGate[2] = {0.0f, 0.0f};
  38. SchmittTrigger eventTrigger[2];
  39. bool isGated[2] = {0, 0};
  40. bool phaseRolloverFlag[2] = {0, 0};
  41. bool retriggerFlag[2] = {0, 0};
  42. int tCount[2] = {0, 0};
  43. int fadeCount[2]; /* for soft gate process */
  44. fadeFSMStates fadeState[2] = {OFF, OFF};
  45. tweedFSMStates tweedState[2] = {NOT, NOT};
  46. bool runnable = 0;
  47. /* overkill for simple intialization, yet my best way of sandwiching it on in there */
  48. json_t *toJson() override {
  49. json_t *rootJ = json_object();
  50. if (!runnable) {
  51. for (int ii = 0; ii < 2; ii++) {
  52. phase[ii] = 0.0f;
  53. // previousGate[ii] = 0.0f;
  54. isGated[ii] =0;
  55. tCount[ii] = 0;
  56. fadeState[ii] = OFF;
  57. tweedState[ii] = NOT;
  58. phaseRolloverFlag[ii] = 0;
  59. retriggerFlag[ii] = 0;
  60. }
  61. runnable = 1;
  62. }
  63. return (rootJ);
  64. }
  65. void fromJson(json_t *rootJ) override {
  66. for (int ii = 0; ii < 2; ii++) {
  67. }
  68. }
  69. /* json_t *rootJ = json_object();
  70. json_t *mstate = json_array();
  71. for (int i = 0; i < 2; i++)
  72. json_array_insert_new(mstate, i, json_integer((int) mState[i]));
  73. json_object_set_new(rootJ, "mstate", mstate);
  74. return rootJ;
  75. }
  76. void fromJson(json_t *rootJ) override {
  77. json_t *mstate = json_object_get(rootJ, "mstate");
  78. if (mstate) {
  79. for (int i = 0; i < 2; i++) {
  80. json_t *wha = json_array_get(mstate, i);
  81. if (wha)
  82. mState[i] = json_integer_value(wha);
  83. }
  84. }
  85. }
  86. */
  87. // void accumulatePhaseAndOutput(int, float);
  88. cheapFX() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  89. void step() override;
  90. };
  91. struct myBoltA : SVGScrew {
  92. myBoltA() {
  93. sw->setSVG(SVG::load(assetPlugin(plugin, "res/myBoltA.svg")));
  94. box.size = sw->box.size;
  95. }
  96. };
  97. struct myBoltB : SVGScrew {
  98. myBoltB() {
  99. sw->setSVG(SVG::load(assetPlugin(plugin, "res/myBoltB.svg")));
  100. box.size = sw->box.size;
  101. }
  102. };
  103. struct myBoltC : SVGScrew {
  104. myBoltC() {
  105. sw->setSVG(SVG::load(assetPlugin(plugin, "res/myBoltC.svg")));
  106. box.size = sw->box.size;
  107. }
  108. };
  109. struct myBoltD : SVGScrew {
  110. myBoltD() {
  111. sw->setSVG(SVG::load(assetPlugin(plugin, "res/myBoltD.svg")));
  112. box.size = sw->box.size;
  113. }
  114. };
  115. //void cheapFX::accumulatePhaseAndOutput(int ii, float deltaT) {}
  116. // accumulatePhaseAndOutput(ii);
  117. void cheapFX::step() {
  118. /* first - a square wave at frequency see Template.cpp */
  119. float deltaTime = engineGetSampleTime();
  120. for (int ii = 0; ii < 2; ii++) { /* [ii] */
  121. // ram pup or down the gate output for softer transitions
  122. /* inline because I am not confidant about scope and stuff. Sad. */
  123. switch (fadeState[ii]) {
  124. case OFF : /* we dead, kill it again */
  125. outputs[GATE_OUTPUT + ii].value = 0.0f;
  126. break;
  127. case ON : /* we full on */
  128. outputs[GATE_OUTPUT + ii].value = 10.0f;
  129. break;
  130. case START : /* externally kicked */
  131. fadeCount[ii] = 0;
  132. fadeState[ii] = COMING;
  133. /* break not, get right to it */
  134. case COMING :
  135. if (fadeCount[ii] < FADE_STEPS) {
  136. ++fadeCount[ii];
  137. outputs[GATE_OUTPUT + ii].value = (10.0f * fadeCount[ii]) / FADE_STEPS;
  138. }
  139. else fadeState[ii] = ON;
  140. break;
  141. case STOP : /* also externally kicked */
  142. fadeState[ii] = GOING;
  143. /* break not, get right to it */
  144. case GOING :
  145. if (fadeCount[ii] > 0) {
  146. --fadeCount[ii];
  147. outputs[GATE_OUTPUT + ii].value = (10.0f * fadeCount[ii]) / FADE_STEPS;
  148. }
  149. else fadeState[ii] = OFF;
  150. break;
  151. }
  152. /**/
  153. switch (tweedState[ii]) {
  154. case INIT :
  155. /* when we start a tweedle cycle */
  156. phase[ii] = 0.0f; /* restart the tweedle waveform */
  157. phaseRolloverFlag[ii] = 0;
  158. retriggerFlag[ii] = 0;
  159. fadeState[ii] = START; /* send in the clowns */
  160. /* break not, get going right now */
  161. tweedState[ii] = TWEEDLE;
  162. case TWEEDLE :
  163. /* this carries out one full tweedle, maybe retriggers/stays on */
  164. if (eventTrigger[ii].process(inputs[TRIGGER_INPUT + ii].value))
  165. retriggerFlag[ii] = 1; /* any trigger during buys another cycle */
  166. if (phaseRolloverFlag[ii]) {
  167. if (retriggerFlag[ii] || eventTrigger[ii].isHigh()) {
  168. retriggerFlag[ii] = 0;
  169. phaseRolloverFlag[ii] = 0;
  170. /* state remains the same */
  171. }
  172. else { /* we've finished a tweedle and should stop it */
  173. tweedState[ii] = FINI;
  174. break;
  175. }
  176. }
  177. /* break not, NOT is just what we need to do anyway */
  178. /* but there's a slight chance to see a trigger, so if around that by state YUCK! */
  179. case NOT :
  180. if (tweedState[ii] == NOT) {
  181. if (eventTrigger[ii].process(inputs[TRIGGER_INPUT + ii].value)) {
  182. tweedState[ii] = INIT; /* and get right to it */
  183. break;
  184. }
  185. }
  186. if (1) { /* cannot jump from switch statement to this case label */
  187. float pitch = params[FREQUENCY_PARAM + ii].value;
  188. pitch += inputs[FREQUENCY_CV_INPUT + ii].value;
  189. pitch = clamp(pitch, -4.0f, 4.0f);
  190. float freq = 2.04395f * powf(2.0f, pitch); // LFO, right?
  191. //--> don't advance phase in the middle of a fade out on the gate
  192. // ARGH! too late, the phase done rolled over, that's what kicked us
  193. // if ((fadeState[ii] == ON) || (fadeState[ii] == OFF))
  194. phase[ii] += freq * deltaTime;
  195. if (phase[ii] >= 1.0f) {
  196. phaseRolloverFlag[ii] = 1;
  197. phase[ii] -= 1.0f;
  198. }
  199. /* YIKES !!! */
  200. if ((tweedState[ii] == TWEEDLE) || (tweedState[ii] == NOT)) {
  201. float x = params[SHAPE_PARAM + ii].value + inputs[SHAPE_CV_INPUT + ii].value * 0.1f;
  202. float t = phase[ii]; /* hey! */
  203. float y;
  204. /* yuck. skip one sample update at phase rollover. FIGURE THIS AWAY! */
  205. if (!phaseRolloverFlag[ii])
  206. outputs[RECTANGLE_OUTPUT + ii].value = (phase[ii] > x) ? 0.0f : 10.0f;
  207. if (x >= 1.0f) y = t;
  208. else if(x <= 0.0f) y = 1.0f - t;
  209. else if (t < x) y = t / x;
  210. else y = (1.0f - t) / (1.0f - x);
  211. if (!phaseRolloverFlag[ii])
  212. outputs[TRIANGLE_OUTPUT + ii].value = 10.0f * y;
  213. }
  214. } /* if (1) */
  215. break;
  216. case FINI :
  217. fadeState[ii] = STOP;
  218. tweedState[ii] = BUSY;
  219. break;
  220. case BUSY :
  221. if (fadeState[ii] == OFF) tweedState[ii] = NOT;
  222. break;
  223. }
  224. /**/
  225. }
  226. }
  227. struct cheapFXWidget : ModuleWidget {
  228. cheapFXWidget(cheapFX *module) : ModuleWidget(module) {
  229. setPanel(SVG::load(assetPlugin(plugin, "res/cheapFX.svg")));
  230. addChild(Widget::create<myBoltA>(Vec(0, 0)));
  231. addChild(Widget::create<myBoltB>(Vec(box.size.x - RACK_GRID_WIDTH, 0)));
  232. addChild(Widget::create<myBoltD>(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  233. addChild(Widget::create<myBoltC>(Vec(box.size.x - RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  234. addParam(ParamWidget::create<RoundLargeBlackKnob>(mm2px(Vec(2.4f, 12.845f)), module, cheapFX::FREQUENCY_PARAM + 0, -3.0, 3.0, 0.0));
  235. addParam(ParamWidget::create<RoundLargeBlackKnob>(mm2px(Vec(20.461f, 12.845f)), module, cheapFX::SHAPE_PARAM + 0, 0.0, 1.0, 0.5));
  236. addParam(ParamWidget::create<RoundLargeBlackKnob>(mm2px(Vec(2.4f, 72.641f)), module, cheapFX::FREQUENCY_PARAM + 1, -3.0, 3.0, 0.0));
  237. addParam(ParamWidget::create<RoundLargeBlackKnob>(mm2px(Vec(20.461f, 72.641f)), module, cheapFX::SHAPE_PARAM + 1, 0.0, 1.0, 0.5));
  238. addInput(Port::create<PJ301MPort>(mm2px(Vec(4.572f, 28.358f)), Port::INPUT, module, cheapFX::FREQUENCY_CV_INPUT + 0));
  239. addInput(Port::create<PJ301MPort>(mm2px(Vec(22.449f, 28.359f)), Port::INPUT, module, cheapFX::SHAPE_CV_INPUT + 0));
  240. addInput(Port::create<PJ301MPort>(mm2px(Vec(4.572f, 53.229f)), Port::INPUT, module, cheapFX::TRIGGER_INPUT + 0));
  241. addInput(Port::create<PJ301MPort>(mm2px(Vec(4.572f, 88.154f)), Port::INPUT, module, cheapFX::FREQUENCY_CV_INPUT + 1));
  242. addInput(Port::create<PJ301MPort>(mm2px(Vec(22.449f, 88.155f)), Port::INPUT, module, cheapFX::SHAPE_CV_INPUT + 1));
  243. addInput(Port::create<PJ301MPort>(mm2px(Vec(4.572f, 113.024f)), Port::INPUT, module, cheapFX::TRIGGER_INPUT + 1));
  244. addOutput(Port::create<PJ301MPort>(mm2px(Vec(4.572f, 40.11f)), Port::OUTPUT, module, cheapFX::TRIANGLE_OUTPUT + 0));
  245. addOutput(Port::create<PJ301MPort>(mm2px(Vec(22.633f, 40.111f)), Port::OUTPUT, module, cheapFX::RECTANGLE_OUTPUT + 0));
  246. addOutput(Port::create<PJ301MPort>(mm2px(Vec(22.633f, 53.229f)), Port::OUTPUT, module, cheapFX::GATE_OUTPUT + 0));
  247. addOutput(Port::create<PJ301MPort>(mm2px(Vec(4.572f, 99.906f)), Port::OUTPUT, module, cheapFX::TRIANGLE_OUTPUT + 1));
  248. addOutput(Port::create<PJ301MPort>(mm2px(Vec(22.633f, 99.907f)), Port::OUTPUT, module, cheapFX::RECTANGLE_OUTPUT + 1));
  249. addOutput(Port::create<PJ301MPort>(mm2px(Vec(22.633f, 113.024f)), Port::OUTPUT, module, cheapFX::GATE_OUTPUT + 1));
  250. }
  251. };
  252. } // namespace rack_plugin_alto777_LFSR
  253. using namespace rack_plugin_alto777_LFSR;
  254. RACK_PLUGIN_MODEL_INIT(alto777_LFSR, cheapFX) {
  255. Model *modelcheapFX = Model::create<cheapFX, cheapFXWidget>("alto777_LFSR", "cheapFX", "Cheap F/X", LFO_TAG);
  256. return modelcheapFX;
  257. }