FourFO.cpp (10309B)
1 2 #include "FourFO.hpp" 3 4 const Phasor::phase_delta_t basePhase3Offset = Phasor::radiansToPhase(1.5f * M_PI); 5 const Phasor::phase_delta_t basePhase2Offset = Phasor::radiansToPhase(M_PI); 6 const Phasor::phase_delta_t basePhase1Offset = Phasor::radiansToPhase(0.5f * M_PI); 7 const Phasor::phase_delta_t basePhase0Offset = Phasor::radiansToPhase(0.0f); 8 9 void FourFO::Engine::reset() { 10 resetTrigger.reset(); 11 sampleStep = phasor._sampleRate; 12 } 13 14 void FourFO::Engine::sampleRateChange() { 15 phasor.setSampleRate(APP->engine->getSampleRate()); 16 sampleStep = phasor._sampleRate; 17 } 18 19 void FourFO::reset() { 20 for (int c = 0; c < _channels; ++c) { 21 _engines[c]->reset(); 22 } 23 } 24 25 void FourFO::sampleRateChange() { 26 for (int c = 0; c < _channels; ++c) { 27 _engines[c]->sampleRateChange(); 28 } 29 } 30 31 bool FourFO::active() { 32 return ( 33 outputs[PHASE3_OUTPUT].isConnected() || 34 outputs[PHASE2_OUTPUT].isConnected() || 35 outputs[PHASE1_OUTPUT].isConnected() || 36 outputs[PHASE0_OUTPUT].isConnected() 37 ); 38 } 39 40 int FourFO::channels() { 41 return inputs[PITCH_INPUT].getChannels(); 42 } 43 44 void FourFO::addChannel(int c) { 45 _engines[c] = new Engine(); 46 _engines[c]->reset(); 47 _engines[c]->sampleRateChange(); 48 if (c > 0) { 49 _engines[c]->phasor.syncPhase(_engines[0]->phasor); 50 } 51 } 52 53 void FourFO::removeChannel(int c) { 54 delete _engines[c]; 55 _engines[c] = NULL; 56 } 57 58 void FourFO::modulate() { 59 _wave = (Wave)roundf(params[WAVE_PARAM].getValue()); 60 _slowMode = params[SLOW_PARAM].getValue() > 0.5f; 61 } 62 63 void FourFO::modulateChannel(int c) { 64 Engine& e = *_engines[c]; 65 66 setFrequency(params[FREQUENCY_PARAM], inputs[PITCH_INPUT], e.phasor, c); 67 68 switch (_wave) { 69 case SQUARE_WAVE: { 70 float pw = params[SAMPLE_PWM_PARAM].getValue(); 71 if (inputs[SAMPLE_PWM_INPUT].isConnected()) { 72 pw *= clamp(inputs[SAMPLE_PWM_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); 73 } 74 pw *= 1.0f - 2.0f * e.square.minPulseWidth; 75 pw *= 0.5f; 76 pw += 0.5f; 77 e.square.setPulseWidth(pw); 78 e.sampleSteps = 1; 79 break; 80 } 81 case STEPPED_WAVE: { 82 e.sampleSteps = 1; 83 break; 84 } 85 default: { 86 float sample = fabsf(params[SAMPLE_PWM_PARAM].getValue()); 87 if (inputs[SAMPLE_PWM_INPUT].isConnected()) { 88 sample *= clamp(fabsf(inputs[SAMPLE_PWM_INPUT].getPolyVoltage(c)) / 5.0f, 0.0f, 1.0f); 89 } 90 float maxSampleSteps = (e.phasor._sampleRate / e.phasor._frequency) / 4.0f; 91 e.sampleSteps = clamp((int)(sample * maxSampleSteps), 1, (int)maxSampleSteps); 92 } 93 } 94 95 float smooth = params[SMOOTH_PARAM].getValue(); 96 if (inputs[SMOOTH_INPUT].isConnected()) { 97 smooth *= clamp(inputs[SMOOTH_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 98 } 99 float sr = APP->engine->getSampleRate(); 100 e.phase3Smoother.setParams(sr, e.phasor._frequency, smooth); 101 e.phase2Smoother.setParams(sr, e.phasor._frequency, smooth); 102 e.phase1Smoother.setParams(sr, e.phasor._frequency, smooth); 103 e.phase0Smoother.setParams(sr, e.phasor._frequency, smooth); 104 105 e.offset = params[OFFSET_PARAM].getValue(); 106 if (inputs[OFFSET_INPUT].isConnected()) { 107 e.offset *= clamp(inputs[OFFSET_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); 108 } 109 e.offset *= _offsetScale; 110 e.offset *= 5.0f; 111 e.scale = params[SCALE_PARAM].getValue(); 112 if (inputs[SCALE_INPUT].isConnected()) { 113 e.scale *= clamp(inputs[SCALE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 114 } 115 116 e.phase3Offset = phaseOffset(c, params[PHASE3_PARAM], inputs[PHASE3_INPUT], basePhase3Offset); 117 e.phase2Offset = phaseOffset(c, params[PHASE2_PARAM], inputs[PHASE2_INPUT], basePhase2Offset); 118 e.phase1Offset = phaseOffset(c, params[PHASE1_PARAM], inputs[PHASE1_INPUT], basePhase1Offset); 119 e.phase0Offset = phaseOffset(c, params[PHASE0_PARAM], inputs[PHASE0_INPUT], basePhase0Offset); 120 } 121 122 void FourFO::processChannel(const ProcessArgs& args, int c) { 123 Engine& e = *_engines[c]; 124 125 if (e.resetTrigger.next(inputs[RESET_INPUT].getPolyVoltage(c))) { 126 e.phasor.resetPhase(); 127 } 128 129 e.phasor.advancePhase(); 130 bool useSample = false; 131 if (e.sampleSteps > 1) { 132 ++e.sampleStep; 133 if (e.sampleStep >= e.sampleSteps) { 134 e.sampleStep = 0; 135 } 136 else { 137 useSample = true; 138 } 139 } 140 updateOutput(c, useSample, outputs[PHASE3_OUTPUT], e.phase3Offset, e.phase3Sample, e.phase3Active, e.phase3Smoother); 141 updateOutput(c, useSample, outputs[PHASE2_OUTPUT], e.phase2Offset, e.phase2Sample, e.phase2Active, e.phase2Smoother); 142 updateOutput(c, useSample, outputs[PHASE1_OUTPUT], e.phase1Offset, e.phase1Sample, e.phase1Active, e.phase1Smoother); 143 updateOutput(c, useSample, outputs[PHASE0_OUTPUT], e.phase0Offset, e.phase0Sample, e.phase0Active, e.phase0Smoother); 144 } 145 146 Phasor::phase_delta_t FourFO::phaseOffset(int c, Param& p, Input& i, Phasor::phase_delta_t baseOffset) { 147 float o = p.getValue() * Phasor::cyclePhase / 2.0f; 148 if (i.isConnected()) { 149 o *= clamp(i.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); 150 } 151 return baseOffset - o; 152 } 153 154 void FourFO::updateOutput(int c, bool useSample, Output& output, Phasor::phase_delta_t& offset, float& sample, bool& active, Smoother& smoother) { 155 if (output.isConnected()) { 156 output.setChannels(_channels); 157 if (!useSample || !active) { 158 float v = 0.0f; 159 switch (_wave) { 160 case NO_WAVE: { 161 assert(false); 162 } 163 case SINE_WAVE: { 164 v = _engines[c]->sine.nextFromPhasor(_engines[c]->phasor, offset); 165 break; 166 } 167 case TRIANGLE_WAVE: { 168 v = _engines[c]->triangle.nextFromPhasor(_engines[c]->phasor, offset); 169 break; 170 } 171 case RAMP_UP_WAVE: { 172 v = _engines[c]->ramp.nextFromPhasor(_engines[c]->phasor, offset); 173 break; 174 } 175 case RAMP_DOWN_WAVE: { 176 v = -_engines[c]->ramp.nextFromPhasor(_engines[c]->phasor, offset); 177 break; 178 } 179 case SQUARE_WAVE: { 180 v = _engines[c]->square.nextFromPhasor(_engines[c]->phasor, offset); 181 break; 182 } 183 case STEPPED_WAVE: { 184 v = _engines[c]->stepped.nextFromPhasor(_engines[c]->phasor, offset); 185 break; 186 } 187 } 188 sample = amplitude * _engines[c]->scale * v + _engines[c]->offset; 189 } 190 output.setVoltage(clamp(smoother.next(sample), -12.0f, 12.0f), c); 191 active = true; 192 } 193 else { 194 active = false; 195 } 196 } 197 198 struct FourFOWidget : LFOBaseModuleWidget { 199 static constexpr int hp = 10; 200 201 FourFOWidget(FourFO* module) { 202 setModule(module); 203 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 204 setPanel(box.size, "FourFO"); 205 createScrews(); 206 207 // generated by svg_widgets.rb 208 auto frequencyParamPosition = Vec(23.0, 42.0); 209 auto waveParamPosition = Vec(95.0, 53.0); 210 auto slowParamPosition = Vec(49.0, 108.7); 211 auto samplePwmParamPosition = Vec(13.0, 149.0); 212 auto smoothParamPosition = Vec(48.0, 149.0); 213 auto offsetParamPosition = Vec(13.0, 198.0); 214 auto scaleParamPosition = Vec(48.0, 198.0); 215 auto phase0ParamPosition = Vec(121.0, 193.0); 216 auto phase1ParamPosition = Vec(84.0, 193.0); 217 auto phase2ParamPosition = Vec(84.0, 251.0); 218 auto phase3ParamPosition = Vec(121.0, 251.0); 219 220 auto samplePwmInputPosition = Vec(11.0, 230.0); 221 auto smoothInputPosition = Vec(43.0, 230.0); 222 auto offsetInputPosition = Vec(11.0, 274.0); 223 auto scaleInputPosition = Vec(43.0, 274.0); 224 auto pitchInputPosition = Vec(11.0, 318.0); 225 auto resetInputPosition = Vec(43.0, 318.0); 226 auto phase0InputPosition = Vec(117.0, 104.0); 227 auto phase1InputPosition = Vec(80.0, 104.0); 228 auto phase2InputPosition = Vec(80.0, 322.0); 229 auto phase3InputPosition = Vec(117.0, 322.0); 230 231 auto phase0OutputPosition = Vec(117.0, 146.0); 232 auto phase1OutputPosition = Vec(80.0, 146.0); 233 auto phase2OutputPosition = Vec(80.0, 280.0); 234 auto phase3OutputPosition = Vec(117.0, 280.0); 235 // end generated by svg_widgets.rb 236 237 addParam(createParam<Knob38>(frequencyParamPosition, module, FourFO::FREQUENCY_PARAM)); 238 { 239 auto w = createParam<Knob16>(waveParamPosition, module, FourFO::WAVE_PARAM); 240 auto k = dynamic_cast<SvgKnob*>(w); 241 k->minAngle = 0.0; 242 k->maxAngle = M_PI; 243 k->speed = 3.0; 244 addParam(w); 245 } 246 addParam(createParam<IndicatorButtonGreen9>(slowParamPosition, module, FourFO::SLOW_PARAM)); 247 addParam(createParam<Knob16>(samplePwmParamPosition, module, FourFO::SAMPLE_PWM_PARAM)); 248 addParam(createParam<Knob16>(smoothParamPosition, module, FourFO::SMOOTH_PARAM)); 249 addParam(createParam<Knob16>(offsetParamPosition, module, FourFO::OFFSET_PARAM)); 250 addParam(createParam<Knob16>(scaleParamPosition, module, FourFO::SCALE_PARAM)); 251 addPhaseParam(phase3ParamPosition, module, FourFO::PHASE3_PARAM, Phasor::phaseToRadians(basePhase3Offset)); 252 addPhaseParam(phase2ParamPosition, module, FourFO::PHASE2_PARAM, Phasor::phaseToRadians(basePhase2Offset)); 253 addPhaseParam(phase1ParamPosition, module, FourFO::PHASE1_PARAM, Phasor::phaseToRadians(basePhase1Offset)); 254 addPhaseParam(phase0ParamPosition, module, FourFO::PHASE0_PARAM, Phasor::phaseToRadians(basePhase0Offset)); 255 256 addInput(createInput<Port24>(samplePwmInputPosition, module, FourFO::SAMPLE_PWM_INPUT)); 257 addInput(createInput<Port24>(smoothInputPosition, module, FourFO::SMOOTH_INPUT)); 258 addInput(createInput<Port24>(offsetInputPosition, module, FourFO::OFFSET_INPUT)); 259 addInput(createInput<Port24>(scaleInputPosition, module, FourFO::SCALE_INPUT)); 260 addInput(createInput<Port24>(pitchInputPosition, module, FourFO::PITCH_INPUT)); 261 addInput(createInput<Port24>(resetInputPosition, module, FourFO::RESET_INPUT)); 262 addInput(createInput<Port24>(phase0InputPosition, module, FourFO::PHASE0_INPUT)); 263 addInput(createInput<Port24>(phase1InputPosition, module, FourFO::PHASE1_INPUT)); 264 addInput(createInput<Port24>(phase2InputPosition, module, FourFO::PHASE2_INPUT)); 265 addInput(createInput<Port24>(phase3InputPosition, module, FourFO::PHASE3_INPUT)); 266 267 addOutput(createOutput<Port24>(phase0OutputPosition, module, FourFO::PHASE0_OUTPUT)); 268 addOutput(createOutput<Port24>(phase1OutputPosition, module, FourFO::PHASE1_OUTPUT)); 269 addOutput(createOutput<Port24>(phase2OutputPosition, module, FourFO::PHASE2_OUTPUT)); 270 addOutput(createOutput<Port24>(phase3OutputPosition, module, FourFO::PHASE3_OUTPUT)); 271 } 272 273 void addPhaseParam(const Vec& position, Module* module, FourFO::ParamsIds paramId, float rotation) { 274 auto w = createParam<Knob16>(position, module, paramId); 275 auto k = dynamic_cast<SvgKnob*>(w); 276 k->minAngle += 0.5 * M_PI - rotation; 277 k->maxAngle += 0.5 * M_PI - rotation; 278 addParam(w); 279 } 280 }; 281 282 Model* modelFourFO = createModel<FourFO, FourFOWidget>("Bogaudio-FourFO", "4FO", "Quadrature LFO", "LFO", "Random", "Polyphonic");