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.

260 lines
7.8KB

  1. #include "mental.hpp"
  2. #include "dsp/digital.hpp"
  3. namespace rack_plugin_mental {
  4. struct LowFrequencyOscillator {
  5. float phase = 0.0;
  6. float pw = 0.5;
  7. float freq = 1.0;
  8. bool offset = false;
  9. bool invert = false;
  10. SchmittTrigger resetTrigger;
  11. LowFrequencyOscillator() {
  12. }
  13. void setFreq(float freq_to_set)
  14. {
  15. freq = freq_to_set;
  16. }
  17. void setPitch(float pitch) {
  18. pitch = fminf(pitch, 8.0);
  19. freq = powf(2.0, pitch);
  20. }
  21. void setPhase(float phase_to_set)
  22. {
  23. phase = phase_to_set;
  24. }
  25. void setPulseWidth(float pw_) {
  26. const float pwMin = 0.01;
  27. pw = clamp(pw_, pwMin, 1.0f - pwMin);
  28. }
  29. void setReset(float reset) {
  30. if (resetTrigger.process(reset)) {
  31. phase = 0.0;
  32. }
  33. }
  34. void step(float dt) {
  35. float deltaPhase = fminf(freq * dt, 0.5);
  36. phase += deltaPhase;
  37. if (phase >= 1.0)
  38. phase -= 1.0;
  39. }
  40. float sin() {
  41. if (offset)
  42. return 1.0 - cosf(2*M_PI * phase) * (invert ? -1.0 : 1.0);
  43. else
  44. return sinf(2*M_PI * phase) * (invert ? -1.0 : 1.0);
  45. }
  46. float tri(float x) {
  47. return 4.0 * fabsf(x - roundf(x));
  48. }
  49. float tri() {
  50. if (offset)
  51. return tri(invert ? phase - 0.5 : phase);
  52. else
  53. return -1.0 + tri(invert ? phase - 0.25 : phase - 0.75);
  54. }
  55. float saw(float x) {
  56. return 2.0 * (x - roundf(x));
  57. }
  58. float saw() {
  59. if (offset)
  60. return invert ? 2.0 * (1.0 - phase) : 2.0 * phase;
  61. else
  62. return saw(phase) * (invert ? -1.0 : 1.0);
  63. }
  64. float sqr() {
  65. float sqr = (phase < pw) ^ invert ? 1.0 : -1.0;
  66. return offset ? sqr + 1.0 : sqr;
  67. }
  68. float light() {
  69. return sinf(2*M_PI * phase);
  70. }
  71. };
  72. struct MentalQuadLFO : Module {
  73. enum ParamIds {
  74. MODE_BUTTON_PARAM,
  75. FREQ_PARAM,
  76. NUM_PARAMS = FREQ_PARAM + 4
  77. };
  78. enum InputIds {
  79. FREQ_INPUT,
  80. RESET_INPUT = FREQ_INPUT + 4,
  81. NUM_INPUTS = RESET_INPUT + 4
  82. };
  83. enum OutputIds {
  84. SIN_OUTPUT,
  85. TRI_OUTPUT = SIN_OUTPUT + 4,
  86. SAW_OUTPUT = TRI_OUTPUT + 4,
  87. SQR_OUTPUT = SAW_OUTPUT + 4,
  88. NUM_OUTPUTS = SQR_OUTPUT + 4
  89. };
  90. enum LightIds {
  91. PHASE_POS_LIGHT,
  92. PHASE_NEG_LIGHT = PHASE_POS_LIGHT + 4,
  93. MODE_LIGHTS = PHASE_NEG_LIGHT + 4 ,
  94. NUM_LIGHTS = MODE_LIGHTS + 5
  95. };
  96. LowFrequencyOscillator oscillator[4];
  97. SchmittTrigger mode_button_trigger;
  98. int mode = 0;
  99. MentalQuadLFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  100. void step() override;
  101. json_t *toJson() override
  102. {
  103. json_t *rootJ = json_object();
  104. // save mode
  105. json_t *modeJ = json_integer((int)mode);
  106. json_object_set_new(rootJ, "mode", modeJ);
  107. return rootJ;
  108. }
  109. void fromJson(json_t *rootJ) override
  110. {
  111. // read mode
  112. json_t *modeJ = json_object_get(rootJ, "mode");
  113. if (modeJ)
  114. {
  115. mode = json_integer_value(modeJ);
  116. }
  117. }
  118. };
  119. void MentalQuadLFO::step()
  120. {
  121. if (mode_button_trigger.process(params[MODE_BUTTON_PARAM].value))
  122. {
  123. mode ++;
  124. for (int i = 0 ; i < 4 ; i ++)
  125. {
  126. oscillator[i].setReset(5.00);
  127. }
  128. if (mode > 4) mode = 0;
  129. for (int i = 0 ; i < 5 ; i ++)
  130. {
  131. lights[MODE_LIGHTS + i].value = 0.0;
  132. }
  133. }
  134. lights[MODE_LIGHTS + mode].value = 1.0;
  135. if (mode == 0)
  136. {
  137. for (int i = 0 ; i < 4 ; i++)
  138. {
  139. oscillator[i].setPitch((params[FREQ_PARAM + i].value * 10 - 5) + inputs[FREQ_INPUT + i].value);
  140. oscillator[i].setReset(inputs[RESET_INPUT + i].value);
  141. }
  142. } else
  143. if (mode == 1)
  144. {
  145. for (int i = 0 ; i < 4 ; i++)
  146. {
  147. oscillator[i].setPitch((params[FREQ_PARAM].value * 10 - 5) + inputs[FREQ_INPUT].value);
  148. oscillator[i].setReset(inputs[RESET_INPUT].value);
  149. oscillator[i].setPhase(oscillator[0].phase + i * 0.25);
  150. }
  151. } else
  152. if (mode == 2)
  153. {
  154. for (int i = 0 ; i < 4 ; i++)
  155. {
  156. oscillator[i].setPitch((params[FREQ_PARAM].value * 10 - 5) + inputs[FREQ_INPUT].value);
  157. oscillator[i].setReset(inputs[RESET_INPUT].value);
  158. if (i > 0) oscillator[i].setPhase(oscillator[0].phase + (params[FREQ_PARAM + i].value));
  159. }
  160. } else
  161. if (mode == 3)
  162. {
  163. oscillator[0].setPitch((params[FREQ_PARAM].value * 10 - 5) + inputs[FREQ_INPUT].value);
  164. oscillator[1].setFreq(oscillator[0].freq / (std::round(params[FREQ_PARAM + 1].value * 11 + 1)));
  165. oscillator[2].setFreq(oscillator[0].freq / (std::round(params[FREQ_PARAM + 2].value * 11 + 1)));
  166. oscillator[3].setFreq(oscillator[0].freq / (std::round(params[FREQ_PARAM + 3].value * 11 + 1)));
  167. oscillator[0].setReset(inputs[RESET_INPUT].value);
  168. oscillator[1].setReset(inputs[RESET_INPUT].value);
  169. oscillator[2].setReset(inputs[RESET_INPUT].value);
  170. oscillator[3].setReset(inputs[RESET_INPUT].value);
  171. }
  172. if (mode == 4)
  173. {
  174. oscillator[0].setPitch((params[FREQ_PARAM].value * 10 - 5) + inputs[FREQ_INPUT].value);
  175. oscillator[1].setFreq(oscillator[0].freq * (std::round(params[FREQ_PARAM + 1].value * 11 + 1)));
  176. oscillator[2].setFreq(oscillator[0].freq * (std::round(params[FREQ_PARAM + 2].value * 11 + 1)));
  177. oscillator[3].setFreq(oscillator[0].freq * (std::round(params[FREQ_PARAM + 3].value * 11 + 1)));
  178. oscillator[0].setReset(inputs[RESET_INPUT].value);
  179. oscillator[1].setReset(inputs[RESET_INPUT].value);
  180. oscillator[2].setReset(inputs[RESET_INPUT].value);
  181. oscillator[3].setReset(inputs[RESET_INPUT].value);
  182. if (oscillator[0].phase == 0.0)
  183. {
  184. oscillator[1].setReset(5.0);
  185. oscillator[2].setReset(5.0);
  186. oscillator[3].setReset(5.0);
  187. }
  188. }
  189. for (int i = 0 ; i < 4 ; i++)
  190. {
  191. oscillator[i].step(1.0 / engineGetSampleRate());
  192. outputs[SIN_OUTPUT + i].value = 5.0 * oscillator[i].sin();
  193. outputs[TRI_OUTPUT + i].value = 5.0 * oscillator[i].tri();
  194. outputs[SAW_OUTPUT + i].value = 5.0 * oscillator[i].saw();
  195. outputs[SQR_OUTPUT + i].value = 5.0 * oscillator[i].sqr();
  196. lights[PHASE_POS_LIGHT + i].setBrightnessSmooth(fmaxf(0.0, oscillator[i].light()));
  197. lights[PHASE_NEG_LIGHT + i].setBrightnessSmooth(fmaxf(0.0, -oscillator[i].light()));
  198. }
  199. }
  200. ////////////////////////////////////////////////////////////////////////////////
  201. struct MentalQuadLFOWidget : ModuleWidget {
  202. MentalQuadLFOWidget(MentalQuadLFO *module);
  203. };
  204. MentalQuadLFOWidget::MentalQuadLFOWidget(MentalQuadLFO *module) : ModuleWidget(module)
  205. {
  206. setPanel(SVG::load(assetPlugin(plugin, "res/MentalQuadLFO.svg")));
  207. int x_offset = 10.10;
  208. for (int i = 0 ; i < 4 ; i++)
  209. {
  210. addParam(ParamWidget::create<BefacoSlidePot>(mm2px(Vec(2.792 + i * x_offset, 3.937)), module,MentalQuadLFO::FREQ_PARAM + i, 0.0, 1.0, 0.0));
  211. addInput(Port::create<CVInPort>(mm2px(Vec(1.003 + i * x_offset, 61.915)), Port::INPUT, module, MentalQuadLFO::FREQ_INPUT + i));
  212. addInput(Port::create<GateInPort>(mm2px(Vec(1.003 + i * x_offset, 72.858)), Port::INPUT, module, MentalQuadLFO::RESET_INPUT + i));
  213. addOutput(Port::create<OutPort>(mm2px(Vec(1.003 + i * x_offset, 83.759)), Port::OUTPUT, module, MentalQuadLFO::SIN_OUTPUT + i));
  214. addOutput(Port::create<OutPort>(mm2px(Vec(1.003 + i * x_offset, 94.173)), Port::OUTPUT, module, MentalQuadLFO::TRI_OUTPUT + i));
  215. addOutput(Port::create<OutPort>(mm2px(Vec(1.003 + i * x_offset, 105.169)), Port::OUTPUT, module, MentalQuadLFO::SAW_OUTPUT + i));
  216. addOutput(Port::create<OutPort>(mm2px(Vec(1.003 + i * x_offset, 114.583)), Port::OUTPUT, module, MentalQuadLFO::SQR_OUTPUT + i));
  217. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(13 + i * 30, 125), module, MentalQuadLFO::PHASE_POS_LIGHT + i));
  218. }
  219. for (int i = 0 ; i < 5 ; i++)
  220. {
  221. addChild(ModuleLightWidget::create<MedLight<BlueLED>>(mm2px(Vec(2.905 + i * 8 , 50.035)), module, MentalQuadLFO::MODE_LIGHTS + i));
  222. }
  223. addParam(ParamWidget::create<LEDButton>(Vec(50, 160), module, MentalQuadLFO::MODE_BUTTON_PARAM, 0.0, 1.0, 0.0));
  224. }
  225. } // namespace rack_plugin_mental
  226. using namespace rack_plugin_mental;
  227. RACK_PLUGIN_MODEL_INIT(mental, MentalQuadLFO) {
  228. Model *modelMentalQuadLFO = Model::create<MentalQuadLFO, MentalQuadLFOWidget>("mental", "MentalQuadLFO", "Quad LFO", LFO_TAG, QUAD_TAG, CLOCK_TAG);
  229. return modelMentalQuadLFO;
  230. }