@@ -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 |