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.

178 lines
5.4KB

  1. #include "AH.hpp"
  2. #include "Core.hpp"
  3. #include "UI.hpp"
  4. #include "VCO.hpp"
  5. #include "dsp/digital.hpp"
  6. #include "dsp/resampler.hpp"
  7. #include "dsp/filter.hpp"
  8. #include <iostream>
  9. namespace rack_plugin_AmalgamatedHarmonics {
  10. struct Chord : AHModule {
  11. const static int NUM_PITCHES = 6;
  12. enum ParamIds {
  13. ENUMS(WAVE_PARAM,6),
  14. ENUMS(OCTAVE_PARAM,6),
  15. ENUMS(DETUNE_PARAM,6),
  16. ENUMS(PW_PARAM,6),
  17. ENUMS(PWM_PARAM,6),
  18. ENUMS(ATTN_PARAM,6),
  19. ENUMS(PAN_PARAM,6),
  20. SPREAD_PARAM,
  21. NUM_PARAMS
  22. };
  23. enum InputIds {
  24. ENUMS(PITCH_INPUT,6),
  25. ENUMS(PW_INPUT,6),
  26. NUM_INPUTS
  27. };
  28. enum OutputIds {
  29. ENUMS(OUT_OUTPUT,2),
  30. NUM_OUTPUTS
  31. };
  32. enum LightIds {
  33. NUM_LIGHTS
  34. };
  35. Chord() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  36. void step() override;
  37. Core core;
  38. int poll = 50000;
  39. SchmittTrigger moveTrigger;
  40. PulseGenerator triggerPulse;
  41. EvenVCO oscillator[6];
  42. };
  43. void Chord::step() {
  44. AHModule::step();
  45. float out[2] = {0.0f, 0.0f};
  46. int nP[2] = {0, 0};
  47. float spread = params[SPREAD_PARAM].value;
  48. float SQRT2_2 = sqrt(2.0) / 2.0;
  49. for (int i = 0; i < NUM_PITCHES; i++) {
  50. int index = PITCH_INPUT + i;
  51. int side = i % 2;
  52. float pitchCv = inputs[index].value + params[OCTAVE_PARAM + i].value;
  53. float pitchFine = params[DETUNE_PARAM + i].value / 12.0; // +- 1V
  54. float attn = params[ATTN_PARAM + i].value;
  55. oscillator[i].pw = params[PW_PARAM + i].value + params[PWM_PARAM + i].value * inputs[PW_INPUT + i].value / 10.0f;
  56. oscillator[i].step(delta, pitchFine + pitchCv); // 1V/OCT
  57. if (inputs[index].active) {
  58. float amp = 0.0;
  59. nP[side]++;
  60. int wave = params[WAVE_PARAM + i].value;
  61. switch(wave) {
  62. case 0: amp = oscillator[i].sine * attn; break;
  63. case 1: amp = oscillator[i].saw * attn; break;
  64. case 2: amp = oscillator[i].doubleSaw * attn; break;
  65. case 3: amp = oscillator[i].square * attn; break;
  66. case 4: amp = oscillator[i].even * attn; break;
  67. default: amp = oscillator[i].sine * attn; break;
  68. };
  69. float angle = spread * params[PAN_PARAM + i].value;
  70. float left = SQRT2_2 * (cos(angle) - sin(angle));
  71. float right = SQRT2_2 * (cos(angle) + sin(angle));
  72. out[0] += left * amp;
  73. out[1] += right * amp;
  74. }
  75. }
  76. if (nP[0] > 0) {
  77. out[0] = (out[0] * 5.0f) / (float)nP[0];
  78. }
  79. if (nP[1] > 0) {
  80. out[1] = (out[1] * 5.0f) / (float)nP[1];
  81. }
  82. // std::cout << nPitches << " " << out[0] << " " << out[1] << std::endl;
  83. if (outputs[OUT_OUTPUT].active && outputs[OUT_OUTPUT + 1].active) {
  84. outputs[OUT_OUTPUT].value = out[0];
  85. outputs[OUT_OUTPUT + 1].value = out[1];
  86. } else if (!outputs[OUT_OUTPUT].active && outputs[OUT_OUTPUT + 1].active) {
  87. outputs[OUT_OUTPUT].value = 0.0f;
  88. outputs[OUT_OUTPUT + 1].value = (out[0] + out[1]) / 2.0f;
  89. } else if (outputs[OUT_OUTPUT].active && !outputs[OUT_OUTPUT + 1].active) {
  90. outputs[OUT_OUTPUT].value = (out[0] + out[1]) / 2.0f;
  91. outputs[OUT_OUTPUT + 1].value = 0.0f;
  92. }
  93. }
  94. struct ChordWidget : ModuleWidget {
  95. ChordWidget(Chord *module) : ModuleWidget(module) {
  96. UI ui;
  97. float PI_180 = M_PI / 180.0f;
  98. float posMax = 90.0 * 0.5 * PI_180;
  99. float voicePosDeg[6] = {-90.0f, 90.0f, -54.0f, 54.0f, -18.0f, 18.0f};
  100. float voicePosRad[6];
  101. for(int i = 0; i < 6; i++) {
  102. voicePosRad[i] = voicePosDeg[i] * 0.5 * PI_180;
  103. }
  104. box.size = Vec(270, 380);
  105. {
  106. SVGPanel *panel = new SVGPanel();
  107. panel->box.size = box.size;
  108. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Chord.svg")));
  109. addChild(panel);
  110. }
  111. for (int n = 0; n < 6; n++) {
  112. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, n, 0, true, true), Port::INPUT, module, Chord::PITCH_INPUT + n));
  113. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, n, 1, true, true), module, Chord::WAVE_PARAM + n, 0.0f, 4.0f, 0.0f));
  114. addParam(ParamWidget::create<AHKnobSnap>(ui.getPosition(UI::KNOB, n, 2, true, true), module, Chord::OCTAVE_PARAM + n, -3.0f, 3.0f, 0.0f));
  115. addParam(ParamWidget::create<AHKnobNoSnap>(ui.getPosition(UI::KNOB, n, 3, true, true), module, Chord::DETUNE_PARAM + n, -1.0f, 1.0f, 0.0f));
  116. addParam(ParamWidget::create<AHKnobNoSnap>(ui.getPosition(UI::KNOB, n, 4, true, true), module, Chord::PW_PARAM + n, -1.0f, 1.0f, 0.0f));
  117. addInput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, n, 5, true, true), Port::INPUT, module, Chord::PW_INPUT + n));
  118. addParam(ParamWidget::create<AHKnobNoSnap>(ui.getPosition(UI::KNOB, n, 6, true, true), module, Chord::PWM_PARAM + n, 0.0f, 1.0f, 0.0f));
  119. addParam(ParamWidget::create<AHKnobNoSnap>(ui.getPosition(UI::KNOB, n, 7, true, true), module, Chord::ATTN_PARAM + n, 0.0f, 1.0f, 1.0f));
  120. addParam(ParamWidget::create<AHKnobNoSnap>(ui.getPosition(UI::KNOB, n, 8, true, true), module, Chord::PAN_PARAM + n, -posMax, posMax, voicePosRad[n]));
  121. }
  122. addParam(ParamWidget::create<AHKnobNoSnap>(ui.getPosition(UI::KNOB, 0, 9, true, true), module, Chord::SPREAD_PARAM, 0.0f, 1.0f, 1.0f));
  123. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 4, 9, true, true), Port::OUTPUT, module, Chord::OUT_OUTPUT));
  124. addOutput(Port::create<PJ301MPort>(ui.getPosition(UI::PORT, 5, 9, true, true), Port::OUTPUT, module, Chord::OUT_OUTPUT + 1));
  125. }
  126. };
  127. } // namespace rack_plugin_AmalgamatedHarmonics
  128. using namespace rack_plugin_AmalgamatedHarmonics;
  129. RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, Chord) {
  130. Model *modelChord = Model::create<Chord, ChordWidget>( "Amalgamated Harmonics", "Chord", "D'acchord", OSCILLATOR_TAG);
  131. return modelChord;
  132. }
  133. // ♯♭