| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| #!/usr/bin/make -f | ||
| # Makefile for DISTRHO Plugins # | ||
| # ---------------------------- # | ||
| # Created by falkTX | ||
| # | ||
|
|
||
| CC ?= gcc | ||
| CXX ?= g++ | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Fallback to Linux if no other OS defined | ||
|
|
||
| ifneq ($(HAIKU),true) | ||
| ifneq ($(MACOS),true) | ||
| ifneq ($(WIN32),true) | ||
| LINUX=true | ||
| endif | ||
| endif | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Common build and link flags | ||
|
|
||
| BASE_FLAGS = -Wall -Wextra -pipe | ||
| BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections | ||
| ifneq ($(NOOPT),true) | ||
| BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse | ||
| endif | ||
| LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-O1 -Wl,--as-needed -Wl,--gc-sections -Wl,--strip-all | ||
|
|
||
| ifeq ($(MACOS),true) | ||
| # MacOS linker flags | ||
| LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip -Wl,-dead_strip_dylibs | ||
| endif | ||
|
|
||
| ifeq ($(RASPPI),true) | ||
| # Raspberry-Pi flags | ||
| BASE_OPTS = -O2 -ffast-math | ||
| ifneq ($(NOOPT),true) | ||
| BASE_OPTS += -march=armv6 -mfpu=vfp -mfloat-abi=hard | ||
| endif | ||
| LINK_OPTS = -Wl,-O1 -Wl,--as-needed -Wl,--strip-all | ||
| endif | ||
|
|
||
| ifeq ($(PANDORA),true) | ||
| # OpenPandora flags | ||
| BASE_OPTS = -O2 -ffast-math | ||
| ifneq ($(NOOPT),true) | ||
| BASE_OPTS += -march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -mfloat-abi=softfp | ||
| endif | ||
| LINK_OPTS = -Wl,-O1 -Wl,--as-needed -Wl,--strip-all | ||
| endif | ||
|
|
||
| ifneq ($(WIN32),true) | ||
| # not needed for Windows | ||
| BASE_FLAGS += -fPIC -DPIC | ||
| endif | ||
|
|
||
| ifeq ($(DEBUG),true) | ||
| BASE_FLAGS += -DDEBUG -O0 -g | ||
| LINK_OPTS = | ||
| else | ||
| BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden | ||
| CXXFLAGS += -fvisibility-inlines-hidden | ||
| endif | ||
|
|
||
| BUILD_C_FLAGS = $(BASE_FLAGS) -std=c99 -std=gnu99 $(CFLAGS) | ||
| BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x -std=gnu++0x $(CXXFLAGS) $(CPPFLAGS) | ||
| LINK_FLAGS = $(LINK_OPTS) -Wl,--no-undefined $(LDFLAGS) | ||
|
|
||
| ifeq ($(MACOS),true) | ||
| # No C++11 support | ||
| BUILD_CXX_FLAGS = $(BASE_FLAGS) $(CXXFLAGS) $(CPPFLAGS) | ||
| LINK_FLAGS = $(LINK_OPTS) $(LDFLAGS) | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Check for required libs | ||
|
|
||
| ifeq ($(LINUX),true) | ||
| ifneq ($(shell pkg-config --exists jack && echo true),true) | ||
| $(error JACK missing, cannot continue) | ||
| endif | ||
| ifneq ($(shell pkg-config --exists gl && echo true),true) | ||
| $(error OpenGL missing, cannot continue) | ||
| endif | ||
| ifneq ($(shell pkg-config --exists x11 && echo true),true) | ||
| $(error X11 missing, cannot continue) | ||
| endif | ||
| endif | ||
|
|
||
| ifneq ($(shell pkg-config --exists liblo && echo true),true) | ||
| $(error liblo missing, cannot continue) | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Set libs stuff | ||
|
|
||
| ifeq ($(LINUX),true) | ||
| DGL_FLAGS = $(shell pkg-config --cflags gl x11) | ||
| DGL_LIBS = $(shell pkg-config --libs gl x11) | ||
| endif | ||
|
|
||
| ifeq ($(MACOS),true) | ||
| DGL_LIBS = -framework OpenGL -framework Cocoa | ||
| endif | ||
|
|
||
| ifeq ($(WIN32),true) | ||
| DGL_LIBS = -lopengl32 -lgdi32 | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Set extension | ||
|
|
||
| EXT = so | ||
|
|
||
| ifeq ($(MACOS),true) | ||
| EXT = dylib | ||
| endif | ||
|
|
||
| ifeq ($(WIN32),true) | ||
| EXT = dll | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Set shared library CLI arg | ||
|
|
||
| SHARED = -shared | ||
|
|
||
| ifeq ($(MACOS),true) | ||
| SHARED = -dynamiclib | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # DISTRHO Juice Plugins | ||
|
|
||
| TODO... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| All final plugin builds will be placed in this folder. | ||
|
|
||
| There is no "make install" process, simply copy those files to their appropriate place. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| #!/usr/bin/make -f | ||
| # Makefile for DISTRHO Plugins # | ||
| # ---------------------------- # | ||
| # Created by falkTX | ||
| # | ||
|
|
||
| # NAME, OBJS_DSP and OBJS_UI have been defined before | ||
|
|
||
| include ../../Makefile.mk | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Basic setup | ||
|
|
||
| TARGET_DIR = ../../bin | ||
|
|
||
| BUILD_C_FLAGS += -I. | ||
| BUILD_CXX_FLAGS += -I. -I../../dpf/distrho -I../../dpf/dgl | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Set plugin binary file targets | ||
|
|
||
| jack = $(TARGET_DIR)/$(NAME) | ||
| ladspa_dsp = $(TARGET_DIR)/$(NAME)-ladspa.$(EXT) | ||
| dssi_dsp = $(TARGET_DIR)/$(NAME)-dssi.$(EXT) | ||
| dssi_ui = $(TARGET_DIR)/$(NAME)-dssi/$(NAME)_ui | ||
| lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME).$(EXT) | ||
| lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp.$(EXT) | ||
| lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui.$(EXT) | ||
| vst = $(TARGET_DIR)/$(NAME)-vst.$(EXT) | ||
|
|
||
| ifeq ($(WIN32),true) | ||
| dssi_ui += .exe | ||
| endif | ||
|
|
||
| # TODO: MacOS VST bundle | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Set distrho code files | ||
|
|
||
| DISTRHO_PLUGIN_FILES = ../../dpf/distrho/DistrhoPluginMain.cpp | ||
| DISTRHO_UI_FILES = ../../dpf/distrho/DistrhoUIMain.cpp ../../dpf/libdgl.a | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Handle plugins without UI | ||
|
|
||
| ifeq ($(TARGET_NOUI),true) | ||
| dssi_ui = | ||
| lv2_ui = | ||
| DISTRHO_UI_FILES = | ||
| DGL_LIBS = | ||
| OBJS_UI = | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # all needs to be first | ||
|
|
||
| all: | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Common | ||
|
|
||
| %.c.o: %.c | ||
| $(CC) $< $(BUILD_C_FLAGS) -c -o $@ | ||
|
|
||
| %.cpp.o: %.cpp | ||
| $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||
|
|
||
| clean: | ||
| rm -f *.o | ||
| rm -rf $(TARGET_DIR)/$(NAME) $(TARGET_DIR)/$(NAME)-* $(TARGET_DIR)/$(NAME).lv2/ | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # JACK | ||
|
|
||
| jack: $(jack) | ||
|
|
||
| $(jack): $(OBJS_DSP) $(OBJS_UI) $(DISTRHO_PLUGIN_FILES) $(DISTRHO_UI_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell pkg-config --cflags --libs jack) -DDISTRHO_PLUGIN_TARGET_JACK -o $@ | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # LADSPA | ||
|
|
||
| ladspa: $(ladspa_dsp) | ||
|
|
||
| $(ladspa_dsp): $(OBJS_DSP) $(DISTRHO_PLUGIN_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -DDISTRHO_PLUGIN_TARGET_LADSPA -o $@ | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # DSSI | ||
|
|
||
| dssi: $(dssi_dsp) $(dssi_ui) | ||
|
|
||
| $(dssi_dsp): $(OBJS_DSP) $(DISTRHO_PLUGIN_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -DDISTRHO_PLUGIN_TARGET_DSSI -o $@ | ||
|
|
||
| $(dssi_ui): $(OBJS_UI) $(DISTRHO_UI_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell pkg-config --cflags --libs liblo) -DDISTRHO_PLUGIN_TARGET_DSSI -o $@ | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # LV2 | ||
|
|
||
| lv2_one: $(lv2) | ||
| lv2_sep: $(lv2_dsp) $(lv2_ui) | ||
|
|
||
| $(lv2): $(OBJS_DSP) $(OBJS_UI) $(DISTRHO_PLUGIN_FILES) $(DISTRHO_UI_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -DDISTRHO_PLUGIN_TARGET_LV2 -o $@ | ||
|
|
||
| $(lv2_dsp): $(OBJS_DSP) $(DISTRHO_PLUGIN_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -DDISTRHO_PLUGIN_TARGET_LV2 -o $@ | ||
|
|
||
| $(lv2_ui): $(OBJS_UI) $(DISTRHO_UI_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -DDISTRHO_PLUGIN_TARGET_LV2 -o $@ | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # VST | ||
|
|
||
| vst: $(vst) | ||
|
|
||
| $(vst): $(OBJS_DSP) $(OBJS_UI) $(DISTRHO_PLUGIN_FILES) $(DISTRHO_UI_FILES) | ||
| mkdir -p $(shell dirname $@) | ||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -DDISTRHO_PLUGIN_TARGET_VST -o $@ | ||
|
|
||
| # -------------------------------------------------------------- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /* | ||
| * Power 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 "PowerJuice" | ||
|
|
||
| #define DISTRHO_PLUGIN_HAS_UI 1 | ||
| #define DISTRHO_PLUGIN_IS_SYNTH 0 | ||
|
|
||
| #define DISTRHO_PLUGIN_NUM_INPUTS 1 | ||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 1 | ||
|
|
||
| #define DISTRHO_PLUGIN_WANT_LATENCY 0 | ||
| #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | ||
| #define DISTRHO_PLUGIN_WANT_STATE 0 | ||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 0 | ||
|
|
||
| // needed for spectrum | ||
| #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | ||
|
|
||
| #define DISTRHO_PLUGIN_URI "urn:distrho:PowerJuice" | ||
|
|
||
| #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/make -f | ||
| # Makefile for DISTRHO Plugins # | ||
| # ---------------------------- # | ||
| # Created by falkTX | ||
| # | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Project name, used for binaries | ||
|
|
||
| NAME = PowerJuice | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Files to build | ||
|
|
||
| OBJS_DSP = \ | ||
| PowerJuicePlugin.cpp.o | ||
|
|
||
| OBJS_UI = \ | ||
| PowerJuiceArtwork.cpp.o \ | ||
| PowerJuiceUI.cpp.o | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Do some magic | ||
|
|
||
| include ../Makefile.mk | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Enable all possible plugin types | ||
|
|
||
| ifeq ($(LINUX),true) | ||
| all: jack lv2_one vst | ||
| else | ||
| all: lv2_one vst | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /* (Auto-generated binary data file). */ | ||
|
|
||
| #ifndef BINARY_POWERJUICEARTWORK_HPP | ||
| #define BINARY_POWERJUICEARTWORK_HPP | ||
|
|
||
| namespace PowerJuiceArtwork | ||
| { | ||
| 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 = 571956; | ||
| const unsigned int backgroundWidth = 619; | ||
| const unsigned int backgroundHeight = 308; | ||
|
|
||
| extern const char* knobData; | ||
| const unsigned int knobDataSize = 10404; | ||
| const unsigned int knobWidth = 51; | ||
| const unsigned int knobHeight = 51; | ||
| } | ||
|
|
||
| #endif // BINARY_POWERJUICEARTWORK_HPP | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,379 @@ | ||
| /* | ||
| * Power 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 "PowerJuicePlugin.hpp" | ||
| //#include <cstring> | ||
| #include <cstdlib> | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| PowerJuicePlugin::PowerJuicePlugin() | ||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | ||
| { | ||
| // set default values | ||
| d_setProgram(0); | ||
|
|
||
| // reset | ||
| d_deactivate(); | ||
| } | ||
|
|
||
| PowerJuicePlugin::~PowerJuicePlugin() | ||
| { | ||
| free(lookaheadStack.data); | ||
| free(RMSStack.data); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Init | ||
|
|
||
| void PowerJuicePlugin::d_initParameter(uint32_t index, Parameter& parameter) | ||
| { | ||
| switch (index) | ||
| { | ||
| case paramAttack: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Attack"; | ||
| parameter.symbol = "att"; | ||
| parameter.unit = "ms"; | ||
| parameter.ranges.def = 20.0f; | ||
| parameter.ranges.min = 0.1f; | ||
| parameter.ranges.max = 1000.0f; | ||
| break; | ||
| case paramRelease: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Release"; | ||
| parameter.symbol = "rel"; | ||
| parameter.unit = "ms"; | ||
| parameter.ranges.def = 200.0f; | ||
| parameter.ranges.min = 0.1f; | ||
| parameter.ranges.max = 1000.0f; | ||
| break; | ||
| case paramThreshold: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Threshold"; | ||
| parameter.symbol = "thr"; | ||
| parameter.unit = "dB"; | ||
| parameter.ranges.def = 0.0f; | ||
| parameter.ranges.min = -60.0f; | ||
| parameter.ranges.max = 0.0f; | ||
| break; | ||
| case paramRatio: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Ratio"; | ||
| parameter.symbol = "rat"; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 1.0f; | ||
| parameter.ranges.min = 1.0f; | ||
| parameter.ranges.max = 10.0f; | ||
| break; | ||
| case paramMakeup: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Make-Up"; | ||
| parameter.symbol = "mak"; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 0.0f; | ||
| parameter.ranges.min = 0.0f; | ||
| parameter.ranges.max = 20.0f; | ||
| break; | ||
| case paramMix: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Mix"; | ||
| parameter.symbol = "Mix"; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 1.0f; | ||
| parameter.ranges.min = 0.0f; | ||
| parameter.ranges.max = 1.0f; | ||
| break; | ||
|
|
||
| } | ||
| } | ||
|
|
||
| void PowerJuicePlugin::d_initProgramName(uint32_t index, d_string& programName) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| programName = "Default"; | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Internal data | ||
|
|
||
| float PowerJuicePlugin::d_getParameterValue(uint32_t index) const | ||
| { | ||
| switch (index) | ||
| { | ||
| case paramAttack: | ||
| return attack; | ||
| case paramRelease: | ||
| return release; | ||
| case paramThreshold: | ||
| return threshold; | ||
| case paramRatio: | ||
| return ratio; | ||
| case paramMakeup: | ||
| return makeup; | ||
| case paramMix: | ||
| return mix; | ||
| default: | ||
| return 0.0f; | ||
| } | ||
| } | ||
|
|
||
| void PowerJuicePlugin::d_setParameterValue(uint32_t index, float value) | ||
| { | ||
| switch (index) | ||
| { | ||
| case paramAttack: | ||
| attack = value; | ||
| attackSamples = d_getSampleRate()*(attack/1000.0f); | ||
| break; | ||
| case paramRelease: | ||
| release = value; | ||
| releaseSamples = d_getSampleRate()*(release/1000.0f); | ||
| break; | ||
| case paramThreshold: | ||
| threshold = value; | ||
| break; | ||
| case paramRatio: | ||
| ratio = value; | ||
| break; | ||
| case paramMakeup: | ||
| makeup = value; | ||
| makeupFloat = fromDB(makeup); | ||
| break; | ||
| case paramMix: | ||
| mix = value; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| void PowerJuicePlugin::d_setProgram(uint32_t index) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| /* Default parameter values */ | ||
| attack = 20.0f; | ||
| release = 200.0f; | ||
| threshold = 0.0f; | ||
| ratio = 1.0f; | ||
| makeup = 0.0f; | ||
| mix = 1.0f; | ||
|
|
||
| makeupFloat = fromDB(makeup); | ||
| attackSamples = d_getSampleRate()*(attack/1000.0f); | ||
| releaseSamples = d_getSampleRate()*(release/1000.0f); | ||
|
|
||
|
|
||
|
|
||
| w = 563; //waveform plane size, size of the plane in pixels; | ||
| w2 = 1126; //wavefowm array | ||
| h = 121; //waveform plane height | ||
| x = 27; //waveform plane positions | ||
| y = 53; | ||
| dc = 113; //0DC line y position | ||
|
|
||
| /* Default variable values */ | ||
| averageCounter = 0; | ||
| inputMax = 0.0f; | ||
|
|
||
| balancer = 1.0f; | ||
| GR = 1.0f; | ||
|
|
||
| newRepaint = false; | ||
|
|
||
| input.start = 0; | ||
| rms.start = 0; | ||
| gainReduction.start = 0; | ||
| RMSStack.start = 0; | ||
| lookaheadStack.start = 0; | ||
| repaintSkip = 0; | ||
|
|
||
|
|
||
| kFloatRMSStackCount = 400.0f/44100.0f*d_getSampleRate(); | ||
| RMSStack.data = (float*) calloc(kFloatRMSStackCount, sizeof(float)); | ||
|
|
||
| kFloatLookaheadStackCount = 800.0f/44100.0f*d_getSampleRate(); | ||
| lookaheadStack.data = (float*) calloc(kFloatLookaheadStackCount, sizeof(float)); | ||
|
|
||
| refreshSkip= 300.0f/44100.0f*d_getSampleRate(); | ||
|
|
||
| std::memset(rms.data, 0, sizeof(float)*kFloatStackCount); | ||
| std::memset(gainReduction.data, 0, sizeof(float)*kFloatStackCount); | ||
| std::memset(RMSStack.data, 0, sizeof(float)*kFloatRMSStackCount); | ||
| std::memset(lookaheadStack.data, 0, sizeof(float)*kFloatLookaheadStackCount); | ||
|
|
||
| for (int j=0; j < kFloatStackCount; ++j) | ||
| history.rms[j] = h +y; | ||
| for (int j=0; j < kFloatStackCount; ++j) | ||
| history.gainReduction[j] = h +y; | ||
|
|
||
| d_activate(); | ||
|
|
||
| } | ||
|
|
||
| float PowerJuicePlugin::getRMSHistory(int n) { | ||
| return history.rms[n]; | ||
| } | ||
|
|
||
| bool PowerJuicePlugin::repaintNeeded() { | ||
| return newRepaint; | ||
| } | ||
|
|
||
| float PowerJuicePlugin::getGainReductionHistory(int n) { | ||
| if (n == kFloatStackCount-1) { | ||
| newRepaint = false; | ||
| //printf("falsing!\n"); | ||
| } | ||
| return history.gainReduction[n]; | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Process | ||
|
|
||
| void PowerJuicePlugin::d_activate() | ||
| { | ||
| } | ||
|
|
||
| void PowerJuicePlugin::d_deactivate() | ||
| { | ||
| // all values to zero | ||
| } | ||
|
|
||
| void PowerJuicePlugin::d_run(const float** inputs, float** outputs, uint32_t frames) | ||
| { | ||
| const float* in = inputs[0]; | ||
| float* out = outputs[0]; | ||
| float sum; | ||
| float data; | ||
| float difference; | ||
|
|
||
|
|
||
| for (uint32_t i=0; i < frames; i++) { | ||
|
|
||
| sum = 0.0f; | ||
| data = 0.0f; | ||
| difference = 0; | ||
| //sanitizeDenormal(in[i]); // FIXME - you cannot modify inputs | ||
|
|
||
| /* compute last RMS */ | ||
|
|
||
| //store audio samples in an RMS buffer line | ||
| RMSStack.data[RMSStack.start++] = in[i]; | ||
|
|
||
| if (RMSStack.start == kFloatRMSStackCount) | ||
| RMSStack.start = 0; | ||
| //compute RMS over last kFloatRMSStackCount samples | ||
| for (int j=0; j < kFloatRMSStackCount; ++j) { | ||
| data = RMSStack.data[(RMSStack.start+j) % kFloatRMSStackCount]; | ||
| sum += data * data; | ||
| } | ||
|
|
||
| //root mean SQUARE | ||
| float RMS = sqrt(sum / kFloatRMSStackCount); | ||
| sanitizeDenormal(RMS); | ||
|
|
||
|
|
||
| /* compute gain reduction if needed */ | ||
| float RMSDB = toDB(RMS); | ||
|
|
||
| if (RMSDB>threshold) { | ||
| //attack stage | ||
| float difference = (RMSDB-threshold); | ||
|
|
||
| //sanitizeDenormal(difference); | ||
| targetGR = difference - difference/ratio; | ||
| if (targetGR>difference/(ratio/4.0f)) { | ||
| targetGR = difference - difference/(ratio*1.5f); | ||
| //more power! | ||
| } | ||
| // | ||
| if (GR<targetGR) { | ||
| //approach targetGR at attackSamples rate | ||
| GR -= (GR-targetGR)/(attackSamples); | ||
| } else { | ||
| //approach targetGR at releaseSamples rate | ||
| GR -= (GR-targetGR)/releaseSamples; | ||
| } | ||
|
|
||
| sanitizeDenormal(GR); | ||
| } else { | ||
| //release stage | ||
| //approach targetGR at releaseSamples rate, targetGR = 0.0f | ||
| GR -= GR/releaseSamples; | ||
| } | ||
|
|
||
| //store audio in lookahead buffer | ||
|
|
||
| lookaheadStack.data[lookaheadStack.start++] = in[i]; | ||
| //printf("rms\n"); | ||
| if (lookaheadStack.start == kFloatLookaheadStackCount) | ||
| lookaheadStack.start = 0; | ||
|
|
||
| if (++averageCounter >= refreshSkip) { | ||
|
|
||
| //add relevant values to the shared memory | ||
| rms.data[rms.start++] = RMSDB; | ||
| gainReduction.data[gainReduction.start++] = GR; | ||
|
|
||
|
|
||
| //rewind stack reading heads if needed | ||
| if (rms.start == kFloatStackCount) | ||
| rms.start = 0; | ||
| if (gainReduction.start == kFloatStackCount) | ||
| gainReduction.start = 0; | ||
|
|
||
|
|
||
| //saving in gfx format, for speed | ||
| //share memory | ||
|
|
||
| for (int j=0; j < kFloatStackCount; ++j) | ||
| history.rms[j] = -toIEC(rms.data[(rms.start+j) % kFloatStackCount])/200*h +h +y; | ||
| for (int j=0; j < kFloatStackCount; ++j) { | ||
| history.gainReduction[j] = -toIEC(-gainReduction.data[(gainReduction.start+j) % kFloatStackCount])/200*h +h +y; | ||
|
|
||
| } | ||
|
|
||
| repaintSkip++; | ||
| if (repaintSkip>5) { | ||
| repaintSkip = 0; | ||
| newRepaint = true; | ||
| } | ||
|
|
||
| averageCounter = 0; | ||
| inputMax = 0.0f; | ||
| } | ||
|
|
||
| /* compress, mix, done. */ | ||
| float compressedSignal = in[i]*fromDB(-GR); | ||
| out[i] = (compressedSignal*makeupFloat*mix)+in[i]*(1-mix); | ||
| } | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| Plugin* createPlugin() | ||
| { | ||
| return new PowerJuicePlugin(); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| /* | ||
| * Power 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 POWERJUICEPLUGIN_HPP_INCLUDED | ||
| #define POWERJUICEPLUGIN_HPP_INCLUDED | ||
|
|
||
| #include "DistrhoPlugin.hpp" | ||
|
|
||
| #include <cmath> | ||
|
|
||
| static const int kFloatStackCount = 563; | ||
|
|
||
|
|
||
| struct FloatStack { //history for GUI! | ||
| int32_t start; | ||
| float data[kFloatStackCount]; | ||
| }; | ||
|
|
||
| struct FloatRMSStack { //rms, sr-dependent | ||
| int32_t start; | ||
| float* data; | ||
| }; | ||
|
|
||
| struct LookaheadStack { //lookahead buffer, sr-dependent | ||
| int32_t start; | ||
| float* data; | ||
| }; | ||
|
|
||
| struct SharedMemData { //history for the GUI ! | ||
| float rms[kFloatStackCount]; | ||
| float gainReduction[kFloatStackCount]; | ||
| }; | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| class PowerJuicePlugin : public Plugin | ||
| { | ||
| public: | ||
| enum Parameters | ||
| { | ||
| paramAttack = 0, | ||
| paramRelease, | ||
| paramThreshold, | ||
| paramRatio, | ||
| paramMakeup, | ||
| paramMix, | ||
| paramCount | ||
| }; | ||
|
|
||
| PowerJuicePlugin(); | ||
| ~PowerJuicePlugin() override; | ||
|
|
||
| protected: | ||
| // ------------------------------------------------------------------- | ||
| // Information | ||
|
|
||
| const char* d_getLabel() const noexcept override | ||
| { | ||
| return "PowerJuice"; | ||
| } | ||
|
|
||
| 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('P', 'w', 'r', '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(const float** inputs, float** outputs, uint32_t frames) override; | ||
|
|
||
| // ------------------------------------------------------------------- | ||
|
|
||
| private: | ||
| // params | ||
| float attack, release, threshold, ratio, makeup, mix; | ||
| float attackSamples, releaseSamples, makeupFloat; | ||
| float balancer; | ||
| float targetGR; | ||
| float GR; | ||
|
|
||
| SharedMemData history; | ||
|
|
||
| float sum; | ||
| float data; | ||
| float difference; | ||
|
|
||
| int w; //waveform plane size, size of the plane in pixels; | ||
| int w2; //wavefowm array | ||
| int h; //waveform plane height | ||
| int x; //waveform plane positions | ||
| int y; | ||
| int dc; //0DC line y position | ||
|
|
||
| int kFloatRMSStackCount; | ||
| int kFloatLookaheadStackCount; | ||
|
|
||
| float refreshSkip; | ||
|
|
||
| int averageCounter; | ||
| float inputMax; | ||
| FloatStack input, rms, gainReduction; | ||
| struct FloatRMSStack RMSStack; | ||
| struct LookaheadStack lookaheadStack; | ||
|
|
||
| bool newRepaint; | ||
| int repaintSkip; | ||
|
|
||
| float fromDB(float gdb) { | ||
| return (std::exp(gdb/20.f*std::log(10.f))); | ||
| }; | ||
|
|
||
| float toDB(float g) { | ||
| return (20.f*std::log10(g)); | ||
| } | ||
|
|
||
| float toIEC(float db) { | ||
| float def = 0.0f; /* Meter deflection %age */ | ||
|
|
||
| if (db < -70.0f) { | ||
| def = 0.0f; | ||
| } else if (db < -60.0f) { | ||
| def = (db + 70.0f) * 0.25f; | ||
| } else if (db < -50.0f) { | ||
| def = (db + 60.0f) * 0.5f + 5.0f; | ||
| } else if (db < -40.0f) { | ||
| def = (db + 50.0f) * 0.75f + 7.5; | ||
| } else if (db < -30.0f) { | ||
| def = (db + 40.0f) * 1.5f + 15.0f; | ||
| } else if (db < -20.0f) { | ||
| def = (db + 30.0f) * 2.0f + 30.0f; | ||
| } else if (db < 0.0f) { | ||
| def = (db + 20.0f) * 2.5f + 50.0f; | ||
| } else { | ||
| def = 100.0f; | ||
| } | ||
|
|
||
| return (def * 2.0f); | ||
| } | ||
|
|
||
| bool isNan(float& value ) { | ||
| if (((*(uint32_t *) &value) & 0x7fffffff) > 0x7f800000) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| void sanitizeDenormal(float& value) { | ||
| if (isNan(value)) { | ||
| //std::printf("Booo!\n"); | ||
| value = 0.f; | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| //methods | ||
| float getRMSHistory(int n); | ||
| float getGainReductionHistory(int n); | ||
| bool repaintNeeded(); | ||
| }; | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO | ||
|
|
||
| #endif // POWERJUICE_HPP_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,307 @@ | ||
| /* | ||
| * Power 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 "PowerJuiceUI.hpp" | ||
|
|
||
| #include <cstdlib> | ||
| #include <ctime> | ||
|
|
||
| using DGL::Point; | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| PowerJuiceUI::PowerJuiceUI() | ||
| : UI(), | ||
| fAboutWindow(this), | ||
| dsp((PowerJuicePlugin*)d_getPluginInstancePointer()) | ||
| { | ||
| DISTRHO_SAFE_ASSERT(dsp != nullptr); | ||
|
|
||
| // background | ||
| fImgBackground = Image(PowerJuiceArtwork::backgroundData, PowerJuiceArtwork::backgroundWidth, PowerJuiceArtwork::backgroundHeight, GL_BGR); | ||
|
|
||
| // about | ||
| Image imageAbout(PowerJuiceArtwork::aboutData, PowerJuiceArtwork::aboutWidth, PowerJuiceArtwork::aboutHeight, GL_BGR); | ||
| fAboutWindow.setImage(imageAbout); | ||
|
|
||
| // knobs | ||
| Image knobImage(PowerJuiceArtwork::knobData, PowerJuiceArtwork::knobWidth, PowerJuiceArtwork::knobHeight); | ||
|
|
||
| // knob Attack | ||
| fKnobAttack = new ImageKnob(this, knobImage); | ||
| fKnobAttack->setAbsolutePos(37, 213); | ||
| fKnobAttack->setRange(0.1f, 1000.0f); | ||
| fKnobAttack->setStep(0.1f); | ||
| fKnobAttack->setValue(20.0f); | ||
| fKnobAttack->setRotationAngle(270); | ||
| fKnobAttack->setCallback(this); | ||
|
|
||
| // knob Release | ||
| fKnobRelease = new ImageKnob(this, knobImage); | ||
| fKnobRelease->setAbsolutePos(136, 213); | ||
| fKnobRelease->setRange(0.1f, 1000.0f); | ||
| fKnobRelease->setValue(0.1f); | ||
| fKnobRelease->setRotationAngle(270); | ||
| fKnobRelease->setCallback(this); | ||
|
|
||
| // knob Threshold | ||
| fKnobThreshold = new ImageKnob(this, knobImage); | ||
| fKnobThreshold->setAbsolutePos(235, 213); | ||
| fKnobThreshold->setRange(-60.0f, 0.0f); | ||
| fKnobThreshold->setValue(0.0f); | ||
| fKnobThreshold->setRotationAngle(270); | ||
| fKnobThreshold->setCallback(this); | ||
|
|
||
| // knob Ratio | ||
| fKnobRatio = new ImageKnob(this, knobImage); | ||
| fKnobRatio->setAbsolutePos(334, 213); | ||
| fKnobRatio->setRange(1.0f, 10.0f); | ||
| fKnobRatio->setValue(1.0f); | ||
| fKnobRatio->setRotationAngle(270); | ||
| fKnobRatio->setCallback(this); | ||
|
|
||
| // knob Make-Up | ||
| fKnobMakeup = new ImageKnob(this, knobImage); | ||
| fKnobMakeup->setAbsolutePos(433, 213); | ||
| fKnobMakeup->setRange(0.0f, 20.0f); | ||
| fKnobMakeup->setValue(0.0f); | ||
| fKnobMakeup->setRotationAngle(270); | ||
| fKnobMakeup->setCallback(this); | ||
|
|
||
| // knob Mix | ||
| fKnobMix = new ImageKnob(this, knobImage); | ||
| fKnobMix->setAbsolutePos(532, 213); | ||
| fKnobMix->setRange(0.0f, 1.0f); | ||
| fKnobMix->setValue(1.0f); | ||
| fKnobMix->setRotationAngle(270); | ||
| fKnobMix->setCallback(this); | ||
|
|
||
| // about button | ||
| Image aboutImageNormal(PowerJuiceArtwork::aboutButtonNormalData, PowerJuiceArtwork::aboutButtonNormalWidth, PowerJuiceArtwork::aboutButtonNormalHeight); | ||
| Image aboutImageHover(PowerJuiceArtwork::aboutButtonHoverData, PowerJuiceArtwork::aboutButtonHoverWidth, PowerJuiceArtwork::aboutButtonHoverHeight); | ||
| fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | ||
| fButtonAbout->setAbsolutePos(502, 17); | ||
| fButtonAbout->setCallback(this); | ||
|
|
||
| // set default values | ||
| d_programChanged(0); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // DSP Callbacks | ||
|
|
||
| void PowerJuiceUI::d_parameterChanged(uint32_t index, float value) | ||
| { | ||
| switch (index) | ||
| { | ||
| case PowerJuicePlugin::paramAttack: | ||
| fKnobAttack->setValue(value); | ||
| break; | ||
| case PowerJuicePlugin::paramRelease: | ||
| fKnobRelease->setValue(value); | ||
| break; | ||
| case PowerJuicePlugin::paramThreshold: | ||
| fKnobThreshold->setValue(value); | ||
| break; | ||
| case PowerJuicePlugin::paramRatio: | ||
| fKnobRatio->setValue(value); | ||
| break; | ||
| case PowerJuicePlugin::paramMakeup: | ||
| fKnobMakeup->setValue(value); | ||
| break; | ||
| case PowerJuicePlugin::paramMix: | ||
| fKnobMix->setValue(value); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| void PowerJuiceUI::d_programChanged(uint32_t index) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| // Default values | ||
| fKnobAttack->setValue(20.0f); | ||
| fKnobRelease->setValue(200.0f); | ||
| fKnobThreshold->setValue(0.0f); | ||
| fKnobRatio->setValue(1.0f); | ||
| fKnobMakeup->setValue(0.0f); | ||
| fKnobMix->setValue(1.0f); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Widget Callbacks | ||
|
|
||
| void PowerJuiceUI::imageButtonClicked(ImageButton* button, int) | ||
| { | ||
| if (button != fButtonAbout) | ||
| return; | ||
|
|
||
| fAboutWindow.exec(); | ||
| } | ||
|
|
||
| void PowerJuiceUI::imageKnobDragStarted(ImageKnob* knob) | ||
| { | ||
| if (knob == fKnobAttack) | ||
| d_editParameter(PowerJuicePlugin::paramAttack, true); | ||
| else if (knob == fKnobRelease) | ||
| d_editParameter(PowerJuicePlugin::paramRelease, true); | ||
| else if (knob == fKnobThreshold) | ||
| d_editParameter(PowerJuicePlugin::paramThreshold, true); | ||
| else if (knob == fKnobRatio) | ||
| d_editParameter(PowerJuicePlugin::paramRatio, true); | ||
| else if (knob == fKnobMakeup) | ||
| d_editParameter(PowerJuicePlugin::paramMakeup, true); | ||
| else if (knob == fKnobMix) | ||
| d_editParameter(PowerJuicePlugin::paramMix, true); | ||
| } | ||
|
|
||
| void PowerJuiceUI::imageKnobDragFinished(ImageKnob* knob) | ||
| { | ||
| if (knob == fKnobAttack) | ||
| d_editParameter(PowerJuicePlugin::paramAttack, false); | ||
| else if (knob == fKnobRelease) | ||
| d_editParameter(PowerJuicePlugin::paramRelease, false); | ||
| else if (knob == fKnobThreshold) | ||
| d_editParameter(PowerJuicePlugin::paramThreshold, false); | ||
| else if (knob == fKnobRatio) | ||
| d_editParameter(PowerJuicePlugin::paramRatio, false); | ||
| else if (knob == fKnobMakeup) | ||
| d_editParameter(PowerJuicePlugin::paramMakeup, false); | ||
| else if (knob == fKnobMix) | ||
| d_editParameter(PowerJuicePlugin::paramMix, false); | ||
| } | ||
|
|
||
| void PowerJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | ||
| { | ||
| if (knob == fKnobAttack) | ||
| d_setParameterValue(PowerJuicePlugin::paramAttack, value); | ||
| else if (knob == fKnobRelease) | ||
| d_setParameterValue(PowerJuicePlugin::paramRelease, value); | ||
| else if (knob == fKnobThreshold) | ||
| d_setParameterValue(PowerJuicePlugin::paramThreshold, value); | ||
| else if (knob == fKnobRatio) | ||
| d_setParameterValue(PowerJuicePlugin::paramRatio, value); | ||
| else if (knob == fKnobMakeup) | ||
| d_setParameterValue(PowerJuicePlugin::paramMakeup, value); | ||
| else if (knob == fKnobMix) | ||
| d_setParameterValue(PowerJuicePlugin::paramMix, value); | ||
|
|
||
| } | ||
|
|
||
| void PowerJuiceUI::d_uiIdle() | ||
| { | ||
| if (dsp != nullptr && dsp->repaintNeeded()) | ||
| repaint(); | ||
| } | ||
|
|
||
| void PowerJuiceUI::onDisplay() | ||
| { | ||
| fImgBackground.draw(); | ||
|
|
||
| if (dsp == nullptr) | ||
| return; | ||
|
|
||
| int w = 563; //waveform plane size, size of the plane in pixels; | ||
| int w2 = 1126; //wavefowm array | ||
| int h = 121; //waveform plane height | ||
| int x = 27; //waveform plane positions | ||
| int y = 53; | ||
| int dc = 113; //0DC line y position | ||
|
|
||
|
|
||
| glEnable(GL_BLEND); | ||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
| glEnable(GL_LINE_SMOOTH); | ||
| glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | ||
|
|
||
|
|
||
|
|
||
| float thresholdPosition = (-toIEC(fKnobThreshold->getValue()))/200*h+h+y; | ||
|
|
||
| //draw waveform | ||
| /* | ||
| glColor4f(0.0f, 1.0f, 0.0f, 0.4f); | ||
| glLineWidth(1.2f); | ||
| for (int i=0; i<w; i++) { | ||
| glBegin(GL_LINES); | ||
| glVertex2i(x+i, -toIEC(shmData->input[i])/200*h+h+y); | ||
| glVertex2i(x+i, y+h); | ||
| glEnd(); | ||
| } | ||
| */ | ||
| //draw RMS | ||
|
|
||
| glColor4f(0.0f, 0.0f, 1.0f, 1.0f); | ||
| glLineWidth(2.0f); | ||
| glBegin(GL_LINE_STRIP); | ||
| for (int i=2; i<w; i++) { | ||
| float value = dsp->getRMSHistory(i); | ||
| if (value<thresholdPosition) { | ||
| glColor4f(0.0f, 0.5f, 0.0f, 1.0f); | ||
| } else { | ||
| glColor4f(0.0f, 0.5f, 0.2f, 1.0f); | ||
| } | ||
| glVertex2i(x+i, value); | ||
| } | ||
| glEnd(); | ||
|
|
||
| //draw gain reduction | ||
| glColor4f(1.0f, 1.0f, 1.0f, 0.3f); | ||
| glLineWidth(3.0f); | ||
| glBegin(GL_LINES); | ||
| for (int i=2; i<w; i++) { | ||
| glColor4f(1.0f, 1.0f, 1.0f, 0.3f); | ||
| float value = dsp->getGainReductionHistory(i); | ||
|
|
||
| glVertex2i(x+i, value); | ||
| glVertex2i(x+i, y); | ||
|
|
||
| value = dsp->getRMSHistory(i); | ||
| glColor4f(0.0f, 0.5f, 0.2f, 0.1f); | ||
| glVertex2i(x+i, value); | ||
| glVertex2i(x+i, y+h); | ||
| } | ||
| glEnd(); | ||
|
|
||
|
|
||
| //draw Threshold | ||
| glLineWidth(2.0f); | ||
| glColor4f(0.4f, 0.4f, 1.0f, 0.8f); | ||
| //float thresholdPosition = ((60-fKnobThreshold->getValue())/60); | ||
| glBegin(GL_LINES); | ||
| glVertex2i(x, thresholdPosition); | ||
| glVertex2i(x+w, thresholdPosition); | ||
| glEnd(); | ||
|
|
||
| // reset color | ||
| glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| UI* createUI() | ||
| { | ||
| return new PowerJuiceUI(); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| /* | ||
| * Power 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 POWERJUICEUI_HPP_INCLUDED | ||
| #define POWERJUICEUI_HPP_INCLUDED | ||
|
|
||
| #include "DistrhoUI.hpp" | ||
|
|
||
| #include "ImageAboutWindow.hpp" | ||
| #include "ImageButton.hpp" | ||
| #include "ImageKnob.hpp" | ||
| #include "ImageSlider.hpp" | ||
|
|
||
| #include "PowerJuiceArtwork.hpp" | ||
| #include "PowerJuicePlugin.hpp" | ||
|
|
||
| #include <cmath> | ||
|
|
||
| using DGL::Image; | ||
| using DGL::ImageAboutWindow; | ||
| using DGL::ImageButton; | ||
| using DGL::ImageKnob; | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| class PowerJuiceUI : public UI, | ||
| public ImageButton::Callback, | ||
| public ImageKnob::Callback | ||
| { | ||
| public: | ||
| PowerJuiceUI(); | ||
|
|
||
| protected: | ||
| // ------------------------------------------------------------------- | ||
| // Information | ||
|
|
||
| uint d_getWidth() const noexcept override | ||
| { | ||
| return PowerJuiceArtwork::backgroundWidth; | ||
| } | ||
|
|
||
| uint d_getHeight() const noexcept override | ||
| { | ||
| return PowerJuiceArtwork::backgroundHeight; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------- | ||
| // DSP Callbacks | ||
|
|
||
| void d_parameterChanged(uint32_t index, float value) override; | ||
| void d_programChanged(uint32_t index) override; | ||
|
|
||
| // ------------------------------------------------------------------- | ||
| // UI Callbacks | ||
|
|
||
| void d_uiIdle() 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; | ||
|
|
||
| ScopedPointer<ImageKnob> fKnobAttack, fKnobRelease, fKnobThreshold; | ||
| ScopedPointer<ImageKnob> fKnobRatio, fKnobMakeup, fKnobMix; | ||
| ScopedPointer<ImageButton> fButtonAbout; | ||
|
|
||
| PowerJuicePlugin* const dsp; | ||
|
|
||
| float fromDB(float gdb) { | ||
| return (std::exp(gdb/20.f*std::log(10.f))); | ||
| }; | ||
|
|
||
| float toDB(float g) { | ||
| return (20.f*std::log10(g)); | ||
| } | ||
|
|
||
| float toIEC(float db) { | ||
| float def = 0.0f; /* Meter deflection %age */ | ||
|
|
||
| if (db < -70.0f) { | ||
| def = 0.0f; | ||
| } else if (db < -60.0f) { | ||
| def = (db + 70.0f) * 0.25f; | ||
| } else if (db < -50.0f) { | ||
| def = (db + 60.0f) * 0.5f + 5.0f; | ||
| } else if (db < -40.0f) { | ||
| def = (db + 50.0f) * 0.75f + 7.5; | ||
| } else if (db < -30.0f) { | ||
| def = (db + 40.0f) * 1.5f + 15.0f; | ||
| } else if (db < -20.0f) { | ||
| def = (db + 30.0f) * 2.0f + 30.0f; | ||
| } else if (db < 0.0f) { | ||
| def = (db + 20.0f) * 2.5f + 50.0f; | ||
| } else { | ||
| def = 100.0f; | ||
| } | ||
|
|
||
| return (def * 2.0f); | ||
| } | ||
| }; | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO | ||
|
|
||
| #endif // POWERJUICEUI_HPP_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /* | ||
| * Power 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 "PowerJuiceX2" | ||
|
|
||
| #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 0 | ||
|
|
||
| // needed for spectrum | ||
| #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | ||
|
|
||
| #define DISTRHO_PLUGIN_URI "urn:distrho:PowerJuiceX2" | ||
|
|
||
| #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/make -f | ||
| # Makefile for DISTRHO Plugins # | ||
| # ---------------------------- # | ||
| # Created by falkTX | ||
| # | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Project name, used for binaries | ||
|
|
||
| NAME = PowerJuiceX2 | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Files to build | ||
|
|
||
| OBJS_DSP = \ | ||
| PowerJuiceX2Plugin.cpp.o | ||
|
|
||
| OBJS_UI = \ | ||
| PowerJuiceX2Artwork.cpp.o \ | ||
| PowerJuiceX2UI.cpp.o | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Do some magic | ||
|
|
||
| include ../Makefile.mk | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Enable all possible plugin types | ||
|
|
||
| ifeq ($(LINUX),true) | ||
| all: jack lv2_one vst | ||
| else | ||
| all: lv2_one vst | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /* (Auto-generated binary data file). */ | ||
|
|
||
| #ifndef BINARY_POWERJUICEX2ARTWORK_HPP | ||
| #define BINARY_POWERJUICEX2ARTWORK_HPP | ||
|
|
||
| namespace PowerJuiceX2Artwork | ||
| { | ||
| 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 = 571956; | ||
| const unsigned int backgroundWidth = 619; | ||
| const unsigned int backgroundHeight = 308; | ||
|
|
||
| extern const char* knobData; | ||
| const unsigned int knobDataSize = 10404; | ||
| const unsigned int knobWidth = 51; | ||
| const unsigned int knobHeight = 51; | ||
| } | ||
|
|
||
| #endif // BINARY_POWERJUICEX2ARTWORK_HPP | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,385 @@ | ||
| /* | ||
| * Power 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 "PowerJuiceX2Plugin.hpp" | ||
| #include <cstdlib> | ||
| #include <algorithm> | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| PowerJuiceX2Plugin::PowerJuiceX2Plugin() | ||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | ||
| { | ||
| // set default values | ||
| d_setProgram(0); | ||
|
|
||
| // reset | ||
| d_deactivate(); | ||
| } | ||
|
|
||
| PowerJuiceX2Plugin::~PowerJuiceX2Plugin() | ||
| { | ||
| free(lookaheadStack.data); | ||
| free(RMSStack.data); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Init | ||
|
|
||
| void PowerJuiceX2Plugin::d_initParameter(uint32_t index, Parameter& parameter) | ||
| { | ||
| switch (index) | ||
| { | ||
| case paramAttack: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Attack"; | ||
| parameter.symbol = "att"; | ||
| parameter.unit = "ms"; | ||
| parameter.ranges.def = 20.0f; | ||
| parameter.ranges.min = 0.1f; | ||
| parameter.ranges.max = 1000.0f; | ||
| break; | ||
| case paramRelease: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Release"; | ||
| parameter.symbol = "rel"; | ||
| parameter.unit = "ms"; | ||
| parameter.ranges.def = 200.0f; | ||
| parameter.ranges.min = 0.1f; | ||
| parameter.ranges.max = 1000.0f; | ||
| break; | ||
| case paramThreshold: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Threshold"; | ||
| parameter.symbol = "thr"; | ||
| parameter.unit = "dB"; | ||
| parameter.ranges.def = 0.0f; | ||
| parameter.ranges.min = -60.0f; | ||
| parameter.ranges.max = 0.0f; | ||
| break; | ||
| case paramRatio: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Ratio"; | ||
| parameter.symbol = "rat"; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 1.0f; | ||
| parameter.ranges.min = 1.0f; | ||
| parameter.ranges.max = 10.0f; | ||
| break; | ||
| case paramMakeup: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Make-Up"; | ||
| parameter.symbol = "mak"; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 0.0f; | ||
| parameter.ranges.min = 0.0f; | ||
| parameter.ranges.max = 20.0f; | ||
| break; | ||
| case paramMix: | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = "Mix"; | ||
| parameter.symbol = "Mix"; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 1.0f; | ||
| parameter.ranges.min = 0.0f; | ||
| parameter.ranges.max = 1.0f; | ||
| break; | ||
|
|
||
| } | ||
| } | ||
|
|
||
| void PowerJuiceX2Plugin::d_initProgramName(uint32_t index, d_string& programName) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| programName = "Default"; | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Internal data | ||
|
|
||
| float PowerJuiceX2Plugin::d_getParameterValue(uint32_t index) const | ||
| { | ||
| switch (index) | ||
| { | ||
| case paramAttack: | ||
| return attack; | ||
| case paramRelease: | ||
| return release; | ||
| case paramThreshold: | ||
| return threshold; | ||
| case paramRatio: | ||
| return ratio; | ||
| case paramMakeup: | ||
| return makeup; | ||
| case paramMix: | ||
| return mix; | ||
| default: | ||
| return 0.0f; | ||
| } | ||
| } | ||
|
|
||
| void PowerJuiceX2Plugin::d_setParameterValue(uint32_t index, float value) | ||
| { | ||
| switch (index) | ||
| { | ||
| case paramAttack: | ||
| attack = value; | ||
| attackSamples = d_getSampleRate()*(attack/1000.0f); | ||
| break; | ||
| case paramRelease: | ||
| release = value; | ||
| releaseSamples = d_getSampleRate()*(release/1000.0f); | ||
| break; | ||
| case paramThreshold: | ||
| threshold = value; | ||
| break; | ||
| case paramRatio: | ||
| ratio = value; | ||
| break; | ||
| case paramMakeup: | ||
| makeup = value; | ||
| makeupFloat = fromDB(makeup); | ||
| break; | ||
| case paramMix: | ||
| mix = value; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| void PowerJuiceX2Plugin::d_setProgram(uint32_t index) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| /* Default parameter values */ | ||
| attack = 20.0f; | ||
| release = 200.0f; | ||
| threshold = 0.0f; | ||
| ratio = 1.0f; | ||
| makeup = 0.0f; | ||
| mix = 1.0f; | ||
|
|
||
| makeupFloat = fromDB(makeup); | ||
| attackSamples = d_getSampleRate()*(attack/1000.0f); | ||
| releaseSamples = d_getSampleRate()*(release/1000.0f); | ||
|
|
||
|
|
||
|
|
||
| w = 563; //waveform plane size, size of the plane in pixels; | ||
| w2 = 1126; //wavefowm array | ||
| h = 121; //waveform plane height | ||
| x = 27; //waveform plane positions | ||
| y = 53; | ||
| dc = 113; //0DC line y position | ||
|
|
||
| /* Default variable values */ | ||
| averageCounter = 0; | ||
| inputMax = 0.0f; | ||
|
|
||
| balancer = 1.0f; | ||
| GR = 1.0f; | ||
|
|
||
| newRepaint = false; | ||
|
|
||
| input.start = 0; | ||
| rms.start = 0; | ||
| gainReduction.start = 0; | ||
| RMSStack.start = 0; | ||
| lookaheadStack.start = 0; | ||
| repaintSkip = 0; | ||
|
|
||
|
|
||
| kFloatRMSStackCount = 400.0f/44100.0f*d_getSampleRate(); | ||
| RMSStack.data = (float*) calloc(kFloatRMSStackCount, sizeof(float)); | ||
|
|
||
| kFloatLookaheadStackCount = 800.0f/44100.0f*d_getSampleRate(); | ||
| lookaheadStack.data = (float*) calloc(kFloatLookaheadStackCount, sizeof(float)); | ||
|
|
||
| refreshSkip= 300.0f/44100.0f*d_getSampleRate(); | ||
|
|
||
| std::memset(rms.data, 0, sizeof(float)*kFloatStackCount); | ||
| std::memset(gainReduction.data, 0, sizeof(float)*kFloatStackCount); | ||
| std::memset(RMSStack.data, 0, sizeof(float)*kFloatRMSStackCount); | ||
| std::memset(lookaheadStack.data, 0, sizeof(float)*kFloatLookaheadStackCount); | ||
|
|
||
| for (int j=0; j < kFloatStackCount; ++j) | ||
| history.rms[j] = h +y; | ||
| for (int j=0; j < kFloatStackCount; ++j) | ||
| history.gainReduction[j] = h +y; | ||
|
|
||
| d_activate(); | ||
|
|
||
| } | ||
|
|
||
| float PowerJuiceX2Plugin::getRMSHistory(int n) { | ||
| return history.rms[n]; | ||
| } | ||
|
|
||
| bool PowerJuiceX2Plugin::repaintNeeded() { | ||
| return newRepaint; | ||
| } | ||
|
|
||
| float PowerJuiceX2Plugin::getGainReductionHistory(int n) { | ||
| if (n == kFloatStackCount-1) { | ||
| newRepaint = false; | ||
| //printf("falsing!\n"); | ||
| } | ||
| return history.gainReduction[n]; | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Process | ||
|
|
||
| void PowerJuiceX2Plugin::d_activate() | ||
| { | ||
| } | ||
|
|
||
| void PowerJuiceX2Plugin::d_deactivate() | ||
| { | ||
| // all values to zero | ||
| } | ||
|
|
||
| void PowerJuiceX2Plugin::d_run(const float** inputs, float** outputs, uint32_t frames) | ||
| { | ||
| const float* in1 = inputs[0]; | ||
| const float* in2 = inputs[1]; | ||
| float* out1 = outputs[0]; | ||
| float* out2 = outputs[1]; | ||
| float sum; | ||
| float data; | ||
| float difference; | ||
|
|
||
|
|
||
| for (uint32_t i=0; i < frames; i++) { | ||
|
|
||
| sum = 0.0f; | ||
| data = 0.0f; | ||
| difference = 0; | ||
| //sanitizeDenormal(in1[i]); // FIXME - you cannot modify inputs | ||
| //sanitizeDenormal(in2[i]); // FIXME - you cannot modify inputs | ||
|
|
||
| /* compute last RMS */ | ||
|
|
||
| //store audio samples in an RMS buffer line | ||
| RMSStack.data[RMSStack.start++] = std::max(in1[i], in2[i]); | ||
|
|
||
| if (RMSStack.start == kFloatRMSStackCount) | ||
| RMSStack.start = 0; | ||
| //compute RMS over last kFloatRMSStackCount samples | ||
| for (int j=0; j < kFloatRMSStackCount; ++j) { | ||
| data = RMSStack.data[(RMSStack.start+j) % kFloatRMSStackCount]; | ||
| sum += data * data; | ||
| } | ||
|
|
||
| //root mean SQUARE | ||
| float RMS = sqrt(sum / kFloatRMSStackCount); | ||
| sanitizeDenormal(RMS); | ||
|
|
||
|
|
||
| /* compute gain reduction if needed */ | ||
| float RMSDB = toDB(RMS); | ||
|
|
||
| if (RMSDB>threshold) { | ||
| //attack stage | ||
| float difference = (RMSDB-threshold); | ||
|
|
||
| //sanitizeDenormal(difference); | ||
| targetGR = difference - difference/ratio; | ||
| if (targetGR>difference/(ratio/4.0f)) { | ||
| targetGR = difference - difference/(ratio*1.5f); | ||
| //more power! | ||
| } | ||
| // | ||
| if (GR<targetGR) { | ||
| //approach targetGR at attackSamples rate | ||
| GR -= (GR-targetGR)/(attackSamples); | ||
| } else { | ||
| //approach targetGR at releaseSamples rate | ||
| GR -= (GR-targetGR)/releaseSamples; | ||
| } | ||
|
|
||
| sanitizeDenormal(GR); | ||
| } else { | ||
| //release stage | ||
| //approach targetGR at releaseSamples rate, targetGR = 0.0f | ||
| GR -= GR/releaseSamples; | ||
| } | ||
|
|
||
| //store audio in lookahead buffer | ||
|
|
||
| lookaheadStack.data[lookaheadStack.start++] = std::max(in1[i], in2[i]); | ||
| //printf("rms\n"); | ||
| if (lookaheadStack.start == kFloatLookaheadStackCount) | ||
| lookaheadStack.start = 0; | ||
|
|
||
| if (++averageCounter >= refreshSkip) { | ||
|
|
||
| //add relevant values to the shared memory | ||
| rms.data[rms.start++] = RMSDB; | ||
| gainReduction.data[gainReduction.start++] = GR; | ||
|
|
||
|
|
||
| //rewind stack reading heads if needed | ||
| if (rms.start == kFloatStackCount) | ||
| rms.start = 0; | ||
| if (gainReduction.start == kFloatStackCount) | ||
| gainReduction.start = 0; | ||
|
|
||
|
|
||
| //saving in gfx format, for speed | ||
| //share memory | ||
|
|
||
| for (int j=0; j < kFloatStackCount; ++j) | ||
| history.rms[j] = -toIEC(rms.data[(rms.start+j) % kFloatStackCount])/200*h +h +y; | ||
| for (int j=0; j < kFloatStackCount; ++j) { | ||
| history.gainReduction[j] = -toIEC(-gainReduction.data[(gainReduction.start+j) % kFloatStackCount])/200*h +h +y; | ||
|
|
||
| } | ||
|
|
||
| repaintSkip++; | ||
| if (repaintSkip>5) { | ||
| repaintSkip = 0; | ||
| newRepaint = true; | ||
| } | ||
|
|
||
| averageCounter = 0; | ||
| inputMax = 0.0f; | ||
| } | ||
|
|
||
| /* compress, mix, done. */ | ||
| float realGR = fromDB(-GR); | ||
| float compressedSignal1 = in1[i]*realGR; | ||
| float compressedSignal2 = in2[i]*realGR; | ||
| out1[i] = (compressedSignal1*makeupFloat*mix)+in1[i]*(1-mix); | ||
| out2[i] = (compressedSignal2*makeupFloat*mix)+in2[i]*(1-mix); | ||
| } | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| Plugin* createPlugin() | ||
| { | ||
| return new PowerJuiceX2Plugin(); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| /* | ||
| * Power 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 POWERJUICEPLUGIN_HPP_INCLUDED | ||
| #define POWERJUICEPLUGIN_HPP_INCLUDED | ||
|
|
||
| #include "DistrhoPlugin.hpp" | ||
|
|
||
| #include <cmath> | ||
|
|
||
| static const int kFloatStackCount = 563; | ||
|
|
||
|
|
||
| struct FloatStack { //history for GUI! | ||
| int32_t start; | ||
| float data[kFloatStackCount]; | ||
| }; | ||
|
|
||
| struct FloatRMSStack { //rms, sr-dependent | ||
| int32_t start; | ||
| float* data; | ||
| }; | ||
|
|
||
| struct LookaheadStack { //lookahead buffer, sr-dependent | ||
| int32_t start; | ||
| float* data; | ||
| }; | ||
|
|
||
| struct SharedMemData { //history for the GUI ! | ||
| float rms[kFloatStackCount]; | ||
| float gainReduction[kFloatStackCount]; | ||
| }; | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| class PowerJuiceX2Plugin : public Plugin | ||
| { | ||
| public: | ||
| enum Parameters | ||
| { | ||
| paramAttack = 0, | ||
| paramRelease, | ||
| paramThreshold, | ||
| paramRatio, | ||
| paramMakeup, | ||
| paramMix, | ||
| paramCount | ||
| }; | ||
|
|
||
| PowerJuiceX2Plugin(); | ||
| ~PowerJuiceX2Plugin() override; | ||
|
|
||
| protected: | ||
| // ------------------------------------------------------------------- | ||
| // Information | ||
|
|
||
| const char* d_getLabel() const noexcept override | ||
| { | ||
| return "PowerJuiceX2"; | ||
| } | ||
|
|
||
| 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('P', 'w', 'J', 'X'); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------- | ||
| // 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(const float** inputs, float** outputs, uint32_t frames) override; | ||
|
|
||
| // ------------------------------------------------------------------- | ||
|
|
||
| private: | ||
| // params | ||
| float attack, release, threshold, ratio, makeup, mix; | ||
| float attackSamples, releaseSamples, makeupFloat; | ||
| float balancer; | ||
| float targetGR; | ||
| float GR; | ||
|
|
||
| SharedMemData history; | ||
|
|
||
| float sum; | ||
| float data; | ||
| float difference; | ||
|
|
||
| int w; //waveform plane size, size of the plane in pixels; | ||
| int w2; //wavefowm array | ||
| int h; //waveform plane height | ||
| int x; //waveform plane positions | ||
| int y; | ||
| int dc; //0DC line y position | ||
|
|
||
| int kFloatRMSStackCount; | ||
| int kFloatLookaheadStackCount; | ||
|
|
||
| float refreshSkip; | ||
|
|
||
| int averageCounter; | ||
| float inputMax; | ||
| FloatStack input, rms, gainReduction; | ||
| struct FloatRMSStack RMSStack; | ||
| struct LookaheadStack lookaheadStack; | ||
|
|
||
| bool newRepaint; | ||
| int repaintSkip; | ||
|
|
||
| float fromDB(float gdb) { | ||
| return (std::exp(gdb/20.f*std::log(10.f))); | ||
| }; | ||
|
|
||
| float toDB(float g) { | ||
| return (20.f*std::log10(g)); | ||
| } | ||
|
|
||
| float toIEC(float db) { | ||
| float def = 0.0f; /* Meter deflection %age */ | ||
|
|
||
| if (db < -70.0f) { | ||
| def = 0.0f; | ||
| } else if (db < -60.0f) { | ||
| def = (db + 70.0f) * 0.25f; | ||
| } else if (db < -50.0f) { | ||
| def = (db + 60.0f) * 0.5f + 5.0f; | ||
| } else if (db < -40.0f) { | ||
| def = (db + 50.0f) * 0.75f + 7.5; | ||
| } else if (db < -30.0f) { | ||
| def = (db + 40.0f) * 1.5f + 15.0f; | ||
| } else if (db < -20.0f) { | ||
| def = (db + 30.0f) * 2.0f + 30.0f; | ||
| } else if (db < 0.0f) { | ||
| def = (db + 20.0f) * 2.5f + 50.0f; | ||
| } else { | ||
| def = 100.0f; | ||
| } | ||
|
|
||
| return (def * 2.0f); | ||
| } | ||
|
|
||
| bool isNan(float& value ) { | ||
| if (((*(uint32_t *) &value) & 0x7fffffff) > 0x7f800000) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| void sanitizeDenormal(float& value) { | ||
| if (isNan(value)) { | ||
| //std::printf("Booo!\n"); | ||
| value = 0.f; | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| //methods | ||
| float getRMSHistory(int n); | ||
| float getGainReductionHistory(int n); | ||
| bool repaintNeeded(); | ||
| }; | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO | ||
|
|
||
| #endif // POWERJUICE_HPP_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,307 @@ | ||
| /* | ||
| * Power 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 "PowerJuiceX2UI.hpp" | ||
|
|
||
| #include <cstdlib> | ||
| #include <ctime> | ||
|
|
||
| using DGL::Point; | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| PowerJuiceX2UI::PowerJuiceX2UI() | ||
| : UI(), | ||
| fAboutWindow(this), | ||
| dsp((PowerJuiceX2Plugin*)d_getPluginInstancePointer()) | ||
| { | ||
| DISTRHO_SAFE_ASSERT(dsp != nullptr); | ||
|
|
||
| // background | ||
| fImgBackground = Image(PowerJuiceX2Artwork::backgroundData, PowerJuiceX2Artwork::backgroundWidth, PowerJuiceX2Artwork::backgroundHeight, GL_BGR); | ||
|
|
||
| // about | ||
| Image imageAbout(PowerJuiceX2Artwork::aboutData, PowerJuiceX2Artwork::aboutWidth, PowerJuiceX2Artwork::aboutHeight, GL_BGR); | ||
| fAboutWindow.setImage(imageAbout); | ||
|
|
||
| // knobs | ||
| Image knobImage(PowerJuiceX2Artwork::knobData, PowerJuiceX2Artwork::knobWidth, PowerJuiceX2Artwork::knobHeight); | ||
|
|
||
| // knob Attack | ||
| fKnobAttack = new ImageKnob(this, knobImage); | ||
| fKnobAttack->setAbsolutePos(37, 213); | ||
| fKnobAttack->setRange(0.1f, 1000.0f); | ||
| fKnobAttack->setStep(0.1f); | ||
| fKnobAttack->setValue(20.0f); | ||
| fKnobAttack->setRotationAngle(270); | ||
| fKnobAttack->setCallback(this); | ||
|
|
||
| // knob Release | ||
| fKnobRelease = new ImageKnob(this, knobImage); | ||
| fKnobRelease->setAbsolutePos(136, 213); | ||
| fKnobRelease->setRange(0.1f, 1000.0f); | ||
| fKnobRelease->setValue(0.1f); | ||
| fKnobRelease->setRotationAngle(270); | ||
| fKnobRelease->setCallback(this); | ||
|
|
||
| // knob Threshold | ||
| fKnobThreshold = new ImageKnob(this, knobImage); | ||
| fKnobThreshold->setAbsolutePos(235, 213); | ||
| fKnobThreshold->setRange(-60.0f, 0.0f); | ||
| fKnobThreshold->setValue(0.0f); | ||
| fKnobThreshold->setRotationAngle(270); | ||
| fKnobThreshold->setCallback(this); | ||
|
|
||
| // knob Ratio | ||
| fKnobRatio = new ImageKnob(this, knobImage); | ||
| fKnobRatio->setAbsolutePos(334, 213); | ||
| fKnobRatio->setRange(1.0f, 10.0f); | ||
| fKnobRatio->setValue(1.0f); | ||
| fKnobRatio->setRotationAngle(270); | ||
| fKnobRatio->setCallback(this); | ||
|
|
||
| // knob Make-Up | ||
| fKnobMakeup = new ImageKnob(this, knobImage); | ||
| fKnobMakeup->setAbsolutePos(433, 213); | ||
| fKnobMakeup->setRange(0.0f, 20.0f); | ||
| fKnobMakeup->setValue(0.0f); | ||
| fKnobMakeup->setRotationAngle(270); | ||
| fKnobMakeup->setCallback(this); | ||
|
|
||
| // knob Mix | ||
| fKnobMix = new ImageKnob(this, knobImage); | ||
| fKnobMix->setAbsolutePos(532, 213); | ||
| fKnobMix->setRange(0.0f, 1.0f); | ||
| fKnobMix->setValue(1.0f); | ||
| fKnobMix->setRotationAngle(270); | ||
| fKnobMix->setCallback(this); | ||
|
|
||
| // about button | ||
| Image aboutImageNormal(PowerJuiceX2Artwork::aboutButtonNormalData, PowerJuiceX2Artwork::aboutButtonNormalWidth, PowerJuiceX2Artwork::aboutButtonNormalHeight); | ||
| Image aboutImageHover(PowerJuiceX2Artwork::aboutButtonHoverData, PowerJuiceX2Artwork::aboutButtonHoverWidth, PowerJuiceX2Artwork::aboutButtonHoverHeight); | ||
| fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | ||
| fButtonAbout->setAbsolutePos(502, 17); | ||
| fButtonAbout->setCallback(this); | ||
|
|
||
| // set default values | ||
| d_programChanged(0); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // DSP Callbacks | ||
|
|
||
| void PowerJuiceX2UI::d_parameterChanged(uint32_t index, float value) | ||
| { | ||
| switch (index) | ||
| { | ||
| case PowerJuiceX2Plugin::paramAttack: | ||
| fKnobAttack->setValue(value); | ||
| break; | ||
| case PowerJuiceX2Plugin::paramRelease: | ||
| fKnobRelease->setValue(value); | ||
| break; | ||
| case PowerJuiceX2Plugin::paramThreshold: | ||
| fKnobThreshold->setValue(value); | ||
| break; | ||
| case PowerJuiceX2Plugin::paramRatio: | ||
| fKnobRatio->setValue(value); | ||
| break; | ||
| case PowerJuiceX2Plugin::paramMakeup: | ||
| fKnobMakeup->setValue(value); | ||
| break; | ||
| case PowerJuiceX2Plugin::paramMix: | ||
| fKnobMix->setValue(value); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| void PowerJuiceX2UI::d_programChanged(uint32_t index) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| // Default values | ||
| fKnobAttack->setValue(20.0f); | ||
| fKnobRelease->setValue(200.0f); | ||
| fKnobThreshold->setValue(0.0f); | ||
| fKnobRatio->setValue(1.0f); | ||
| fKnobMakeup->setValue(0.0f); | ||
| fKnobMix->setValue(1.0f); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Widget Callbacks | ||
|
|
||
| void PowerJuiceX2UI::imageButtonClicked(ImageButton* button, int) | ||
| { | ||
| if (button != fButtonAbout) | ||
| return; | ||
|
|
||
| fAboutWindow.exec(); | ||
| } | ||
|
|
||
| void PowerJuiceX2UI::imageKnobDragStarted(ImageKnob* knob) | ||
| { | ||
| if (knob == fKnobAttack) | ||
| d_editParameter(PowerJuiceX2Plugin::paramAttack, true); | ||
| else if (knob == fKnobRelease) | ||
| d_editParameter(PowerJuiceX2Plugin::paramRelease, true); | ||
| else if (knob == fKnobThreshold) | ||
| d_editParameter(PowerJuiceX2Plugin::paramThreshold, true); | ||
| else if (knob == fKnobRatio) | ||
| d_editParameter(PowerJuiceX2Plugin::paramRatio, true); | ||
| else if (knob == fKnobMakeup) | ||
| d_editParameter(PowerJuiceX2Plugin::paramMakeup, true); | ||
| else if (knob == fKnobMix) | ||
| d_editParameter(PowerJuiceX2Plugin::paramMix, true); | ||
| } | ||
|
|
||
| void PowerJuiceX2UI::imageKnobDragFinished(ImageKnob* knob) | ||
| { | ||
| if (knob == fKnobAttack) | ||
| d_editParameter(PowerJuiceX2Plugin::paramAttack, false); | ||
| else if (knob == fKnobRelease) | ||
| d_editParameter(PowerJuiceX2Plugin::paramRelease, false); | ||
| else if (knob == fKnobThreshold) | ||
| d_editParameter(PowerJuiceX2Plugin::paramThreshold, false); | ||
| else if (knob == fKnobRatio) | ||
| d_editParameter(PowerJuiceX2Plugin::paramRatio, false); | ||
| else if (knob == fKnobMakeup) | ||
| d_editParameter(PowerJuiceX2Plugin::paramMakeup, false); | ||
| else if (knob == fKnobMix) | ||
| d_editParameter(PowerJuiceX2Plugin::paramMix, false); | ||
| } | ||
|
|
||
| void PowerJuiceX2UI::imageKnobValueChanged(ImageKnob* knob, float value) | ||
| { | ||
| if (knob == fKnobAttack) | ||
| d_setParameterValue(PowerJuiceX2Plugin::paramAttack, value); | ||
| else if (knob == fKnobRelease) | ||
| d_setParameterValue(PowerJuiceX2Plugin::paramRelease, value); | ||
| else if (knob == fKnobThreshold) | ||
| d_setParameterValue(PowerJuiceX2Plugin::paramThreshold, value); | ||
| else if (knob == fKnobRatio) | ||
| d_setParameterValue(PowerJuiceX2Plugin::paramRatio, value); | ||
| else if (knob == fKnobMakeup) | ||
| d_setParameterValue(PowerJuiceX2Plugin::paramMakeup, value); | ||
| else if (knob == fKnobMix) | ||
| d_setParameterValue(PowerJuiceX2Plugin::paramMix, value); | ||
|
|
||
| } | ||
|
|
||
| void PowerJuiceX2UI::d_uiIdle() | ||
| { | ||
| if (dsp != nullptr && dsp->repaintNeeded()) | ||
| repaint(); | ||
| } | ||
|
|
||
| void PowerJuiceX2UI::onDisplay() | ||
| { | ||
| fImgBackground.draw(); | ||
|
|
||
| if (dsp == nullptr) | ||
| return; | ||
|
|
||
| int w = 563; //waveform plane size, size of the plane in pixels; | ||
| int w2 = 1126; //wavefowm array | ||
| int h = 121; //waveform plane height | ||
| int x = 27; //waveform plane positions | ||
| int y = 53; | ||
| int dc = 113; //0DC line y position | ||
|
|
||
|
|
||
| glEnable(GL_BLEND); | ||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
| glEnable(GL_LINE_SMOOTH); | ||
| glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | ||
|
|
||
|
|
||
|
|
||
| float thresholdPosition = (-toIEC(fKnobThreshold->getValue()))/200*h+h+y; | ||
|
|
||
| //draw waveform | ||
| /* | ||
| glColor4f(0.0f, 1.0f, 0.0f, 0.4f); | ||
| glLineWidth(1.2f); | ||
| for (int i=0; i<w; i++) { | ||
| glBegin(GL_LINES); | ||
| glVertex2i(x+i, -toIEC(shmData->input[i])/200*h+h+y); | ||
| glVertex2i(x+i, y+h); | ||
| glEnd(); | ||
| } | ||
| */ | ||
| //draw RMS | ||
|
|
||
| glColor4f(0.0f, 0.0f, 1.0f, 1.0f); | ||
| glLineWidth(2.0f); | ||
| glBegin(GL_LINE_STRIP); | ||
| for (int i=2; i<w; i++) { | ||
| float value = dsp->getRMSHistory(i); | ||
| if (value<thresholdPosition) { | ||
| glColor4f(0.0f, 0.5f, 0.0f, 1.0f); | ||
| } else { | ||
| glColor4f(0.0f, 0.5f, 0.2f, 1.0f); | ||
| } | ||
| glVertex2i(x+i, value); | ||
| } | ||
| glEnd(); | ||
|
|
||
| //draw gain reduction | ||
| glColor4f(1.0f, 1.0f, 1.0f, 0.3f); | ||
| glLineWidth(3.0f); | ||
| glBegin(GL_LINES); | ||
| for (int i=2; i<w; i++) { | ||
| glColor4f(1.0f, 1.0f, 1.0f, 0.3f); | ||
| float value = dsp->getGainReductionHistory(i); | ||
|
|
||
| glVertex2i(x+i, value); | ||
| glVertex2i(x+i, y); | ||
|
|
||
| value = dsp->getRMSHistory(i); | ||
| glColor4f(0.0f, 0.5f, 0.2f, 0.1f); | ||
| glVertex2i(x+i, value); | ||
| glVertex2i(x+i, y+h); | ||
| } | ||
| glEnd(); | ||
|
|
||
|
|
||
| //draw Threshold | ||
| glLineWidth(2.0f); | ||
| glColor4f(0.4f, 0.4f, 1.0f, 0.8f); | ||
| //float thresholdPosition = ((60-fKnobThreshold->getValue())/60); | ||
| glBegin(GL_LINES); | ||
| glVertex2i(x, thresholdPosition); | ||
| glVertex2i(x+w, thresholdPosition); | ||
| glEnd(); | ||
|
|
||
| // reset color | ||
| glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| UI* createUI() | ||
| { | ||
| return new PowerJuiceX2UI(); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| /* | ||
| * Power 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 POWERJUICEUI_HPP_INCLUDED | ||
| #define POWERJUICEUI_HPP_INCLUDED | ||
|
|
||
| #include "DistrhoUI.hpp" | ||
|
|
||
| #include "ImageAboutWindow.hpp" | ||
| #include "ImageButton.hpp" | ||
| #include "ImageKnob.hpp" | ||
| #include "ImageSlider.hpp" | ||
|
|
||
| #include "PowerJuiceX2Artwork.hpp" | ||
| #include "PowerJuiceX2Plugin.hpp" | ||
|
|
||
| #include <cmath> | ||
|
|
||
| using DGL::Image; | ||
| using DGL::ImageAboutWindow; | ||
| using DGL::ImageButton; | ||
| using DGL::ImageKnob; | ||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| class PowerJuiceX2UI : public UI, | ||
| public ImageButton::Callback, | ||
| public ImageKnob::Callback | ||
| { | ||
| public: | ||
| PowerJuiceX2UI(); | ||
|
|
||
| protected: | ||
| // ------------------------------------------------------------------- | ||
| // Information | ||
|
|
||
| uint d_getWidth() const noexcept override | ||
| { | ||
| return PowerJuiceX2Artwork::backgroundWidth; | ||
| } | ||
|
|
||
| uint d_getHeight() const noexcept override | ||
| { | ||
| return PowerJuiceX2Artwork::backgroundHeight; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------- | ||
| // DSP Callbacks | ||
|
|
||
| void d_parameterChanged(uint32_t index, float value) override; | ||
| void d_programChanged(uint32_t index) override; | ||
|
|
||
| // ------------------------------------------------------------------- | ||
| // UI Callbacks | ||
|
|
||
| void d_uiIdle() 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; | ||
|
|
||
| ScopedPointer<ImageKnob> fKnobAttack, fKnobRelease, fKnobThreshold; | ||
| ScopedPointer<ImageKnob> fKnobRatio, fKnobMakeup, fKnobMix; | ||
| ScopedPointer<ImageButton> fButtonAbout; | ||
|
|
||
| PowerJuiceX2Plugin* const dsp; | ||
|
|
||
| float fromDB(float gdb) { | ||
| return (std::exp(gdb/20.f*std::log(10.f))); | ||
| }; | ||
|
|
||
| float toDB(float g) { | ||
| return (20.f*std::log10(g)); | ||
| } | ||
|
|
||
| float toIEC(float db) { | ||
| float def = 0.0f; /* Meter deflection %age */ | ||
|
|
||
| if (db < -70.0f) { | ||
| def = 0.0f; | ||
| } else if (db < -60.0f) { | ||
| def = (db + 70.0f) * 0.25f; | ||
| } else if (db < -50.0f) { | ||
| def = (db + 60.0f) * 0.5f + 5.0f; | ||
| } else if (db < -40.0f) { | ||
| def = (db + 50.0f) * 0.75f + 7.5; | ||
| } else if (db < -30.0f) { | ||
| def = (db + 40.0f) * 1.5f + 15.0f; | ||
| } else if (db < -20.0f) { | ||
| def = (db + 30.0f) * 2.0f + 30.0f; | ||
| } else if (db < 0.0f) { | ||
| def = (db + 20.0f) * 2.5f + 50.0f; | ||
| } else { | ||
| def = 100.0f; | ||
| } | ||
|
|
||
| return (def * 2.0f); | ||
| } | ||
| }; | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO | ||
|
|
||
| #endif // POWERJUICEUI_HPP_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* | ||
| * Trigger 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 "StutterJuice" | ||
|
|
||
| #define DISTRHO_PLUGIN_HAS_UI 1 | ||
| #define DISTRHO_PLUGIN_IS_SYNTH 1 | ||
|
|
||
| #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:StutterJuice" | ||
|
|
||
| #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #!/usr/bin/make -f | ||
| # Makefile for DISTRHO Plugins # | ||
| # ---------------------------- # | ||
| # Created by falkTX | ||
| # | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Project name, used for binaries | ||
|
|
||
| NAME = StutterJuice | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Files to build | ||
|
|
||
| OBJS_DSP = \ | ||
| StutterJuicePlugin.cpp.o | ||
|
|
||
| OBJS_UI = \ | ||
| StutterJuiceArtwork.cpp.o \ | ||
| StutterJuiceUI.cpp.o | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Do some magic | ||
|
|
||
| include ../Makefile.mk | ||
|
|
||
| # -------------------------------------------------------------- | ||
| # Enable all possible plugin types | ||
|
|
||
| ifeq ($(LINUX),true) | ||
| all: jack lv2_sep vst | ||
| else | ||
| all: lv2_sep vst | ||
| endif | ||
|
|
||
| # -------------------------------------------------------------- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| /* (Auto-generated binary data file). */ | ||
|
|
||
| #ifndef BINARY_STUTTERJUICEARTWORK_HPP | ||
| #define BINARY_STUTTERJUICEARTWORK_HPP | ||
|
|
||
| namespace StutterJuiceArtwork | ||
| { | ||
| extern const char* aboutData; | ||
| const unsigned int aboutDataSize = 240000; | ||
| 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 = 933432; | ||
| const unsigned int backgroundWidth = 712; | ||
| const unsigned int backgroundHeight = 437; | ||
|
|
||
| extern const char* knobData; | ||
| const unsigned int knobDataSize = 10404; | ||
| const unsigned int knobWidth = 51; | ||
| const unsigned int knobHeight = 51; | ||
|
|
||
| extern const char* overlayData; | ||
| const unsigned int overlayDataSize = 1244576; | ||
| const unsigned int overlayWidth = 712; | ||
| const unsigned int overlayHeight = 437; | ||
|
|
||
| extern const char* sliderData; | ||
| const unsigned int sliderDataSize = 2600; | ||
| const unsigned int sliderWidth = 26; | ||
| const unsigned int sliderHeight = 25; | ||
| } | ||
|
|
||
| #endif // BINARY_STUTTERJUICEARTWORK_HPP | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| /* | ||
| * Stutter 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 "StutterJuicePlugin.hpp" | ||
| #include <iostream> | ||
|
|
||
|
|
||
|
|
||
| START_NAMESPACE_DISTRHO | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
|
|
||
|
|
||
| StutterJuicePlugin::StutterJuicePlugin() | ||
| : Plugin(paramCount, 1, 0) // 1 program, 0 states | ||
| { | ||
|
|
||
| // set default values | ||
| d_setProgram(0); | ||
|
|
||
| // reset | ||
| d_deactivate(); | ||
| } | ||
|
|
||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Init | ||
|
|
||
| void StutterJuicePlugin::d_initParameter(uint32_t index, Parameter& parameter) | ||
| { | ||
|
|
||
| if (index<26) { | ||
| parameter.hints = PARAMETER_IS_AUTOMABLE; | ||
| parameter.name = ""; | ||
| parameter.symbol = ""; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 0.0f; | ||
| parameter.ranges.min = 0.0f; | ||
| parameter.ranges.max = 1.0f; | ||
| } else { | ||
| parameter.hints = PARAMETER_IS_OUTPUT; | ||
| parameter.name = ""; | ||
| parameter.symbol = ""; | ||
| parameter.unit = ""; | ||
| parameter.ranges.def = 0.0f; | ||
| parameter.ranges.min = 0.0f; | ||
| parameter.ranges.max = 1.0f; | ||
| } | ||
| } | ||
|
|
||
| void StutterJuicePlugin::d_initProgramName(uint32_t index, d_string& programName) | ||
| { | ||
| if (index != 0) | ||
| return; | ||
|
|
||
| programName = "Default"; | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Internal data | ||
|
|
||
| float StutterJuicePlugin::d_getParameterValue(uint32_t index) const | ||
| { | ||
| if (index<26) { | ||
| int module = index/3; | ||
| int param = index%3; | ||
| return params[module][param]; | ||
| } else { | ||
| return outputParams[index-26]; | ||
| } | ||
| } | ||
|
|
||
| void StutterJuicePlugin::d_setParameterValue(uint32_t index, float value) | ||
| { | ||
| int module = index/3; | ||
| int param = index%3; | ||
| params[module][param] = value; | ||
| modules[module]->setParam(value, param); | ||
| if (param ==2) { | ||
| //modules[module]->resetSinePos(); | ||
| } | ||
| } | ||
|
|
||
| void StutterJuicePlugin::d_setProgram(uint32_t index) | ||
| { | ||
|
|
||
| if (index != 0) | ||
| return; | ||
|
|
||
| //default params[][] values | ||
| for (int module=0; module<6; module++) { | ||
| moduleActive[module] = false; | ||
| for (int param=0; param<3; param++) { | ||
| params[module][param] = 0.5; | ||
| } | ||
| } | ||
|
|
||
| modules[0] = new CGate(); | ||
| modules[1] = new CReverse(); | ||
| modules[2] = new CRepeat(); | ||
| modules[3] = new CSequence(); | ||
| modules[4] = new CShift(); | ||
| modules[5] = new CFilter(); | ||
|
|
||
| for (int module=0; module<6; module++) { | ||
| modules[module]->setSampleRate(d_getSampleRate()); | ||
| modules[module]->initBuffers(); | ||
| } | ||
|
|
||
| d_activate(); | ||
|
|
||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
| // Process | ||
|
|
||
| void StutterJuicePlugin::d_activate() | ||
| { | ||
|
|
||
| } | ||
|
|
||
| void StutterJuicePlugin::d_deactivate() | ||
| { | ||
| } | ||
|
|
||
| void StutterJuicePlugin::d_run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) | ||
| { | ||
|
|
||
|
|
||
| for (uint32_t i; i<frames; i++) { | ||
|
|
||
| float audioL = inputs[0][i]; | ||
| float audioR = inputs[1][i]; | ||
|
|
||
| rollLFOs(); | ||
|
|
||
| prepareOutputParams(); | ||
|
|
||
| for (int i=0; i<6; i++) { | ||
| modules[i]->process(audioL, audioR); | ||
| } | ||
|
|
||
| outputs[0][i] = audioL; | ||
| outputs[1][i] = audioR; | ||
|
|
||
| } | ||
|
|
||
|
|
||
|
|
||
| for (uint32_t i; i<midiEventCount; i++) { | ||
|
|
||
| int userNote = 48;//TODO | ||
| int range=6; | ||
|
|
||
| int mType = midiEvents[i].buf[0] & 0xF0; | ||
| int mChan = midiEvents[i].buf[0] & 0x0F; | ||
| int mNum = midiEvents[i].buf[1]; | ||
|
|
||
| if (mNum>=userNote && mNum<userNote+range) { | ||
| int module = mNum-userNote; | ||
| //printf("note: %i\n", module); | ||
| if (mType == 0x90) { | ||
| //NOTE ON | ||
| moduleActive[module] = true; | ||
| modules[module]->activate(); | ||
| } else if (mType == 0x80) { | ||
| //NOTE OFF | ||
| moduleActive[module] = false; | ||
| modules[module]->deactivate(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| Plugin* createPlugin() | ||
| { | ||
| return new StutterJuicePlugin(); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------- | ||
|
|
||
| END_NAMESPACE_DISTRHO |