| @@ -90,6 +90,9 @@ OBJS += \ | |||
| distrho-nekobi.cpp.o | |||
| # distrho-stereoenhancer.cpp.o | |||
| OBJS += \ | |||
| distrho-wobblejuice.cpp.o | |||
| ifeq ($(HAVE_JUCE),true) | |||
| # -------------------------------------------------------------- | |||
| # JUCE based plugins | |||
| @@ -228,6 +231,9 @@ distrho-pingpongpan.cpp.o: distrho-pingpongpan.cpp pingpongpan/*.cpp pingpongpan | |||
| distrho-stereoenhancer.cpp.o: distrho-stereoenhancer.cpp stereoenhancer/*.cpp stereoenhancer/*.h stereoenhancer/*.hpp ../distrho/* $(CXXDEPS) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -I../dgl -Istereoenhancer -DDISTRHO_NAMESPACE=DISTRHO_StereoEnhancer -c -o $@ | |||
| distrho-wobblejuice.cpp.o: distrho-wobblejuice.cpp wobblejuice/*.cpp wobblejuice/*.h wobblejuice/*.hpp wobblejuice/*.hxx ../distrho/* $(CXXDEPS) | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -I../dgl -Iwobblejuice -DDISTRHO_NAMESPACE=DISTRHO_WobbleJuice -c -o $@ | |||
| juce-patchbay.cpp.o: juce-patchbay.cpp | |||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
| @@ -42,6 +42,8 @@ extern void carla_register_native_plugin_nekobi(); | |||
| extern void carla_register_native_plugin_pingpongpan(); | |||
| extern void carla_register_native_plugin_stereoenhancer(); | |||
| extern void carla_register_native_plugin_wobblejuice(); | |||
| #ifdef HAVE_JUCE | |||
| // JUCE based plugins | |||
| extern void carla_register_native_plugin_jucepatchbay(); | |||
| @@ -95,6 +97,8 @@ void carla_register_all_plugins() | |||
| carla_register_native_plugin_pingpongpan(); | |||
| //carla_register_native_plugin_stereoenhancer(); | |||
| carla_register_native_plugin_wobblejuice(); | |||
| #ifdef HAVE_JUCE | |||
| // JUCE based plugins | |||
| carla_register_native_plugin_jucepatchbay(); | |||
| @@ -0,0 +1,36 @@ | |||
| /* | |||
| * Wobble Juice Plugin | |||
| * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_NAME "WobbleJuice" | |||
| #define DISTRHO_PLUGIN_HAS_UI 1 | |||
| #define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 0 | |||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
| #define DISTRHO_PLUGIN_URI "urn:distrho:WobbleJuice" | |||
| #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| @@ -0,0 +1,35 @@ | |||
| /* (Auto-generated binary data file). */ | |||
| #ifndef BINARY_WOBBLEJUICEARTWORK_HPP | |||
| #define BINARY_WOBBLEJUICEARTWORK_HPP | |||
| namespace WobbleJuiceArtwork | |||
| { | |||
| extern const char* aboutData; | |||
| const unsigned int aboutDataSize = 180000; | |||
| const unsigned int aboutWidth = 300; | |||
| const unsigned int aboutHeight = 200; | |||
| extern const char* aboutButtonHoverData; | |||
| const unsigned int aboutButtonHoverDataSize = 5888; | |||
| const unsigned int aboutButtonHoverWidth = 92; | |||
| const unsigned int aboutButtonHoverHeight = 16; | |||
| extern const char* aboutButtonNormalData; | |||
| const unsigned int aboutButtonNormalDataSize = 5888; | |||
| const unsigned int aboutButtonNormalWidth = 92; | |||
| const unsigned int aboutButtonNormalHeight = 16; | |||
| extern const char* backgroundData; | |||
| const unsigned int backgroundDataSize = 450000; | |||
| const unsigned int backgroundWidth = 500; | |||
| const unsigned int backgroundHeight = 300; | |||
| extern const char* knobData; | |||
| const unsigned int knobDataSize = 12544; | |||
| const unsigned int knobWidth = 56; | |||
| const unsigned int knobHeight = 56; | |||
| } | |||
| #endif // BINARY_WOBBLEJUICEARTWORK_HPP | |||
| @@ -0,0 +1,255 @@ | |||
| /* | |||
| * Wobble Juice Plugin | |||
| * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "WobbleJuicePlugin.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| WobbleJuicePlugin::WobbleJuicePlugin() | |||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | |||
| { | |||
| // set default values | |||
| d_setProgram(0); | |||
| // reset | |||
| d_deactivate(); | |||
| } | |||
| WobbleJuicePlugin::~WobbleJuicePlugin() | |||
| { | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Init | |||
| void WobbleJuicePlugin::d_initParameter(uint32_t index, Parameter& parameter) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramDivision: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE|PARAMETER_IS_INTEGER; | |||
| parameter.name = "Division"; | |||
| parameter.symbol = "div"; | |||
| parameter.unit = "times"; | |||
| parameter.ranges.def = 4.0f; | |||
| parameter.ranges.min = 1.0f; | |||
| parameter.ranges.max = 16.0f; | |||
| break; | |||
| case paramReso: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Resonance"; | |||
| parameter.symbol = "reso"; | |||
| parameter.unit = "amount"; | |||
| parameter.ranges.def = 0.1f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 0.2f; | |||
| break; | |||
| case paramRange: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Range"; | |||
| parameter.symbol = "rng"; | |||
| parameter.unit = "Hz"; | |||
| parameter.ranges.def = 16000.0f; | |||
| parameter.ranges.min = 500.0f; | |||
| parameter.ranges.max = 16000.0f; | |||
| break; | |||
| case paramPhase: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Phase"; | |||
| parameter.symbol = "phs"; | |||
| parameter.unit = "Deg"; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = -1.0f; | |||
| parameter.ranges.max = 1.0f; | |||
| break; | |||
| case paramWave: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Wave"; | |||
| parameter.symbol = "wav"; | |||
| parameter.unit = ""; | |||
| parameter.ranges.def = 2.0f; | |||
| parameter.ranges.min = 1.0f; | |||
| parameter.ranges.max = 4.0f; | |||
| break; | |||
| case paramDrive: | |||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | |||
| parameter.name = "Drive"; | |||
| parameter.symbol = "drv"; | |||
| parameter.unit = "amount"; | |||
| parameter.ranges.def = 0.1f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 1.0f; | |||
| break; | |||
| } | |||
| } | |||
| void WobbleJuicePlugin::d_initProgramName(uint32_t index, d_string& programName) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| programName = "Default"; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Internal data | |||
| float WobbleJuicePlugin::d_getParameterValue(uint32_t index) const | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramDivision: | |||
| return division; | |||
| case paramReso: | |||
| return reso; | |||
| case paramRange: | |||
| return range; | |||
| case paramPhase: | |||
| return phase; | |||
| case paramWave: | |||
| return wave; | |||
| case paramDrive: | |||
| return drive; | |||
| default: | |||
| return 0.0f; | |||
| } | |||
| } | |||
| void WobbleJuicePlugin::d_setParameterValue(uint32_t index, float value) | |||
| { | |||
| switch (index) | |||
| { | |||
| case paramDivision: | |||
| division = value; | |||
| break; | |||
| case paramReso: | |||
| reso = value; | |||
| break; | |||
| case paramRange: | |||
| range = value; | |||
| break; | |||
| case paramPhase: | |||
| phase = value; | |||
| break; | |||
| case paramWave: | |||
| wave = value; | |||
| break; | |||
| case paramDrive: | |||
| drive = value; | |||
| break; | |||
| } | |||
| } | |||
| void WobbleJuicePlugin::d_setProgram(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| /* Default parameter values */ | |||
| division = 4.0f; | |||
| reso = 0.1f; | |||
| range = 16000.0f; | |||
| phase = 0.0f; | |||
| wave = 2.0f; | |||
| drive = 0.5f; | |||
| /* Default variable values */ | |||
| bar=tick=tickOffset=percentage=phaseOffset=currentPhaseL=0; | |||
| currentPhaseR=posL=posR=cutoffL=cutoffR=0; | |||
| waveType = 2; | |||
| /* reset filter values */ | |||
| d_activate(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Process | |||
| void WobbleJuicePlugin::d_activate() | |||
| { | |||
| sinePos = 0; | |||
| } | |||
| void WobbleJuicePlugin::d_deactivate() | |||
| { | |||
| // all values to zero | |||
| } | |||
| void WobbleJuicePlugin::d_run(float** inputs, float** outputs, uint32_t frames) | |||
| { | |||
| //fetch the timepos struct from host; | |||
| const TimePos& time = d_getTimePos(); | |||
| /* sample count for one bar */ | |||
| bar = ((120.0/(time.bbt.valid ? time.bbt.beatsPerMinute : 120.0))*(d_getSampleRate())); //ONE, two, three, four | |||
| tick = bar/(std::round(division)); //size of one target wob | |||
| phaseOffset = phase*M_PI; //2pi = 1 whole cycle | |||
| if (time.playing) | |||
| { | |||
| /* if rolling then sync to timepos */ | |||
| tickOffset = time.frame-std::floor(time.frame/tick)*tick; //how much after last tick | |||
| if (tickOffset!=0) { | |||
| //TODO: why do we need this?? | |||
| percentage = tickOffset/tick; | |||
| } else { | |||
| percentage = 0; | |||
| } | |||
| sinePos = (M_PI*2)*percentage; | |||
| if (sinePos>2*M_PI) { | |||
| //TODO: can this ever happen?? | |||
| sinePos = 0; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| /* else just keep on wobblin' */ | |||
| sinePos += (M_PI)/(tick/2000); //wtf, but works | |||
| if (sinePos>2*M_PI) { | |||
| sinePos = 0; | |||
| } | |||
| } | |||
| /* phase of 0..1 filter = 500..16k */ | |||
| currentPhaseL = getBlendedPhase(sinePos+phaseOffset, wave); | |||
| currentPhaseR = getBlendedPhase(sinePos-phaseOffset, wave); | |||
| /* logarithmic */ | |||
| cutoffL = std::exp((std::log(range)-std::log(500))*currentPhaseL+std::log(500)); | |||
| cutoffR = std::exp((std::log(range)-std::log(500))*currentPhaseR+std::log(500)); | |||
| //output filtered signal | |||
| filterL.recalc(cutoffL, reso*4, d_getSampleRate(), drive); | |||
| filterR.recalc(cutoffR, reso*4, d_getSampleRate(), drive); | |||
| filterL.process(frames, inputs[0], outputs[0]); | |||
| filterR.process(frames, inputs[1], outputs[1]); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| Plugin* createPlugin() | |||
| { | |||
| return new WobbleJuicePlugin(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,142 @@ | |||
| /* | |||
| * Wobble Juice Plugin | |||
| * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #ifndef WOBBLEJUICEPLUGIN_HPP_INCLUDED | |||
| #define WOBBLEJUICEPLUGIN_HPP_INCLUDED | |||
| #include "DistrhoPlugin.hpp" | |||
| #include "moogVCF.hxx" | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| class WobbleJuicePlugin : public Plugin | |||
| { | |||
| public: | |||
| enum Parameters | |||
| { | |||
| paramDivision = 0, | |||
| paramReso, | |||
| paramRange, | |||
| paramPhase, | |||
| paramWave, | |||
| paramDrive, | |||
| paramCount | |||
| }; | |||
| float getSinePhase(float x) { | |||
| return ((-std::cos(x)+1)/2); | |||
| } | |||
| float getSawPhase(float x) { | |||
| return (-((2/M_PI * std::atan(1/std::tan(x/2)))-1)/2); | |||
| } | |||
| float getRevSawPhase(float x) { | |||
| return (((2/M_PI * std::atan(1/std::tan(x/2)))+1)/2); | |||
| } | |||
| float getSquarePhase(float x) { | |||
| return (std::round((std::sin(x)+1)/2)); | |||
| } | |||
| //saw, sqr, sin, revSaw | |||
| float getBlendedPhase(float x, float wave) | |||
| { | |||
| //wave = 2; | |||
| if (wave>=1 && wave<2) { | |||
| /* saw vs sqr */ | |||
| waveBlend = wave-1; | |||
| return (getSawPhase(x)*(1-waveBlend) + getSquarePhase(x)*waveBlend); | |||
| } else if (wave>=2 && wave<3) { | |||
| /* sqr vs sin */ | |||
| waveBlend = wave-2; | |||
| return (getSquarePhase(x)*(1-waveBlend) + getSinePhase(x)*waveBlend); | |||
| } else if (wave>=3 && wave<=4) { | |||
| /* sin vs revSaw */ | |||
| waveBlend = wave-3; | |||
| return (getSinePhase(x)*(1-waveBlend) + getRevSawPhase(x)*waveBlend); | |||
| } else { | |||
| return 0.0f; | |||
| } | |||
| } | |||
| WobbleJuicePlugin(); | |||
| ~WobbleJuicePlugin() override; | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // Information | |||
| const char* d_getLabel() const noexcept override | |||
| { | |||
| return "WobbleJuice"; | |||
| } | |||
| const char* d_getMaker() const noexcept override | |||
| { | |||
| return "Andre Sklenar"; | |||
| } | |||
| const char* d_getLicense() const noexcept override | |||
| { | |||
| return "GPL v2+"; | |||
| } | |||
| uint32_t d_getVersion() const noexcept override | |||
| { | |||
| return 0x1000; | |||
| } | |||
| long d_getUniqueId() const noexcept override | |||
| { | |||
| return d_cconst('W', 'b', 'l', 'J'); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // Init | |||
| void d_initParameter(uint32_t index, Parameter& parameter) override; | |||
| void d_initProgramName(uint32_t index, d_string& programName) override; | |||
| // ------------------------------------------------------------------- | |||
| // Internal data | |||
| float d_getParameterValue(uint32_t index) const override; | |||
| void d_setParameterValue(uint32_t index, float value) override; | |||
| void d_setProgram(uint32_t index) override; | |||
| // ------------------------------------------------------------------- | |||
| // Process | |||
| void d_activate() override; | |||
| void d_deactivate() override; | |||
| void d_run(float** inputs, float** outputs, uint32_t frames) override; | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| MoogVCF filterL, filterR; | |||
| float division, reso, range, phase, wave, drive; //parameters | |||
| float bar, tick, tickOffset, percentage, phaseOffset, currentPhaseL, currentPhaseR, posL, posR, cutoffL, cutoffR; | |||
| double sinePos; | |||
| float waveType, waveBlend; | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // WOBBLEJUICE_HPP_INCLUDED | |||
| @@ -0,0 +1,223 @@ | |||
| /* | |||
| * Wobble Juice Plugin | |||
| * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "WobbleJuiceUI.hpp" | |||
| using DGL::Point; | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| WobbleJuiceUI::WobbleJuiceUI() | |||
| : UI(), | |||
| fAboutWindow(this) | |||
| { | |||
| // background | |||
| fImgBackground = Image(WobbleJuiceArtwork::backgroundData, WobbleJuiceArtwork::backgroundWidth, WobbleJuiceArtwork::backgroundHeight, GL_BGR); | |||
| // about | |||
| Image imageAbout(WobbleJuiceArtwork::aboutData, WobbleJuiceArtwork::aboutWidth, WobbleJuiceArtwork::aboutHeight, GL_BGR); | |||
| fAboutWindow.setImage(imageAbout); | |||
| // knobs | |||
| Image knobImage(WobbleJuiceArtwork::knobData, WobbleJuiceArtwork::knobWidth, WobbleJuiceArtwork::knobHeight); | |||
| // knob Division | |||
| fKnobDivision = new ImageKnob(this, knobImage); | |||
| fKnobDivision->setPos(222, 74); | |||
| fKnobDivision->setRange(1.0f, 16.0f); | |||
| fKnobDivision->setStep(1.0f); | |||
| fKnobDivision->setValue(4.0f); | |||
| fKnobDivision->setRotationAngle(270); | |||
| fKnobDivision->setCallback(this); | |||
| // knob Resonance | |||
| fKnobResonance = new ImageKnob(this, knobImage); | |||
| fKnobResonance->setPos(222, 199); | |||
| fKnobResonance->setRange(0.0f, 0.2f); | |||
| fKnobResonance->setValue(0.1f); | |||
| fKnobResonance->setRotationAngle(270); | |||
| fKnobResonance->setCallback(this); | |||
| // knob Range | |||
| fKnobRange = new ImageKnob(this, knobImage); | |||
| fKnobRange->setPos(77, 199); | |||
| fKnobRange->setRange(500.0f, 16000.0f); | |||
| fKnobRange->setValue(16000.0f); | |||
| fKnobRange->setRotationAngle(270); | |||
| fKnobRange->setCallback(this); | |||
| // knob Wave | |||
| fKnobWave = new ImageKnob(this, knobImage); | |||
| fKnobWave->setPos(77, 74); | |||
| fKnobWave->setRange(1.0f, 4.0f); | |||
| fKnobWave->setValue(2.0f); | |||
| fKnobWave->setRotationAngle(270); | |||
| fKnobWave->setCallback(this); | |||
| // knob Drive | |||
| fKnobDrive = new ImageKnob(this, knobImage); | |||
| fKnobDrive->setPos(362, 199); | |||
| fKnobDrive->setRange(0.0f, 1.0f); | |||
| fKnobDrive->setValue(0.5f); | |||
| fKnobDrive->setRotationAngle(270); | |||
| fKnobDrive->setCallback(this); | |||
| // knob Phase | |||
| fKnobPhase = new ImageKnob(this, knobImage); | |||
| fKnobPhase->setPos(362, 74); | |||
| fKnobPhase->setRange(-1.0f, 1.0f); | |||
| fKnobPhase->setValue(0.0f); | |||
| fKnobPhase->setRotationAngle(270); | |||
| fKnobPhase->setCallback(this); | |||
| // about button | |||
| Image aboutImageNormal(WobbleJuiceArtwork::aboutButtonNormalData, WobbleJuiceArtwork::aboutButtonNormalWidth, WobbleJuiceArtwork::aboutButtonNormalHeight); | |||
| Image aboutImageHover(WobbleJuiceArtwork::aboutButtonHoverData, WobbleJuiceArtwork::aboutButtonHoverWidth, WobbleJuiceArtwork::aboutButtonHoverHeight); | |||
| fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||
| fButtonAbout->setPos(390, 20); | |||
| fButtonAbout->setCallback(this); | |||
| } | |||
| WobbleJuiceUI::~WobbleJuiceUI() | |||
| { | |||
| delete fKnobDivision; | |||
| delete fKnobResonance; | |||
| delete fKnobRange; | |||
| delete fKnobWave; | |||
| delete fKnobDrive; | |||
| delete fKnobPhase; | |||
| delete fButtonAbout; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // DSP Callbacks | |||
| void WobbleJuiceUI::d_parameterChanged(uint32_t index, float value) | |||
| { | |||
| switch (index) | |||
| { | |||
| case WobbleJuicePlugin::paramDivision: | |||
| fKnobDivision->setValue(value); | |||
| break; | |||
| case WobbleJuicePlugin::paramReso: | |||
| fKnobResonance->setValue(value); | |||
| break; | |||
| case WobbleJuicePlugin::paramRange: | |||
| fKnobRange->setValue(value); | |||
| break; | |||
| case WobbleJuicePlugin::paramPhase: | |||
| fKnobPhase->setValue(value); | |||
| break; | |||
| case WobbleJuicePlugin::paramWave: | |||
| fKnobWave->setValue(value); | |||
| break; | |||
| case WobbleJuicePlugin::paramDrive: | |||
| fKnobDrive->setValue(value); | |||
| break; | |||
| } | |||
| } | |||
| void WobbleJuiceUI::d_programChanged(uint32_t index) | |||
| { | |||
| if (index != 0) | |||
| return; | |||
| // Default values | |||
| fKnobDivision->setValue(4.0f); | |||
| fKnobResonance->setValue(0.1f); | |||
| fKnobRange->setValue(16000.0f); | |||
| fKnobPhase->setValue(.0f); | |||
| fKnobWave->setValue(2.0f); | |||
| fKnobDrive->setValue(0.5f); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Widget Callbacks | |||
| void WobbleJuiceUI::imageButtonClicked(ImageButton* button, int) | |||
| { | |||
| if (button != fButtonAbout) | |||
| return; | |||
| fAboutWindow.exec(); | |||
| } | |||
| void WobbleJuiceUI::imageKnobDragStarted(ImageKnob* knob) | |||
| { | |||
| if (knob == fKnobDivision) | |||
| d_editParameter(WobbleJuicePlugin::paramDivision, true); | |||
| else if (knob == fKnobResonance) | |||
| d_editParameter(WobbleJuicePlugin::paramReso, true); | |||
| else if (knob == fKnobRange) | |||
| d_editParameter(WobbleJuicePlugin::paramRange, true); | |||
| else if (knob == fKnobPhase) | |||
| d_editParameter(WobbleJuicePlugin::paramPhase, true); | |||
| else if (knob == fKnobWave) | |||
| d_editParameter(WobbleJuicePlugin::paramWave, true); | |||
| else if (knob == fKnobDrive) | |||
| d_editParameter(WobbleJuicePlugin::paramDrive, true); | |||
| } | |||
| void WobbleJuiceUI::imageKnobDragFinished(ImageKnob* knob) | |||
| { | |||
| if (knob == fKnobDivision) | |||
| d_editParameter(WobbleJuicePlugin::paramDivision, false); | |||
| else if (knob == fKnobResonance) | |||
| d_editParameter(WobbleJuicePlugin::paramReso, false); | |||
| else if (knob == fKnobRange) | |||
| d_editParameter(WobbleJuicePlugin::paramRange, false); | |||
| else if (knob == fKnobPhase) | |||
| d_editParameter(WobbleJuicePlugin::paramPhase, false); | |||
| else if (knob == fKnobWave) | |||
| d_editParameter(WobbleJuicePlugin::paramWave, false); | |||
| else if (knob == fKnobDrive) | |||
| d_editParameter(WobbleJuicePlugin::paramDrive, false); | |||
| } | |||
| void WobbleJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | |||
| { | |||
| if (knob == fKnobDivision) | |||
| d_setParameterValue(WobbleJuicePlugin::paramDivision, value); | |||
| else if (knob == fKnobResonance) | |||
| d_setParameterValue(WobbleJuicePlugin::paramReso, value); | |||
| else if (knob == fKnobRange) | |||
| d_setParameterValue(WobbleJuicePlugin::paramRange, value); | |||
| else if (knob == fKnobPhase) | |||
| d_setParameterValue(WobbleJuicePlugin::paramPhase, value); | |||
| else if (knob == fKnobWave) | |||
| d_setParameterValue(WobbleJuicePlugin::paramWave, value); | |||
| else if (knob == fKnobDrive) | |||
| d_setParameterValue(WobbleJuicePlugin::paramDrive, value); | |||
| } | |||
| void WobbleJuiceUI::onDisplay() | |||
| { | |||
| fImgBackground.draw(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| UI* createUI() | |||
| { | |||
| return new WobbleJuiceUI(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,95 @@ | |||
| /* | |||
| * Wobble Juice Plugin | |||
| * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #ifndef WOBBLEJUICEUI_HPP_INCLUDED | |||
| #define WOBBLEJUICEUI_HPP_INCLUDED | |||
| #include "DistrhoUI.hpp" | |||
| #include "ImageAboutWindow.hpp" | |||
| #include "ImageButton.hpp" | |||
| #include "ImageKnob.hpp" | |||
| #include "ImageSlider.hpp" | |||
| #include "WobbleJuiceArtwork.hpp" | |||
| #include "WobbleJuicePlugin.hpp" | |||
| using DGL::Image; | |||
| using DGL::ImageAboutWindow; | |||
| using DGL::ImageButton; | |||
| using DGL::ImageKnob; | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| class WobbleJuiceUI : public UI, | |||
| public ImageButton::Callback, | |||
| public ImageKnob::Callback | |||
| { | |||
| public: | |||
| WobbleJuiceUI(); | |||
| ~WobbleJuiceUI() override; | |||
| protected: | |||
| // ------------------------------------------------------------------- | |||
| // Information | |||
| unsigned int d_getWidth() const noexcept override | |||
| { | |||
| return WobbleJuiceArtwork::backgroundWidth; | |||
| } | |||
| unsigned int d_getHeight() const noexcept override | |||
| { | |||
| return WobbleJuiceArtwork::backgroundHeight; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // DSP Callbacks | |||
| void d_parameterChanged(uint32_t index, float value) override; | |||
| void d_programChanged(uint32_t index) override; | |||
| // ------------------------------------------------------------------- | |||
| // Widget Callbacks | |||
| void imageButtonClicked(ImageButton* button, int) override; | |||
| void imageKnobDragStarted(ImageKnob* knob) override; | |||
| void imageKnobDragFinished(ImageKnob* knob) override; | |||
| void imageKnobValueChanged(ImageKnob* knob, float value) override; | |||
| void onDisplay() override; | |||
| private: | |||
| Image fImgBackground; | |||
| ImageAboutWindow fAboutWindow; | |||
| ImageKnob* fKnobDivision; | |||
| ImageKnob* fKnobResonance; | |||
| ImageKnob* fKnobRange; | |||
| ImageKnob* fKnobPhase; | |||
| ImageKnob* fKnobDrive; | |||
| ImageKnob* fKnobWave; | |||
| ImageButton* fButtonAbout; | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // WOBBLEJUICEUI_HPP_INCLUDED | |||
| @@ -0,0 +1,76 @@ | |||
| /* | |||
| * Moog-like resonant LPF | |||
| * Implemented by Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz . | |||
| * | |||
| * Filter design from http://www.musicdsp.com . | |||
| */ | |||
| #ifndef MOOG_VCF_HXX_INCLUDED | |||
| #define MOOG_VCF_HXX_INCLUDED | |||
| #include <cmath> | |||
| #include <cstdlib> | |||
| class MoogVCF | |||
| { | |||
| public: | |||
| MoogVCF() | |||
| { | |||
| cutoff = 16000; | |||
| res = 0.5; | |||
| f=k=p=scale=r=0; | |||
| y1=y2=y3=y4=oldIn=oldY1=oldY2=oldY3=0; | |||
| in=oldIn=0; | |||
| pureInput=drivenInput=processedInput=0; | |||
| } | |||
| void recalc(float cutoff, float reso, int sr, float nDrive) | |||
| { | |||
| f = 2*cutoff/sr; | |||
| k=2*std::sin(f*M_PI/2)-1; | |||
| p = (k+1)*0.5; | |||
| scale = std::pow(2.71828, (1-p)*1.386249); | |||
| r = reso*scale; | |||
| drive = nDrive; | |||
| } | |||
| void process (long frames, float* inputs, float* outputs) | |||
| { | |||
| //run the shit | |||
| for (long i=0; i<frames; i++) | |||
| { | |||
| pureInput = inputs[i]; //clean signal | |||
| drivenInput = std::tanh(pureInput*(drive*15+1)) * (drive); //a touch of waveshaping | |||
| processedInput = pureInput*(1-drive) + drivenInput; // combine | |||
| processedInput*=1-drive/3; //reduce gain a little | |||
| /* filter */ | |||
| in = processedInput-r*y4; | |||
| y1 = in*p + oldIn*p - k*y1; | |||
| y2 = y1*p + oldY1*p - k*y2; | |||
| y3 = y2*p + oldY2*p - k*y3; | |||
| y4 = y3*p + oldY3*p - k*y4; | |||
| oldIn = in; | |||
| oldY1 = y1; | |||
| oldY2 = y2; | |||
| oldY3 = y3; | |||
| /* output */ | |||
| outputs[i] = y4; | |||
| } | |||
| } | |||
| private: | |||
| /* vcf filter */ | |||
| float cutoff; //freq in Hz | |||
| float res; //resonance 0..1 | |||
| float drive; //drive 1...2; | |||
| float f, k, p, scale, r; | |||
| float y1, y2, y3, y4, oldY1, oldY2, oldY3; | |||
| float in, oldIn; | |||
| /* waveshaping vars */ | |||
| float pureInput, drivenInput, processedInput; | |||
| }; | |||
| #endif // MOOG_VCF_HXX_INCLUDED | |||