diff --git a/plugin.json b/plugin.json index 0057648..fb290b0 100644 --- a/plugin.json +++ b/plugin.json @@ -2,7 +2,7 @@ "slug": "TinyTricks", "name": "Tiny Tricks", "brand": "Tiny Tricks", - "version": "1.5.0", + "version": "2.5.0", "license": "GPL-3.0-only", "author": "Thomas René Sidor", "authorEmail": "mail@thomassidor.com", diff --git a/src/arithmetic.cpp b/src/arithmetic.cpp index 24f5720..90bb389 100644 --- a/src/arithmetic.cpp +++ b/src/arithmetic.cpp @@ -33,29 +33,42 @@ struct TTA : TinyTricksModule { TTA() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(A_INPUT, "A"); + configInput(B_INPUT, "B"); + configOutput(APLUSB_OUTPUT, "A+B"); + configOutput(AVGAB_OUTPUT, "Average"); + configOutput(AMINUSB_OUTPUT, "A-B"); + configOutput(BMINUSA_OUTPUT, "B-A"); + configOutput(ADIVB_OUTPUT, "A/B"); + configOutput(BDIVA_OUTPUT, "B/A"); + configOutput(AMULB_OUTPUT, "A*B"); + configOutput(AEXPB_OUTPUT, "A^B"); + configOutput(ONEOVERA_OUTPUT, "1/A"); + configOutput(ONEOVERB_OUTPUT, "1/B"); + configOutput(MINUSA_OUTPUT, "-A"); + configOutput(MINUSB_OUTPUT, "-B"); } void process(const ProcessArgs &args) override { int nChan = std::max(1, inputs[A_INPUT].getChannels()); - for( int op=APLUSB_OUTPUT; op < NUM_OUTPUTS; op++ ) - outputs[op].setChannels(nChan); + for (int op = APLUSB_OUTPUT; op < NUM_OUTPUTS; op++) + outputs[op].setChannels(nChan); - for( auto c=0; c(mm2px(Vec(7.7f,11.055f)), module, A8::LEVEL_PARAM)); + addParam(createParam(mm2px(Vec(7.7f, 11.055f)), module, A8::LEVEL_PARAM)); for (int i = 0; i < NUM_CHANNELS; i++) addInput(createInput(mm2px(Vec(3.131f, 29.859f + 11.5f * i)), module, A8::ATT_INPUT + i)); diff --git a/src/logic.cpp b/src/logic.cpp index 7c55040..ed50eca 100644 --- a/src/logic.cpp +++ b/src/logic.cpp @@ -33,35 +33,48 @@ struct TTL : TinyTricksModule { TTL() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(A_INPUT, "A"); + configInput(B_INPUT, "B"); + configOutput(AND_OUTPUT, "AND"); + configOutput(OR_OUTPUT, "OR"); + configOutput(XOR_OUTPUT, "XOR"); + configOutput(NOR_OUTPUT, "NOR"); + configOutput(ALTB_OUTPUT, "AB"); + configOutput(ALTEB_OUTPUT, "A<=B"); + configOutput(AGTEB_OUTPUT, "A>=B"); + configOutput(AISB_OUTPUT, "A=B"); + configOutput(AISNOTB_OUTPUT, "A!=B"); + configOutput(NOTA_OUTPUT, "¬A"); + configOutput(NOTB_OUTPUT, "¬B"); } void process(const ProcessArgs &args) override { int nChan = std::max(1, inputs[A_INPUT].getChannels()); - for( int op=AND_OUTPUT; op < NUM_OUTPUTS; op++ ) - outputs[op].setChannels(nChan); - - for( auto c=0; cb?10.f:0.f), c); - outputs[ALTEB_OUTPUT].setVoltage((a<=b?10.f:0.f), c); - outputs[AGTEB_OUTPUT].setVoltage((a>=b?10.f:0.f), c); - outputs[AISB_OUTPUT].setVoltage((a==b?10.f:0.f), c); - outputs[AISNOTB_OUTPUT].setVoltage((a!=b?10.f:0.f), c); - outputs[NOTA_OUTPUT].setVoltage(!a, c); - outputs[NOTB_OUTPUT].setVoltage(!b, c); - } + for (int op = AND_OUTPUT; op < NUM_OUTPUTS; op++) + outputs[op].setChannels(nChan); + + for (auto c = 0; c < nChan; ++c) { + if (inputs[A_INPUT].isConnected() && inputs[B_INPUT].isConnected()) { + float a = inputs[A_INPUT].getVoltage(c); + float b = inputs[B_INPUT].getPolyVoltage(c); + + bool isA = (a != 0.f); + bool isB = (b != 0.f); + + outputs[AND_OUTPUT].setVoltage((isA && isB ? 10.f : 0.f), c); + outputs[OR_OUTPUT].setVoltage((isA || isB ? 10.f : 0.f), c); + outputs[XOR_OUTPUT].setVoltage((isA != isB ? 10.f : 0.f), c); + outputs[NOR_OUTPUT].setVoltage((!(a || b) ? 10.f : 0.f), c); + outputs[ALTB_OUTPUT].setVoltage((a < b ? 10.f : 0.f), c); + outputs[AGTB_OUTPUT].setVoltage((a > b ? 10.f : 0.f), c); + outputs[ALTEB_OUTPUT].setVoltage((a <= b ? 10.f : 0.f), c); + outputs[AGTEB_OUTPUT].setVoltage((a >= b ? 10.f : 0.f), c); + outputs[AISB_OUTPUT].setVoltage((a == b ? 10.f : 0.f), c); + outputs[AISNOTB_OUTPUT].setVoltage((a != b ? 10.f : 0.f), c); + outputs[NOTA_OUTPUT].setVoltage(!a, c); + outputs[NOTB_OUTPUT].setVoltage(!b, c); + } } } }; diff --git a/src/modulation-generator.cpp b/src/modulation-generator.cpp index 50f86ea..d56e0c2 100644 --- a/src/modulation-generator.cpp +++ b/src/modulation-generator.cpp @@ -5,12 +5,11 @@ #include "oscillators/lfo.cpp" #include "shared/shared.cpp" - struct ModulationSource { const float FREQ_LOW_BOUND = -8.f; - const float FREQ_HIGH_BOUND = 8.f; - const float FREQ_MAX_SPREAD = 8.f; - const float FREQ_MIDDLE = 0.f; + const float FREQ_HIGH_BOUND = 8.f; + const float FREQ_MAX_SPREAD = 8.f; + const float FREQ_MIDDLE = 0.f; LowFrequencyOscillator oscillator; float lfoWave; @@ -20,60 +19,57 @@ struct ModulationSource { float value = 0.f; - ModulationSource(){} - + ModulationSource() {} - void regenerate(float rangeParam, float biasParam, bool shOn){ + void regenerate(float rangeParam, float biasParam, bool shOn) { //Randomly select S&H or LFO - if(shOn){ + if (shOn) { holding = (random::uniform() >= 0.5f); } - else{ + else { holding = false; } //Generate S&H - if(holding){ + if (holding) { //std::cout << "Regenerated: Holding" << std::endl; - float spread = 5.f*rangeParam; - float rescaledBiasParam = rescale(biasParam,-1.f,1.f,-5.f,5.f); - float lowerRange = fmax(-5.f,rescaledBiasParam-spread); - float upperRange = fmin(5.f,rescaledBiasParam+spread); + float spread = 5.f * rangeParam; + float rescaledBiasParam = rescale(biasParam, -1.f, 1.f, -5.f, 5.f); + float lowerRange = fmax(-5.f, rescaledBiasParam - spread); + float upperRange = fmin(5.f, rescaledBiasParam + spread); - holdValue = rescale(random::uniform(),0.f, 1.f,lowerRange,upperRange); + holdValue = rescale(random::uniform(), 0.f, 1.f, lowerRange, upperRange); value = holdValue; } //Generate LFO - else{ + else { //Choosing wave - lfoWave = random::uniform() * 3.0f; //should be between 0.f and 3.f + lfoWave = random::uniform() * 3.0f; //should be between 0.f and 3.f - //Setting pitch - float spread = FREQ_MAX_SPREAD*rangeParam; - float rescaledBiasParam = rescale(biasParam,-1.f,1.f,FREQ_LOW_BOUND,FREQ_HIGH_BOUND); - float lowerRange = fmax(FREQ_LOW_BOUND,rescaledBiasParam-spread); - float upperRange = fmin(FREQ_HIGH_BOUND,rescaledBiasParam+spread); + //Setting pitch + float spread = FREQ_MAX_SPREAD * rangeParam; + float rescaledBiasParam = rescale(biasParam, -1.f, 1.f, FREQ_LOW_BOUND, FREQ_HIGH_BOUND); + float lowerRange = fmax(FREQ_LOW_BOUND, rescaledBiasParam - spread); + float upperRange = fmin(FREQ_HIGH_BOUND, rescaledBiasParam + spread); - float pitch = rescale(random::uniform(),0.f, 1.f,lowerRange,upperRange); + float pitch = rescale(random::uniform(), 0.f, 1.f, lowerRange, upperRange); - oscillator.setPitch(pitch); + oscillator.setPitch(pitch); oscillator.setPhase(random::normal()); - //Resetting - oscillator.setReset(1.f); + //Resetting + oscillator.setReset(1.f); } } - - void setOffset(bool offset){ + void setOffset(bool offset) { isOffset = offset; } - - bool tick(float timeDelta){ + bool tick(float timeDelta) { //Tick LFO if not S&H - if(!holding){ + if (!holding) { oscillator.step(timeDelta); float v = 0.f; @@ -87,7 +83,7 @@ struct ModulationSource { } //S&H but offset changed - else if(holdValue != value){ + else if (holdValue != value) { value = holdValue; return true; } @@ -95,177 +91,163 @@ struct ModulationSource { return false; } - - float getValue(){ - if(isOffset) - return value+5.f; + float getValue() { + if (isOffset) + return value + 5.f; else return value; } }; - - struct ModulationGeneratorBase : TinyTricksModule { - enum ParamIds { - OFFSET_PARAM, - RANGE_PARAM, - BIAS_PARAM, - SH_ON_PARAM, - NUM_PARAMS - }; + enum ParamIds { + OFFSET_PARAM, + RANGE_PARAM, + BIAS_PARAM, + SH_ON_PARAM, + NUM_PARAMS + }; public: - enum InputIds { - TRIG_INPUT, - NUM_INPUTS - }; - enum OutputIds { - ENUMS(MOD_OUTPUT,16), - NUM_OUTPUTS - }; - enum LightIds { - NUM_LIGHTS - }; - - - int outChannelsCount = 1; - dsp::SchmittTrigger trigger; - ModulationSource* modSources; - - void initializeModule(){ - modSources = new ModulationSource[outChannelsCount]; - - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(OFFSET_PARAM, 0.f, 1.f, 0.f, "Offset"); - configParam(SH_ON_PARAM, 0.f, 1.f, 1.f, "Enable random S&H values"); - configParam(RANGE_PARAM, 0.f, 1.f, 1.f, "Frequency variance"); - configParam(BIAS_PARAM, -1.f, 1.f, 0.f, "Bias"); - } - - - - ModulationGeneratorBase() { - initializeModule(); - } + enum InputIds { + TRIG_INPUT, + NUM_INPUTS + }; + enum OutputIds { + ENUMS(MOD_OUTPUT, 16), + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + + int outChannelsCount = 1; + dsp::SchmittTrigger trigger; + ModulationSource *modSources; + + void initializeModule() { + modSources = new ModulationSource[outChannelsCount]; + + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(TRIG_INPUT, "Trigger"); + configSwitch(OFFSET_PARAM, 0.f, 1.f, 0.f, "Offset", {"Bipolar", "Unipolar"}); + configSwitch(SH_ON_PARAM, 0.f, 1.f, 1.f, "Enable random S&H values", {"Off", "On"}); + configParam(RANGE_PARAM, 0.f, 1.f, 1.f, "Frequency variance"); + configParam(BIAS_PARAM, -1.f, 1.f, 0.f, "Bias"); + for (int i = 0; i < outChannelsCount; i++) { + configOutput(MOD_OUTPUT + i, string::f("Modulation %d", i + 1)); + } + } - ModulationGeneratorBase(int c){ - outChannelsCount = c; - initializeModule(); - } + ModulationGeneratorBase() { + initializeModule(); + } + ModulationGeneratorBase(int c) { + outChannelsCount = c; + initializeModule(); + } - void process(const ProcessArgs &args) override { + void process(const ProcessArgs &args) override { - bool regenerate = inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage()); - bool offsetOn = (params[OFFSET_PARAM].getValue() == 1.f); + bool regenerate = inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage()); + bool offsetOn = (params[OFFSET_PARAM].getValue() == 1.f); - float rangeParam = 1.f; - float biasParam = 1.f; - bool shOn; + float rangeParam = 1.f; + float biasParam = 1.f; + bool shOn; - if (regenerate){ - rangeParam = params[RANGE_PARAM].getValue(); - biasParam = params[BIAS_PARAM].getValue(); - shOn = (params[SH_ON_PARAM].getValue() == 1.f); - } + if (regenerate) { + rangeParam = params[RANGE_PARAM].getValue(); + biasParam = params[BIAS_PARAM].getValue(); + shOn = (params[SH_ON_PARAM].getValue() == 1.f); + } - for(int i = 0; i < outChannelsCount; i++){ - ModulationSource *modSource = &modSources[i]; + for (int i = 0; i < outChannelsCount; i++) { + ModulationSource *modSource = &modSources[i]; - //Sending offset - modSource->setOffset(offsetOn); + //Sending offset + modSource->setOffset(offsetOn); - //Triggered - generate new LFO or S&H - if (regenerate) { - modSource->regenerate(rangeParam,biasParam,shOn); - } + //Triggered - generate new LFO or S&H + if (regenerate) { + modSource->regenerate(rangeParam, biasParam, shOn); + } - if(outputs[MOD_OUTPUT + i].isConnected()) - { - if(modSource->tick(1.0f / args.sampleRate)){ - float newValue = modSource->getValue(); - //std::cout << "New Value: " << newValue << std::endl; - outputs[MOD_OUTPUT + i].setVoltage(newValue); + if (outputs[MOD_OUTPUT + i].isConnected()) { + if (modSource->tick(1.0f / args.sampleRate)) { + float newValue = modSource->getValue(); + //std::cout << "New Value: " << newValue << std::endl; + outputs[MOD_OUTPUT + i].setVoltage(newValue); + } } } } - } }; - struct ModulationGeneratorBaseWidget : TinyTricksModuleWidget { - ModulationGeneratorBaseWidget(ModulationGeneratorBase *module) { - setModule(module); + ModulationGeneratorBaseWidget(ModulationGeneratorBase *module) { + setModule(module); - addInput(createInput(mm2px(Vec(3.567f,12.003f)), module, ModulationGeneratorBase::TRIG_INPUT)); + addInput(createInput(mm2px(Vec(3.567f, 12.003f)), module, ModulationGeneratorBase::TRIG_INPUT)); - addParam(createParam(mm2px(Vec(2.62f,29.749f)), module, ModulationGeneratorBase::RANGE_PARAM)); - addParam(createParam(mm2px(Vec(2.62f,49.743f)), module, ModulationGeneratorBase::BIAS_PARAM)); + addParam(createParam(mm2px(Vec(2.62f, 29.749f)), module, ModulationGeneratorBase::RANGE_PARAM)); + addParam(createParam(mm2px(Vec(2.62f, 49.743f)), module, ModulationGeneratorBase::BIAS_PARAM)); - addParam(createParam(mm2px(Vec(5.151f,70.697f)), module, ModulationGeneratorBase::SH_ON_PARAM)); - addParam(createParam(mm2px(Vec(5.151f,88.025f)), module, ModulationGeneratorBase::OFFSET_PARAM)); + addParam(createParam(mm2px(Vec(5.151f, 70.697f)), module, ModulationGeneratorBase::SH_ON_PARAM)); + addParam(createParam(mm2px(Vec(5.151f, 88.025f)), module, ModulationGeneratorBase::OFFSET_PARAM)); - - } + } }; - - - - // X1 -------------------------------------------------------------------------------------------------------------- -struct ModulationGeneratorX1 : ModulationGeneratorBase{ - ModulationGeneratorX1():ModulationGeneratorBase(1){ +struct ModulationGeneratorX1 : ModulationGeneratorBase { + ModulationGeneratorX1(): ModulationGeneratorBase(1) { } }; struct ModulationGeneratorX1Widget : ModulationGeneratorBaseWidget { - ModulationGeneratorX1Widget(ModulationGeneratorBase *module) : ModulationGeneratorBaseWidget(module) { - addOutput(createOutput(mm2px(Vec(3.567f,113.359f)), module, ModulationGeneratorBase::MOD_OUTPUT+0)); + ModulationGeneratorX1Widget(ModulationGeneratorBase *module) : ModulationGeneratorBaseWidget(module) { + addOutput(createOutput(mm2px(Vec(3.567f, 113.359f)), module, ModulationGeneratorBase::MOD_OUTPUT + 0)); InitializeSkin("LFO1.svg"); - } + } }; Model *modelModulationGeneratorX1 = createModel("MG1"); - - - // X8 -------------------------------------------------------------------------------------------------------------- const int X8_CHANNELS = 8; -struct ModulationGeneratorX8 : ModulationGeneratorBase{ - ModulationGeneratorX8():ModulationGeneratorBase(X8_CHANNELS){ +struct ModulationGeneratorX8 : ModulationGeneratorBase { + ModulationGeneratorX8(): ModulationGeneratorBase(X8_CHANNELS) { } }; struct ModulationGeneratorX8Widget : ModulationGeneratorBaseWidget { - ModulationGeneratorX8Widget(ModulationGeneratorBase *module) : ModulationGeneratorBaseWidget(module) { - for(int i = 0; i < X8_CHANNELS; i++){ - addOutput(createOutput(mm2px(Vec(18.501f,12.003f + (i*14.f))), module, ModulationGeneratorBase::MOD_OUTPUT + i)); + ModulationGeneratorX8Widget(ModulationGeneratorBase *module) : ModulationGeneratorBaseWidget(module) { + for (int i = 0; i < X8_CHANNELS; i++) { + addOutput(createOutput(mm2px(Vec(18.501f, 12.003f + (i * 14.f))), module, ModulationGeneratorBase::MOD_OUTPUT + i)); } InitializeSkin("LFO8.svg"); - } + } }; Model *modelModulationGeneratorX8 = createModel("MG8"); - // X16 -------------------------------------------------------------------------------------------------------------- const int X16_CHANNELS = 16; -struct ModulationGeneratorX16 : ModulationGeneratorBase{ - ModulationGeneratorX16():ModulationGeneratorBase(X16_CHANNELS){ +struct ModulationGeneratorX16 : ModulationGeneratorBase { + ModulationGeneratorX16(): ModulationGeneratorBase(X16_CHANNELS) { } }; struct ModulationGeneratorX16Widget : ModulationGeneratorBaseWidget { - ModulationGeneratorX16Widget(ModulationGeneratorBase *module) : ModulationGeneratorBaseWidget(module) { - for(int i = 0; i < X16_CHANNELS/2; i++) - addOutput(createOutput(mm2px(Vec(18.501,12.003f + (i*14.f))), module, ModulationGeneratorBase::MOD_OUTPUT + i)); + ModulationGeneratorX16Widget(ModulationGeneratorBase *module) : ModulationGeneratorBaseWidget(module) { + for (int i = 0; i < X16_CHANNELS / 2; i++) + addOutput(createOutput(mm2px(Vec(18.501, 12.003f + (i * 14.f))), module, ModulationGeneratorBase::MOD_OUTPUT + i)); + + for (int i = 0; i < X16_CHANNELS / 2; i++) + addOutput(createOutput(mm2px(Vec(28.818f, 12.003f + (i * 14.f))), module, ModulationGeneratorBase::MOD_OUTPUT + i + X16_CHANNELS / 2)); - for(int i = 0; i < X16_CHANNELS/2; i++) - addOutput(createOutput(mm2px(Vec(28.818f,12.003f + (i*14.f))), module, ModulationGeneratorBase::MOD_OUTPUT + i + X16_CHANNELS/2)); - InitializeSkin("LFO16.svg"); - } + } }; Model *modelModulationGeneratorX16 = createModel("MG16"); diff --git a/src/oscillators/barebone.cpp b/src/oscillators/barebone.cpp index 1c2f1ad..63543ca 100644 --- a/src/oscillators/barebone.cpp +++ b/src/oscillators/barebone.cpp @@ -1,13 +1,13 @@ #include "plugin.hpp" -struct BareboneOscillator{ +struct BareboneOscillator { float phase = 0.0f; float freq = 0.0f; float isStepEOC = false; - void step(float dt){ + void step(float dt) { //phase+= freq; - phase+= freq / dt; - if (phase >= 1.0f){ + phase += freq / dt; + if (phase >= 1.0f) { phase = 0.f; isStepEOC = true; } @@ -15,17 +15,17 @@ struct BareboneOscillator{ isStepEOC = false; } - void reset(){ - phase = 0.f; - isStepEOC = true; + void reset() { + phase = 0.f; + isStepEOC = true; } - bool isEOC(){ + bool isEOC() { return isStepEOC; } - void setPitch(float pitch){ + void setPitch(float pitch) { freq = dsp::FREQ_C4 * powf(2.0f, pitch); } }; diff --git a/src/oscillators/lfo.cpp b/src/oscillators/lfo.cpp index 6f5b697..0367fc9 100644 --- a/src/oscillators/lfo.cpp +++ b/src/oscillators/lfo.cpp @@ -2,64 +2,64 @@ #include struct LowFrequencyOscillator { - float phase = 0.0f; - float pw = 0.5f; - float freq = 1.0f; - bool offset = false; - bool invert = false; - SchmittTrigger resetTrigger; - LowFrequencyOscillator() {} - void setPitch(float pitch) { - pitch = fminf(pitch, 8.0f); - freq = powf(2.0f, pitch); - } - void setPulseWidth(float pw_) { - const float pwMin = 0.01f; - pw = clamp(pw_, pwMin, 1.0f - pwMin); - } - void setReset(float reset) { - if (resetTrigger.process(reset)) { - phase = 0.0f; - } - } - void setPhase(float p){ - phase = p; - } - void step(float dt) { - float deltaPhase = fminf(freq * dt, 0.5f); - phase += deltaPhase; - if (phase >= 1.0f) - phase -= 1.0f; - } - float sin() { - if (offset) - return 1.0f - cosf(2.0f*M_PI * phase) * (invert ? -1.0f : 1.0f); - else - return sinf(2.0f*M_PI * phase) * (invert ? -1.0f : 1.0f); - } - float tri(float x) { - return 4.0f * fabsf(x - roundf(x)); - } - float tri() { - if (offset) - return tri(invert ? phase - 0.5f : phase); - else - return -1.0f + tri(invert ? phase - 0.25f : phase - 0.75f); - } - float saw(float x) { - return 2.0f * (x - roundf(x)); - } - float saw() { - if (offset) - return invert ? 2.0f * (1.0f - phase) : 2.0f * phase; - else - return saw(phase) * (invert ? -1.0f : 1.0f); - } - float sqr() { - float sqr = (phase < pw) ^ invert ? 1.0f : -1.0f; - return offset ? sqr + 1.0f : sqr; - } - float light() { - return sinf(2.0f*M_PI * phase); + float phase = 0.0f; + float pw = 0.5f; + float freq = 1.0f; + bool offset = false; + bool invert = false; + rack::dsp::SchmittTrigger resetTrigger; + LowFrequencyOscillator() {} + void setPitch(float pitch) { + pitch = fminf(pitch, 8.0f); + freq = powf(2.0f, pitch); + } + void setPulseWidth(float pw_) { + const float pwMin = 0.01f; + pw = clamp(pw_, pwMin, 1.0f - pwMin); + } + void setReset(float reset) { + if (resetTrigger.process(reset)) { + phase = 0.0f; } + } + void setPhase(float p) { + phase = p; + } + void step(float dt) { + float deltaPhase = fminf(freq * dt, 0.5f); + phase += deltaPhase; + if (phase >= 1.0f) + phase -= 1.0f; + } + float sin() { + if (offset) + return 1.0f - cosf(2.0f * M_PI * phase) * (invert ? -1.0f : 1.0f); + else + return sinf(2.0f * M_PI * phase) * (invert ? -1.0f : 1.0f); + } + float tri(float x) { + return 4.0f * fabsf(x - roundf(x)); + } + float tri() { + if (offset) + return tri(invert ? phase - 0.5f : phase); + else + return -1.0f + tri(invert ? phase - 0.25f : phase - 0.75f); + } + float saw(float x) { + return 2.0f * (x - roundf(x)); + } + float saw() { + if (offset) + return invert ? 2.0f * (1.0f - phase) : 2.0f * phase; + else + return saw(phase) * (invert ? -1.0f : 1.0f); + } + float sqr() { + float sqr = (phase < pw) ^ invert ? 1.0f : -1.0f; + return offset ? sqr + 1.0f : sqr; + } + float light() { + return sinf(2.0f * M_PI * phase); + } }; diff --git a/src/oscillators/oscillator.cpp b/src/oscillators/oscillator.cpp index dfb1773..a1a0aa5 100644 --- a/src/oscillators/oscillator.cpp +++ b/src/oscillators/oscillator.cpp @@ -1,5 +1,5 @@ #include "plugin.hpp" -struct TinyOscillator{ +struct TinyOscillator { private: float phase = 0.0f; float freq = 0.0f; @@ -14,10 +14,10 @@ struct TinyOscillator{ TRI }; - void step(float dt){ + void step(float dt) { //phase+= freq; - phase+= freq / dt; - if (phase >= 1.0f){ + phase += freq / dt; + if (phase >= 1.0f) { phase -= 1.f; isStepEOC = true; } @@ -25,44 +25,44 @@ struct TinyOscillator{ isStepEOC = false; } - void reset(){ - phase = 0.f; - isStepEOC = true; + void reset() { + phase = 0.f; + isStepEOC = true; } - void setTheta(float t){ + void setTheta(float t) { theta = t; } - float getSin(){ + float getSin() { return sinf(2.0f * M_PI * phase) * 5.0f; } - float getSaw(){ - return ((1+triInternal((2.f*phase-1.f)/4.f)*sqrInternal(phase/2.f))/2.f)*10.f-5.f; + float getSaw() { + return ((1 + triInternal((2.f * phase - 1.f) / 4.f) * sqrInternal(phase / 2.f)) / 2.f) * 10.f - 5.f; } - float getTri(){ - return triInternal(phase)*5.f; + float getTri() { + return triInternal(phase) * 5.f; } - float triInternal(float x){ - return 1.f - 2.f*(acos((1.f-theta)*sin(2.f*M_PI*x)))/M_PI; + float triInternal(float x) { + return 1.f - 2.f * (acos((1.f - theta) * sin(2.f * M_PI * x))) / M_PI; } - float getSqr(){ - return sqrInternal(phase)*5.f; + float getSqr() { + return sqrInternal(phase) * 5.f; } - float sqrInternal(float x){ - return 2*atan(sin(2.0f*M_PI*x)/theta)/M_PI; + float sqrInternal(float x) { + return 2 * atan(sin(2.0f * M_PI * x) / theta) / M_PI; } - bool isEOC(){ + bool isEOC() { return isStepEOC; } - void setPitch(float pitch){ + void setPitch(float pitch) { freq = dsp::FREQ_C4 * powf(2.0f, pitch); } diff --git a/src/oscillators/simplex.cpp b/src/oscillators/simplex.cpp index 4f808a5..066d215 100644 --- a/src/oscillators/simplex.cpp +++ b/src/oscillators/simplex.cpp @@ -1,16 +1,16 @@ #include #include "../utility/SimplexNoise.hpp" -struct SimplexOscillator{ - static const int BUFFER_LENGTH = 2048; - float phase = 0.0f; - float freq = 0.0f; +struct SimplexOscillator { + static const int BUFFER_LENGTH = 2048; + float phase = 0.0f; + float freq = 0.0f; unsigned int tick = 0; - bool isStepEOC = false; + bool isStepEOC = false; - bool reverse = false; + bool reverse = false; float buffer[BUFFER_LENGTH] = {0}; int bufferIndex = 0; @@ -18,96 +18,96 @@ struct SimplexOscillator{ float min = -1.f; float max = 1.f; - float mirror = false; + float mirror = false; SimplexNoise simp; - SimplexOscillator(){ - simp.init(); - } - - void setMirror(bool _mirror){ - mirror = _mirror; - min = -1.f; - max = 1.f; - tick = 0; - reset(); - } - - void step(float dt){ - float delta = freq / dt; - - isStepEOC = false; - if(mirror){ - if(!reverse){ - phase += delta; - if (phase >= 0.5f) - reverse = true; - } - else{ - phase -= delta; - if(phase < 0.f){ - reverse = false; - //phase = 0.f; - phase = -phase; - isStepEOC = true; - } - } - } - else{ - phase += delta; - if (phase >= 1.0f){ - //phase = 0.f;//-= 1.0f; - phase -= 1.0f; - isStepEOC = true; - } - } - } - - void reset(){ - phase = 0.f; - reverse = false; - } - - bool isEOC(){ - return isStepEOC; - } - - void setPitch(float pitch){ - freq = dsp::FREQ_C4 * powf(2.0f, pitch); - } - - float getValue(float detaillevel, float x, float y, float z, float scale){ - return simp.SumOctaveSmooth(detaillevel,x+phase,y,z,scale); + SimplexOscillator() { + simp.init(); } - float getOsc(float detaillevel, float x, float y, float z, float scale){ - float value = getValue(detaillevel, x, y, z, scale); - return value*5.f; - } + void setMirror(bool _mirror) { + mirror = _mirror; + min = -1.f; + max = 1.f; + tick = 0; + reset(); + } + + void step(float dt) { + float delta = freq / dt; + + isStepEOC = false; + if (mirror) { + if (!reverse) { + phase += delta; + if (phase >= 0.5f) + reverse = true; + } + else { + phase -= delta; + if (phase < 0.f) { + reverse = false; + //phase = 0.f; + phase = -phase; + isStepEOC = true; + } + } + } + else { + phase += delta; + if (phase >= 1.0f) { + //phase = 0.f;//-= 1.0f; + phase -= 1.0f; + isStepEOC = true; + } + } + } + + void reset() { + phase = 0.f; + reverse = false; + } + + bool isEOC() { + return isStepEOC; + } + + void setPitch(float pitch) { + freq = dsp::FREQ_C4 * powf(2.0f, pitch); + } + + float getValue(float detaillevel, float x, float y, float z, float scale) { + return simp.SumOctaveSmooth(detaillevel, x + phase, y, z, scale); + } + + float getOsc(float detaillevel, float x, float y, float z, float scale) { + float value = getValue(detaillevel, x, y, z, scale); + return value * 5.f; + } - float getNormalizedOsc(float detaillevel, float x, float y, float z, float scale){ + float getNormalizedOsc(float detaillevel, float x, float y, float z, float scale) { float value = getValue(detaillevel, x, y, z, scale); - if(bufferIndex >= BUFFER_LENGTH){ - bufferIndex = 0; - } + if (bufferIndex >= BUFFER_LENGTH) { + bufferIndex = 0; + } - buffer[bufferIndex] = value; - bufferIndex++; + buffer[bufferIndex] = value; + bufferIndex++; - if(tick % 256 == 0){ - auto result = std::minmax_element(begin(buffer),end(buffer)); - min = *result.first; - max = *result.second; - } - tick++; + if (tick % 256 == 0) { + auto result = std::minmax_element(begin(buffer), end(buffer)); + min = *result.first; + max = *result.second; + } + tick++; - value = clamp(rescale(value,min,max,-1.f,1.f),-1.f,1.f); - return value*5.f;; + value = clamp(rescale(value, min, max, -1.f, 1.f), -1.f, 1.f); + return value * 5.f;; } }; diff --git a/src/oscillators/wavetable.cpp b/src/oscillators/wavetable.cpp index 5956822..6461185 100644 --- a/src/oscillators/wavetable.cpp +++ b/src/oscillators/wavetable.cpp @@ -1,11 +1,11 @@ -struct WaveTable{ +struct WaveTable { static const int WAVEFORM_COUNT = 3; static const int MAX_SAMPLE_COUNT = 2048; int WAVETABLE_SIZE = MAX_SAMPLE_COUNT; float lookuptable[WAVEFORM_COUNT][MAX_SAMPLE_COUNT] = {{0}}; int recordingIndex = 0; - float getSample(float y, float x){ + float getSample(float y, float x) { //Getting indexes for current place in table int index0 = (int) x; @@ -15,7 +15,7 @@ struct WaveTable{ float indexFrac = x - (float) index0; //Getting indexes for the levels based on y - float frac = y * (WAVEFORM_COUNT-1); + float frac = y * (WAVEFORM_COUNT - 1); int level0 = floor(frac); int level1 = ceil(frac); float levelFrac = frac - (float) level0; @@ -36,35 +36,35 @@ struct WaveTable{ return finalValue; } - void reset(){ + void reset() { recordingIndex = 0.f; } - void startCapture(){ + void startCapture() { reset(); } - void endCapture(){ + void endCapture() { WAVETABLE_SIZE = recordingIndex; reset(); } - void addSampleToFrame(float sampleValue, int waveId){ + void addSampleToFrame(float sampleValue, int waveId) { lookuptable[waveId][recordingIndex] = sampleValue; } - void endFrame(){ + void endFrame() { recordingIndex = recordingIndex + 1; } }; -struct WaveTableOscillator{ - WaveTable* waveTable; +struct WaveTableOscillator { + WaveTable *waveTable; float currentIndex = 0.f; float tableDelta = 0.f; - bool isStepEOC = false; + bool isStepEOC = false; bool mirror = false; bool reverse = false; @@ -74,56 +74,56 @@ struct WaveTableOscillator{ float phase = 0.f; float freq = 0.f; - WaveTableOscillator(){ + WaveTableOscillator() { waveTable = new WaveTable(); } - float getSample(float y){ - if(waveTable == nullptr) + float getSample(float y) { + if (waveTable == nullptr) return 0.f; else - return waveTable->getSample(y,currentIndex); + return waveTable->getSample(y, currentIndex); } - void step(){ - if(waveTable == nullptr) + void step() { + if (waveTable == nullptr) return; isStepEOC = false; - if(mirror){ - if(!reverse){ + if (mirror) { + if (!reverse) { currentIndex += tableDelta; - if (currentIndex >= waveTable->WAVETABLE_SIZE/2.f) + if (currentIndex >= waveTable->WAVETABLE_SIZE / 2.f) reverse = true; } - else{ + else { currentIndex -= tableDelta; - if(currentIndex < 0.f){ + if (currentIndex < 0.f) { reverse = false; currentIndex = 0.f; isStepEOC = true; } } } - else{ + else { currentIndex += tableDelta; - if (currentIndex >= waveTable->WAVETABLE_SIZE){ + if (currentIndex >= waveTable->WAVETABLE_SIZE) { currentIndex -= waveTable->WAVETABLE_SIZE; isStepEOC = true; } } } - bool isEOC(){ - return isStepEOC; - } + bool isEOC() { + return isStepEOC; + } - void setPitch(float pitch, float sampleRate){ - if(waveTable == nullptr) + void setPitch(float pitch, float sampleRate) { + if (waveTable == nullptr) return; - if(pitch != prevPitch){ + if (pitch != prevPitch) { float frequency = dsp::FREQ_C4 * powf(2.0f, pitch); auto tableSizeOverSampleRate = waveTable->WAVETABLE_SIZE / sampleRate; tableDelta = frequency * tableSizeOverSampleRate; @@ -131,13 +131,13 @@ struct WaveTableOscillator{ } } - void setMirror(bool _mirror){ - mirror = _mirror; - reset(); - } + void setMirror(bool _mirror) { + mirror = _mirror; + reset(); + } - void reset(){ + void reset() { currentIndex = 0.f; } }; diff --git a/src/plugin.hpp b/src/plugin.hpp index 88ac2ee..09c7f1f 100644 --- a/src/plugin.hpp +++ b/src/plugin.hpp @@ -1,6 +1,5 @@ -#include "rack0.hpp" -#include "window.hpp" - +#pragma once +#include "rack.hpp" using namespace rack; diff --git a/src/plus-oscillators.cpp b/src/plus-oscillators.cpp index 5228749..872cf7a 100644 --- a/src/plus-oscillators.cpp +++ b/src/plus-oscillators.cpp @@ -7,101 +7,105 @@ const int OSC_COUNT = 3; struct TTOBasePlus : TinyTricksModule { - enum ParamIds { - FREQ_PARAM, + enum ParamIds { + FREQ_PARAM, FREQ_FINE_PARAM, THETA_PARAM, - DETUNE_PARAM, - HARDSYNC2_PARAM, - HARDSYNC3_PARAM, - NUM_PARAMS - }; - enum InputIds { - FREQ_CV_INPUT, + DETUNE_PARAM, + HARDSYNC2_PARAM, + HARDSYNC3_PARAM, + NUM_PARAMS + }; + enum InputIds { + FREQ_CV_INPUT, FREQ_FINE_CV_INPUT, THETA_CV_INPUT, - DETUNE_CV_INPUT, - NUM_INPUTS - }; - enum OutputIds { - OSC_OUTPUT, - NUM_OUTPUTS - }; - enum LightIds { - HARDSYNC2_LIGHT, - HARDSYNC3_LIGHT, - NUM_LIGHTS - }; - - TinyOscillator* oscillators[POLY_SIZE]; + DETUNE_CV_INPUT, + NUM_INPUTS + }; + enum OutputIds { + OSC_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + HARDSYNC2_LIGHT, + HARDSYNC3_LIGHT, + NUM_LIGHTS + }; + + TinyOscillator *oscillators[POLY_SIZE]; TinyOscillator::OscillatorType oscType; - dsp::SchmittTrigger hardsync2Trigger; - dsp::SchmittTrigger hardsync3Trigger; - bool hardsync2 = false; - bool hardsync3 = false; + dsp::SchmittTrigger hardsync2Trigger; + dsp::SchmittTrigger hardsync3Trigger; + bool hardsync2 = false; + bool hardsync3 = false; float prevPitch[POLY_SIZE]; float prevTheta[POLY_SIZE]; - float prevDetune[POLY_SIZE]; + float prevDetune[POLY_SIZE]; - void Initialize(){ - for(auto i=0; isetPitch(pitch+(detune*i)); + if (pitchChanged) + oscillator->setPitch(pitch + (detune * i)); - if(thetaChanged) + if (thetaChanged) oscillator->setTheta(theta); //Stepping oscillator->step(args.sampleRate); - if(i>0){ - TinyOscillator *prevOscillator = &oscillators[c][i-1]; - if( - (i==1 && hardsync2 && prevOscillator->isEOC())|| - (i==2 && hardsync3 && prevOscillator->isEOC()) - ) + if (i > 0) { + TinyOscillator *prevOscillator = &oscillators[c][i - 1]; + if ( + (i == 1 && hardsync2 && prevOscillator->isEOC()) || + (i == 2 && hardsync3 && prevOscillator->isEOC()) + ) oscillator->reset(); } //Getting the value switch (oscType) { - case TinyOscillator::OscillatorType::SIN: - value += oscillator->getSin()/OSC_COUNT; - break; + case TinyOscillator::OscillatorType::SIN: + value += oscillator->getSin() / OSC_COUNT; + break; - case TinyOscillator::OscillatorType::SAW: - value += oscillator->getSaw()/OSC_COUNT; - break; + case TinyOscillator::OscillatorType::SAW: + value += oscillator->getSaw() / OSC_COUNT; + break; - case TinyOscillator::OscillatorType::SQR: - value += oscillator->getSqr()/OSC_COUNT; - break; + case TinyOscillator::OscillatorType::SQR: + value += oscillator->getSqr() / OSC_COUNT; + break; - case TinyOscillator::OscillatorType::TRI: - value += oscillator->getTri()/OSC_COUNT; - break; + case TinyOscillator::OscillatorType::TRI: + value += oscillator->getTri() / OSC_COUNT; + break; } } //Setting output @@ -203,99 +206,99 @@ struct TTOBasePlus : TinyTricksModule { struct TTOBasePlusWidget : TinyTricksModuleWidget { - TTOBasePlusWidget(TTOBasePlus *module) { - setModule(module); + TTOBasePlusWidget(TTOBasePlus *module) { + setModule(module); - addInput(createInput(mm2px(Vec(8.667f,22.403f)), module, TTOBasePlus::FREQ_CV_INPUT)); - addParam(createParam(mm2px(Vec(7.7f,11.051f)), module, TTOBasePlus::FREQ_PARAM)); + addInput(createInput(mm2px(Vec(8.667f, 22.403f)), module, TTOBasePlus::FREQ_CV_INPUT)); + addParam(createParam(mm2px(Vec(7.7f, 11.051f)), module, TTOBasePlus::FREQ_PARAM)); - //Fine tuning - addParam(createParam(mm2px(Vec(3.f,40.415f)), module, TTOBasePlus::FREQ_FINE_PARAM)); - addInput(createInput(mm2px(Vec(14.082f,40.015f)), module, TTOBasePlus::FREQ_FINE_CV_INPUT)); + //Fine tuning + addParam(createParam(mm2px(Vec(3.f, 40.415f)), module, TTOBasePlus::FREQ_FINE_PARAM)); + addInput(createInput(mm2px(Vec(14.082f, 40.015f)), module, TTOBasePlus::FREQ_FINE_CV_INPUT)); - //Detune - addParam(createParam(mm2px(Vec(3.f,54.934f)), module, TTOBasePlus::DETUNE_PARAM)); - addInput(createInput(mm2px(Vec(14.082f,54.534f)), module, TTOBasePlus::DETUNE_CV_INPUT)); + //Detune + addParam(createParam(mm2px(Vec(3.f, 54.934f)), module, TTOBasePlus::DETUNE_PARAM)); + addInput(createInput(mm2px(Vec(14.082f, 54.534f)), module, TTOBasePlus::DETUNE_CV_INPUT)); - //Hard sync buttons - addParam(createParam(mm2px(Vec(3.825f,91.955f)), module, TTOBasePlus::HARDSYNC2_PARAM)); - addChild(createLight>(mm2px(Vec(3.825f+0.45f,91.955f+0.45f)), module, TTOBasePlus::HARDSYNC2_LIGHT)); + //Hard sync buttons + addParam(createParam(mm2px(Vec(3.825f, 91.955f)), module, TTOBasePlus::HARDSYNC2_PARAM)); + addChild(createLight>(mm2px(Vec(3.825f + 0.45f, 91.955f + 0.45f)), module, TTOBasePlus::HARDSYNC2_LIGHT)); - addParam(createParam(mm2px(Vec(15.004f,91.955f)), module, TTOBasePlus::HARDSYNC3_PARAM)); - addChild(createLight>(mm2px(Vec(15.004f+0.45f,91.955f+0.45f)), module, TTOBasePlus::HARDSYNC3_LIGHT)); + addParam(createParam(mm2px(Vec(15.004f, 91.955f)), module, TTOBasePlus::HARDSYNC3_PARAM)); + addChild(createLight>(mm2px(Vec(15.004f + 0.45f, 91.955f + 0.45f)), module, TTOBasePlus::HARDSYNC3_LIGHT)); - //Output - addOutput(createOutput(mm2px(Vec(8.804f,113.016f)), module, TTOBasePlus::OSC_OUTPUT)); + //Output + addOutput(createOutput(mm2px(Vec(8.804f, 113.016f)), module, TTOBasePlus::OSC_OUTPUT)); - } + } }; // Sine -------------------------------------------------------------------------------------------------------------- -struct TTOSinPlus : TTOBasePlus{ - TTOSinPlus():TTOBasePlus(TinyOscillator::OscillatorType::SIN){ +struct TTOSinPlus : TTOBasePlus { + TTOSinPlus(): TTOBasePlus(TinyOscillator::OscillatorType::SIN) { } }; struct TTOSinPlusWidget : TTOBasePlusWidget { - TTOSinPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { - InitializeSkin("TTSINPLUS.svg"); - } + TTOSinPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { + InitializeSkin("TTSINPLUS.svg"); + } }; Model *modelTTSINPLUS = createModel("TTSINPLUS"); // Saw -------------------------------------------------------------------------------------------------------------- -struct TTOSawPlus : TTOBasePlus{ - TTOSawPlus():TTOBasePlus(TinyOscillator::OscillatorType::SAW){ +struct TTOSawPlus : TTOBasePlus { + TTOSawPlus(): TTOBasePlus(TinyOscillator::OscillatorType::SAW) { } }; struct TTOSawPlusWidget : TTOBasePlusWidget { - TTOSawPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { - //Theta - addParam(createParam(mm2px(Vec(3.f,69.452f)), module, TTOBasePlus::THETA_PARAM)); - addInput(createInput(mm2px(Vec(14.082f,69.053f)), module, TTOBasePlus::THETA_CV_INPUT)); + TTOSawPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { + //Theta + addParam(createParam(mm2px(Vec(3.f, 69.452f)), module, TTOBasePlus::THETA_PARAM)); + addInput(createInput(mm2px(Vec(14.082f, 69.053f)), module, TTOBasePlus::THETA_CV_INPUT)); - InitializeSkin("TTSAWPLUS.svg"); - } + InitializeSkin("TTSAWPLUS.svg"); + } }; Model *modelTTSAWPLUS = createModel("TTSAWPLUS"); // Square -------------------------------------------------------------------------------------------------------------- -struct TTOSqrPlus : TTOBasePlus{ - TTOSqrPlus():TTOBasePlus(TinyOscillator::OscillatorType::SQR){ +struct TTOSqrPlus : TTOBasePlus { + TTOSqrPlus(): TTOBasePlus(TinyOscillator::OscillatorType::SQR) { } }; struct TTOSqrPlusWidget : TTOBasePlusWidget { - TTOSqrPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { - //Theta - addParam(createParam(mm2px(Vec(3.f,69.452f)), module, TTOBasePlus::THETA_PARAM)); - addInput(createInput(mm2px(Vec(14.082f,69.053f)), module, TTOBasePlus::THETA_CV_INPUT)); + TTOSqrPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { + //Theta + addParam(createParam(mm2px(Vec(3.f, 69.452f)), module, TTOBasePlus::THETA_PARAM)); + addInput(createInput(mm2px(Vec(14.082f, 69.053f)), module, TTOBasePlus::THETA_CV_INPUT)); - InitializeSkin("TTSQRPLUS.svg"); - } + InitializeSkin("TTSQRPLUS.svg"); + } }; Model *modelTTSQRPLUS = createModel("TTSQRPLUS"); // Square -------------------------------------------------------------------------------------------------------------- -struct TTOTriPlus : TTOBasePlus{ - TTOTriPlus():TTOBasePlus(TinyOscillator::OscillatorType::TRI){ +struct TTOTriPlus : TTOBasePlus { + TTOTriPlus(): TTOBasePlus(TinyOscillator::OscillatorType::TRI) { } }; struct TTOTriPlusWidget : TTOBasePlusWidget { - TTOTriPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { - //Theta - addParam(createParam(mm2px(Vec(3.f,69.452f)), module, TTOBasePlus::THETA_PARAM)); - addInput(createInput(mm2px(Vec(14.082f,69.053f)), module, TTOBasePlus::THETA_CV_INPUT)); + TTOTriPlusWidget(TTOBasePlus *module) : TTOBasePlusWidget(module) { + //Theta + addParam(createParam(mm2px(Vec(3.f, 69.452f)), module, TTOBasePlus::THETA_PARAM)); + addInput(createInput(mm2px(Vec(14.082f, 69.053f)), module, TTOBasePlus::THETA_CV_INPUT)); - InitializeSkin("TTTRIPLUS.svg"); - } + InitializeSkin("TTTRIPLUS.svg"); + } }; Model *modelTTTRIPLUS = createModel("TTTRIPLUS"); diff --git a/src/random-mix.cpp b/src/random-mix.cpp index dd6a121..2da1dea 100644 --- a/src/random-mix.cpp +++ b/src/random-mix.cpp @@ -40,13 +40,16 @@ struct RX8Base : TinyTricksModule { bool stereo = false; SimplexNoise simp; - void initialize(){ - simp.init(); - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(SPEED_PARAM, SPEED_MIN, SPEED_MAX, 0.5f, "Speed of change"); - configParam(JITTER_PARAM, JITTER_MIN, JITTER_MAX, JITTER_MIN, "jitter of change"); - configParam(TRIGONLY_PARAM, 0.f, 1.f, 1.f, "Flow free or only change on trigger"); - configParam(PINNING_PARAM, 1.f, 10.f, 1.5f, "Amount to pin at top og bottom of curve"); + void initialize() { + simp.init(); + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configParam(SPEED_PARAM, SPEED_MIN, SPEED_MAX, 0.5f, "Speed of change"); + configParam(JITTER_PARAM, JITTER_MIN, JITTER_MAX, JITTER_MIN, "Jitter of change"); + configSwitch(TRIGONLY_PARAM, 0.f, 1.f, 1.f, "Mode", {"Flow free", "Only change on trigger"}); + configParam(PINNING_PARAM, 1.f, 10.f, 1.5f, "Amount to pin at top of bottom of curve"); + configInput(TRIG_INPUT, "Trigger"); + configInput(SPEED_CV_INPUT, "Speed of change CV"); + configInput(JITTER_CV_INPUT, "Jitter of change CV"); } @@ -68,48 +71,48 @@ struct RX8Base : TinyTricksModule { bool freeflow = (params[TRIGONLY_PARAM].getValue() == 0.f); - float delta = 1.0f / args.sampleRate; - if(!reverse){ + float delta = 1.0f / args.sampleRate; + if (!reverse) { t += delta; if (t >= 128.f) reverse = true; } - else{ + else { t -= delta; - if(t < 0){ + if (t < 0) { reverse = false; t = -t; } } - if(freeflow || (inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage()))){ + if (freeflow || (inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage()))) { //Getting pinning float pinning = params[PINNING_PARAM].getValue(); //Getting the speed float speed = params[SPEED_PARAM].getValue(); - if(inputs[SPEED_CV_INPUT].isConnected()){ + if (inputs[SPEED_CV_INPUT].isConnected()) { float speedCV = inputs[SPEED_CV_INPUT].getVoltage(); speedCV /= 10.f; - speed = clamp(speed+speedCV,SPEED_MIN,SPEED_MAX); + speed = clamp(speed + speedCV, SPEED_MIN, SPEED_MAX); } //Getting jitter float jitter = params[JITTER_PARAM].getValue(); - if(inputs[JITTER_CV_INPUT].isConnected()){ + if (inputs[JITTER_CV_INPUT].isConnected()) { float jitterCV = inputs[JITTER_CV_INPUT].getVoltage(); jitterCV = rescale(jitterCV, -5.f, 5.f, 0.f, 10.f); jitterCV /= 2.f; - jitter = clamp(jitter + jitterCV,JITTER_MIN,JITTER_MAX); + jitter = clamp(jitter + jitterCV, JITTER_MIN, JITTER_MAX); } //Getting new levels summedLevels = 0.f; for (int i = 0; i < NUM_CHANNELS; i++) { - if(inputs[AUDIO_L_INPUT + i].isConnected()){ - float y = (2.f*i); - float noiseVal = simp.SumOctave(jitter,t,y,0.7f,speed); - float level = clamp(noiseVal*(pinning),-1.f,1.f); + if (inputs[AUDIO_L_INPUT + i].isConnected()) { + float y = (2.f * i); + float noiseVal = simp.SumOctave(jitter, t, y, 0.7f, speed); + float level = clamp(noiseVal * (pinning), -1.f, 1.f); level *= level; summedLevels += level; levels[i] = level; @@ -122,17 +125,17 @@ struct RX8Base : TinyTricksModule { //Mixing signal for output float mix = 0.f; int connected = 0; - if(outputs[MIX_L_OUTPUT].isConnected()){ + if (outputs[MIX_L_OUTPUT].isConnected()) { for (int i = 0; i < NUM_CHANNELS; i++) { - if(inputs[AUDIO_L_INPUT + i].isConnected()) { + if (inputs[AUDIO_L_INPUT + i].isConnected()) { connected++; - mix += inputs[AUDIO_L_INPUT + i].getVoltage()*levels[i]; + mix += inputs[AUDIO_L_INPUT + i].getVoltage() * levels[i]; } } - if(connected==1) - outputs[MIX_L_OUTPUT].setVoltage(mix); - else if(summedLevels>0.f) - outputs[MIX_L_OUTPUT].setVoltage(mix/summedLevels); + if (connected == 1) + outputs[MIX_L_OUTPUT].setVoltage(mix); + else if (summedLevels > 0.f) + outputs[MIX_L_OUTPUT].setVoltage(mix / summedLevels); else outputs[MIX_L_OUTPUT].setVoltage(0.f); @@ -147,18 +150,18 @@ struct RX8BaseWidget : TinyTricksModuleWidget { addInput(createInput(mm2px(Vec(3.977f, 12.003f)), module, RX8Base::TRIG_INPUT)); - for (int i = 0; i < NUM_CHANNELS; i++){ + for (int i = 0; i < NUM_CHANNELS; i++) { addChild(createLight>(mm2px(Vec(9.641f, 35.995f + 11.6f * i)), module, RX8Base::LEVEL_LIGHT + i)); addInput(createInput(mm2px(Vec(3.933f, 29.5f + 11.6f * i)), module, RX8Base::AUDIO_L_INPUT + i)); } - addParam(createParam(mm2px(Vec(19.981f,10.992f)), module, RX8Base::TRIGONLY_PARAM)); + addParam(createParam(mm2px(Vec(19.981f, 10.992f)), module, RX8Base::TRIGONLY_PARAM)); //Internal selection controls - addParam(createParam(mm2px(Vec(17.45f,30.677f)), module, RX8Base::SPEED_PARAM)); + addParam(createParam(mm2px(Vec(17.45f, 30.677f)), module, RX8Base::SPEED_PARAM)); addInput(createInput(mm2px(Vec(18.389f, 41.992f)), module, RX8Base::SPEED_CV_INPUT)); - addParam(createParam(mm2px(Vec(17.45f,58.239f)), module, RX8Base::JITTER_PARAM)); + addParam(createParam(mm2px(Vec(17.45f, 58.239f)), module, RX8Base::JITTER_PARAM)); addInput(createInput(mm2px(Vec(18.398f, 69.585f)), module, RX8Base::JITTER_CV_INPUT)); /*{ @@ -167,7 +170,7 @@ struct RX8BaseWidget : TinyTricksModuleWidget { addParam(w); }*/ - addParam(createParam(mm2px(Vec(17.45f,87.104f)), module, RX8Base::PINNING_PARAM)); + addParam(createParam(mm2px(Vec(17.45f, 87.104f)), module, RX8Base::PINNING_PARAM)); //Mix output @@ -178,13 +181,13 @@ struct RX8BaseWidget : TinyTricksModuleWidget { // Mono -------------------------------------------------------------------------------------------------------------- -struct RX8Mono : RX8Base{ - RX8Mono():RX8Base(false){ +struct RX8Mono : RX8Base { + RX8Mono(): RX8Base(false) { } }; struct RX8MonoWidget : RX8BaseWidget { - RX8MonoWidget(RX8Base *module) : RX8BaseWidget(module) { + RX8MonoWidget(RX8Base *module) : RX8BaseWidget(module) { InitializeSkin("RX8.svg"); } }; diff --git a/src/random-mute.cpp b/src/random-mute.cpp index dd45ccc..d97f9d0 100644 --- a/src/random-mute.cpp +++ b/src/random-mute.cpp @@ -31,9 +31,23 @@ struct RM8Base : TinyTricksModule { bool stereo = false; - void initialize(){ - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(MUTE_COUNT_PARAM, 0.f, NUM_CHANNELS, 0.f, "Number of channels to leave unmuted"); + void initialize() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configParam(MUTE_COUNT_PARAM, 0.f, NUM_CHANNELS, 0.f, "Number of channels to leave unmuted"); + configInput(TRIG_INPUT, "Trigger"); + configInput(MUTE_COUNT_CV_INPUT, "Mute CV"); + for (int i = 0; i < NUM_CHANNELS; i++) { + if (stereo) { + configInput(MUTE_L_INPUT + i, string::f("Channel L%d", i + 1)); + configOutput(MUTE_L_OUTPUT + i, string::f("Channel L%d", i + 1)); + configInput(MUTE_R_INPUT + i, string::f("Channel R%d", i + 1)); + configOutput(MUTE_R_OUTPUT + i, string::f("Channel R%d", i + 1)); + } + else { + configInput(MUTE_L_INPUT + i, string::f("Channel %d", i + 1)); + configOutput(MUTE_L_OUTPUT + i, string::f("Channel %d", i + 1)); + } + } } @@ -49,51 +63,50 @@ struct RM8Base : TinyTricksModule { void process(const ProcessArgs &args) override { - if (inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage())) { + if (inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage())) { int muteCount = 0; muteCount = params[MUTE_COUNT_PARAM].getValue(); - if(inputs[MUTE_COUNT_CV_INPUT].isConnected()) - muteCount += static_cast(round(rescale(inputs[MUTE_COUNT_CV_INPUT].getVoltage(),-5.f,5.f,0.f,8.f))); + if (inputs[MUTE_COUNT_CV_INPUT].isConnected()) + muteCount += static_cast(round(rescale(inputs[MUTE_COUNT_CV_INPUT].getVoltage(), -5.f, 5.f, 0.f, 8.f))); //Getting candidates for mutes = connected channels std::vector candidates; - for (int i = 0; i < NUM_CHANNELS; i++){ + for (int i = 0; i < NUM_CHANNELS; i++) { muted[i] = true; //reset mutes while we're at it bool leftIsConnected = (inputs[MUTE_L_INPUT + i].isConnected() && outputs[MUTE_L_OUTPUT + i].isConnected()); bool rightIsConnected = (stereo && (inputs[MUTE_R_INPUT + i].isConnected() && outputs[MUTE_R_OUTPUT + i].isConnected())); - if(leftIsConnected || rightIsConnected) - candidates.push_back(i); + if (leftIsConnected || rightIsConnected) + candidates.push_back(i); } int candidateCount = static_cast(candidates.size()); - if(candidateCount > muteCount){ - std::random_shuffle (candidates.begin(), candidates.end()); - for(int i = 0; i < candidateCount - muteCount; i++) - muted[candidates[i]] = false; + if (candidateCount > muteCount) { + std::random_shuffle(candidates.begin(), candidates.end()); + for (int i = 0; i < candidateCount - muteCount; i++) + muted[candidates[i]] = false; } } for (int i = 0; i < NUM_CHANNELS; i++) { - bool leftIsConnected = (inputs[MUTE_L_INPUT + i].isConnected() && outputs[MUTE_L_OUTPUT + i].isConnected()); - bool rightIsConnected = (stereo && (inputs[MUTE_R_INPUT + i].isConnected() && outputs[MUTE_R_OUTPUT + i].isConnected())); - - if(!muted[i]) - { - lights[MUTE_LIGHT + i].value = 1.f; - if(leftIsConnected) - outputs[MUTE_L_OUTPUT + i].setVoltage(inputs[MUTE_L_INPUT + i].getVoltage()); - if(rightIsConnected) - outputs[MUTE_R_OUTPUT + i].setVoltage(inputs[MUTE_R_INPUT + i].getVoltage()); - } - else{ - lights[MUTE_LIGHT + i].value = 0.f; - if(leftIsConnected) - outputs[MUTE_L_OUTPUT + i].setVoltage(0.f); - if(rightIsConnected) - outputs[MUTE_R_OUTPUT + i].setVoltage(0.f); - } + bool leftIsConnected = (inputs[MUTE_L_INPUT + i].isConnected() && outputs[MUTE_L_OUTPUT + i].isConnected()); + bool rightIsConnected = (stereo && (inputs[MUTE_R_INPUT + i].isConnected() && outputs[MUTE_R_OUTPUT + i].isConnected())); + + if (!muted[i]) { + lights[MUTE_LIGHT + i].value = 1.f; + if (leftIsConnected) + outputs[MUTE_L_OUTPUT + i].setVoltage(inputs[MUTE_L_INPUT + i].getVoltage()); + if (rightIsConnected) + outputs[MUTE_R_OUTPUT + i].setVoltage(inputs[MUTE_R_INPUT + i].getVoltage()); + } + else { + lights[MUTE_LIGHT + i].value = 0.f; + if (leftIsConnected) + outputs[MUTE_L_OUTPUT + i].setVoltage(0.f); + if (rightIsConnected) + outputs[MUTE_R_OUTPUT + i].setVoltage(0.f); + } } } @@ -107,9 +120,9 @@ struct RM8BaseWidget : TinyTricksModuleWidget { addInput(createInput(mm2px(Vec(3.847f, 12.003f)), module, RM8Base::TRIG_INPUT)); { - auto w = createParam(mm2px(Vec(3.9f,31.62f)), module, RM8Base::MUTE_COUNT_PARAM); - dynamic_cast(w)->snap = true; - addParam(w); + auto w = createParam(mm2px(Vec(3.9f, 31.62f)), module, RM8Base::MUTE_COUNT_PARAM); + dynamic_cast(w)->snap = true; + addParam(w); } addInput(createInput(mm2px(Vec(3.847, 41.251f)), module, RM8Base::MUTE_COUNT_CV_INPUT)); } @@ -117,32 +130,32 @@ struct RM8BaseWidget : TinyTricksModuleWidget { // Mono -------------------------------------------------------------------------------------------------------------- -struct RM8Mono : RM8Base{ - RM8Mono():RM8Base(false){ +struct RM8Mono : RM8Base { + RM8Mono(): RM8Base(false) { } }; struct RM8MonoWidget : RM8BaseWidget { - RM8MonoWidget(RM8Base *module) : RM8BaseWidget(module) { - for (int i = 0; i < NUM_CHANNELS; i++){ + RM8MonoWidget(RM8Base *module) : RM8BaseWidget(module) { + for (int i = 0; i < NUM_CHANNELS; i++) { addInput(createInput(mm2px(Vec(17.424f, 11.782f + 14.f * i)), module, RM8Base::MUTE_L_INPUT + i)); addChild(createLight>(mm2px(Vec(26.209, 14.701 + 14.f * i)), module, RM8Base::MUTE_LIGHT + i)); addOutput(createOutput(mm2px(Vec(29.122f, 11.782f + 14.f * i)), module, RM8Base::MUTE_L_OUTPUT + i)); } InitializeSkin("RM8.svg"); - } + } }; Model *modelRM8 = createModel("RM8"); // Stereo -------------------------------------------------------------------------------------------------------------- -struct RM8Stereo : RM8Base{ - RM8Stereo():RM8Base(true){ +struct RM8Stereo : RM8Base { + RM8Stereo(): RM8Base(true) { } }; struct RM8StereoWidget : RM8BaseWidget { - RM8StereoWidget(RM8Base *module) : RM8BaseWidget(module) { - for (int i = 0; i < NUM_CHANNELS; i++){ + RM8StereoWidget(RM8Base *module) : RM8BaseWidget(module) { + for (int i = 0; i < NUM_CHANNELS; i++) { addInput(createInput(mm2px(Vec(17.788f, 12.003f + 14.f * i)), module, RM8Base::MUTE_L_INPUT + i)); addInput(createInput(mm2px(Vec(26.994f, 12.003f + 14.f * i)), module, RM8Base::MUTE_R_INPUT + i)); addChild(createLight>(mm2px(Vec(36.199, 14.992 + 14.f * i)), module, RM8Base::MUTE_LIGHT + i)); @@ -150,6 +163,6 @@ struct RM8StereoWidget : RM8BaseWidget { addOutput(createOutput(mm2px(Vec(48.773f, 12.003f + 14.f * i)), module, RM8Base::MUTE_R_OUTPUT + i)); } InitializeSkin("RM8S.svg"); - } + } }; Model *modelRM8S = createModel("RM8S"); diff --git a/src/randomwrangler.cpp b/src/randomwrangler.cpp index df8a2a4..34f9e30 100644 --- a/src/randomwrangler.cpp +++ b/src/randomwrangler.cpp @@ -46,8 +46,8 @@ struct RANDOMWRANGLER : TinyTricksModule { float smoothFrac = 0.f; std::default_random_engine generator; - std::piecewise_linear_distribution* distributionLinear; - std::piecewise_constant_distribution* distributionConstant; + std::piecewise_linear_distribution *distributionLinear; + std::piecewise_constant_distribution *distributionConstant; std::vector intervals; std::vector weights; @@ -63,7 +63,7 @@ struct RANDOMWRANGLER : TinyTricksModule { int tick = 0; - CurveWidget* curve; + CurveWidget *curve; std::vector tmp; @@ -71,67 +71,82 @@ struct RANDOMWRANGLER : TinyTricksModule { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (size_t i = 0; i < NUM_CURVE_POINTS; i++) { - float initValue = RANDOM_MAX/(i+1); + float initValue = RANDOM_MAX / (i + 1); configParam(RANDOMWRANGLER::CURVE_PARAM + i, RANDOM_MIN, RANDOM_MAX, initValue, "Probability weight"); weights.push_back(9000); tmp.push_back(9000); } configParam(RANDOMWRANGLER::RATE_PARAM, RATE_MIN, RATE_MAX, RATE_MAX, "Rate"); - configParam(RANDOMWRANGLER::SMOOTH_RATE_PARAM, SMOOTH_RATE_MIN, SMOOTH_RATE_MAX, SMOOTH_RATE_MIN, "Smoothing amout"); - configParam(RANDOMWRANGLER::LIN_SMOOTH_PARAM, 0.0f, 1.0f, 1.0f, "Smooth shape"); + configParam(RANDOMWRANGLER::SMOOTH_RATE_PARAM, SMOOTH_RATE_MIN, SMOOTH_RATE_MAX, SMOOTH_RATE_MIN, "Smoothing amount"); + configParam(RANDOMWRANGLER::LIN_SMOOTH_PARAM, 0.0f, 1.0f, 1.0f, "Smooth shape", {"Exponential", "Linear"}); + // ENUMS(CURVE_CV_INPUT, NUM_CURVE_POINTS), + configInput(TRIG_INPUT, "Trigger"); + configInput(RATE_CV_INPUT, "Rate CV"); + configInput(SMOOTH_RATE_CV_INPUT, "Smoothing amount CV"); + configInput(CURVE_CV_INPUT + 0, "Probability weight A CV"); + configInput(CURVE_CV_INPUT + 1, "Probability weight B CV"); + configInput(CURVE_CV_INPUT + 2, "Probability weight C CV"); + configInput(CURVE_CV_INPUT + 3, "Probability weight D CV"); + configInput(CURVE_CV_INPUT + 4, "Probability weight E CV"); + configInput(CURVE_CV_INPUT + 5, "Probability weight F CV"); + configInput(CURVE_CV_INPUT + 6, "Probability weight G CV"); + configInput(CURVE_CV_INPUT + 7, "Probability weight H CV"); + configInput(CURVE_CV_INPUT + 8, "Probability weight I CV"); + configOutput(NOISE_OUTPUT, "Noise"); initIntervals(); //regenerateDistribution(); } - void onReset() override{ + void onReset() override { processCurveParams(true); } - void onRandomize() override{ + void onRandomize() override { processCurveParams(true); } json_t *dataToJson() override { - json_t *rootJ = json_object(); - // Mode - json_object_set_new(rootJ, "isLiniearMode", json_boolean(isLiniearMode)); + json_t *rootJ = json_object(); + // Mode + json_object_set_new(rootJ, "isLiniearMode", json_boolean(isLiniearMode)); - AppendBaseJson(rootJ); - return rootJ; - } + AppendBaseJson(rootJ); + return rootJ; + } - void dataFromJson(json_t *rootJ) override { - TinyTricksModule::dataFromJson(rootJ); + void dataFromJson(json_t *rootJ) override { + TinyTricksModule::dataFromJson(rootJ); //Mode json_t *isLiniearModeJ = json_object_get(rootJ, "isLiniearMode"); - if (isLiniearModeJ) isLiniearMode = json_is_true(isLiniearModeJ); + if (isLiniearModeJ) + isLiniearMode = json_is_true(isLiniearModeJ); curve->setMode(isLiniearMode); //processCurveParams(true); } - void toggleMode(){ + void toggleMode() { isLiniearMode = !isLiniearMode; curve->setMode(isLiniearMode); regenerateDistribution(); } - void initIntervals(){ + void initIntervals() { intervals.reserve(NUM_CURVE_POINTS); for (size_t i = 0; i < NUM_CURVE_POINTS; i++) { - float interval = (i/(float)(NUM_CURVE_POINTS-1))*RANDOM_MAX; + float interval = (i / (float)(NUM_CURVE_POINTS - 1)) * RANDOM_MAX; intervals.push_back(interval); } } - void regenerateDistribution(){ + void regenerateDistribution() { //std::cout << "regenerating" << std::endl; - if(isLiniearMode) - distributionLinear = new std::piecewise_linear_distribution(intervals.begin(),intervals.end(),weights.begin()); + if (isLiniearMode) + distributionLinear = new std::piecewise_linear_distribution(intervals.begin(), intervals.end(), weights.begin()); else - distributionConstant = new std::piecewise_constant_distribution(intervals.begin(),intervals.end(),weights.begin()); + distributionConstant = new std::piecewise_constant_distribution(intervals.begin(), intervals.end(), weights.begin()); /* std::cout << "min: " << (*distributionLinear).min() << std::endl; @@ -145,18 +160,18 @@ struct RANDOMWRANGLER : TinyTricksModule { */ } - float getRandom(){ - if(isLiniearMode && distributionLinear != nullptr) + float getRandom() { + if (isLiniearMode && distributionLinear != nullptr) return (*distributionLinear)(generator); - else if(distributionConstant != nullptr) + else if (distributionConstant != nullptr) return (*distributionConstant)(generator); else return 0.f; } - void updateCurve(){ + void updateCurve() { //Only update every 100 samples to increase performance - if(tick%1000==0){ + if (tick % 1000 == 0) { tick = 0; processCurveParams(false); } @@ -164,69 +179,69 @@ struct RANDOMWRANGLER : TinyTricksModule { } - void processCurveParams(bool regenerate){ + void processCurveParams(bool regenerate) { bool dirty = false; for (size_t i = 0; i < NUM_CURVE_POINTS; i++) { float value = params[CURVE_PARAM + i].getValue(); - if(inputs[CURVE_CV_INPUT + i].isConnected()) + if (inputs[CURVE_CV_INPUT + i].isConnected()) value += inputs[CURVE_CV_INPUT + i].getVoltage(); value = clamp(value, 0.f, 10.f); - if(abs(value-weights[i]) > sensitivity) + if (abs(value - weights[i]) > sensitivity) dirty = true; tmp[i] = value; } - if(dirty){ + if (dirty) { curve->setPoints(tmp); - if(regenerate){ + if (regenerate) { weights = tmp; regenerateDistribution(); } } } - void updateRate(){ + void updateRate() { float rate = params[RATE_PARAM].getValue(); - if(inputs[RATE_CV_INPUT].isConnected()) - rate += inputs[RATE_CV_INPUT].getVoltage()*2.f; + if (inputs[RATE_CV_INPUT].isConnected()) + rate += inputs[RATE_CV_INPUT].getVoltage() * 2.f; rate = clamp(rate, RATE_MIN, RATE_MAX); - if(rate != prevRate){ + if (rate != prevRate) { oscillator.setPitch(rate); //oscillator.reset(); prevRate = rate; } } - void updateSmoothRate(){ + void updateSmoothRate() { smoothRate = params[SMOOTH_RATE_PARAM].getValue(); - if(inputs[SMOOTH_RATE_CV_INPUT].isConnected()) - smoothRate += inputs[SMOOTH_RATE_CV_INPUT].getVoltage()/10.f; + if (inputs[SMOOTH_RATE_CV_INPUT].isConnected()) + smoothRate += inputs[SMOOTH_RATE_CV_INPUT].getVoltage() / 10.f; smoothRate = clamp(smoothRate, SMOOTH_RATE_MIN, SMOOTH_RATE_MAX); } - void resetSmooth(){ + void resetSmooth() { smoothFrac = 0.f; - if(currentOutValue != toOutValue) + if (currentOutValue != toOutValue) fromOutValue = currentOutValue; } - float smooth(float st){ - if(smoothRate == 0.f) + float smooth(float st) { + if (smoothRate == 0.f) return toOutValue; - else{ + else { smoothFrac += st; float frac = smoothFrac / smoothRate; - frac = clamp(frac,0.f,1.f); + frac = clamp(frac, 0.f, 1.f); if (params[LIN_SMOOTH_PARAM].getValue() != 1.f) frac = rescale(std::pow(50.f, frac), 1.f, 50.f, 0.f, 1.f); float diff = toOutValue - fromOutValue; - return fromOutValue + (diff*frac); + return fromOutValue + (diff * frac); } } @@ -241,20 +256,20 @@ struct RANDOMWRANGLER : TinyTricksModule { //Determining whether to generate new value or not bool generate; - if(inputs[TRIG_INPUT].isConnected()) + if (inputs[TRIG_INPUT].isConnected()) generate = trigTrigger.process(inputs[TRIG_INPUT].getVoltage()); else generate = oscillator.isEOC(); //Generating new value - if(generate){ + if (generate) { processCurveParams(true); fromOutValue = toOutValue; toOutValue = getRandom(); resetSmooth(); } - else{ + else { updateCurve(); } @@ -262,49 +277,49 @@ struct RANDOMWRANGLER : TinyTricksModule { currentOutValue = smooth(args.sampleTime); //Setting output - outputs[NOISE_OUTPUT].setVoltage(currentOutValue-5.f); + outputs[NOISE_OUTPUT].setVoltage(currentOutValue - 5.f); } }; struct RANDOMWRANGLERWidget : TinyTricksModuleWidget { - CurveWidget* curve; - RANDOMWRANGLER* randModule; + CurveWidget *curve; + RANDOMWRANGLER *randModule; const float widgetSpacing = 10.807f; - void appendContextMenu(Menu* menu) override { - menu->addChild(new MenuEntry); - menu->addChild(createMenuLabel("Mode")); + void appendContextMenu(Menu *menu) override { + menu->addChild(new MenuEntry); + menu->addChild(createMenuLabel("Mode")); - struct LocalItem : MenuItem { - RANDOMWRANGLER* module; - void onAction(const event::Action& e) override { - module->toggleMode(); - } - }; + struct LocalItem : MenuItem { + RANDOMWRANGLER *module; + void onAction(const event::Action &e) override { + module->toggleMode(); + } + }; - LocalItem* localItem = createMenuItem("Constant distribution (instead of linear)"); - localItem->rightText = CHECKMARK(!randModule->isLiniearMode); - localItem->module = randModule; - menu->addChild(localItem); + LocalItem *localItem = createMenuItem("Constant distribution (instead of linear)"); + localItem->rightText = CHECKMARK(!randModule->isLiniearMode); + localItem->module = randModule; + menu->addChild(localItem); - TinyTricksModuleWidget::appendContextMenu(menu); - } + TinyTricksModuleWidget::appendContextMenu(menu); + } - RANDOMWRANGLERWidget(RANDOMWRANGLER* module) { - if(module) + RANDOMWRANGLERWidget(RANDOMWRANGLER *module) { + if (module) randModule = module; setModule(module); //Top row for (size_t i = 0; i < 5; i++) { - int index = i*2; - addParam(createParam(mm2px(Vec(4.868f+i*widgetSpacing,10.312f)), module, RANDOMWRANGLER::CURVE_PARAM + index)); - addInput(createInput(mm2px(Vec(4.815f+i*widgetSpacing,19.545f)), module, RANDOMWRANGLER::CURVE_CV_INPUT + index)); + int index = i * 2; + addParam(createParam(mm2px(Vec(4.868f + i * widgetSpacing, 10.312f)), module, RANDOMWRANGLER::CURVE_PARAM + index)); + addInput(createInput(mm2px(Vec(4.815f + i * widgetSpacing, 19.545f)), module, RANDOMWRANGLER::CURVE_CV_INPUT + index)); } //Curve widget @@ -313,33 +328,33 @@ struct RANDOMWRANGLERWidget : TinyTricksModuleWidget { curve->box.size = mm2px(Vec(43.224f, 18.396f)); curve->setup(); addChild(curve); - if(module) + if (module) module->curve = curve; //Bottom row for (size_t i = 0; i < 4; i++) { - int index = (i*2)+1; - addParam(createParam(mm2px(Vec(10.271f+i*widgetSpacing,67.069f)), module, RANDOMWRANGLER::CURVE_PARAM + index)); - addInput(createInput(mm2px(Vec(10.218f+i*widgetSpacing,57.611f)), module, RANDOMWRANGLER::CURVE_CV_INPUT + index)); + int index = (i * 2) + 1; + addParam(createParam(mm2px(Vec(10.271f + i * widgetSpacing, 67.069f)), module, RANDOMWRANGLER::CURVE_PARAM + index)); + addInput(createInput(mm2px(Vec(10.218f + i * widgetSpacing, 57.611f)), module, RANDOMWRANGLER::CURVE_CV_INPUT + index)); } //Trigger - addInput(createInput(mm2px(Vec(5.863f,87.153f)), module, RANDOMWRANGLER::TRIG_INPUT)); + addInput(createInput(mm2px(Vec(5.863f, 87.153f)), module, RANDOMWRANGLER::TRIG_INPUT)); //Rate - addParam(createParam(mm2px(Vec(19.969f,87.153f)), module, RANDOMWRANGLER::RATE_PARAM)); - addInput(createInput(mm2px(Vec(19.915f,96.387f)), module, RANDOMWRANGLER::RATE_CV_INPUT)); + addParam(createParam(mm2px(Vec(19.969f, 87.153f)), module, RANDOMWRANGLER::RATE_PARAM)); + addInput(createInput(mm2px(Vec(19.915f, 96.387f)), module, RANDOMWRANGLER::RATE_CV_INPUT)); //Smooth rate - addParam(createParam(mm2px(Vec(32.992f,87.153f)), module, RANDOMWRANGLER::SMOOTH_RATE_PARAM)); - addInput(createInput(mm2px(Vec(32.387f,96.387f)), module, RANDOMWRANGLER::SMOOTH_RATE_CV_INPUT)); + addParam(createParam(mm2px(Vec(32.992f, 87.153f)), module, RANDOMWRANGLER::SMOOTH_RATE_PARAM)); + addInput(createInput(mm2px(Vec(32.387f, 96.387f)), module, RANDOMWRANGLER::SMOOTH_RATE_CV_INPUT)); //Smooth shape - addParam(createParam(mm2px(Vec(46.991f,87.565f)), module, RANDOMWRANGLER::LIN_SMOOTH_PARAM)); + addParam(createParam(mm2px(Vec(46.991f, 87.565f)), module, RANDOMWRANGLER::LIN_SMOOTH_PARAM)); //Output - addOutput(createOutput(mm2px(Vec(26.427f,113.255f)), module, RANDOMWRANGLER::NOISE_OUTPUT)); + addOutput(createOutput(mm2px(Vec(26.427f, 113.255f)), module, RANDOMWRANGLER::NOISE_OUTPUT)); InitializeSkin("RW.svg"); } diff --git a/src/sample-hold.cpp b/src/sample-hold.cpp index 067ca80..84c8ca9 100644 --- a/src/sample-hold.cpp +++ b/src/sample-hold.cpp @@ -24,19 +24,23 @@ struct SH16 : TinyTricksModule { SH16() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configInput(TRIG_INPUT, "Trigger"); + for (int i = 0; i < NUM_CHANNELS; i++) { + configOutput(HOLD_OUTPUT + i, string::f("Hold %d", i + 1)); + } } void process(const ProcessArgs &args) override; }; void SH16::process(const ProcessArgs &args) { - if (inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage())) { - for (int i = 0; i < NUM_CHANNELS; i++) { - float v = (random::uniform() * 10.0) - 5.0f; - // std::cout << "v: " << v << std::endl; - outputs[HOLD_OUTPUT + i].setVoltage(v); - } - } + if (inputs[TRIG_INPUT].isConnected() && trigger.process(inputs[TRIG_INPUT].getVoltage())) { + for (int i = 0; i < NUM_CHANNELS; i++) { + float v = (random::uniform() * 10.0) - 5.0f; + // std::cout << "v: " << v << std::endl; + outputs[HOLD_OUTPUT + i].setVoltage(v); + } + } } @@ -45,7 +49,7 @@ struct SH16Widget : TinyTricksModuleWidget { SH16Widget(SH16 *module) { setModule(module); addInput(createInput(mm2px(Vec(8.647f, 12.003f)), module, SH16::TRIG_INPUT)); - + for (int i = 0; i < NUM_CHANNELS_PER_COLUMN; i++) addOutput(createOutput(mm2px(Vec(3.321f, 29.859f + 11.5f * i)), module, SH16::HOLD_OUTPUT + i)); diff --git a/src/shared/shared.cpp b/src/shared/shared.cpp index ec87ec6..5d4dc14 100644 --- a/src/shared/shared.cpp +++ b/src/shared/shared.cpp @@ -1,21 +1,21 @@ struct TinyTricksPortLight : app::SvgPort { TinyTricksPortLight() { - setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/PortLight.svg"))); - } + setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/PortLight.svg"))); + } }; struct TinyTricksPort : app::SvgPort { - TinyTricksPort() { - setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/PortLight.svg"))); - } + TinyTricksPort() { + setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/PortLight.svg"))); + } - void SetDark(bool value){ - if(value){ - setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/PortDark.svg"))); + void SetDark(bool value) { + if (value) { + setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/PortDark.svg"))); } - else{ - setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/PortLight.svg"))); + else { + setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/PortLight.svg"))); } } @@ -26,7 +26,7 @@ struct TinyTricksModule : Module { int APPLIED_SKIN = 0; bool FORCED_BRIGHT = false; - TinyTricksModule(){ + TinyTricksModule() { } json_t *dataToJson() override { @@ -37,15 +37,17 @@ struct TinyTricksModule : Module { } void dataFromJson(json_t *rootJ) override { - json_t *skinJ = json_object_get(rootJ, "skin"); - if (skinJ) APPLIED_SKIN = (int)json_integer_value(skinJ); + json_t *skinJ = json_object_get(rootJ, "skin"); + if (skinJ) + APPLIED_SKIN = (int)json_integer_value(skinJ); json_t *forcebrightJ = json_object_get(rootJ, "forcebright"); - if (forcebrightJ) FORCED_BRIGHT = json_is_true(forcebrightJ); + if (forcebrightJ) + FORCED_BRIGHT = json_is_true(forcebrightJ); } - void AppendBaseJson(json_t *rootJ){ + void AppendBaseJson(json_t *rootJ) { json_t *base = TinyTricksModule::dataToJson(); /* obj is a JSON object */ @@ -53,12 +55,12 @@ struct TinyTricksModule : Module { json_t *value; json_object_foreach(base, key, value) { - json_object_set_new(rootJ,key,value); + json_object_set_new(rootJ, key, value); } } }; -struct TinyTricksModuleWidget : ModuleWidget{ +struct TinyTricksModuleWidget : ModuleWidget { static const int SKIN_COUNT = 6; std::string SKIN_NAMES[SKIN_COUNT] = {"Light (Default)", "River bed", "Shark", "Oxford Blue", "Cod gray", "Firefly"}; @@ -66,22 +68,22 @@ struct TinyTricksModuleWidget : ModuleWidget{ std::string SKIN_SVG = ""; - Widget* topSilver; - Widget* bottomSilver; + Widget *topSilver; + Widget *bottomSilver; - Widget* topBlack; - Widget* bottomBlack; + Widget *topBlack; + Widget *bottomBlack; int currentSkin; bool forceUseLightPorts = false; - TinyTricksModuleWidget(){ + TinyTricksModuleWidget() { } - void InitializeSkin(std::string svgName){ + void InitializeSkin(std::string svgName) { SKIN_SVG = svgName; //std::cout << "svg: " << SKIN_SVG << std::endl; @@ -104,47 +106,47 @@ struct TinyTricksModuleWidget : ModuleWidget{ updateScrewsAndPorts(); } - void setSkin(int skinId){ + void setSkin(int skinId) { currentSkin = skinId; - if(module) - dynamic_cast(module)->APPLIED_SKIN = skinId; + if (module) + dynamic_cast(module)->APPLIED_SKIN = skinId; //std::cout << "path: " << "res/" + SKIN_FOLDERS[skinId] + "/"+SKIN_SVG << std::endl; - setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/" + SKIN_FOLDERS[skinId] + "/"+SKIN_SVG))); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/" + SKIN_FOLDERS[skinId] + "/" + SKIN_SVG))); } - void updateScrewsAndPorts(){ + void updateScrewsAndPorts() { topSilver->visible = (currentSkin == 0); bottomSilver->visible = (currentSkin == 0); topBlack->visible = (currentSkin != 0); bottomBlack->visible = (currentSkin != 0); - if(forceUseLightPorts) + if (forceUseLightPorts) updatePorts(false); else updatePorts(currentSkin != 0); } - void updatePorts(bool useDark){ + void updatePorts(bool useDark) { - if(module) - dynamic_cast(module)->FORCED_BRIGHT = forceUseLightPorts; + if (module) + dynamic_cast(module)->FORCED_BRIGHT = forceUseLightPorts; - std::list::iterator it; - for (it = children.begin(); it != children.end(); ++it){ - TinyTricksPort* port = dynamic_cast((*it)); - if(port != nullptr) + std::list::iterator it; + for (it = children.begin(); it != children.end(); ++it) { + TinyTricksPort *port = dynamic_cast((*it)); + if (port != nullptr) port->SetDark(useDark); } } bool updatedFromModule = false; - void step() override{ - if(!updatedFromModule && module){ - TinyTricksModule* castModule = dynamic_cast(module); - if(castModule != nullptr){ + void step() override { + if (!updatedFromModule && module) { + TinyTricksModule *castModule = dynamic_cast(module); + if (castModule != nullptr) { updatedFromModule = true; forceUseLightPorts = castModule->FORCED_BRIGHT; setSkin(castModule->APPLIED_SKIN); @@ -154,21 +156,21 @@ struct TinyTricksModuleWidget : ModuleWidget{ ModuleWidget::step(); } - void appendContextMenu(Menu* menu) override { + void appendContextMenu(Menu *menu) override { menu->addChild(new MenuEntry); menu->addChild(createMenuLabel("Theme")); struct ModeItem : MenuItem { - TinyTricksModuleWidget* widget; + TinyTricksModuleWidget *widget; int skin; - void onAction(const event::Action& e) override { + void onAction(const event::Action &e) override { widget->setSkin(skin); widget->updateScrewsAndPorts(); } }; for (int i = 0; i < SKIN_COUNT; i++) { - ModeItem* modeItem = createMenuItem(SKIN_NAMES[i]); + ModeItem *modeItem = createMenuItem(SKIN_NAMES[i]); modeItem->rightText = CHECKMARK(currentSkin == i); modeItem->widget = this; modeItem->skin = i; @@ -176,15 +178,15 @@ struct TinyTricksModuleWidget : ModuleWidget{ } struct PortItem : MenuItem { - TinyTricksModuleWidget* widget; + TinyTricksModuleWidget *widget; int skin; - void onAction(const event::Action& e) override { + void onAction(const event::Action &e) override { widget->forceUseLightPorts = !widget->forceUseLightPorts; widget->updateScrewsAndPorts(); } }; - PortItem* portItem = createMenuItem("- Use light theme for input ports"); + PortItem *portItem = createMenuItem("- Use light theme for input ports"); portItem->rightText = CHECKMARK(forceUseLightPorts == true); portItem->widget = this; menu->addChild(portItem); diff --git a/src/simple-oscillators.cpp b/src/simple-oscillators.cpp index 9df1dc6..8ad55c8 100644 --- a/src/simple-oscillators.cpp +++ b/src/simple-oscillators.cpp @@ -5,27 +5,27 @@ #define POLY_SIZE 16 struct TTOBase : TinyTricksModule { - enum ParamIds { - FREQ_PARAM, + enum ParamIds { + FREQ_PARAM, FREQ_FINE_PARAM, THETA_PARAM, - NUM_PARAMS - }; - enum InputIds { - FREQ_CV_INPUT, + NUM_PARAMS + }; + enum InputIds { + FREQ_CV_INPUT, FREQ_FINE_CV_INPUT, THETA_CV_INPUT, SYNC_INPUT, - NUM_INPUTS - }; - enum OutputIds { - OSC_OUTPUT, + NUM_INPUTS + }; + enum OutputIds { + OSC_OUTPUT, SYNC_OUTPUT, - NUM_OUTPUTS - }; - enum LightIds { - NUM_LIGHTS - }; + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; TinyOscillator oscillator[POLY_SIZE]; TinyOscillator::OscillatorType oscType; @@ -33,101 +33,105 @@ struct TTOBase : TinyTricksModule { float prevTheta[POLY_SIZE]; dsp::SchmittTrigger syncTrigger[POLY_SIZE]; - void Initialize(){ + void Initialize() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(TTOBase::FREQ_PARAM, -3.0f, 3.0f, 0.0f, "Tuning"); configParam(TTOBase::FREQ_FINE_PARAM, -0.5f, 0.5f, 0.0f, "Fine tuning"); configParam(TTOBase::THETA_PARAM, 0.0001f, 0.1f, 0.01f, "Theta (smoothness)"); - - for( auto i=0; i(mm2px(Vec(3.567f,22.402f)), module, TTOBase::FREQ_CV_INPUT)); + addInput(createInput(mm2px(Vec(3.567f, 22.402f)), module, TTOBase::FREQ_CV_INPUT)); - addParam(createParam(mm2px(Vec(2.62f,11.05f)), module, TTOBase::FREQ_PARAM)); - addParam(createParam(mm2px(Vec(3.62f,35.626f)), module, TTOBase::FREQ_FINE_PARAM)); - addInput(createInput(mm2px(Vec(3.567f,44.86f)), module, TTOBase::FREQ_FINE_CV_INPUT)); + addParam(createParam(mm2px(Vec(2.62f, 11.05f)), module, TTOBase::FREQ_PARAM)); + addParam(createParam(mm2px(Vec(3.62f, 35.626f)), module, TTOBase::FREQ_FINE_PARAM)); + addInput(createInput(mm2px(Vec(3.567f, 44.86f)), module, TTOBase::FREQ_FINE_CV_INPUT)); - addInput(createInput(mm2px(Vec(3.567f,84.325f)), module, TTOBase::SYNC_INPUT)); - addOutput(createOutput(mm2px(Vec(3.567f,99.804f)), module, TTOBase::SYNC_OUTPUT)); + addInput(createInput(mm2px(Vec(3.567f, 84.325f)), module, TTOBase::SYNC_INPUT)); + addOutput(createOutput(mm2px(Vec(3.567f, 99.804f)), module, TTOBase::SYNC_OUTPUT)); - addOutput(createOutput(mm2px(Vec(3.567f,113.016f)), module, TTOBase::OSC_OUTPUT)); + addOutput(createOutput(mm2px(Vec(3.567f, 113.016f)), module, TTOBase::OSC_OUTPUT)); - } + } }; // Sine -------------------------------------------------------------------------------------------------------------- -struct TTOSin : TTOBase{ - TTOSin():TTOBase(TinyOscillator::OscillatorType::SIN){ +struct TTOSin : TTOBase { + TTOSin(): TTOBase(TinyOscillator::OscillatorType::SIN) { } }; struct TTOSinWidget : TTOBaseWidget { - TTOSinWidget(TTOBase *module) : TTOBaseWidget(module) { - InitializeSkin("TTSIN.svg"); - } + TTOSinWidget(TTOBase *module) : TTOBaseWidget(module) { + InitializeSkin("TTSIN.svg"); + } }; Model *modelTTSIN = createModel("TTSIN"); // Saw -------------------------------------------------------------------------------------------------------------- -struct TTOSaw : TTOBase{ - TTOSaw():TTOBase(TinyOscillator::OscillatorType::SAW){ +struct TTOSaw : TTOBase { + TTOSaw(): TTOBase(TinyOscillator::OscillatorType::SAW) { } }; struct TTOSawWidget : TTOBaseWidget { - TTOSawWidget(TTOBase *module) : TTOBaseWidget(module) { - addParam(createParam(mm2px(Vec(3.62f,61.225f)), module, TTOBase::THETA_PARAM)); - addInput(createInput(mm2px(Vec(3.567f,70.476f)), module, TTOBase::THETA_CV_INPUT)); - InitializeSkin("TTSAW.svg"); - } + TTOSawWidget(TTOBase *module) : TTOBaseWidget(module) { + addParam(createParam(mm2px(Vec(3.62f, 61.225f)), module, TTOBase::THETA_PARAM)); + addInput(createInput(mm2px(Vec(3.567f, 70.476f)), module, TTOBase::THETA_CV_INPUT)); + InitializeSkin("TTSAW.svg"); + } }; Model *modelTTSAW = createModel("TTSAW"); // Square -------------------------------------------------------------------------------------------------------------- -struct TTOSqr : TTOBase{ - TTOSqr():TTOBase(TinyOscillator::OscillatorType::SQR){ +struct TTOSqr : TTOBase { + TTOSqr(): TTOBase(TinyOscillator::OscillatorType::SQR) { } }; struct TTOSqrWidget : TTOBaseWidget { - TTOSqrWidget(TTOBase *module) : TTOBaseWidget(module) { - addParam(createParam(mm2px(Vec(3.62f,61.225f)), module, TTOBase::THETA_PARAM)); - addInput(createInput(mm2px(Vec(3.567f,70.476f)), module, TTOBase::THETA_CV_INPUT)); - InitializeSkin("TTSQR.svg"); - } + TTOSqrWidget(TTOBase *module) : TTOBaseWidget(module) { + addParam(createParam(mm2px(Vec(3.62f, 61.225f)), module, TTOBase::THETA_PARAM)); + addInput(createInput(mm2px(Vec(3.567f, 70.476f)), module, TTOBase::THETA_CV_INPUT)); + InitializeSkin("TTSQR.svg"); + } }; Model *modelTTSQR = createModel("TTSQR"); // Square -------------------------------------------------------------------------------------------------------------- -struct TTOTri : TTOBase{ - TTOTri():TTOBase(TinyOscillator::OscillatorType::TRI){ +struct TTOTri : TTOBase { + TTOTri(): TTOBase(TinyOscillator::OscillatorType::TRI) { } }; struct TTOTriWidget : TTOBaseWidget { - TTOTriWidget(TTOBase *module) : TTOBaseWidget(module) { - addParam(createParam(mm2px(Vec(3.62f,61.225f)), module, TTOBase::THETA_PARAM)); - addInput(createInput(mm2px(Vec(3.567f,70.476f)), module, TTOBase::THETA_CV_INPUT)); - InitializeSkin("TTTRI.svg"); - } + TTOTriWidget(TTOBase *module) : TTOBaseWidget(module) { + addParam(createParam(mm2px(Vec(3.62f, 61.225f)), module, TTOBase::THETA_PARAM)); + addInput(createInput(mm2px(Vec(3.567f, 70.476f)), module, TTOBase::THETA_CV_INPUT)); + InitializeSkin("TTTRI.svg"); + } }; Model *modelTTTRI = createModel("TTTRI"); diff --git a/src/simplex-noise-lfo.cpp b/src/simplex-noise-lfo.cpp index 0c642c5..0e0aeab 100644 --- a/src/simplex-noise-lfo.cpp +++ b/src/simplex-noise-lfo.cpp @@ -33,13 +33,18 @@ struct SNBase : TinyTricksModule { int numChannels = 1; SimplexNoise simp; - void initialize(){ - simp.init(); - - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - configParam(SPEED_PARAM, SPEED_MIN, SPEED_MAX, 0.5f, "Speed of change"); - configParam(JITTER_PARAM, JITTER_MIN, JITTER_MAX, JITTER_MIN, "jitter of change"); - configParam(PINNING_PARAM, 1.f, 10.f, 1.5f, "Amount to pin at top og bottom of curve"); + void initialize() { + simp.init(); + + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configParam(SPEED_PARAM, SPEED_MIN, SPEED_MAX, 0.5f, "Speed of change"); + configParam(JITTER_PARAM, JITTER_MIN, JITTER_MAX, JITTER_MIN, "Jitter of change"); + configParam(PINNING_PARAM, 1.f, 10.f, 1.5f, "Amount to pin at top of bottom of curve"); + configInput(SPEED_CV_INPUT, "Speed CV"); + configInput(JITTER_CV_INPUT, "Jitter CV"); + for (int i = 0; i < numChannels; i++) { + configOutput(SIMPLEX_OUTPUT + i, rack::string::f("Noise %d", i + 1)); + } } @@ -59,18 +64,18 @@ struct SNBase : TinyTricksModule { void process(const ProcessArgs &args) override { float delta = 1.0f / args.sampleRate; - if(!reverse){ - t += delta; - if (t >= 128.f) - reverse = true; - } - else{ - t -= delta; - if(t < 0){ - reverse = false; - t = -t; - } - } + if (!reverse) { + t += delta; + if (t >= 128.f) + reverse = true; + } + else { + t -= delta; + if (t < 0) { + reverse = false; + t = -t; + } + } //Getting pinning @@ -78,29 +83,29 @@ struct SNBase : TinyTricksModule { //Getting the speed float speed = params[SPEED_PARAM].getValue(); - if(inputs[SPEED_CV_INPUT].isConnected()){ + if (inputs[SPEED_CV_INPUT].isConnected()) { float speedCV = inputs[SPEED_CV_INPUT].getVoltage(); speedCV /= 10.f; - speed = clamp(speed+speedCV,SPEED_MIN,SPEED_MAX); + speed = clamp(speed + speedCV, SPEED_MIN, SPEED_MAX); } //Getting jitter float jitter = params[JITTER_PARAM].getValue(); - if(inputs[JITTER_CV_INPUT].isConnected()){ + if (inputs[JITTER_CV_INPUT].isConnected()) { float jitterCV = inputs[JITTER_CV_INPUT].getVoltage(); jitterCV = rescale(jitterCV, -5.f, 5.f, 0.f, 10.f); jitterCV /= 2.f; - jitter = clamp(jitter + jitterCV,JITTER_MIN,JITTER_MAX); + jitter = clamp(jitter + jitterCV, JITTER_MIN, JITTER_MAX); } //Getting new levels float x = t; for (int i = 0; i < numChannels; i++) { - if(outputs[SIMPLEX_OUTPUT + i].isConnected()){ - float y = (2.f*i); - float noiseVal = simp.SumOctaveSmooth(jitter,x,y,0.7f,speed); - float level = clamp(noiseVal*(pinning),-1.f,1.f); - outputs[SIMPLEX_OUTPUT + i].setVoltage(level*5.f); + if (outputs[SIMPLEX_OUTPUT + i].isConnected()) { + float y = (2.f * i); + float noiseVal = simp.SumOctaveSmooth(jitter, x, y, 0.7f, speed); + float level = clamp(noiseVal * (pinning), -1.f, 1.f); + outputs[SIMPLEX_OUTPUT + i].setVoltage(level * 5.f); } } } @@ -111,26 +116,26 @@ struct SNBaseWidget : TinyTricksModuleWidget { SNBaseWidget(SNBase *module) { setModule(module); - addParam(createParam(mm2px(Vec(2.62f,11.051f)), module, SNBase::SPEED_PARAM)); + addParam(createParam(mm2px(Vec(2.62f, 11.051f)), module, SNBase::SPEED_PARAM)); addInput(createInput(mm2px(Vec(3.567f, 22.366f)), module, SNBase::SPEED_CV_INPUT)); - addParam(createParam(mm2px(Vec(2.62f,38.613f)), module, SNBase::JITTER_PARAM)); + addParam(createParam(mm2px(Vec(2.62f, 38.613f)), module, SNBase::JITTER_PARAM)); addInput(createInput(mm2px(Vec(3.567f, 49.96f)), module, SNBase::JITTER_CV_INPUT)); - addParam(createParam(mm2px(Vec(2.62f,67.478f)), module, SNBase::PINNING_PARAM)); + addParam(createParam(mm2px(Vec(2.62f, 67.478f)), module, SNBase::PINNING_PARAM)); } }; // 1x -------------------------------------------------------------------------------------------------------------- -struct SN1 : SNBase{ - SN1():SNBase(1){ +struct SN1 : SNBase { + SN1(): SNBase(1) { } }; struct SN1Widget : SNBaseWidget { - SN1Widget(SNBase *module) : SNBaseWidget(module) { - addOutput(createOutput(mm2px(Vec(3.523f,113.403f)), module, SNBase::SIMPLEX_OUTPUT+0)); + SN1Widget(SNBase *module) : SNBaseWidget(module) { + addOutput(createOutput(mm2px(Vec(3.523f, 113.403f)), module, SNBase::SIMPLEX_OUTPUT + 0)); InitializeSkin("SN1.svg"); } }; @@ -139,15 +144,15 @@ Model *modelSN1 = createModel("SN1"); // 8x -------------------------------------------------------------------------------------------------------------- const int X8_CHANNELS = 8; -struct SN8 : SNBase{ - SN8():SNBase(X8_CHANNELS){ +struct SN8 : SNBase { + SN8(): SNBase(X8_CHANNELS) { } }; struct SN8Widget : SNBaseWidget { - SN8Widget(SNBase *module) : SNBaseWidget(module) { - for(int i = 0; i < X8_CHANNELS; i++){ - addOutput(createOutput(mm2px(Vec(18.501f,12.003f + (i*14.f))), module, SNBase::SIMPLEX_OUTPUT + i)); + SN8Widget(SNBase *module) : SNBaseWidget(module) { + for (int i = 0; i < X8_CHANNELS; i++) { + addOutput(createOutput(mm2px(Vec(18.501f, 12.003f + (i * 14.f))), module, SNBase::SIMPLEX_OUTPUT + i)); } InitializeSkin("SN8.svg"); } diff --git a/src/simplex-oscillator.cpp b/src/simplex-oscillator.cpp index 4c5dd6e..a77ec2b 100644 --- a/src/simplex-oscillator.cpp +++ b/src/simplex-oscillator.cpp @@ -12,90 +12,99 @@ const float DETAIL_MIN = 1.f; const float DETAIL_MAX = 8.f; struct SNOSC : TinyTricksModule { - enum ParamIds { + enum ParamIds { SCALE_PARAM, DETAIL_PARAM, - FREQ_PARAM, - FREQ_FINE_PARAM, + FREQ_PARAM, + FREQ_FINE_PARAM, X_PARAM, Y_PARAM, - MIRROR_PARAM, - NUM_PARAMS - }; - enum InputIds { - FREQ_CV_INPUT, + MIRROR_PARAM, + NUM_PARAMS + }; + enum InputIds { + FREQ_CV_INPUT, FREQ_FINE_CV_INPUT, SYNC_INPUT, - X_CV_INPUT, + X_CV_INPUT, Y_CV_INPUT, - SCALE_CV_INPUT, + SCALE_CV_INPUT, DETAIL_CV_INPUT, - MIRROR_TRIGGER_INPUT, - NUM_INPUTS - }; - enum OutputIds { - OSC_OUTPUT, - SYNC_OUTPUT, - NUM_OUTPUTS - }; - enum LightIds { - MIRROR_LIGHT, - NUM_LIGHTS - }; - - - MiniScope* scope; - - SimplexOscillator oscillator[POLY_SIZE]; - float prevPitch[POLY_SIZE]; - dsp::SchmittTrigger syncTrigger[POLY_SIZE]; - dsp::SchmittTrigger mirrorButtonTrigger; - bool mirror = false; - - void Initialize(){ + MIRROR_TRIGGER_INPUT, + NUM_INPUTS + }; + enum OutputIds { + OSC_OUTPUT, + SYNC_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + MIRROR_LIGHT, + NUM_LIGHTS + }; + + + MiniScope *scope; + + SimplexOscillator oscillator[POLY_SIZE]; + float prevPitch[POLY_SIZE]; + dsp::SchmittTrigger syncTrigger[POLY_SIZE]; + dsp::SchmittTrigger mirrorButtonTrigger; + bool mirror = false; + + void Initialize() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(SNOSC::SCALE_PARAM, SCALE_MIN, SCALE_MAX, 2.5f, "Scale"); configParam(SNOSC::DETAIL_PARAM, DETAIL_MIN, DETAIL_MAX, DETAIL_MIN, "Level of detail"); configParam(SNOSC::X_PARAM, 0.f, 5.f, 2.5f, "X modulation"); configParam(SNOSC::Y_PARAM, 0.f, 5.f, 2.5f, "Y modulation"); - configParam(SNOSC::FREQ_PARAM, -3.0f, 3.0f, 0.0f, "Tuning"); + configParam(SNOSC::FREQ_PARAM, -3.0f, 3.0f, 0.0f, "Tuning"); configParam(SNOSC::FREQ_FINE_PARAM, -0.5f, 0.5f, 0.0f, "Fine tuning"); - configParam(SNOSC::MIRROR_PARAM, 0.f, 1.f, 0.f, "Mirror waveform"); - - for( auto i=0; i= 11.f && c==0){ + if (voltage >= 11.f && c == 0) { scope->reset(); ticksSinceScopeReset = 0; } } } - else{ - if(c==0) - ticksSinceScopeReset = 0; + else { + if (c == 0) + ticksSinceScopeReset = 0; } //Stepping @@ -183,24 +191,24 @@ struct SNOSC : TinyTricksModule { //Setting output outputs[OSC_OUTPUT].setVoltage(value, c); - if(c == 0) //Updating scope. To Consider - polyphonic scope? + if (c == 0) //Updating scope. To Consider - polyphonic scope? scope->addFrame(value); //TODO: Clean up this logic. It's not pretty. - if(forwardSyncReset){ + if (forwardSyncReset) { outputs[SYNC_OUTPUT].setVoltage(11.f, c); } - else if(oscillator[c].isEOC()){ - if(!inputs[SYNC_INPUT].isConnected()) + else if (oscillator[c].isEOC()) { + if (!inputs[SYNC_INPUT].isConnected()) outputs[SYNC_OUTPUT].setVoltage(11.f, c); else outputs[SYNC_OUTPUT].setVoltage(10.f, c); // Normally we'll reset the scope on EOC, // but not if sync is connected - unless it's been too long since last sync - if(c==0 && (!inputs[SYNC_INPUT].isConnected() || ticksSinceScopeReset > SimplexOscillator::BUFFER_LENGTH)) + if (c == 0 && (!inputs[SYNC_INPUT].isConnected() || ticksSinceScopeReset > SimplexOscillator::BUFFER_LENGTH)) scope->reset(); } - else{ + else { outputs[SYNC_OUTPUT].setVoltage(0.f, c); } } @@ -209,63 +217,63 @@ struct SNOSC : TinyTricksModule { struct SNOSCWidget : TinyTricksModuleWidget { - //void appendContextMenu(Menu *menu) override; - - SNOSCWidget(SNOSC *module) { - setModule(module); - - if(module){ - MiniScope *scope = new MiniScope(); - scope->box.pos = mm2px(Vec(3.571f, 9.0f)); - scope->box.size = mm2px(Vec(23.337f, 10.366f)); - scope->setGain(1.0f); - addChild(scope); - module->scope = scope; - } - else{ - SvgWidget* placeholder = createWidget(mm2px(Vec(3.571f, 11.0f))); - placeholder->setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/Wave.svg"))); - addChild(placeholder); - } - - //Mirror buttons - addParam(createParam(mm2px(Vec(12.065f,25.062f)), module, SNOSC::MIRROR_PARAM)); - addChild(createLight>(mm2px(Vec(12.065f+0.45f,25.062f+0.45f)), module, SNOSC::MIRROR_LIGHT)); - addInput(createInput(mm2px(Vec(20.759f,24.184f)), module, SNOSC::MIRROR_TRIGGER_INPUT)); - - //Freq - addParam(createParam(mm2px(Vec(11.24f,34.816f)), module, SNOSC::FREQ_PARAM)); - addInput(createInput(mm2px(Vec(20.759f,34.763f)), module, SNOSC::FREQ_CV_INPUT)); - - //Fine - addParam(createParam(mm2px(Vec(11.24f,45.395f)), module, SNOSC::FREQ_FINE_PARAM)); - addInput(createInput(mm2px(Vec(20.759f,45.342f)), module, SNOSC::FREQ_FINE_CV_INPUT)); - - //X - addParam(createParam(mm2px(Vec(11.24f,55.975f)), module, SNOSC::X_PARAM)); - addInput(createInput(mm2px(Vec(20.759f,55.922f)), module, SNOSC::X_CV_INPUT)); - - //Y - addParam(createParam(mm2px(Vec(11.24f,66.554f)), module, SNOSC::Y_PARAM)); - addInput(createInput(mm2px(Vec(20.759f,66.501f)), module, SNOSC::Y_CV_INPUT)); - - //Scale - addParam(createParam(mm2px(Vec(11.24f,77.133f)), module, SNOSC::SCALE_PARAM)); - addInput(createInput(mm2px(Vec(20.759f,77.08f)), module, SNOSC::SCALE_CV_INPUT)); - - //Detail - addParam(createParam(mm2px(Vec(11.24f,87.712f)), module, SNOSC::DETAIL_PARAM)); - addInput(createInput(mm2px(Vec(20.759f,87.659f)), module, SNOSC::DETAIL_CV_INPUT)); - - //Sync - addInput(createInput(mm2px(Vec(11.143f,98.238f)), module, SNOSC::SYNC_INPUT)); - - addOutput(createOutput(mm2px(Vec(4.617f,113.358f)), module, SNOSC::SYNC_OUTPUT)); - - addOutput(createOutput(mm2px(Vec(17.669f,113.358f)), module, SNOSC::OSC_OUTPUT)); - - InitializeSkin("SNOSC.svg"); - } + //void appendContextMenu(Menu *menu) override; + + SNOSCWidget(SNOSC *module) { + setModule(module); + + if (module) { + MiniScope *scope = new MiniScope(); + scope->box.pos = mm2px(Vec(3.571f, 9.0f)); + scope->box.size = mm2px(Vec(23.337f, 10.366f)); + scope->setGain(1.0f); + addChild(scope); + module->scope = scope; + } + else { + SvgWidget *placeholder = createWidget(mm2px(Vec(3.571f, 11.0f))); + placeholder->setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/Wave.svg"))); + addChild(placeholder); + } + + //Mirror buttons + addParam(createParam(mm2px(Vec(12.065f, 25.062f)), module, SNOSC::MIRROR_PARAM)); + addChild(createLight>(mm2px(Vec(12.065f + 0.45f, 25.062f + 0.45f)), module, SNOSC::MIRROR_LIGHT)); + addInput(createInput(mm2px(Vec(20.759f, 24.184f)), module, SNOSC::MIRROR_TRIGGER_INPUT)); + + //Freq + addParam(createParam(mm2px(Vec(11.24f, 34.816f)), module, SNOSC::FREQ_PARAM)); + addInput(createInput(mm2px(Vec(20.759f, 34.763f)), module, SNOSC::FREQ_CV_INPUT)); + + //Fine + addParam(createParam(mm2px(Vec(11.24f, 45.395f)), module, SNOSC::FREQ_FINE_PARAM)); + addInput(createInput(mm2px(Vec(20.759f, 45.342f)), module, SNOSC::FREQ_FINE_CV_INPUT)); + + //X + addParam(createParam(mm2px(Vec(11.24f, 55.975f)), module, SNOSC::X_PARAM)); + addInput(createInput(mm2px(Vec(20.759f, 55.922f)), module, SNOSC::X_CV_INPUT)); + + //Y + addParam(createParam(mm2px(Vec(11.24f, 66.554f)), module, SNOSC::Y_PARAM)); + addInput(createInput(mm2px(Vec(20.759f, 66.501f)), module, SNOSC::Y_CV_INPUT)); + + //Scale + addParam(createParam(mm2px(Vec(11.24f, 77.133f)), module, SNOSC::SCALE_PARAM)); + addInput(createInput(mm2px(Vec(20.759f, 77.08f)), module, SNOSC::SCALE_CV_INPUT)); + + //Detail + addParam(createParam(mm2px(Vec(11.24f, 87.712f)), module, SNOSC::DETAIL_PARAM)); + addInput(createInput(mm2px(Vec(20.759f, 87.659f)), module, SNOSC::DETAIL_CV_INPUT)); + + //Sync + addInput(createInput(mm2px(Vec(11.143f, 98.238f)), module, SNOSC::SYNC_INPUT)); + + addOutput(createOutput(mm2px(Vec(4.617f, 113.358f)), module, SNOSC::SYNC_OUTPUT)); + + addOutput(createOutput(mm2px(Vec(17.669f, 113.358f)), module, SNOSC::OSC_OUTPUT)); + + InitializeSkin("SNOSC.svg"); + } }; diff --git a/src/utility/PerlinNoise.cpp b/src/utility/PerlinNoise.cpp index 3874216..cf2f4db 100644 --- a/src/utility/PerlinNoise.cpp +++ b/src/utility/PerlinNoise.cpp @@ -13,82 +13,83 @@ // Initialize with the reference values for the permutation vector PerlinNoise::PerlinNoise() { - // Initialize the permutation vector with the reference values - p = { - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, - 8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, - 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71, - 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, - 55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89, - 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226, - 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, - 189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, - 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246, - 97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239, - 107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; - // Duplicate the permutation vector - p.insert(p.end(), p.begin(), p.end()); + // Initialize the permutation vector with the reference values + p = { + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, + 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, + 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, + 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, + 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, + 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, + 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, + 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, + 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, + 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, + 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 + }; + // Duplicate the permutation vector + p.insert(p.end(), p.begin(), p.end()); } // Generate a new permutation vector based on the value of seed PerlinNoise::PerlinNoise(unsigned int seed) { - p.resize(256); + p.resize(256); - // Fill p with values from 0 to 255 - std::iota(p.begin(), p.end(), 0); + // Fill p with values from 0 to 255 + std::iota(p.begin(), p.end(), 0); - // Initialize a random engine with seed - std::default_random_engine engine(seed); + // Initialize a random engine with seed + std::default_random_engine engine(seed); - // Suffle using the above random engine - std::shuffle(p.begin(), p.end(), engine); + // Suffle using the above random engine + std::shuffle(p.begin(), p.end(), engine); - // Duplicate the permutation vector - p.insert(p.end(), p.begin(), p.end()); + // Duplicate the permutation vector + p.insert(p.end(), p.begin(), p.end()); } double PerlinNoise::noise(double x, double y, double z) { - // Find the unit cube that contains the point - int X = (int) floor(x) & 255; - int Y = (int) floor(y) & 255; - int Z = (int) floor(z) & 255; - - // Find relative x, y,z of point in cube - x -= floor(x); - y -= floor(y); - z -= floor(z); - - // Compute fade curves for each of x, y, z - double u = fade(x); - double v = fade(y); - double w = fade(z); - - // Hash coordinates of the 8 cube corners - int A = p[X] + Y; - int AA = p[A] + Z; - int AB = p[A + 1] + Z; - int B = p[X + 1] + Y; - int BA = p[B] + Z; - int BB = p[B + 1] + Z; - - // Add blended results from 8 corners of cube - double res = lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x-1, y, z)), lerp(u, grad(p[AB], x, y-1, z), grad(p[BB], x-1, y-1, z))), lerp(v, lerp(u, grad(p[AA+1], x, y, z-1), grad(p[BA+1], x-1, y, z-1)), lerp(u, grad(p[AB+1], x, y-1, z-1), grad(p[BB+1], x-1, y-1, z-1)))); - return (res + 1.0)/2.0; + // Find the unit cube that contains the point + int X = (int) floor(x) & 255; + int Y = (int) floor(y) & 255; + int Z = (int) floor(z) & 255; + + // Find relative x, y,z of point in cube + x -= floor(x); + y -= floor(y); + z -= floor(z); + + // Compute fade curves for each of x, y, z + double u = fade(x); + double v = fade(y); + double w = fade(z); + + // Hash coordinates of the 8 cube corners + int A = p[X] + Y; + int AA = p[A] + Z; + int AB = p[A + 1] + Z; + int B = p[X + 1] + Y; + int BA = p[B] + Z; + int BB = p[B + 1] + Z; + + // Add blended results from 8 corners of cube + double res = lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)), lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z))), lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)), lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); + return (res + 1.0) / 2.0; } double PerlinNoise::fade(double t) { - return t * t * t * (t * (t * 6 - 15) + 10); + return t * t * t * (t * (t * 6 - 15) + 10); } double PerlinNoise::lerp(double t, double a, double b) { - return a + t * (b - a); + return a + t * (b - a); } double PerlinNoise::grad(int hash, double x, double y, double z) { - int h = hash & 15; - // Convert lower 4 bits of hash into 12 gradient directions - double u = h < 8 ? x : y, - v = h < 4 ? y : h == 12 || h == 14 ? x : z; - return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); + int h = hash & 15; + // Convert lower 4 bits of hash into 12 gradient directions + double u = h < 8 ? x : y, + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); } diff --git a/src/utility/PerlinNoise.hpp b/src/utility/PerlinNoise.hpp index 9ef109b..891f5da 100644 --- a/src/utility/PerlinNoise.hpp +++ b/src/utility/PerlinNoise.hpp @@ -10,19 +10,19 @@ #define PERLINNOISE_H class PerlinNoise { - // The permutation vector - std::vector p; -public: - // Initialize with the reference values for the permutation vector - PerlinNoise(); - // Generate a new permutation vector based on the value of seed - PerlinNoise(unsigned int seed); - // Get a noise value, for 2D images z can have any value - double noise(double x, double y, double z); -private: - double fade(double t); - double lerp(double t, double a, double b); - double grad(int hash, double x, double y, double z); + // The permutation vector + std::vector p; + public: + // Initialize with the reference values for the permutation vector + PerlinNoise(); + // Generate a new permutation vector based on the value of seed + PerlinNoise(unsigned int seed); + // Get a noise value, for 2D images z can have any value + double noise(double x, double y, double z); + private: + double fade(double t); + double lerp(double t, double a, double b); + double grad(int hash, double x, double y, double z); }; #endif diff --git a/src/utility/Ramer-Douglas-Peucker.cpp b/src/utility/Ramer-Douglas-Peucker.cpp index b438508..681cfa8 100644 --- a/src/utility/Ramer-Douglas-Peucker.cpp +++ b/src/utility/Ramer-Douglas-Peucker.cpp @@ -8,69 +8,69 @@ using namespace std; //Source: https://rosettacode.org/wiki/Ramer-Douglas-Peucker_line_simplification#C.2B.2B typedef std::pair Point; -static double PerpendicularDistance(const Point &pt, const Point &lineStart, const Point &lineEnd){ - double dx = lineEnd.first - lineStart.first; - double dy = lineEnd.second - lineStart.second; +static double PerpendicularDistance(const Point &pt, const Point &lineStart, const Point &lineEnd) { + double dx = lineEnd.first - lineStart.first; + double dy = lineEnd.second - lineStart.second; - //Normalise - double mag = pow(pow(dx,2.0)+pow(dy,2.0),0.5); - if(mag > 0.0){ - dx /= mag; dy /= mag; - } + //Normalise + double mag = pow(pow(dx, 2.0) + pow(dy, 2.0), 0.5); + if (mag > 0.0) { + dx /= mag; dy /= mag; + } - double pvx = pt.first - lineStart.first; - double pvy = pt.second - lineStart.second; + double pvx = pt.first - lineStart.first; + double pvy = pt.second - lineStart.second; - //Get dot product (project pv onto normalized direction) - double pvdot = dx * pvx + dy * pvy; + //Get dot product (project pv onto normalized direction) + double pvdot = dx * pvx + dy * pvy; - //Scale line direction vector - double dsx = pvdot * dx; - double dsy = pvdot * dy; + //Scale line direction vector + double dsx = pvdot * dx; + double dsy = pvdot * dy; - //Subtract this from pv - double ax = pvx - dsx; - double ay = pvy - dsy; + //Subtract this from pv + double ax = pvx - dsx; + double ay = pvy - dsy; - return pow(pow(ax,2.0)+pow(ay,2.0),0.5); + return pow(pow(ax, 2.0) + pow(ay, 2.0), 0.5); } -static void RamerDouglasPeucker(const vector &pointList, double epsilon, vector &out){ - if(pointList.size()<2) - return; //invalid list size +static void RamerDouglasPeucker(const vector &pointList, double epsilon, vector &out) { + if (pointList.size() < 2) + return; //invalid list size - // Find the point with the maximum distance from line between start and end - double dmax = 0.0; - size_t index = 0; - size_t end = pointList.size()-1; - for(size_t i = 1; i < end; i++){ - double d = PerpendicularDistance(pointList[i], pointList[0], pointList[end]); - if (d > dmax){ - index = i; - dmax = d; - } - } + // Find the point with the maximum distance from line between start and end + double dmax = 0.0; + size_t index = 0; + size_t end = pointList.size() - 1; + for (size_t i = 1; i < end; i++) { + double d = PerpendicularDistance(pointList[i], pointList[0], pointList[end]); + if (d > dmax) { + index = i; + dmax = d; + } + } - // If max distance is greater than epsilon, recursively simplify - if(dmax > epsilon){ - // Recursive call - vector recResults1; - vector recResults2; - vector firstLine(pointList.begin(), pointList.begin()+index+1); - vector lastLine(pointList.begin()+index, pointList.end()); - RamerDouglasPeucker(firstLine, epsilon, recResults1); - RamerDouglasPeucker(lastLine, epsilon, recResults2); + // If max distance is greater than epsilon, recursively simplify + if (dmax > epsilon) { + // Recursive call + vector recResults1; + vector recResults2; + vector firstLine(pointList.begin(), pointList.begin() + index + 1); + vector lastLine(pointList.begin() + index, pointList.end()); + RamerDouglasPeucker(firstLine, epsilon, recResults1); + RamerDouglasPeucker(lastLine, epsilon, recResults2); - // Build the result list - out.assign(recResults1.begin(), recResults1.end()-1); - out.insert(out.end(), recResults2.begin(), recResults2.end()); - if(out.size()<2) - return;//throw runtime_error("Problem assembling output"); - } - else { - //Just return start and end points - out.clear(); - out.push_back(pointList[0]); - out.push_back(pointList[end]); - } + // Build the result list + out.assign(recResults1.begin(), recResults1.end() - 1); + out.insert(out.end(), recResults2.begin(), recResults2.end()); + if (out.size() < 2) + return;//throw runtime_error("Problem assembling output"); + } + else { + //Just return start and end points + out.clear(); + out.push_back(pointList[0]); + out.push_back(pointList[end]); + } } diff --git a/src/utility/SimplexNoise.cpp b/src/utility/SimplexNoise.cpp index 4fa546c..4add28c 100644 --- a/src/utility/SimplexNoise.cpp +++ b/src/utility/SimplexNoise.cpp @@ -3,22 +3,22 @@ #include int SimplexNoise::FastFloor(double x) { - int xi = (int)x; - return x < xi ? xi - 1 : xi; + int xi = (int)x; + return x < xi ? xi - 1 : xi; } -float SimplexNoise::SumOctave(int num_iterations, float x, float y, float persistence, float scale){ +float SimplexNoise::SumOctave(int num_iterations, float x, float y, float persistence, float scale) { float maxAmp = 0.f; float amp = 1.f; float freq = scale; float noise = 0.f; - for(int i = 0; i < num_iterations; ++i){ - noise += this->noise(x * freq, y * freq) * amp; - maxAmp += amp; - amp *= persistence; - freq *= 2.f; - } + for (int i = 0; i < num_iterations; ++i) { + noise += this->noise(x * freq, y * freq) * amp; + maxAmp += amp; + amp *= persistence; + freq *= 2.f; + } //take the average value of the iterations noise /= maxAmp; @@ -26,22 +26,22 @@ float SimplexNoise::SumOctave(int num_iterations, float x, float y, float persis return noise; }; -float SimplexNoise::SumOctaveSmooth(float num_iterations_float, float x, float y, float persistence, float scale){ +float SimplexNoise::SumOctaveSmooth(float num_iterations_float, float x, float y, float persistence, float scale) { int num_iterations_int = ceil(num_iterations_float); - num_iterations_int = max(num_iterations_int,1); + num_iterations_int = max(num_iterations_int, 1); float lastLevelPersistence = num_iterations_int == 1 ? 1.f : num_iterations_float - floor(num_iterations_float); float maxAmp = 0.f; float amp = 1.f; float freq = scale; float noise = 0.f; - for(int i = 0; i < num_iterations_int; ++i){ - if(i == num_iterations_int-1){ + for (int i = 0; i < num_iterations_int; ++i) { + if (i == num_iterations_int - 1) { noise += this->noise(x * freq, y * freq) * amp * lastLevelPersistence; maxAmp += amp * lastLevelPersistence; } - else{ + else { noise += this->noise(x * freq, y * freq) * amp; maxAmp += amp; } @@ -58,69 +58,73 @@ float SimplexNoise::SumOctaveSmooth(float num_iterations_float, float x, float y double SimplexNoise::noise(double xin, double yin) { - double n0, n1, n2; // Noise contributions from the three corners - double F2 = 0.5 * (sqrt(3.0) - 1.0); // Skew the input space to determine which simplex cell we're in - double s = (xin + yin) * F2; // Hairy factor for 2D - int i = SimplexNoise::FastFloor(xin + s); - int j = SimplexNoise::FastFloor(yin + s); - double G2 = (3.0 -sqrt(3.0)) / 6.0; - double t = (i + j) * G2; - double X0 = i - t; // Unskew the cell origin back to (x,y) space - double Y0 = j - t; - double x0 = xin - X0; // The x,y distances from the cell origin - double y0 = yin - Y0; - - // For the 2D case, the simplex shape is an equilateral triangle. - // Determine which simplex we are in. - int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords - if (x0 > y0) { - i1 = 1; j1 = 0; // lower triangle, XY order: (0,0)->(1,0)->(1,1) - } else { // upper triangle, YX order: (0,0)->(0,1)->(1,1) - i1 = 0; j1 = 1; - } + double n0, n1, n2; // Noise contributions from the three corners + double F2 = 0.5 * (sqrt(3.0) - 1.0); // Skew the input space to determine which simplex cell we're in + double s = (xin + yin) * F2; // Hairy factor for 2D + int i = SimplexNoise::FastFloor(xin + s); + int j = SimplexNoise::FastFloor(yin + s); + double G2 = (3.0 - sqrt(3.0)) / 6.0; + double t = (i + j) * G2; + double X0 = i - t; // Unskew the cell origin back to (x,y) space + double Y0 = j - t; + double x0 = xin - X0; // The x,y distances from the cell origin + double y0 = yin - Y0; + + // For the 2D case, the simplex shape is an equilateral triangle. + // Determine which simplex we are in. + int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords + if (x0 > y0) { + i1 = 1; j1 = 0; // lower triangle, XY order: (0,0)->(1,0)->(1,1) + } + else { // upper triangle, YX order: (0,0)->(0,1)->(1,1) + i1 = 0; j1 = 1; + } - // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and - // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where - // c = (3-sqrt(3))/6 - double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords - double y1 = y0 - j1 + G2; - double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords - double y2 = y0 - 1.0 + 2.0 * G2; - - // Work out the hashed gradient indices of the three simplex corners - int ii = i & 255; - int jj = j & 255; - int gi0 = this->permMod12[ii + perm[jj]]; - int gi1 = this->permMod12[ii + i1 + this->perm[jj + j1]]; - int gi2 = this->permMod12[ii + 1 + this->perm[jj + 1]]; - - // Calculate the contribution from the three corners - double t0 = 0.5 - x0 * x0 - y0 * y0; - if(t0 < 0) { - n0 = 0.0; - } else { - t0 *= t0; - n0 = t0 * t0 * this->dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient - } - double t1 = 0.5 - x1 * x1 - y1 * y1; - if(t1 < 0) { - n1 = 0.0; - } else { - t1 *= t1; - n1 = t1 * t1 * this->dot(grad3[gi1], x1, y1); - } - double t2 = 0.5 - x2 * x2 - y2 * y2; - if(t2 < 0) { - n2 = 0.0; - } else { - t2 *= t2; - n2 = t2 * t2 * this->dot(grad3[gi2], x2, y2); - } - // Add contributions from each corner to get the final noise value. - // The result is scaled to return values in the interval [-1,1]. - return 70.0 * (n0 + n1 + n2); + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + double y1 = y0 - j1 + G2; + double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords + double y2 = y0 - 1.0 + 2.0 * G2; + + // Work out the hashed gradient indices of the three simplex corners + int ii = i & 255; + int jj = j & 255; + int gi0 = this->permMod12[ii + perm[jj]]; + int gi1 = this->permMod12[ii + i1 + this->perm[jj + j1]]; + int gi2 = this->permMod12[ii + 1 + this->perm[jj + 1]]; + + // Calculate the contribution from the three corners + double t0 = 0.5 - x0 * x0 - y0 * y0; + if (t0 < 0) { + n0 = 0.0; + } + else { + t0 *= t0; + n0 = t0 * t0 * this->dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient + } + double t1 = 0.5 - x1 * x1 - y1 * y1; + if (t1 < 0) { + n1 = 0.0; + } + else { + t1 *= t1; + n1 = t1 * t1 * this->dot(grad3[gi1], x1, y1); + } + double t2 = 0.5 - x2 * x2 - y2 * y2; + if (t2 < 0) { + n2 = 0.0; + } + else { + t2 *= t2; + n2 = t2 * t2 * this->dot(grad3[gi2], x2, y2); + } + // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + return 70.0 * (n0 + n1 + n2); }; double SimplexNoise::dot(int g[3], double x, double y) { - return g[0] * x + g[1] * y; + return g[0] * x + g[1] * y; }; diff --git a/src/utility/SimplexNoise.hpp b/src/utility/SimplexNoise.hpp index 22be456..4bc15ae 100644 --- a/src/utility/SimplexNoise.hpp +++ b/src/utility/SimplexNoise.hpp @@ -15,18 +15,18 @@ using namespace std; class SimplexNoise { int grad3[12][3] = { - {1, 1, 0}, - {-1, 1, 0}, - {1, -1, 0}, - {-1, -1, 0}, - {1, 0, 1}, - {-1, 0, 1}, - {1, 0, -1}, - {-1, 0, -1}, - {0, 1, 1}, - {0, -1, 1}, - {0, 1, -1}, - {0, -1,- 1} + {1, 1, 0}, + {-1, 1, 0}, + {1, -1, 0}, + {-1, -1, 0}, + {1, 0, 1}, + {-1, 0, 1}, + {1, 0, -1}, + {-1, 0, -1}, + {0, 1, 1}, + {0, -1, 1}, + {0, 1, -1}, + {0, -1, - 1} }; int p[256]; @@ -34,26 +34,26 @@ class SimplexNoise { int permMod12[512]; int simplex[64][4] = { - {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 0, 0, 0}, {0, 2, 3, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 2, 3, 0}, - {0, 2, 1, 3}, {0, 0, 0, 0}, {0, 3, 1, 2}, {0, 3, 2, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 3, 2, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {1, 2, 0, 3}, {0, 0, 0, 0}, {1, 3, 0, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, - {1, 0, 2, 3}, {1, 0, 3, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 0, 3, 1}, {0, 0, 0, 0}, {2, 1, 3, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {2, 0, 1, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {3, 0, 1, 2}, {3, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 2, 0}, - {2, 1, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {3, 1, 0, 2}, {0, 0, 0, 0}, {3, 2, 0, 1}, {3, 2, 1, 0} + {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 0, 0, 0}, {0, 2, 3, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 2, 3, 0}, + {0, 2, 1, 3}, {0, 0, 0, 0}, {0, 3, 1, 2}, {0, 3, 2, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 3, 2, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {1, 2, 0, 3}, {0, 0, 0, 0}, {1, 3, 0, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, + {1, 0, 2, 3}, {1, 0, 3, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 0, 3, 1}, {0, 0, 0, 0}, {2, 1, 3, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {2, 0, 1, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {3, 0, 1, 2}, {3, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 2, 0}, + {2, 1, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {3, 1, 0, 2}, {0, 0, 0, 0}, {3, 2, 0, 1}, {3, 2, 1, 0} }; -public: + public: void init() { - for (int i = 0; i < 256; ++i) { - this->p[i] = floor((rand() % 256 + 1)); - } - for (int i = 0; i < 512; ++i) { - this->perm[i] = p[i & 255]; - this->permMod12[i] = perm[i] % 12; - } + for (int i = 0; i < 256; ++i) { + this->p[i] = floor((rand() % 256 + 1)); + } + for (int i = 0; i < 512; ++i) { + this->perm[i] = p[i & 255]; + this->permMod12[i] = perm[i] % 12; + } }; double noise(double xin, double yin); diff --git a/src/wavetable-oscillator.cpp b/src/wavetable-oscillator.cpp index fa3d118..5020760 100644 --- a/src/wavetable-oscillator.cpp +++ b/src/wavetable-oscillator.cpp @@ -8,367 +8,380 @@ #define POLY_SIZE 16 struct WAVE : TinyTricksModule { - enum ParamIds { - FREQ_PARAM, - FREQ_FINE_PARAM, - OSC1_Y_PARAM, - CAPTURE_PARAM, - MIRROR_PARAM, - OSC2_ENABLE_PARAM, - OSC2_SYNC_PARAM, - OSC2_DETUNE_PARAM, - OSC2_Y_PARAM, - OSC3_ENABLE_PARAM, - OSC3_SYNC_PARAM, - OSC3_DETUNE_PARAM, - OSC3_Y_PARAM, - NUM_PARAMS - }; - enum InputIds { - FREQ_CV_INPUT, - FREQ_FINE_CV_INPUT, - OSC1_Y_CV_INPUT, - TOP_INPUT, - MIDDLE_INPUT, - BOTTOM_INPUT, - SYNC_INPUT, - OSC2_DETUNE_CV_INPUT, - OSC2_Y_CV_INPUT, - OSC3_DETUNE_CV_INPUT, - OSC3_Y_CV_INPUT, - CAPTURE_TRIGGER_INPUT, - MIRROR_TRIGGER_INPUT, - NUM_INPUTS - }; - enum OutputIds { - AUDIO_OUTPUT, - NUM_OUTPUTS - }; - enum LightIds { - CAPTURE_LIGHT, - MIRROR_LIGHT, - OSC2_ENABLE_LIGHT, - OSC3_ENABLE_LIGHT, - NUM_LIGHTS - }; - - WaveTableOscillator oscillator1[POLY_SIZE]; - WaveTableOscillator oscillator2[POLY_SIZE]; - WaveTableOscillator oscillator3[POLY_SIZE]; - - WaveTableScope* scope = nullptr; - WaveTable* waveTable = nullptr; - - dsp::SchmittTrigger syncTrigger; - - dsp::SchmittTrigger mirrorButtonTrigger; - dsp::SchmittTrigger mirrorTrigger; - bool mirror = false; - - dsp::SchmittTrigger inCaptureModeButtonTrigger; - dsp::SchmittTrigger inCaptureModeTrigger; - bool inCaptureMode = false; - - dsp::SchmittTrigger osc2EnableTrigger; - bool osc2Enabled = false; - - dsp::SchmittTrigger osc3EnableTrigger; - bool osc3Enabled = false; - - - void Initialize(){ + enum ParamIds { + FREQ_PARAM, + FREQ_FINE_PARAM, + OSC1_Y_PARAM, + CAPTURE_PARAM, + MIRROR_PARAM, + OSC2_ENABLE_PARAM, + OSC2_SYNC_PARAM, + OSC2_DETUNE_PARAM, + OSC2_Y_PARAM, + OSC3_ENABLE_PARAM, + OSC3_SYNC_PARAM, + OSC3_DETUNE_PARAM, + OSC3_Y_PARAM, + NUM_PARAMS + }; + enum InputIds { + FREQ_CV_INPUT, + FREQ_FINE_CV_INPUT, + OSC1_Y_CV_INPUT, + TOP_INPUT, + MIDDLE_INPUT, + BOTTOM_INPUT, + SYNC_INPUT, + OSC2_DETUNE_CV_INPUT, + OSC2_Y_CV_INPUT, + OSC3_DETUNE_CV_INPUT, + OSC3_Y_CV_INPUT, + CAPTURE_TRIGGER_INPUT, + MIRROR_TRIGGER_INPUT, + NUM_INPUTS + }; + enum OutputIds { + AUDIO_OUTPUT, + NUM_OUTPUTS + }; + enum LightIds { + CAPTURE_LIGHT, + MIRROR_LIGHT, + OSC2_ENABLE_LIGHT, + OSC3_ENABLE_LIGHT, + NUM_LIGHTS + }; + + WaveTableOscillator oscillator1[POLY_SIZE]; + WaveTableOscillator oscillator2[POLY_SIZE]; + WaveTableOscillator oscillator3[POLY_SIZE]; + + WaveTableScope *scope = nullptr; + WaveTable *waveTable = nullptr; + + dsp::SchmittTrigger syncTrigger; + + dsp::SchmittTrigger mirrorButtonTrigger; + dsp::SchmittTrigger mirrorTrigger; + bool mirror = false; + + dsp::SchmittTrigger inCaptureModeButtonTrigger; + dsp::SchmittTrigger inCaptureModeTrigger; + bool inCaptureMode = false; + + dsp::SchmittTrigger osc2EnableTrigger; + bool osc2Enabled = false; + + dsp::SchmittTrigger osc3EnableTrigger; + bool osc3Enabled = false; + + + void Initialize() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); - //Recording - configParam(WAVE::CAPTURE_PARAM, 0.f, 1.f, 0.f, "Record new waveforms"); - configParam(WAVE::MIRROR_PARAM, 0.f, 1.f, 0.f, "Mirror waveform"); - - //Main oscillator - configParam(WAVE::FREQ_PARAM, -3.0f, 3.0f, 0.0f, "Tuning"); - configParam(WAVE::FREQ_FINE_PARAM, -0.5f, 0.5f, 0.0f, "Fine tuning"); - configParam(WAVE::OSC1_Y_PARAM, 0.0f, 1.0f, 0.5f, "Pos"); - - //Oscillator 2 - configParam(WAVE::OSC2_DETUNE_PARAM, 0.0f, 1.0f, 0.0f, "Detune amount"); - configParam(WAVE::OSC2_Y_PARAM, -1.0f, 1.0f, 0.0f, "Pos"); - configParam(WAVE::OSC2_SYNC_PARAM, 0.0f, 1.0f, 0.0f, "Sync mode"); - - //Oscillator 3 - configParam(WAVE::OSC3_DETUNE_PARAM, 0.0f, 1.0f, 0.0f, "Detune amount"); - configParam(WAVE::OSC3_Y_PARAM, -1.0f, 1.0f, 0.0f, "Pos"); - configParam(WAVE::OSC3_SYNC_PARAM, 0.0f, 2.0f, 0.0f, "Sync mode"); - - waveTable = new WaveTable(); - for( auto i=0; iWAVETABLE_SIZE)); - json_t *wavetableJ = json_array(); - for (int v = 0; v < waveTable->WAVEFORM_COUNT; v++) { - json_t *waveformJ = json_array(); - for (int s = 0; s < waveTable->WAVETABLE_SIZE; s++) { - json_t *sampleJ = json_real(waveTable->lookuptable[v][s]); - json_array_append_new(waveformJ, sampleJ); - } - json_array_append_new(wavetableJ, waveformJ); - - } - json_object_set_new(rootJ, "wavetable", wavetableJ); - - AppendBaseJson(rootJ); - return rootJ; - } - - - - void dataFromJson(json_t *rootJ) override { - TinyTricksModule::dataFromJson(rootJ); - - JSON_REAL_PRECISION(31); - - //Reading wavetable - int waveEnd = 0; - json_t *waveEndJ = json_object_get(rootJ, "waveEnd"); - if (waveEndJ) waveEnd = (int)json_integer_value(waveEndJ); - - json_t *wavetableJ = json_object_get(rootJ, "wavetable"); - if(wavetableJ){ - for (int s = 0; s < waveEnd; s++) { - for (int v = 0; v < WaveTable::WAVEFORM_COUNT; v++) { - json_t *waveJ = json_array_get(wavetableJ, v); - if(waveJ){ - float value = json_number_value(json_array_get(waveJ, s)); - waveTable->addSampleToFrame(value,v); - } - } - waveTable->endFrame(); - } - waveTable->endCapture(); - if( scope ) - scope->generate(waveTable,10); - } - - // Mirror - json_t *mirrorJ = json_object_get(rootJ, "mirror"); - if (mirrorJ) mirror = json_is_true(mirrorJ); - lights[MIRROR_LIGHT].value = mirror; - for( auto i=0; iWAVETABLE_SIZE)); + json_t *wavetableJ = json_array(); + for (int v = 0; v < waveTable->WAVEFORM_COUNT; v++) { + json_t *waveformJ = json_array(); + for (int s = 0; s < waveTable->WAVETABLE_SIZE; s++) { + json_t *sampleJ = json_real(waveTable->lookuptable[v][s]); + json_array_append_new(waveformJ, sampleJ); + } + json_array_append_new(wavetableJ, waveformJ); + + } + json_object_set_new(rootJ, "wavetable", wavetableJ); + + AppendBaseJson(rootJ); + return rootJ; + } + + + + void dataFromJson(json_t *rootJ) override { + TinyTricksModule::dataFromJson(rootJ); + + JSON_REAL_PRECISION(31); + + //Reading wavetable + int waveEnd = 0; + json_t *waveEndJ = json_object_get(rootJ, "waveEnd"); + if (waveEndJ) + waveEnd = (int)json_integer_value(waveEndJ); + + json_t *wavetableJ = json_object_get(rootJ, "wavetable"); + if (wavetableJ) { + for (int s = 0; s < waveEnd; s++) { + for (int v = 0; v < WaveTable::WAVEFORM_COUNT; v++) { + json_t *waveJ = json_array_get(wavetableJ, v); + if (waveJ) { + float value = json_number_value(json_array_get(waveJ, s)); + waveTable->addSampleToFrame(value, v); + } + } + waveTable->endFrame(); + } + waveTable->endCapture(); + if (scope) + scope->generate(waveTable, 10); + } + + // Mirror + json_t *mirrorJ = json_object_get(rootJ, "mirror"); + if (mirrorJ) + mirror = json_is_true(mirrorJ); + lights[MIRROR_LIGHT].value = mirror; + for (auto i = 0; i < POLY_SIZE; ++i) { oscillator1[i].setMirror(mirror); oscillator2[i].setMirror(mirror); oscillator3[i].setMirror(mirror); } - if( scope ) + if (scope) scope->impl->setMirror(mirror); - //Osc2 - json_t *osc2EnabledJ = json_object_get(rootJ, "osc2Enabled"); - if (osc2EnabledJ) osc2Enabled = json_is_true(osc2EnabledJ); - lights[OSC2_ENABLE_LIGHT].value = osc2Enabled; - - //Osc3 - json_t *osc3EnabledJ = json_object_get(rootJ, "osc3Enabled"); - if (osc3EnabledJ) osc3Enabled = json_is_true(osc3EnabledJ); - lights[OSC3_ENABLE_LIGHT].value = osc3Enabled; - } - - - - //Capture management - unsigned int ticksSinceRecordingStarted = 0; - bool useSync = false; - bool recording = false; - bool finalizeRecording = false; - void manageinCaptureMode(){ - //Setting inCaptureMode - if (!inCaptureMode && (inCaptureModeButtonTrigger.process(params[CAPTURE_PARAM].value) || (inputs[CAPTURE_TRIGGER_INPUT].isConnected() && inCaptureModeTrigger.process(inputs[CAPTURE_TRIGGER_INPUT].value)))) { - inCaptureMode = true; - finalizeRecording = false; - useSync = inputs[SYNC_INPUT].isConnected(); - - waveTable->startCapture(); - if( scope ) + //Osc2 + json_t *osc2EnabledJ = json_object_get(rootJ, "osc2Enabled"); + if (osc2EnabledJ) + osc2Enabled = json_is_true(osc2EnabledJ); + lights[OSC2_ENABLE_LIGHT].value = osc2Enabled; + + //Osc3 + json_t *osc3EnabledJ = json_object_get(rootJ, "osc3Enabled"); + if (osc3EnabledJ) + osc3Enabled = json_is_true(osc3EnabledJ); + lights[OSC3_ENABLE_LIGHT].value = osc3Enabled; + } + + + + //Capture management + unsigned int ticksSinceRecordingStarted = 0; + bool useSync = false; + bool recording = false; + bool finalizeRecording = false; + void manageinCaptureMode() { + //Setting inCaptureMode + if (!inCaptureMode && (inCaptureModeButtonTrigger.process(params[CAPTURE_PARAM].value) || (inputs[CAPTURE_TRIGGER_INPUT].isConnected() && inCaptureModeTrigger.process(inputs[CAPTURE_TRIGGER_INPUT].value)))) { + inCaptureMode = true; + finalizeRecording = false; + useSync = inputs[SYNC_INPUT].isConnected(); + + waveTable->startCapture(); + if (scope) scope->impl->stop(); - if(useSync) - recording = false; - else - recording = true; - - ticksSinceRecordingStarted = 0; - } - lights[CAPTURE_LIGHT].value = inCaptureMode; - - if(inCaptureMode){ - //Starting recording on sync - if we use sync - if(useSync && !recording && syncTrigger.process(inputs[SYNC_INPUT].getVoltage())) - recording = true; - //Stopping recording on second sync or if no more room for recording - else if( - (ticksSinceRecordingStarted >= WaveTable::MAX_SAMPLE_COUNT) - || - (useSync && recording && syncTrigger.process(inputs[SYNC_INPUT].getVoltage())) - ){ - recording = false; - finalizeRecording = true; - } - if(recording){ - float topV = inputs[TOP_INPUT].getNormalVoltage(0.0f); - waveTable->addSampleToFrame(topV,0); - - float middleV = inputs[MIDDLE_INPUT].getNormalVoltage(0.0f); - waveTable->addSampleToFrame(middleV,1); - - float bottomV = inputs[BOTTOM_INPUT].getNormalVoltage(0.0f); - waveTable->addSampleToFrame(bottomV,2); - - waveTable->endFrame(); - - ticksSinceRecordingStarted++; - } - - if(finalizeRecording){ - waveTable->endCapture(); - if( scope ) + if (useSync) + recording = false; + else + recording = true; + + ticksSinceRecordingStarted = 0; + } + lights[CAPTURE_LIGHT].value = inCaptureMode; + + if (inCaptureMode) { + //Starting recording on sync - if we use sync + if (useSync && !recording && syncTrigger.process(inputs[SYNC_INPUT].getVoltage())) + recording = true; + //Stopping recording on second sync or if no more room for recording + else if ( + (ticksSinceRecordingStarted >= WaveTable::MAX_SAMPLE_COUNT) + || + (useSync && recording && syncTrigger.process(inputs[SYNC_INPUT].getVoltage())) + ) { + recording = false; + finalizeRecording = true; + } + if (recording) { + float topV = inputs[TOP_INPUT].getNormalVoltage(0.0f); + waveTable->addSampleToFrame(topV, 0); + + float middleV = inputs[MIDDLE_INPUT].getNormalVoltage(0.0f); + waveTable->addSampleToFrame(middleV, 1); + + float bottomV = inputs[BOTTOM_INPUT].getNormalVoltage(0.0f); + waveTable->addSampleToFrame(bottomV, 2); + + waveTable->endFrame(); + + ticksSinceRecordingStarted++; + } + + if (finalizeRecording) { + waveTable->endCapture(); + if (scope) scope->impl->start(); - inCaptureMode = false; - recording = false; - finalizeRecording = false; - for( auto i=0; igenerate(waveTable,10); - } - } - } + if (scope) + scope->generate(waveTable, 10); + } + } + } - void process(const ProcessArgs &args) override{ - //Setting mirror - if (mirrorButtonTrigger.process(params[MIRROR_PARAM].value) || + void process(const ProcessArgs &args) override { + //Setting mirror + if (mirrorButtonTrigger.process(params[MIRROR_PARAM].value) || (inputs[MIRROR_TRIGGER_INPUT].isConnected() && mirrorButtonTrigger.process(inputs[MIRROR_TRIGGER_INPUT].value))) { - mirror = !mirror; - for( auto i=0; iimpl->setMirror(mirror); - } - lights[MIRROR_LIGHT].value = mirror; + } + lights[MIRROR_LIGHT].value = mirror; - //Setting osc2 enable - if (osc2EnableTrigger.process(params[OSC2_ENABLE_PARAM].value)) { - osc2Enabled = !osc2Enabled; - for( auto i=0; i ys; - if(c == 0) - ys.reserve(3); + if (c == 0) + ys.reserve(3); float osc1Y = params[OSC1_Y_PARAM].getValue(); - if(inputs[OSC1_Y_CV_INPUT].isConnected()){ - osc1Y += inputs[OSC1_Y_CV_INPUT].getPolyVoltage(c)/10.f; + if (inputs[OSC1_Y_CV_INPUT].isConnected()) { + osc1Y += inputs[OSC1_Y_CV_INPUT].getPolyVoltage(c) / 10.f; osc1Y = clamp(osc1Y, 0.f, 1.f); } ys.push_back(osc1Y); float osc2Y; - if(osc2Enabled){ + if (osc2Enabled) { osc2Y = osc1Y + params[OSC2_Y_PARAM].getValue(); - if(inputs[OSC2_Y_CV_INPUT].isConnected()) - osc2Y += inputs[OSC2_Y_CV_INPUT].getPolyVoltage(c)/10.f; + if (inputs[OSC2_Y_CV_INPUT].isConnected()) + osc2Y += inputs[OSC2_Y_CV_INPUT].getPolyVoltage(c) / 10.f; osc2Y = clamp(osc2Y, 0.f, 1.f); - if(c == 0) - ys.push_back(osc2Y); + if (c == 0) + ys.push_back(osc2Y); } float osc3Y; - if(osc3Enabled){ + if (osc3Enabled) { osc3Y = osc1Y + params[OSC3_Y_PARAM].getValue(); - if(inputs[OSC3_Y_CV_INPUT].isConnected()) - osc3Y += inputs[OSC3_Y_CV_INPUT].getPolyVoltage(c)/10.f; + if (inputs[OSC3_Y_CV_INPUT].isConnected()) + osc3Y += inputs[OSC3_Y_CV_INPUT].getPolyVoltage(c) / 10.f; osc3Y = clamp(osc3Y, 0.f, 1.f); - if(c == 0) - ys.push_back(osc3Y); + if (c == 0) + ys.push_back(osc3Y); } - if(c == 0 && scope) + if (c == 0 && scope) scope->impl->setYs(ys); //Stepping and syncing @@ -377,14 +390,14 @@ struct WAVE : TinyTricksModule { oscillator1[c].step(); //Syncing osc2 - if(syncOsc2ToMain && oscillator1[c].isEOC()) + if (syncOsc2ToMain && oscillator1[c].isEOC()) oscillator2[c].reset(); oscillator2[c].step(); - if(osc3SyncMode != 0.f){ - if(osc3SyncMode == 1.f && osc2Enabled && oscillator2[c].isEOC()) + if (osc3SyncMode != 0.f) { + if (osc3SyncMode == 1.f && osc2Enabled && oscillator2[c].isEOC()) oscillator3[c].reset(); - else if(osc3SyncMode == 2.f && oscillator1[c].isEOC()) + else if (osc3SyncMode == 2.f && oscillator1[c].isEOC()) oscillator3[c].reset(); } oscillator3[c].step(); @@ -392,15 +405,15 @@ struct WAVE : TinyTricksModule { //Getting samples int divisor = 1; float out = oscillator1[c].getSample(osc1Y); - if(osc2Enabled){ + if (osc2Enabled) { out += oscillator2[c].getSample(osc2Y); divisor++; } - if(osc3Enabled){ + if (osc3Enabled) { out += oscillator3[c].getSample(osc3Y); divisor++; } - float mix = (out)/(float)divisor; + float mix = (out) / (float)divisor; //Setting the mix out outputs[AUDIO_OUTPUT].setVoltage(mix, c); } @@ -414,117 +427,117 @@ struct WAVE : TinyTricksModule { struct WAVEWidget : TinyTricksModuleWidget { - WaveTableScope* scope; + WaveTableScope *scope; - void appendContextMenu(Menu* menu) override { - menu->addChild(new MenuEntry); - menu->addChild(createMenuLabel("Scope")); + void appendContextMenu(Menu *menu) override { + menu->addChild(new MenuEntry); + menu->addChild(createMenuLabel("Scope")); - struct ScopeItem : MenuItem { - WAVEWidget* widget; - void onAction(const event::Action& e) override { - if( widget->scope ) + struct ScopeItem : MenuItem { + WAVEWidget *widget; + void onAction(const event::Action &e) override { + if (widget->scope) widget->scope->visible = !widget->scope->visible; - } - }; + } + }; - ScopeItem* modeItem = createMenuItem("Hide scope (increases performance)"); - modeItem->rightText = CHECKMARK(!scope->visible); - modeItem->widget = this; - menu->addChild(modeItem); + ScopeItem *modeItem = createMenuItem("Hide scope (increases performance)"); + modeItem->rightText = CHECKMARK(!scope->visible); + modeItem->widget = this; + menu->addChild(modeItem); - TinyTricksModuleWidget::appendContextMenu(menu); - } + TinyTricksModuleWidget::appendContextMenu(menu); + } - WAVEWidget(WAVE *module) { - setModule(module); + WAVEWidget(WAVE *module) { + setModule(module); - //inCaptureMode button - addParam(createParam(mm2px(Vec(7.511f,11.481f)), module, WAVE::CAPTURE_PARAM)); - addChild(createLight>(mm2px(Vec(7.511f+0.45f,11.481f+0.45f)), module, WAVE::CAPTURE_LIGHT)); - addInput(createInput(mm2px(Vec(6.634f,18.831f)), module, WAVE::CAPTURE_TRIGGER_INPUT)); + //inCaptureMode button + addParam(createParam(mm2px(Vec(7.511f, 11.481f)), module, WAVE::CAPTURE_PARAM)); + addChild(createLight>(mm2px(Vec(7.511f + 0.45f, 11.481f + 0.45f)), module, WAVE::CAPTURE_LIGHT)); + addInput(createInput(mm2px(Vec(6.634f, 18.831f)), module, WAVE::CAPTURE_TRIGGER_INPUT)); - //Inputs - addInput(createInput(mm2px(Vec(6.634f,49.167f)), module, WAVE::TOP_INPUT)); - addInput(createInput(mm2px(Vec(6.634f,59.273f)), module, WAVE::MIDDLE_INPUT)); - addInput(createInput(mm2px(Vec(6.634f,69.387f)), module, WAVE::BOTTOM_INPUT)); + //Inputs + addInput(createInput(mm2px(Vec(6.634f, 49.167f)), module, WAVE::TOP_INPUT)); + addInput(createInput(mm2px(Vec(6.634f, 59.273f)), module, WAVE::MIDDLE_INPUT)); + addInput(createInput(mm2px(Vec(6.634f, 69.387f)), module, WAVE::BOTTOM_INPUT)); - //Sync - addInput(createInput(mm2px(Vec(6.634f,33.821f)), module, WAVE::SYNC_INPUT)); + //Sync + addInput(createInput(mm2px(Vec(6.634f, 33.821f)), module, WAVE::SYNC_INPUT)); - //Mirror button - addParam(createParam(mm2px(Vec(7.511f,87.578f)), module, WAVE::MIRROR_PARAM)); - addChild(createLight>(mm2px(Vec(7.511f+0.45f,87.578f+0.45f)), module, WAVE::MIRROR_LIGHT)); - addInput(createInput(mm2px(Vec(6.634f,94.928f)), module, WAVE::MIRROR_TRIGGER_INPUT)); + //Mirror button + addParam(createParam(mm2px(Vec(7.511f, 87.578f)), module, WAVE::MIRROR_PARAM)); + addChild(createLight>(mm2px(Vec(7.511f + 0.45f, 87.578f + 0.45f)), module, WAVE::MIRROR_LIGHT)); + addInput(createInput(mm2px(Vec(6.634f, 94.928f)), module, WAVE::MIRROR_TRIGGER_INPUT)); - //Output - addOutput(createOutput(mm2px(Vec(6.634f, 113.255f)), module, WAVE::AUDIO_OUTPUT)); + //Output + addOutput(createOutput(mm2px(Vec(6.634f, 113.255f)), module, WAVE::AUDIO_OUTPUT)); - if(module){ - //Top scope - scope = new WaveTableScope(); - scope->box.pos = mm2px(Vec(23.775f, 9.1f)); - scope->box.size = mm2px(Vec(35.807f, 110.354f)); + if (module) { + //Top scope + scope = new WaveTableScope(); + scope->box.pos = mm2px(Vec(23.775f, 9.1f)); + scope->box.size = mm2px(Vec(35.807f, 110.354f)); scope->setup(); - addChild(scope); - module->scope = scope; - } - else{ - SvgWidget* placeholder = createWidget(mm2px(Vec(24.575f, 11.1f))); - placeholder->setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/Wavetable.svg"))); - addChild(placeholder); - } - - // Main oscillator ------------------------------------------------ - //Freq - addParam(createParam(mm2px(Vec(65.349f,17.068f)), module, WAVE::FREQ_PARAM)); - addInput(createInput(mm2px(Vec(66.253f,28.339f)), module, WAVE::FREQ_CV_INPUT)); - - //Fine - addParam(createParam(mm2px(Vec(78.83f,17.068f)), module, WAVE::FREQ_FINE_PARAM)); - addInput(createInput(mm2px(Vec(79.733f,28.339f)), module, WAVE::FREQ_FINE_CV_INPUT)); - - //Y - addParam(createParam(mm2px(Vec(92.31f,17.068f)), module, WAVE::OSC1_Y_PARAM)); - addInput(createInput(mm2px(Vec(93.213f,28.339f)), module, WAVE::OSC1_Y_CV_INPUT)); - - // Oscillator 2 ------------------------------------------------ - //Enable - addParam(createParam(mm2px(Vec(67.175f,54.602f)), module, WAVE::OSC2_ENABLE_PARAM)); - addChild(createLight>(mm2px(Vec(67.175f+0.45f,54.602f+0.45f)), module, WAVE::OSC2_ENABLE_LIGHT)); - - //Sync - addParam(createParam(mm2px(Vec(67.88f,68.698f)), module, WAVE::OSC2_SYNC_PARAM)); - - //Detune - addParam(createParam(mm2px(Vec(83.794f,53.777f)), module, WAVE::OSC2_DETUNE_PARAM)); - addInput(createInput(mm2px(Vec(93.213f,53.68f)), module, WAVE::OSC2_DETUNE_CV_INPUT)); - - //Pos - addParam(createParam(mm2px(Vec(83.794f,68.33f)), module, WAVE::OSC2_Y_PARAM)); - addInput(createInput(mm2px(Vec(93.213f,68.232f)), module, WAVE::OSC2_Y_CV_INPUT)); - - // Oscillator 3 ------------------------------------------------ - //Enable - addParam(createParam(mm2px(Vec(67.177f,96.01f)), module, WAVE::OSC3_ENABLE_PARAM)); - addChild(createLight>(mm2px(Vec(67.177f+0.45f,96.01f+0.45f)), module, WAVE::OSC3_ENABLE_LIGHT)); - - //Sync - addParam(createParam(mm2px(Vec(67.978f,109.738f)), module, WAVE::OSC3_SYNC_PARAM)); - - //Detune - addParam(createParam(mm2px(Vec(83.797f,95.186f)), module, WAVE::OSC3_DETUNE_PARAM)); - addInput(createInput(mm2px(Vec(93.215f,95.089f)), module, WAVE::OSC3_DETUNE_CV_INPUT)); - - //Pos - addParam(createParam(mm2px(Vec(83.797f,109.738f)), module, WAVE::OSC3_Y_PARAM)); - addInput(createInput(mm2px(Vec(93.215f,109.641f)), module, WAVE::OSC3_Y_CV_INPUT)); - - InitializeSkin("WAVE.svg"); - } + addChild(scope); + module->scope = scope; + } + else { + SvgWidget *placeholder = createWidget(mm2px(Vec(24.575f, 11.1f))); + placeholder->setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/Wavetable.svg"))); + addChild(placeholder); + } + + // Main oscillator ------------------------------------------------ + //Freq + addParam(createParam(mm2px(Vec(65.349f, 17.068f)), module, WAVE::FREQ_PARAM)); + addInput(createInput(mm2px(Vec(66.253f, 28.339f)), module, WAVE::FREQ_CV_INPUT)); + + //Fine + addParam(createParam(mm2px(Vec(78.83f, 17.068f)), module, WAVE::FREQ_FINE_PARAM)); + addInput(createInput(mm2px(Vec(79.733f, 28.339f)), module, WAVE::FREQ_FINE_CV_INPUT)); + + //Y + addParam(createParam(mm2px(Vec(92.31f, 17.068f)), module, WAVE::OSC1_Y_PARAM)); + addInput(createInput(mm2px(Vec(93.213f, 28.339f)), module, WAVE::OSC1_Y_CV_INPUT)); + + // Oscillator 2 ------------------------------------------------ + //Enable + addParam(createParam(mm2px(Vec(67.175f, 54.602f)), module, WAVE::OSC2_ENABLE_PARAM)); + addChild(createLight>(mm2px(Vec(67.175f + 0.45f, 54.602f + 0.45f)), module, WAVE::OSC2_ENABLE_LIGHT)); + + //Sync + addParam(createParam(mm2px(Vec(67.88f, 68.698f)), module, WAVE::OSC2_SYNC_PARAM)); + + //Detune + addParam(createParam(mm2px(Vec(83.794f, 53.777f)), module, WAVE::OSC2_DETUNE_PARAM)); + addInput(createInput(mm2px(Vec(93.213f, 53.68f)), module, WAVE::OSC2_DETUNE_CV_INPUT)); + + //Pos + addParam(createParam(mm2px(Vec(83.794f, 68.33f)), module, WAVE::OSC2_Y_PARAM)); + addInput(createInput(mm2px(Vec(93.213f, 68.232f)), module, WAVE::OSC2_Y_CV_INPUT)); + + // Oscillator 3 ------------------------------------------------ + //Enable + addParam(createParam(mm2px(Vec(67.177f, 96.01f)), module, WAVE::OSC3_ENABLE_PARAM)); + addChild(createLight>(mm2px(Vec(67.177f + 0.45f, 96.01f + 0.45f)), module, WAVE::OSC3_ENABLE_LIGHT)); + + //Sync + addParam(createParam(mm2px(Vec(67.978f, 109.738f)), module, WAVE::OSC3_SYNC_PARAM)); + + //Detune + addParam(createParam(mm2px(Vec(83.797f, 95.186f)), module, WAVE::OSC3_DETUNE_PARAM)); + addInput(createInput(mm2px(Vec(93.215f, 95.089f)), module, WAVE::OSC3_DETUNE_CV_INPUT)); + + //Pos + addParam(createParam(mm2px(Vec(83.797f, 109.738f)), module, WAVE::OSC3_Y_PARAM)); + addInput(createInput(mm2px(Vec(93.215f, 109.641f)), module, WAVE::OSC3_Y_CV_INPUT)); + + InitializeSkin("WAVE.svg"); + } }; Model *modelWAVE = createModel("WAVE"); diff --git a/src/widgets/curve-widget.cpp b/src/widgets/curve-widget.cpp index df3e7b8..cbd5227 100644 --- a/src/widgets/curve-widget.cpp +++ b/src/widgets/curve-widget.cpp @@ -1,87 +1,87 @@ -struct CurveWidgetInternal : OpaqueWidget{ - std::vector ys; - float lineWeight = 1.5f; - bool isLiniearMode = true; +struct CurveWidgetInternal : OpaqueWidget { + std::vector ys; + float lineWeight = 1.5f; + bool isLiniearMode = true; - CurveWidgetInternal(){ - } + CurveWidgetInternal() { + } void draw(const DrawArgs &args) override { - Rect b = Rect(Vec(0, 0), box.size); - nvgSave(args.vg); - - //Draw scope - nvgBeginPath(args.vg); - nvgStrokeColor(args.vg, nvgRGBA(255,255,255,255)); - nvgStrokeWidth(args.vg, lineWeight); - - size_t points = ys.size(); - - //Adding the points - for (size_t i = 0; i < points; i++) { - if(!isLiniearMode && i == points-1) - break; - - Vec v; - v.x = i/(float)(points-1); - v.y = ys[i]; - Vec p; - p.x = rescale(v.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); - p.y = rescale(v.y, 0.f, 10.f, b.pos.y + b.size.y, b.pos.y); - - - if (i == 0) - nvgMoveTo(args.vg, p.x, p.y); - else - nvgLineTo(args.vg, p.x, p.y); - - if(!isLiniearMode && i < points-1){ - Vec v1; - v1.x = (i+1)/(float)(points-1); - v1.y = ys[i]; - Vec p1; - p1.x = rescale(v1.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); - p1.y = rescale(v1.y, 0.f, 10.f, b.pos.y + b.size.y, b.pos.y); - nvgLineTo(args.vg, p1.x, p1.y); - } - } - - nvgLineCap(args.vg, NVG_ROUND); - nvgLineJoin(args.vg, NVG_ROUND); - nvgStroke(args.vg); - nvgClosePath(args.vg); - //Done with scope - - nvgRestore(args.vg); + Rect b = Rect(Vec(0, 0), box.size); + nvgSave(args.vg); + + //Draw scope + nvgBeginPath(args.vg); + nvgStrokeColor(args.vg, nvgRGBA(255, 255, 255, 255)); + nvgStrokeWidth(args.vg, lineWeight); + + size_t points = ys.size(); + + //Adding the points + for (size_t i = 0; i < points; i++) { + if (!isLiniearMode && i == points - 1) + break; + + Vec v; + v.x = i / (float)(points - 1); + v.y = ys[i]; + Vec p; + p.x = rescale(v.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); + p.y = rescale(v.y, 0.f, 10.f, b.pos.y + b.size.y, b.pos.y); + + + if (i == 0) + nvgMoveTo(args.vg, p.x, p.y); + else + nvgLineTo(args.vg, p.x, p.y); + + if (!isLiniearMode && i < points - 1) { + Vec v1; + v1.x = (i + 1) / (float)(points - 1); + v1.y = ys[i]; + Vec p1; + p1.x = rescale(v1.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); + p1.y = rescale(v1.y, 0.f, 10.f, b.pos.y + b.size.y, b.pos.y); + nvgLineTo(args.vg, p1.x, p1.y); + } + } + + nvgLineCap(args.vg, NVG_ROUND); + nvgLineJoin(args.vg, NVG_ROUND); + nvgStroke(args.vg); + nvgClosePath(args.vg); + //Done with scope + + nvgRestore(args.vg); } }; struct CurveWidget : FramebufferWidget { - CurveWidgetInternal* internal; + CurveWidgetInternal *internal; - CurveWidget(){ + CurveWidget() { - } + } - void setMode(bool isLinear){ - internal->isLiniearMode = isLinear; - dirty = true; - } + void setMode(bool isLinear) { + internal->isLiniearMode = isLinear; + dirty = true; + } - void setPoints(std::vector _ys){ - internal->ys = _ys; - dirty = true; - } + void setPoints(std::vector _ys) { + internal->ys = _ys; + dirty = true; + } - void rePaint(){ - dirty = true; - } + void rePaint() { + dirty = true; + } - void setup(){ - internal = new CurveWidgetInternal(); - internal->box.pos = Vec(0,0); - internal->box.size = box.size; - addChild(internal); - } + void setup() { + internal = new CurveWidgetInternal(); + internal->box.pos = Vec(0, 0); + internal->box.size = box.size; + addChild(internal); + } }; diff --git a/src/widgets/mini-scope.cpp b/src/widgets/mini-scope.cpp index 9c76dbd..8c56fd5 100644 --- a/src/widgets/mini-scope.cpp +++ b/src/widgets/mini-scope.cpp @@ -1,92 +1,92 @@ //#include struct MiniScope : TransparentWidget { - static const int SCOPE_BUFFER_SIZE = 2048; - float buffer[SCOPE_BUFFER_SIZE] = {}; - int bufferIndex = 0; - int waveEnd = 0; - bool stopped = false; - float lineWeight = 1.5f; - int id = 0; - float gainCalculated = 0; - float alpha = 1.0f; - bool mirror = false; - - - MiniScope(){ - } + static const int SCOPE_BUFFER_SIZE = 2048; + float buffer[SCOPE_BUFFER_SIZE] = {}; + int bufferIndex = 0; + int waveEnd = 0; + bool stopped = false; + float lineWeight = 1.5f; + int id = 0; + float gainCalculated = 0; + float alpha = 1.0f; + bool mirror = false; + + + MiniScope() { + } - MiniScope(int _id){ - id = _id; - } + MiniScope(int _id) { + id = _id; + } - void setGain(float gain){ - gainCalculated = std::pow(2.f, std::round(gain)) / 10.f; - } + void setGain(float gain) { + gainCalculated = std::pow(2.f, std::round(gain)) / 10.f; + } - void setMirror(bool _mirror){ - mirror = _mirror; - } + void setMirror(bool _mirror) { + mirror = _mirror; + } - void reset(){ - waveEnd = bufferIndex-1; - bufferIndex = 0; - stopped = false; + void reset() { + waveEnd = bufferIndex - 1; + bufferIndex = 0; + stopped = false; - //std::cout << "reset miniscope: " << id <= SCOPE_BUFFER_SIZE) - bufferIndex = 0; + void addFrame(float value) { + if (bufferIndex >= SCOPE_BUFFER_SIZE) + bufferIndex = 0; - buffer[bufferIndex] = value; - bufferIndex++; + buffer[bufferIndex] = value; + bufferIndex++; - //std::cout << "added frame miniscope: " << id < halfway){ - adjustedIndex = halfway - (i-halfway); - } - Vec v; - v.x = (float) i / (waveEnd - 1); - v.y = buffer[adjustedIndex] * gainCalculated / 2.f + 0.5f; - Vec p; - p.x = rescale(v.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); - p.y = rescale(v.y, 0.f, 1.f, b.pos.y + b.size.y, b.pos.y); - if (i == 0) - nvgMoveTo(args.vg, p.x, p.y); - else - nvgLineTo(args.vg, p.x, p.y); - } - nvgLineCap(args.vg, NVG_ROUND); - nvgLineJoin(args.vg, NVG_ROUND); - nvgStroke(args.vg); - nvgClosePath(args.vg); - //Done with scope - - nvgRestore(args.vg); - } + if (!stopped) { + Rect b = Rect(Vec(0, 0), box.size); + nvgSave(args.vg); + + //Draw scope + nvgBeginPath(args.vg); + nvgStrokeColor(args.vg, nvgRGBA(255, 255, 255, (int)ceil(255.f * alpha))); + nvgStrokeWidth(args.vg, lineWeight * (alpha)); + + float halfway = waveEnd / 2.f; + + //Adding the points + for (int i = 0; i < waveEnd; i++) { + int adjustedIndex = i; + if (mirror && i > halfway) { + adjustedIndex = halfway - (i - halfway); + } + Vec v; + v.x = (float) i / (waveEnd - 1); + v.y = buffer[adjustedIndex] * gainCalculated / 2.f + 0.5f; + Vec p; + p.x = rescale(v.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); + p.y = rescale(v.y, 0.f, 1.f, b.pos.y + b.size.y, b.pos.y); + if (i == 0) + nvgMoveTo(args.vg, p.x, p.y); + else + nvgLineTo(args.vg, p.x, p.y); + } + nvgLineCap(args.vg, NVG_ROUND); + nvgLineJoin(args.vg, NVG_ROUND); + nvgStroke(args.vg); + nvgClosePath(args.vg); + //Done with scope + + nvgRestore(args.vg); + } } }; diff --git a/src/widgets/wavetable-scope.cpp b/src/widgets/wavetable-scope.cpp index bb0d1fe..47046e0 100644 --- a/src/widgets/wavetable-scope.cpp +++ b/src/widgets/wavetable-scope.cpp @@ -2,165 +2,165 @@ struct WaveTableScopeInternals : OpaqueWidget { FramebufferWidget *parentAsFb = nullptr; - float SAMPLE_COUNT = 0; + float SAMPLE_COUNT = 0; - float** buffer; + float **buffer; - Rect* rects; + Rect *rects; - bool stopped = false; + bool stopped = false; - int waves; - int subDivisions; - int totalScopes; + int waves; + int subDivisions; + int totalScopes; - bool mirror = false; + bool mirror = false; - float lineWeight = 2.5f; - float spacing = 5.f; + float lineWeight = 2.5f; + float spacing = 5.f; - std::vector highlights; + std::vector highlights; - WaveTableScopeInternals() { + WaveTableScopeInternals() { - } + } - int getScopeIndex(float y){ - return (int)floor(y*(totalScopes-1)); - } + int getScopeIndex(float y) { + return (int)floor(y * (totalScopes - 1)); + } - void setYs(std::vector ys){ - std::vector tmp; - tmp.reserve(3); - for(std::vector::iterator it = ys.begin(); it != ys.end(); it++) - tmp.push_back(getScopeIndex((*it))); + void setYs(std::vector ys) { + std::vector tmp; + tmp.reserve(3); + for (std::vector::iterator it = ys.begin(); it != ys.end(); it++) + tmp.push_back(getScopeIndex((*it))); - std::sort(tmp.begin(), tmp.end()); + std::sort(tmp.begin(), tmp.end()); - if(tmp != highlights) + if (tmp != highlights) dirtyParent(); - highlights = tmp; - } + highlights = tmp; + } - void generate(WaveTable* waveTable, int _subDivisions){ - //Setting up size variables - SAMPLE_COUNT = waveTable->WAVETABLE_SIZE; - waves = waveTable->WAVEFORM_COUNT; - subDivisions = _subDivisions; - totalScopes = (waves-1)*(subDivisions+1)+1; + void generate(WaveTable *waveTable, int _subDivisions) { + //Setting up size variables + SAMPLE_COUNT = waveTable->WAVETABLE_SIZE; + waves = waveTable->WAVEFORM_COUNT; + subDivisions = _subDivisions; + totalScopes = (waves - 1) * (subDivisions + 1) + 1; - //Initializing mem for wavetable - buffer = new float*[totalScopes]; + //Initializing mem for wavetable + buffer = new float*[totalScopes]; // And mem for boxes rects = new Rect[totalScopes]; - float scopeHeight = ( (box.size.y - ((totalScopes-1) * spacing) )/ (float) totalScopes); + float scopeHeight = ((box.size.y - ((totalScopes - 1) * spacing)) / (float) totalScopes); //Copying wavetable and creating boxes for drawing - for(int i = 0; i < totalScopes; i++){ - buffer[i] = new float[waveTable->WAVETABLE_SIZE]; + for (int i = 0; i < totalScopes; i++) { + buffer[i] = new float[waveTable->WAVETABLE_SIZE]; - Vec pos = Vec(0,(scopeHeight + spacing)*i); + Vec pos = Vec(0, (scopeHeight + spacing) * i); Vec size = Vec(box.size.x, scopeHeight); Rect b = Rect(pos, size); rects[i] = b; - } + } //Generating all intermediate waveforms - for (int y = 0; y < totalScopes; y++) { - float level = (float)y/((float)totalScopes-1); - for (int x = 0; x < SAMPLE_COUNT; x++) { - float value = waveTable->getSample(level,(float)x); - buffer[y][x] = value; - } - } + for (int y = 0; y < totalScopes; y++) { + float level = (float)y / ((float)totalScopes - 1); + for (int x = 0; x < SAMPLE_COUNT; x++) { + float value = waveTable->getSample(level, (float)x); + buffer[y][x] = value; + } + } dirtyParent(); - } + } - void setMirror(bool _mirror){ - if(_mirror != mirror){ - mirror = _mirror; + void setMirror(bool _mirror) { + if (_mirror != mirror) { + mirror = _mirror; dirtyParent(); - } - } + } + } - void stop(){ - stopped = true; + void stop() { + stopped = true; dirtyParent(); - } + } - void start(){ - stopped = false; + void start() { + stopped = false; dirtyParent(); - } + } void dirtyParent() { - if( parentAsFb ) + if (parentAsFb) parentAsFb->dirty = true; } - void draw(const DrawArgs &args) override { + void draw(const DrawArgs &args) override { //INFO( "DRAW WAV IMPL" ); // uncomment this to make sure double buffering still works (it does). //std::cout << "Drawing" << std::endl; - if(!stopped){ - for(int i = 0; i < totalScopes; i++){ - float alpha = 0.5f; - if(std::find(highlights.begin(), highlights.end(), i) != highlights.end()) - alpha = alpha + 0.5f; - drawWave(args, rects[i], i, alpha); - } - } - } - - void drawWave(const DrawArgs &args, Rect b, int level, float alpha){ - - nvgSave(args.vg); - - //Draw scope - nvgBeginPath(args.vg); - nvgStrokeColor(args.vg, nvgRGBA(255,255,255,(int)ceil(255.f*alpha))); - nvgStrokeWidth(args.vg, lineWeight*(alpha)); - - float halfway = SAMPLE_COUNT/2.f; - - //Adding the points - for (int i = 0; i < SAMPLE_COUNT; i++) { - int adjustedIndex = i; - if(mirror && i > halfway){ - adjustedIndex = halfway - (i-halfway); - } - Vec v; - v.x = (float) i / (SAMPLE_COUNT - 1); - v.y = buffer[level][adjustedIndex] * 0.2f / 2.f + 0.5f; - Vec p; - p.x = rescale(v.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); - p.y = rescale(v.y, 0.f, 1.f, b.pos.y + b.size.y, b.pos.y); - if (i == 0) - nvgMoveTo(args.vg, p.x, p.y); - else - nvgLineTo(args.vg, p.x, p.y); - } - nvgLineCap(args.vg, NVG_ROUND); - nvgLineJoin(args.vg, NVG_ROUND); - nvgStroke(args.vg); - nvgClosePath(args.vg); - //Done with scope - - nvgRestore(args.vg); - } + if (!stopped) { + for (int i = 0; i < totalScopes; i++) { + float alpha = 0.5f; + if (std::find(highlights.begin(), highlights.end(), i) != highlights.end()) + alpha = alpha + 0.5f; + drawWave(args, rects[i], i, alpha); + } + } + } + + void drawWave(const DrawArgs &args, Rect b, int level, float alpha) { + + nvgSave(args.vg); + + //Draw scope + nvgBeginPath(args.vg); + nvgStrokeColor(args.vg, nvgRGBA(255, 255, 255, (int)ceil(255.f * alpha))); + nvgStrokeWidth(args.vg, lineWeight * (alpha)); + + float halfway = SAMPLE_COUNT / 2.f; + + //Adding the points + for (int i = 0; i < SAMPLE_COUNT; i++) { + int adjustedIndex = i; + if (mirror && i > halfway) { + adjustedIndex = halfway - (i - halfway); + } + Vec v; + v.x = (float) i / (SAMPLE_COUNT - 1); + v.y = buffer[level][adjustedIndex] * 0.2f / 2.f + 0.5f; + Vec p; + p.x = rescale(v.x, 0.f, 1.f, b.pos.x, b.pos.x + b.size.x); + p.y = rescale(v.y, 0.f, 1.f, b.pos.y + b.size.y, b.pos.y); + if (i == 0) + nvgMoveTo(args.vg, p.x, p.y); + else + nvgLineTo(args.vg, p.x, p.y); + } + nvgLineCap(args.vg, NVG_ROUND); + nvgLineJoin(args.vg, NVG_ROUND); + nvgStroke(args.vg); + nvgClosePath(args.vg); + //Done with scope + + nvgRestore(args.vg); + } }; struct WaveTableScope : FramebufferWidget { WaveTableScopeInternals *impl = nullptr; - SvgWidget* helpText; + SvgWidget *helpText; - WaveTableScope(){ + WaveTableScope() { } - void generate(WaveTable* waveTable, int subDivisions){ + void generate(WaveTable *waveTable, int subDivisions) { //Marking dirty and removing help text helpText->visible = false; impl->visible = true; @@ -168,13 +168,13 @@ struct WaveTableScope : FramebufferWidget { } void setup() { - helpText = createWidget(Vec(0,0)); - helpText->setSvg(APP->window->loadSvg(asset::plugin(pluginInstance,"res/components/Wavetable-help.svg"))); + helpText = createWidget(Vec(0, 0)); + helpText->setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/components/Wavetable-help.svg"))); addChild(helpText); - helpText->box.pos = Vec(9,3); + helpText->box.pos = Vec(9, 3); impl = new WaveTableScopeInternals(); - impl->box.pos = Vec(0,0); + impl->box.pos = Vec(0, 0); impl->box.size = box.size; impl->parentAsFb = this; impl->visible = false;