Browse Source

Few bits of cleanup for Chopping Kinky, normal CV A -> B

tags/v1.1.0^2
hemmer 4 years ago
parent
commit
87f3fe0934
1 changed files with 23 additions and 47 deletions
  1. +23
    -47
      src/ChoppingKinky.cpp

+ 23
- 47
src/ChoppingKinky.cpp View File

@@ -2,7 +2,6 @@
#include "Common.hpp"
#include "ChowDSP.hpp"
static const size_t BUF_LEN = 32;
struct ChoppingKinky : Module {
enum ParamIds {
@@ -40,7 +39,7 @@ struct ChoppingKinky : Module {
NUM_CHANNELS
};
static const int WAVESHAPE_CACHE_SIZE = 128;
static const int WAVESHAPE_CACHE_SIZE = 256;
float waveshapeA[WAVESHAPE_CACHE_SIZE + 1] = {0.f};
float waveshapeBPositive[WAVESHAPE_CACHE_SIZE + 1] = {0.f};
float waveshapeBNegative[WAVESHAPE_CACHE_SIZE + 1] = {0.f};
@@ -48,9 +47,9 @@ struct ChoppingKinky : Module {
dsp::SchmittTrigger trigger;
bool outputAToChopp;
float previousA = 0.0;
chowdsp::VariableOversampling<> oversampler[NUM_CHANNELS];
int oversamplingIndex = 2;
int oversamplingIndex = 2; // default is 2^oversamplingIndex == x4 oversampling
dsp::BiquadFilter blockDCFilter;
bool blockDC = false;
@@ -68,9 +67,8 @@ struct ChoppingKinky : Module {
onSampleRateChange();
}
void onSampleRateChange() override {
// SampleRateConverter needs integer value
int sampleRate = APP->engine->getSampleRate();
void onSampleRateChange() override {
float sampleRate = APP->engine->getSampleRate();
blockDCFilter.setParameters(dsp::BiquadFilter::HIGHPASS, 10.3f / sampleRate, M_SQRT1_2, 1.0f);
@@ -80,43 +78,27 @@ struct ChoppingKinky : Module {
}
}
void process(const ProcessArgs& args) override {
float gainA = params[FOLD_A_PARAM].getValue();
if (inputs[CV_A_INPUT].isConnected()) {
gainA += params[CV_A_PARAM].getValue() * inputs[CV_A_INPUT].getVoltage() / 10.f;
}
if (inputs[VCA_CV_A_INPUT].isConnected()) {
gainA += inputs[VCA_CV_A_INPUT].getVoltage() / 10.f;
}
gainA += params[CV_A_PARAM].getValue() * inputs[CV_A_INPUT].getVoltage() / 10.f;
gainA += inputs[VCA_CV_A_INPUT].getVoltage() / 10.f;
// CV_B_INPUT is normalled to CV_A_INPUT (input with attenuverter)
float gainB = params[FOLD_B_PARAM].getValue();
if (inputs[CV_B_INPUT].isConnected()) {
gainB += params[CV_B_PARAM].getValue() * inputs[CV_B_INPUT].getVoltage() / 10.f;
}
if (inputs[VCA_CV_B_INPUT].isConnected()) {
gainB += inputs[VCA_CV_B_INPUT].getVoltage() / 10.f;
}
gainB += params[CV_B_PARAM].getValue() * inputs[CV_B_INPUT].getNormalVoltage(inputs[CV_A_INPUT].getVoltage()) / 10.f;
gainB += inputs[VCA_CV_B_INPUT].getVoltage() / 10.f;
float inA = 0;
float inB = 0;
if (inputs[IN_A_INPUT].isConnected()) {
inA = inputs[IN_A_INPUT].getVoltage();
}
if (inputs[IN_B_INPUT].isConnected()) {
inB = inputs[IN_B_INPUT].getVoltage();
}
else if (inputs[IN_A_INPUT].isConnected()) {
inB = inA;
}
const float inA = inputs[IN_A_INPUT].getVoltage();
const float inB = inputs[IN_B_INPUT].getNormalVoltage(inputs[IN_A_INPUT].getVoltage());
// if the CHOPP gate is wired in, do chop logic
if (inputs[IN_GATE_INPUT].isConnected()) {
// TODO: check rescale?
trigger.process(rescale(inputs[IN_GATE_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f));
outputAToChopp = trigger.isHigh();
}
}
// else zero-crossing detector on input A switches between A and B
else {
if (previousA > 0 && inA < 0) {
outputAToChopp = false;
@@ -127,9 +109,9 @@ struct ChoppingKinky : Module {
}
previousA = inA;
bool choppIsRequired = outputs[OUT_CHOPP_OUTPUT].isConnected();
bool aIsRequired = outputs[OUT_A_OUTPUT].isConnected() || choppIsRequired;
bool bIsRequired = outputs[OUT_B_OUTPUT].isConnected() || choppIsRequired;
const bool choppIsRequired = outputs[OUT_CHOPP_OUTPUT].isConnected();
const bool aIsRequired = outputs[OUT_A_OUTPUT].isConnected() || choppIsRequired;
const bool bIsRequired = outputs[OUT_B_OUTPUT].isConnected() || choppIsRequired;
if (aIsRequired) {
oversampler[CHANNEL_A].upsample(inA * gainA);
@@ -138,8 +120,7 @@ struct ChoppingKinky : Module {
oversampler[CHANNEL_B].upsample(inB * gainB);
}
if (choppIsRequired) {
float inChopp = outputAToChopp ? 1.f : 0.f;
oversampler[CHANNEL_CHOPP].upsample(inChopp);
oversampler[CHANNEL_CHOPP].upsample(outputAToChopp ? 1.f : 0.f);
}
float* osBufferA = oversampler[CHANNEL_A].getOSBuffer();
@@ -148,12 +129,10 @@ struct ChoppingKinky : Module {
for (int i = 0; i < oversampler[0].getOversamplingRatio(); i++) {
if (aIsRequired) {
// TODO: replace with LUT of measured wavefolder response
//osBufferA[i] = wavefolderAResponse(osBufferA[i]);
osBufferA[i] = wavefolderAResponseCached(osBufferA[i]);
}
if (bIsRequired) {
// TODO: replace with LUT of measured wavefolder response
//osBufferB[i] = wavefolderBResponse(osBufferB[i]);
osBufferB[i] = wavefolderBResponseCached(osBufferB[i]);
}
@@ -279,20 +258,17 @@ struct ChoppingKinky : Module {
}
}
// functional form for waveshapers uses a lot of transcendental functions, so we cache
// the response in a LUT
void cacheWaveshaperResponses() {
for (int i = 0; i < WAVESHAPE_CACHE_SIZE; ++i) {
float x = rescale(i, 0, WAVESHAPE_CACHE_SIZE - 1, 0.0, 10.f);
waveshapeA[i] = wavefolderAResponse(x);
float j = rescale(x, 0.0, 10., 0, WAVESHAPE_CACHE_SIZE - 1);
float lookupResult = math::interpolateLinear(waveshapeA, j);
waveshapeBPositive[i] = wavefolderBResponse(+x);
waveshapeBNegative[i] = wavefolderBResponse(-x);
}
}
json_t* dataToJson() override {
json_t* rootJ = json_object();
json_object_set_new(rootJ, "filterDC", json_boolean(blockDC));
@@ -357,9 +333,9 @@ struct ChoppingKinkyWidget : ModuleWidget {
struct ModeItem : MenuItem {
ChoppingKinky* module;
int mode;
int oversamplingIndex;
void onAction(const event::Action& e) override {
module->oversamplingIndex = mode;
module->oversamplingIndex = oversamplingIndex;
module->onSampleRateChange();
}
};
@@ -380,7 +356,7 @@ struct ChoppingKinkyWidget : ModuleWidget {
ModeItem* modeItem = createMenuItem<ModeItem>(std::to_string(int (1 << i)) + "x");
modeItem->rightText = CHECKMARK(module->oversamplingIndex == i);
modeItem->module = module;
modeItem->mode = i;
modeItem->oversamplingIndex = i;
menu->addChild(modeItem);
}
}


Loading…
Cancel
Save