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.

291 lines
12KB

  1. #include "EightFO.hpp"
  2. #include "dsp/pitch.hpp"
  3. void EightFO::onReset() {
  4. _resetTrigger.reset();
  5. _modulationStep = modulationSteps;
  6. _sampleStep = _phasor._sampleRate;
  7. }
  8. void EightFO::onSampleRateChange() {
  9. _phasor.setSampleRate(engineGetSampleRate());
  10. _modulationStep = modulationSteps;
  11. _sampleStep = _phasor._sampleRate;
  12. }
  13. void EightFO::step() {
  14. lights[SLOW_LIGHT].value = _slowMode = params[SLOW_PARAM].value > 0.5f;
  15. if (!(
  16. outputs[PHASE7_OUTPUT].active ||
  17. outputs[PHASE6_OUTPUT].active ||
  18. outputs[PHASE5_OUTPUT].active ||
  19. outputs[PHASE4_OUTPUT].active ||
  20. outputs[PHASE3_OUTPUT].active ||
  21. outputs[PHASE2_OUTPUT].active ||
  22. outputs[PHASE1_OUTPUT].active ||
  23. outputs[PHASE0_OUTPUT].active
  24. )) {
  25. return;
  26. }
  27. ++_modulationStep;
  28. if (_modulationStep >= modulationSteps) {
  29. _modulationStep = 0;
  30. float frequency = params[FREQUENCY_PARAM].value;
  31. if (inputs[PITCH_INPUT].active) {
  32. frequency += inputs[PITCH_INPUT].value;
  33. }
  34. if (_slowMode) {
  35. frequency -= 8.0f;
  36. }
  37. else {
  38. frequency -= 4.0f;
  39. }
  40. frequency = cvToFrequency(frequency);
  41. if (frequency > 2000.0f) {
  42. frequency = 2000.0f;
  43. }
  44. _phasor.setFrequency(frequency);
  45. _wave = (Wave)int(params[WAVE_PARAM].value);
  46. if (_wave == SQUARE_WAVE) {
  47. float pw = params[SAMPLE_PWM_PARAM].value;
  48. if (inputs[SAMPLE_PWM_INPUT].active) {
  49. pw *= clamp(inputs[SAMPLE_PWM_INPUT].value / 5.0f, -1.0f, 1.0f);
  50. }
  51. pw *= 1.0f - 2.0f * _square.minPulseWidth;
  52. pw *= 0.5f;
  53. pw += 0.5f;
  54. _square.setPulseWidth(pw);
  55. _sampleSteps = 1;
  56. }
  57. else {
  58. float sample = fabsf(params[SAMPLE_PWM_PARAM].value);
  59. if (inputs[SAMPLE_PWM_INPUT].active) {
  60. sample *= clamp(fabsf(inputs[SAMPLE_PWM_INPUT].value) / 5.0f, 0.0f, 1.0f);
  61. }
  62. float maxSampleSteps = (_phasor._sampleRate / _phasor._frequency) / 4.0f;
  63. _sampleSteps = clamp((int)(sample * maxSampleSteps), 1, (int)maxSampleSteps);
  64. _square.setPulseWidth(SquareOscillator::defaultPulseWidth);
  65. }
  66. _offset = params[OFFSET_PARAM].value;
  67. if (inputs[OFFSET_INPUT].active) {
  68. _offset *= clamp(inputs[OFFSET_INPUT].value / 5.0f, -1.0f, 1.0f);
  69. }
  70. _offset *= 5.0f;
  71. _scale = params[SCALE_PARAM].value;
  72. if (inputs[SCALE_INPUT].active) {
  73. _scale *= clamp(inputs[SCALE_INPUT].value / 10.0f, 0.0f, 1.0f);
  74. }
  75. _phase7Offset = phaseOffset(params[PHASE7_PARAM], inputs[PHASE7_INPUT], basePhase7Offset);
  76. _phase6Offset = phaseOffset(params[PHASE6_PARAM], inputs[PHASE6_INPUT], basePhase6Offset);
  77. _phase5Offset = phaseOffset(params[PHASE5_PARAM], inputs[PHASE5_INPUT], basePhase5Offset);
  78. _phase4Offset = phaseOffset(params[PHASE4_PARAM], inputs[PHASE4_INPUT], basePhase4Offset);
  79. _phase3Offset = phaseOffset(params[PHASE3_PARAM], inputs[PHASE3_INPUT], basePhase3Offset);
  80. _phase2Offset = phaseOffset(params[PHASE2_PARAM], inputs[PHASE2_INPUT], basePhase2Offset);
  81. _phase1Offset = phaseOffset(params[PHASE1_PARAM], inputs[PHASE1_INPUT], basePhase1Offset);
  82. _phase0Offset = phaseOffset(params[PHASE0_PARAM], inputs[PHASE0_INPUT], basePhase0Offset);
  83. }
  84. if (_resetTrigger.next(inputs[RESET_INPUT].value)) {
  85. _phasor.resetPhase();
  86. }
  87. _phasor.advancePhase();
  88. bool useSample = false;
  89. if (_sampleSteps > 1) {
  90. ++_sampleStep;
  91. if (_sampleStep >= _sampleSteps) {
  92. _sampleStep = 0;
  93. }
  94. else {
  95. useSample = true;
  96. }
  97. }
  98. updateOutput(useSample, outputs[PHASE7_OUTPUT], _phase7Offset, _phase7Sample, _phase7Active);
  99. updateOutput(useSample, outputs[PHASE6_OUTPUT], _phase6Offset, _phase6Sample, _phase6Active);
  100. updateOutput(useSample, outputs[PHASE5_OUTPUT], _phase5Offset, _phase5Sample, _phase5Active);
  101. updateOutput(useSample, outputs[PHASE4_OUTPUT], _phase4Offset, _phase4Sample, _phase4Active);
  102. updateOutput(useSample, outputs[PHASE3_OUTPUT], _phase3Offset, _phase3Sample, _phase3Active);
  103. updateOutput(useSample, outputs[PHASE2_OUTPUT], _phase2Offset, _phase2Sample, _phase2Active);
  104. updateOutput(useSample, outputs[PHASE1_OUTPUT], _phase1Offset, _phase1Sample, _phase1Active);
  105. updateOutput(useSample, outputs[PHASE0_OUTPUT], _phase0Offset, _phase0Sample, _phase0Active);
  106. }
  107. Phasor::phase_delta_t EightFO::phaseOffset(Param& p, Input& i, Phasor::phase_delta_t baseOffset) {
  108. float o = p.value * Phasor::maxPhase / 2.0f;
  109. if (i.active) {
  110. o *= clamp(i.value / 5.0f, -1.0f, 1.0f);
  111. }
  112. return baseOffset - o;
  113. }
  114. void EightFO::updateOutput(bool useSample, Output& output, Phasor::phase_delta_t& offset, float& sample, bool& active) {
  115. if (output.active) {
  116. if (useSample && active) {
  117. output.value = sample;
  118. }
  119. else {
  120. float v = 0.0f;
  121. switch (_wave) {
  122. case NO_WAVE: {
  123. assert(false);
  124. }
  125. case SINE_WAVE: {
  126. v = _sine.nextFromPhasor(_phasor, offset);
  127. break;
  128. }
  129. case TRIANGLE_WAVE: {
  130. v = _triangle.nextFromPhasor(_phasor, offset);
  131. break;
  132. }
  133. case RAMP_UP_WAVE: {
  134. v = _ramp.nextFromPhasor(_phasor, offset);
  135. break;
  136. }
  137. case RAMP_DOWN_WAVE: {
  138. v = -_ramp.nextFromPhasor(_phasor, offset);
  139. break;
  140. }
  141. case SQUARE_WAVE: {
  142. v = _square.nextFromPhasor(_phasor, offset);
  143. break;
  144. }
  145. }
  146. output.value = sample = amplitude * _scale * v + _offset;
  147. }
  148. active = true;
  149. }
  150. else {
  151. active = false;
  152. }
  153. }
  154. struct EightFOWidget : ModuleWidget {
  155. static constexpr int hp = 17;
  156. EightFOWidget(EightFO* module) : ModuleWidget(module) {
  157. box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
  158. {
  159. SVGPanel *panel = new SVGPanel();
  160. panel->box.size = box.size;
  161. panel->setBackground(SVG::load(assetPlugin(plugin, "res/EightFO.svg")));
  162. addChild(panel);
  163. }
  164. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  165. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  166. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  167. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  168. // generated by svg_widgets.rb
  169. auto frequencyParamPosition = Vec(40.0, 45.0);
  170. auto slowParamPosition = Vec(126.0, 333.7);
  171. auto waveParamPosition = Vec(20.0, 168.0);
  172. auto samplePwmParamPosition = Vec(100.0, 163.0);
  173. auto offsetParamPosition = Vec(40.0, 226.0);
  174. auto scaleParamPosition = Vec(100.0, 226.0);
  175. auto phase7ParamPosition = Vec(144.0, 40.0);
  176. auto phase6ParamPosition = Vec(144.0, 80.0);
  177. auto phase5ParamPosition = Vec(144.0, 120.0);
  178. auto phase4ParamPosition = Vec(144.0, 160.0);
  179. auto phase3ParamPosition = Vec(144.0, 200.0);
  180. auto phase2ParamPosition = Vec(144.0, 240.0);
  181. auto phase1ParamPosition = Vec(144.0, 280.0);
  182. auto phase0ParamPosition = Vec(144.0, 320.0);
  183. auto phase7InputPosition = Vec(179.0, 36.0);
  184. auto phase6InputPosition = Vec(179.0, 76.0);
  185. auto phase5InputPosition = Vec(179.0, 116.0);
  186. auto phase4InputPosition = Vec(179.0, 156.0);
  187. auto phase3InputPosition = Vec(179.0, 196.0);
  188. auto phase2InputPosition = Vec(179.0, 236.0);
  189. auto phase1InputPosition = Vec(179.0, 276.0);
  190. auto phase0InputPosition = Vec(179.0, 316.0);
  191. auto samplePwmInputPosition = Vec(14.0, 277.0);
  192. auto offsetInputPosition = Vec(52.0, 277.0);
  193. auto scaleInputPosition = Vec(90.0, 277.0);
  194. auto pitchInputPosition = Vec(14.0, 318.0);
  195. auto resetInputPosition = Vec(52.0, 318.0);
  196. auto phase7OutputPosition = Vec(218.0, 36.0);
  197. auto phase6OutputPosition = Vec(218.0, 76.0);
  198. auto phase5OutputPosition = Vec(218.0, 116.0);
  199. auto phase4OutputPosition = Vec(218.0, 156.0);
  200. auto phase3OutputPosition = Vec(218.0, 196.0);
  201. auto phase2OutputPosition = Vec(218.0, 236.0);
  202. auto phase1OutputPosition = Vec(218.0, 276.0);
  203. auto phase0OutputPosition = Vec(218.0, 316.0);
  204. auto slowLightPosition = Vec(86.0, 335.0);
  205. // end generated by svg_widgets.rb
  206. addParam(ParamWidget::create<Knob68>(frequencyParamPosition, module, EightFO::FREQUENCY_PARAM, -8.0, 5.0, 0.0));
  207. {
  208. auto w = ParamWidget::create<Knob16>(waveParamPosition, module, EightFO::WAVE_PARAM, 1.0, 5.0, 3.0);
  209. auto k = dynamic_cast<SVGKnob*>(w);
  210. k->snap = true;
  211. k->minAngle = 0.0;
  212. k->maxAngle = M_PI;
  213. k->speed = 3.0;
  214. addParam(w);
  215. }
  216. addParam(ParamWidget::create<StatefulButton9>(slowParamPosition, module, EightFO::SLOW_PARAM, 0.0, 1.0, 0.0));
  217. addParam(ParamWidget::create<Knob26>(samplePwmParamPosition, module, EightFO::SAMPLE_PWM_PARAM, -1.0, 1.0, 0.0));
  218. addParam(ParamWidget::create<Knob26>(offsetParamPosition, module, EightFO::OFFSET_PARAM, -1.0, 1.0, 0.0));
  219. addParam(ParamWidget::create<Knob26>(scaleParamPosition, module, EightFO::SCALE_PARAM, 0.0, 1.0, 1.0));
  220. addPhaseParam(phase7ParamPosition, module, EightFO::PHASE7_PARAM, Phasor::phaseToRadians(module->basePhase7Offset));
  221. addPhaseParam(phase6ParamPosition, module, EightFO::PHASE6_PARAM, Phasor::phaseToRadians(module->basePhase6Offset));
  222. addPhaseParam(phase5ParamPosition, module, EightFO::PHASE5_PARAM, Phasor::phaseToRadians(module->basePhase5Offset));
  223. addPhaseParam(phase4ParamPosition, module, EightFO::PHASE4_PARAM, Phasor::phaseToRadians(module->basePhase4Offset));
  224. addPhaseParam(phase3ParamPosition, module, EightFO::PHASE3_PARAM, Phasor::phaseToRadians(module->basePhase3Offset));
  225. addPhaseParam(phase2ParamPosition, module, EightFO::PHASE2_PARAM, Phasor::phaseToRadians(module->basePhase2Offset));
  226. addPhaseParam(phase1ParamPosition, module, EightFO::PHASE1_PARAM, Phasor::phaseToRadians(module->basePhase1Offset));
  227. addPhaseParam(phase0ParamPosition, module, EightFO::PHASE0_PARAM, Phasor::phaseToRadians(module->basePhase0Offset));
  228. addInput(Port::create<Port24>(samplePwmInputPosition, Port::INPUT, module, EightFO::SAMPLE_PWM_INPUT));
  229. addInput(Port::create<Port24>(offsetInputPosition, Port::INPUT, module, EightFO::OFFSET_INPUT));
  230. addInput(Port::create<Port24>(scaleInputPosition, Port::INPUT, module, EightFO::SCALE_INPUT));
  231. addInput(Port::create<Port24>(phase7InputPosition, Port::INPUT, module, EightFO::PHASE7_INPUT));
  232. addInput(Port::create<Port24>(phase6InputPosition, Port::INPUT, module, EightFO::PHASE6_INPUT));
  233. addInput(Port::create<Port24>(phase5InputPosition, Port::INPUT, module, EightFO::PHASE5_INPUT));
  234. addInput(Port::create<Port24>(phase4InputPosition, Port::INPUT, module, EightFO::PHASE4_INPUT));
  235. addInput(Port::create<Port24>(phase3InputPosition, Port::INPUT, module, EightFO::PHASE3_INPUT));
  236. addInput(Port::create<Port24>(phase2InputPosition, Port::INPUT, module, EightFO::PHASE2_INPUT));
  237. addInput(Port::create<Port24>(phase1InputPosition, Port::INPUT, module, EightFO::PHASE1_INPUT));
  238. addInput(Port::create<Port24>(phase0InputPosition, Port::INPUT, module, EightFO::PHASE0_INPUT));
  239. addInput(Port::create<Port24>(pitchInputPosition, Port::INPUT, module, EightFO::PITCH_INPUT));
  240. addInput(Port::create<Port24>(resetInputPosition, Port::INPUT, module, EightFO::RESET_INPUT));
  241. addOutput(Port::create<Port24>(phase7OutputPosition, Port::OUTPUT, module, EightFO::PHASE7_OUTPUT));
  242. addOutput(Port::create<Port24>(phase6OutputPosition, Port::OUTPUT, module, EightFO::PHASE6_OUTPUT));
  243. addOutput(Port::create<Port24>(phase5OutputPosition, Port::OUTPUT, module, EightFO::PHASE5_OUTPUT));
  244. addOutput(Port::create<Port24>(phase4OutputPosition, Port::OUTPUT, module, EightFO::PHASE4_OUTPUT));
  245. addOutput(Port::create<Port24>(phase3OutputPosition, Port::OUTPUT, module, EightFO::PHASE3_OUTPUT));
  246. addOutput(Port::create<Port24>(phase2OutputPosition, Port::OUTPUT, module, EightFO::PHASE2_OUTPUT));
  247. addOutput(Port::create<Port24>(phase1OutputPosition, Port::OUTPUT, module, EightFO::PHASE1_OUTPUT));
  248. addOutput(Port::create<Port24>(phase0OutputPosition, Port::OUTPUT, module, EightFO::PHASE0_OUTPUT));
  249. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(slowLightPosition, module, EightFO::SLOW_LIGHT));
  250. }
  251. void addPhaseParam(const Vec& position, Module* module, EightFO::ParamsIds paramId, float rotation) {
  252. auto w = ParamWidget::create<Knob16>(position, module, paramId, -1.0, 1.0, 0.0);
  253. auto k = dynamic_cast<SVGKnob*>(w);
  254. k->minAngle += 0.5 * M_PI - rotation;
  255. k->maxAngle += 0.5 * M_PI - rotation;
  256. addParam(w);
  257. }
  258. };
  259. RACK_PLUGIN_MODEL_INIT(Bogaudio, EightFO) {
  260. Model *modelEightFO = createModel<EightFO, EightFOWidget>("Bogaudio-EightFO", "8FO", "LFO with 8 phased outputs", LFO_TAG);
  261. return modelEightFO;
  262. }