Additator.cpp (10369B)
1 2 #include "Additator.hpp" 3 4 void Additator::Engine::reset() { 5 syncTrigger.reset(); 6 phase = PHASE_RESET; 7 } 8 9 void Additator::Engine::sampleRateChange() { 10 float sampleRate = APP->engine->getSampleRate(); 11 oscillator.setSampleRate(sampleRate); 12 maxFrequency = 0.475f * sampleRate; 13 phase = PHASE_RESET; 14 widthSL.setParams(sampleRate, slewLimitTime, maxWidth); 15 oddSkewSL.setParams(sampleRate, slewLimitTime, 2.0f * maxSkew); 16 evenSkewSL.setParams(sampleRate, slewLimitTime, 2.0f * maxSkew); 17 amplitudeNormalizationSL.setParams(sampleRate, slewLimitTime, maxAmplitudeNormalization - minAmplitudeNormalization); 18 decaySL.setParams(sampleRate, slewLimitTime, maxDecay - minDecay); 19 balanceSL.setParams(sampleRate, slewLimitTime, 2.0f); 20 filterSL.setParams(sampleRate, slewLimitTime, maxFilter - minFilter); 21 } 22 23 void Additator::reset() { 24 for (int c = 0; c < _channels; ++c) { 25 _engines[c]->reset(); 26 } 27 } 28 29 void Additator::sampleRateChange() { 30 for (int c = 0; c < _channels; ++c) { 31 _engines[c]->sampleRateChange(); 32 } 33 } 34 35 bool Additator::active() { 36 return outputs[AUDIO_OUTPUT].isConnected(); 37 } 38 39 int Additator::channels() { 40 return inputs[PITCH_INPUT].getChannels(); 41 } 42 43 void Additator::addChannel(int c) { 44 Engine& e = *(_engines[c] = new Engine()); 45 e.reset(); 46 e.sampleRateChange(); 47 48 e.widthSL._last = widthParam(c); 49 e.oddSkewSL._last = oddSkewParam(c); 50 e.evenSkewSL._last = evenSkewParam(c); 51 e.amplitudeNormalizationSL._last = amplitudeNormalizationParam(c); 52 e.decaySL._last = decayParam(c); 53 e.balanceSL._last = balanceParam(c); 54 e.filterSL._last = filterParam(c); 55 56 modulateChannel(c); 57 if (c > 0) { 58 e.oscillator.syncTo(_engines[0]->oscillator); 59 } 60 } 61 62 void Additator::removeChannel(int c) { 63 delete _engines[c]; 64 _engines[c] = NULL; 65 } 66 67 float Additator::widthParam(int c) { 68 return clamp(params[WIDTH_PARAM].getValue() + (maxWidth / 2.0f) * cvValue(c, inputs[WIDTH_INPUT]), 0.0f, maxWidth); 69 } 70 71 float Additator::oddSkewParam(int c) { 72 return clamp(params[ODD_SKEW_PARAM].getValue() + cvValue(c, inputs[ODD_SKEW_INPUT]), -maxSkew, maxSkew); 73 } 74 75 float Additator::evenSkewParam(int c) { 76 return clamp(params[EVEN_SKEW_PARAM].getValue() + cvValue(c, inputs[EVEN_SKEW_INPUT]), -maxSkew, maxSkew); 77 } 78 79 float Additator::amplitudeNormalizationParam(int c) { 80 return clamp(params[GAIN_PARAM].getValue() + ((maxAmplitudeNormalization - minAmplitudeNormalization) / 2.0f) * cvValue(c, inputs[GAIN_INPUT]), minAmplitudeNormalization, maxAmplitudeNormalization); 81 } 82 83 float Additator::decayParam(int c) { 84 return clamp(params[DECAY_PARAM].getValue() + ((maxDecay - minDecay) / 2.0f) * cvValue(c, inputs[DECAY_INPUT]), minDecay, maxDecay); 85 } 86 87 float Additator::balanceParam(int c) { 88 return clamp(params[BALANCE_PARAM].getValue() + cvValue(c, inputs[BALANCE_INPUT]), -1.0f, 1.0f); 89 } 90 91 float Additator::filterParam(int c) { 92 return clamp(params[FILTER_PARAM].getValue() + cvValue(c, inputs[FILTER_INPUT]), minFilter, maxFilter); 93 } 94 95 void Additator::modulateChannel(int c) { 96 Engine& e = *_engines[c]; 97 98 float width = e.widthSL.next(widthParam(c)); 99 float oddSkew = e.oddSkewSL.next(oddSkewParam(c)); 100 float evenSkew = e.evenSkewSL.next(evenSkewParam(c)); 101 if ( 102 e.width != width || 103 e.oddSkew != oddSkew || 104 e.evenSkew != evenSkew 105 ) { 106 e.width = width; 107 e.oddSkew = oddSkew; 108 e.evenSkew = evenSkew; 109 110 e.oscillator.setPartialFrequencyRatio(1, 1.0f); 111 e.activePartials = 1; 112 for (int i = 2, n = e.oscillator.partialCount(); i <= n; ++i) { 113 float ii = i; 114 if (i % 2 == 0) { 115 ii += e.evenSkew; 116 } 117 else { 118 ii += e.oddSkew; 119 } 120 if (e.oscillator.setPartialFrequencyRatio(i, powf(ii, e.width))) { 121 e.activePartials = i; 122 } 123 } 124 } 125 126 int partials = clamp((int)roundf(params[PARTIALS_PARAM].getValue() * cvValue(c, inputs[PARTIALS_INPUT], true)), 0, maxPartials); 127 float amplitudeNormalization = e.amplitudeNormalizationSL.next(amplitudeNormalizationParam(c)); 128 float decay = e.decaySL.next(decayParam(c)); 129 float balance = e.balanceSL.next(balanceParam(c)); 130 float filter = e.filterSL.next(filterParam(c)); 131 if ( 132 e.partials != partials || 133 e.amplitudeNormalization != amplitudeNormalization || 134 e.decay != decay || 135 e.balance != balance || 136 e.filter != filter 137 ) { 138 int envelopes = e.partials != partials ? std::max(e.partials, partials) : 0; 139 e.partials = partials; 140 e.amplitudeNormalization = amplitudeNormalization; 141 e.decay = decay; 142 e.balance = balance; 143 e.filter = filter; 144 145 float as[maxPartials + 1]; 146 float total = as[1] = 1.0f; 147 filter = log10f(e.filter) + 1.0f; 148 int np = std::min(e.partials, e.activePartials); 149 for (int i = 2, n = e.oscillator.partialCount(); i <= n; ++i) { 150 as[i] = 0.0f; 151 if (i <= np) { 152 as[i] = powf(i, -e.decay) * powf(e.filter, i); 153 if (i % 2 == 0) { 154 if (e.balance > 0.0f) { 155 as[i] *= 1.0f - e.balance; 156 } 157 } 158 else { 159 if (e.balance < 0.0f) { 160 as[i] *= 1.0f + e.balance; 161 } 162 } 163 total += as[i]; 164 } 165 } 166 float norm = std::max(np / (float)e.oscillator.partialCount(), 0.1f); 167 norm = 1.0f + (e.amplitudeNormalization - 1.0f) * norm; 168 norm = std::max(total / norm, 0.7f); 169 for (int i = 1, n = e.oscillator.partialCount(); i <= n; ++i) { 170 as[i] /= norm; 171 e.oscillator.setPartialAmplitude(i, as[i], i <= envelopes); 172 } 173 } 174 175 float frequency = params[FREQUENCY_PARAM].getValue(); 176 frequency += params[FINE_PARAM].getValue() / 12.0f; 177 if (inputs[PITCH_INPUT].isConnected()) { 178 frequency += clamp(inputs[PITCH_INPUT].getVoltage(c), -5.0f, 5.0f); 179 } 180 frequency = clamp(cvToFrequency(frequency), 20.0f, e.maxFrequency); 181 e.oscillator.setFrequency(frequency); 182 183 Phase phase = params[PHASE_PARAM].getValue() > 1.5f ? PHASE_COSINE : PHASE_SINE; 184 if (e.phase != phase) { 185 e.phase = phase; 186 e.oscillator.syncToPhase(e.phase == PHASE_SINE ? 0.0f : M_PI / 2.0f); 187 } 188 } 189 190 void Additator::processAlways(const ProcessArgs& args) { 191 Phase phase = params[PHASE_PARAM].getValue() > 1.5f ? PHASE_COSINE : PHASE_SINE; 192 lights[SINE_LIGHT].value = phase == PHASE_SINE; 193 lights[COSINE_LIGHT].value = phase == PHASE_COSINE; 194 } 195 196 void Additator::processChannel(const ProcessArgs& args, int c) { 197 Engine& e = *_engines[c]; 198 199 if (e.syncTrigger.next(inputs[SYNC_INPUT].getPolyVoltage(c))) { 200 e.oscillator.syncToPhase(e.phase == PHASE_SINE ? 0.0f : M_PI / 2.0f); 201 } 202 outputs[AUDIO_OUTPUT].setChannels(_channels); 203 outputs[AUDIO_OUTPUT].setVoltage(e.oscillator.next() * 5.0, c); 204 } 205 206 float Additator::cvValue(int c, Input& cv, bool dc) { 207 if (!cv.isConnected()) { 208 return dc ? 1.0f : 0.0f; 209 } 210 if (dc) { 211 return clamp(cv.getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 212 } 213 return clamp(cv.getPolyVoltage(c) / 5.0f, -1.0f, 1.0f); 214 } 215 216 struct AdditatorWidget : BGModuleWidget { 217 static constexpr int hp = 15; 218 219 AdditatorWidget(Additator* module) { 220 setModule(module); 221 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 222 setPanel(box.size, "Additator"); 223 createScrews(); 224 225 // generated by svg_widgets.rb 226 auto frequencyParamPosition = Vec(40.0, 45.0); 227 auto partialsParamPosition = Vec(165.0, 60.0); 228 auto fineParamPosition = Vec(30.0, 160.0); 229 auto widthParamPosition = Vec(79.0, 155.0); 230 auto oddSkewParamPosition = Vec(132.0, 155.0); 231 auto evenSkewParamPosition = Vec(184.0, 155.0); 232 auto gainParamPosition = Vec(25.0, 218.0); 233 auto decayParamPosition = Vec(79.0, 218.0); 234 auto balanceParamPosition = Vec(132.0, 218.0); 235 auto filterParamPosition = Vec(184.0, 218.0); 236 auto phaseParamPosition = Vec(194.0, 299.0); 237 238 auto syncInputPosition = Vec(16.0, 274.0); 239 auto partialsInputPosition = Vec(50.0, 274.0); 240 auto widthInputPosition = Vec(84.0, 274.0); 241 auto oddSkewInputPosition = Vec(118.0, 274.0); 242 auto evenSkewInputPosition = Vec(152.0, 274.0); 243 auto pitchInputPosition = Vec(16.0, 318.0); 244 auto gainInputPosition = Vec(50.0, 318.0); 245 auto decayInputPosition = Vec(84.0, 318.0); 246 auto balanceInputPosition = Vec(118.0, 318.0); 247 auto filterInputPosition = Vec(152.0, 318.0); 248 249 auto audioOutputPosition = Vec(186.0, 318.0); 250 251 auto sineLightPosition = Vec(185.0, 272.0); 252 auto cosineLightPosition = Vec(185.0, 287.0); 253 // end generated by svg_widgets.rb 254 255 addParam(createParam<Knob68>(frequencyParamPosition, module, Additator::FREQUENCY_PARAM)); 256 addParam(createParam<Knob38>(partialsParamPosition, module, Additator::PARTIALS_PARAM)); 257 addParam(createParam<Knob16>(fineParamPosition, module, Additator::FINE_PARAM)); 258 addParam(createParam<Knob26>(widthParamPosition, module, Additator::WIDTH_PARAM)); 259 addParam(createParam<Knob26>(oddSkewParamPosition, module, Additator::ODD_SKEW_PARAM)); 260 addParam(createParam<Knob26>(evenSkewParamPosition, module, Additator::EVEN_SKEW_PARAM)); 261 addParam(createParam<Knob26>(gainParamPosition, module, Additator::GAIN_PARAM)); 262 addParam(createParam<Knob26>(decayParamPosition, module, Additator::DECAY_PARAM)); 263 addParam(createParam<Knob26>(balanceParamPosition, module, Additator::BALANCE_PARAM)); 264 addParam(createParam<Knob26>(filterParamPosition, module, Additator::FILTER_PARAM)); 265 addParam(createParam<StatefulButton9>(phaseParamPosition, module, Additator::PHASE_PARAM)); 266 267 addInput(createInput<Port24>(partialsInputPosition, module, Additator::PARTIALS_INPUT)); 268 addInput(createInput<Port24>(widthInputPosition, module, Additator::WIDTH_INPUT)); 269 addInput(createInput<Port24>(oddSkewInputPosition, module, Additator::ODD_SKEW_INPUT)); 270 addInput(createInput<Port24>(evenSkewInputPosition, module, Additator::EVEN_SKEW_INPUT)); 271 addInput(createInput<Port24>(gainInputPosition, module, Additator::GAIN_INPUT)); 272 addInput(createInput<Port24>(decayInputPosition, module, Additator::DECAY_INPUT)); 273 addInput(createInput<Port24>(balanceInputPosition, module, Additator::BALANCE_INPUT)); 274 addInput(createInput<Port24>(filterInputPosition, module, Additator::FILTER_INPUT)); 275 addInput(createInput<Port24>(pitchInputPosition, module, Additator::PITCH_INPUT)); 276 addInput(createInput<Port24>(syncInputPosition, module, Additator::SYNC_INPUT)); 277 278 addOutput(createOutput<Port24>(audioOutputPosition, module, Additator::AUDIO_OUTPUT)); 279 280 addChild(createLight<BGSmallLight<GreenLight>>(sineLightPosition, module, Additator::SINE_LIGHT)); 281 addChild(createLight<BGSmallLight<GreenLight>>(cosineLightPosition, module, Additator::COSINE_LIGHT)); 282 } 283 }; 284 285 Model* modelAdditator = bogaudio::createModel<Additator, AdditatorWidget>("Bogaudio-Additator", "ADDITATOR", "Additive oscillator", "Oscillator", "Polyphonic");