MCPcopy Create free account
hub / github.com/VCVRack/Befaco / process

Method process

src/EvenVCO.cpp:128–276  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

126 int oversamplingIndex = 2; // default is 2^oversamplingIndex == x4 oversampling
127
128 void process(const ProcessArgs& args) override {
129
130 // pitch inputs determine number of polyphony engines
131 const int channels = std::max({1, inputs[PITCH1_INPUT].getChannels(), inputs[PITCH2_INPUT].getChannels()});
132
133 const float pitchKnobs = 1.f + std::round(params[OCTAVE_PARAM].getValue()) + params[TUNE_PARAM].getValue() / 12.f;
134 const int oversamplingRatio = oversampler[0][0].getOversamplingRatio();
135
136 for (int c = 0; c < channels; c += 4) {
137 float_4 pw = simd::clamp(params[PWM_PARAM].getValue() + inputs[PWM_INPUT].getPolyVoltageSimd<float_4>(c) / 5.f, -1.f, 1.f);
138 if (limitPW) {
139 pw = simd::rescale(pw, -1, +1, 0.05f, 0.95f);
140 }
141 else {
142 pw = simd::rescale(pw, -1.f, +1.f, 0.f, 1.f);
143 }
144
145 const float_4 pitch = inputs[PITCH1_INPUT].getPolyVoltageSimd<float_4>(c) + inputs[PITCH2_INPUT].getPolyVoltageSimd<float_4>(c);
146
147 // pulsewave waveform doesn't have DC even for non 50% duty cycles, but Befaco team would like the option
148 // for it to be added back in for hardware compatibility reasons
149 const float_4 pulseDCOffset = (!removePulseDC) * 2.f * (0.5f - pw);
150
151 // input oversampling buffers
152 float_4* osBufferSync = oversamplerInputs[SYNC_INPUT_UP][c / 4].getOSBuffer();
153 float_4* osBufferFM = oversamplerInputs[FM_INPUT_UP][c / 4].getOSBuffer();
154
155 // upsample hard sync input (if connected)
156 if (inputs[SYNC_INPUT].isConnected()) {
157 oversamplerInputs[SYNC_INPUT_UP][c].upsample(inputs[SYNC_INPUT].getPolyVoltageSimd<float_4>(c));
158 }
159 else {
160 std::fill(osBufferSync, &osBufferSync[oversamplingRatio], float_4::zero());
161 }
162 // upsample FM input (if connected)
163 if (inputs[FM_INPUT].isConnected()) {
164 oversamplerInputs[FM_INPUT_UP][c].upsample(inputs[FM_INPUT].getPolyVoltageSimd<float_4>(c));
165 }
166 else {
167 std::fill(osBufferFM, &osBufferFM[oversamplingRatio], float_4::zero());
168 }
169
170 float_4* osBufferTri = oversampler[TRI_OUTPUT][c / 4].getOSBuffer();
171 float_4* osBufferSaw = oversampler[SAW_OUTPUT][c / 4].getOSBuffer();
172 float_4* osBufferSin = oversampler[SINE_OUTPUT][c / 4].getOSBuffer();
173 float_4* osBufferSquare = oversampler[SQUARE_OUTPUT][c / 4].getOSBuffer();
174 float_4* osBufferEven = oversampler[EVEN_OUTPUT][c / 4].getOSBuffer();
175 for (int i = 0; i < oversamplingRatio; ++i) {
176 // use upsampled FM input
177 const float_4 fmVoltage = osBufferFM[i] * 0.25f;
178 const float_4 freq = dsp::FREQ_C4 * simd::pow(2.f, pitchKnobs + pitch + fmVoltage);
179 const float_4 deltaBasePhase = simd::clamp(freq * args.sampleTime / oversamplingRatio, 1e-6, 0.5f);
180 // floating point arithmetic doesn't work well at low frequencies, specifically because the finite difference denominator
181 // becomes tiny - we check for that scenario and use naive / 1st order waveforms in that frequency regime (as aliasing isn't
182 // a problem there). With no oversampling, at 44100Hz, the threshold frequency is 44.1Hz.
183 const float_4 lowFreqRegime = simd::abs(deltaBasePhase) < 1e-3;
184 // 1 / denominator for the second-order FD
185 const float_4 denominatorInv = 0.25 / (deltaBasePhase * deltaBasePhase);

Callers

nothing calls this directly

Calls 6

getChannelsMethod · 0.80
getValueMethod · 0.80
getOversamplingRatioMethod · 0.80
getOSBufferMethod · 0.45
upsampleMethod · 0.45
downsampleMethod · 0.45

Tested by

no test coverage detected