@@ -0,0 +1,171 @@ | |||||
#!/usr/bin/make -f | |||||
# Makefile for native-plugins # | |||||
# --------------------------- # | |||||
# Created by falkTX | |||||
# | |||||
# NOTE: this file assumes Makefile.mk has been included before | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# DPF plugins | |||||
OBJS_all += \ | |||||
$(OBJDIR)/distrho-3bandeq.cpp.o \ | |||||
$(OBJDIR)/distrho-3bandsplitter.cpp.o \ | |||||
$(OBJDIR)/distrho-kars.cpp.o \ | |||||
$(OBJDIR)/distrho-nekobi.cpp.o \ | |||||
$(OBJDIR)/distrho-pingpongpan.cpp.o | |||||
ifeq ($(HAVE_DGL),true) | |||||
ifeq ($(HAVE_PROJECTM),true) | |||||
OBJS += $(OBJDIR)/distrho-prom.cpp.o | |||||
endif | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# DPF plugins (Juice) | |||||
OBJS_all += \ | |||||
$(OBJDIR)/distrho-vectorjuice.cpp.o \ | |||||
$(OBJDIR)/distrho-wobblejuice.cpp.o | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# ZynAddSubFX | |||||
ifeq ($(HAVE_ZYN_DEPS),true) | |||||
OBJS_all += \ | |||||
$(OBJDIR)/zynaddsubfx-fx.cpp.o \ | |||||
$(OBJDIR)/zynaddsubfx-src.cpp.o | |||||
ifneq ($(SKIP_ZYN_SYNTH),true) | |||||
OBJS_all += \ | |||||
$(OBJDIR)/zynaddsubfx-synth.cpp.o | |||||
endif | |||||
ifeq ($(HAVE_ZYN_UI_DEPS),true) | |||||
TARGETS += resources/zynaddsubfx-ui$(APP_EXT) | |||||
ZYN_UI_FILES_CPP = \ | |||||
external/zynaddsubfx/UI/ADnoteUI.cpp \ | |||||
external/zynaddsubfx/UI/BankUI.cpp \ | |||||
external/zynaddsubfx/UI/ConfigUI.cpp \ | |||||
external/zynaddsubfx/UI/EffUI.cpp \ | |||||
external/zynaddsubfx/UI/EnvelopeUI.cpp \ | |||||
external/zynaddsubfx/UI/FilterUI.cpp \ | |||||
external/zynaddsubfx/UI/LFOUI.cpp \ | |||||
external/zynaddsubfx/UI/MasterUI.cpp \ | |||||
external/zynaddsubfx/UI/MicrotonalUI.cpp \ | |||||
external/zynaddsubfx/UI/OscilGenUI.cpp \ | |||||
external/zynaddsubfx/UI/PADnoteUI.cpp \ | |||||
external/zynaddsubfx/UI/PartUI.cpp \ | |||||
external/zynaddsubfx/UI/PresetsUI.cpp \ | |||||
external/zynaddsubfx/UI/ResonanceUI.cpp \ | |||||
external/zynaddsubfx/UI/SUBnoteUI.cpp \ | |||||
external/zynaddsubfx/UI/VirKeyboard.cpp | |||||
ZYN_UI_FILES_H = \ | |||||
external/zynaddsubfx/UI/ADnoteUI.h \ | |||||
external/zynaddsubfx/UI/BankUI.h \ | |||||
external/zynaddsubfx/UI/ConfigUI.h \ | |||||
external/zynaddsubfx/UI/EffUI.h \ | |||||
external/zynaddsubfx/UI/EnvelopeUI.h \ | |||||
external/zynaddsubfx/UI/FilterUI.h \ | |||||
external/zynaddsubfx/UI/LFOUI.h \ | |||||
external/zynaddsubfx/UI/MasterUI.h \ | |||||
external/zynaddsubfx/UI/MicrotonalUI.h \ | |||||
external/zynaddsubfx/UI/OscilGenUI.h \ | |||||
external/zynaddsubfx/UI/PADnoteUI.h \ | |||||
external/zynaddsubfx/UI/PartUI.h \ | |||||
external/zynaddsubfx/UI/PresetsUI.h \ | |||||
external/zynaddsubfx/UI/ResonanceUI.h \ | |||||
external/zynaddsubfx/UI/SUBnoteUI.h \ | |||||
external/zynaddsubfx/UI/VirKeyboard.h | |||||
endif | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
external/zynaddsubfx/UI/%.cpp: external/zynaddsubfx/UI/%.fl | |||||
@echo "Generating $@|h" | |||||
@$(FLUID) -c -o external/zynaddsubfx/UI/$*.cpp -h external/zynaddsubfx/UI/$*.h $< | |||||
external/zynaddsubfx/UI/%.h: external/zynaddsubfx/UI/%.fl | |||||
@echo "Generating $@|cpp" | |||||
@$(FLUID) -c -o external/zynaddsubfx/UI/$*.cpp -h external/zynaddsubfx/UI/$*.h $< | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
$(OBJDIR)/distrho-3bandeq.cpp.o: external/distrho-3bandeq.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=d3BandEQ -Iexternal/distrho-3bandeq -c -o $@ | |||||
$(OBJDIR)/distrho-3bandsplitter.cpp.o: external/distrho-3bandsplitter.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=d3BandSplitter -Iexternal/distrho-3bandsplitter -c -o $@ | |||||
$(OBJDIR)/distrho-kars.cpp.o: external/distrho-kars.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=dKars -Iexternal/distrho-kars -c -o $@ | |||||
$(OBJDIR)/distrho-nekobi.cpp.o: external/distrho-nekobi.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=dNekobi -Iexternal/distrho-nekobi -w -c -o $@ | |||||
$(OBJDIR)/distrho-pingpongpan.cpp.o: external/distrho-pingpongpan.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=dPingPongPan -Iexternal/distrho-pingpongpan -c -o $@ | |||||
$(OBJDIR)/distrho-prom.cpp.o: external/distrho-prom.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) $(PROJECTM_FLAGS) -DDISTRHO_NAMESPACE=dProM -Iexternal/distrho-prom -c -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
$(OBJDIR)/distrho-vectorjuice.cpp.o: external/distrho-vectorjuice.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=dVectorJuice -Iexternal/distrho-vectorjuice -c -o $@ | |||||
$(OBJDIR)/distrho-wobblejuice.cpp.o: external/distrho-wobblejuice.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(DPF_FLAGS) -DDISTRHO_NAMESPACE=dWobbleJuice -Iexternal/distrho-wobblejuice -c -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
$(OBJDIR)/zynaddsubfx-fx.cpp.o: external/zynaddsubfx-fx.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(ZYN_DSP_FLAGS) -c -o $@ | |||||
$(OBJDIR)/zynaddsubfx-synth.cpp.o: external/zynaddsubfx-synth.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(ZYN_DSP_FLAGS) -Wno-unused-parameter -c -o $@ | |||||
$(OBJDIR)/zynaddsubfx-src.cpp.o: external/zynaddsubfx-src.cpp | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(ZYN_DSP_FLAGS) -Wno-unused-parameter -Wno-unused-variable -c -o $@ | |||||
$(OBJDIR)/zynaddsubfx-ui.cpp.o: external/zynaddsubfx-ui.cpp $(ZYN_UI_FILES_H) $(ZYN_UI_FILES_CPP) | |||||
-@mkdir -p $(OBJDIR) | |||||
@echo "Compiling $<" | |||||
@$(CXX) $< $(BUILD_CXX_FLAGS) $(ZYN_UI_FLAGS) -Wno-unused-parameter -Wno-unused-variable -c -o $@ | |||||
resources/zynaddsubfx-ui$(APP_EXT): $(OBJDIR)/zynaddsubfx-ui.cpp.o | |||||
-@mkdir -p ../resources | |||||
@echo "Linking zynaddsubfx-ui" | |||||
@$(CXX) $^ $(LINK_FLAGS) $(ZYN_UI_LIBS) -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
-include $(OBJDIR)/zynaddsubfx-ui.cpp.d | |||||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,233 @@ | |||||
#!/usr/bin/make -f | |||||
# Makefile for native-plugins # | |||||
# --------------------------- # | |||||
# Created by falkTX | |||||
# | |||||
ifeq ($(TESTBUILD),true) | |||||
ifeq ($(LINUX),true) | |||||
CXXFLAGS += -isystem /opt/kxstudio/include/ntk | |||||
endif | |||||
endif | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
HAVE_DGL = true | |||||
SKIP_ZYN_SYNTH = true | |||||
else | |||||
HAVE_DGL = $(shell pkg-config --exists gl x11 && echo true) | |||||
endif | |||||
HAVE_NTK = $(shell pkg-config --exists ntk ntk_images && echo true) | |||||
HAVE_PROJECTM = $(shell pkg-config --exists libprojectM && echo true) | |||||
ifneq ($(MACOS_OLD),true) | |||||
HAVE_ZYN_DEPS = $(shell pkg-config --exists liblo fftw3 mxml zlib && echo true) | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Check for optional libs (special non-pkgconfig unix tests) | |||||
ifeq ($(UNIX),true) | |||||
# fltk doesn't have a pkg-config file but has fltk-config instead. | |||||
# Also, don't try looking for it if we already have NTK. | |||||
ifneq ($(HAVE_NTK),true) | |||||
ifeq ($(shell which fltk-config 1>/dev/null 2>/dev/null && echo true),true) | |||||
ifeq ($(shell which fluid 1>/dev/null 2>/dev/null && echo true),true) | |||||
HAVE_FLTK = true | |||||
endif | |||||
endif | |||||
endif | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
ifeq ($(HAVE_FLTK),true) | |||||
HAVE_ZYN_UI_DEPS = true | |||||
endif | |||||
ifeq ($(HAVE_NTK),true) | |||||
HAVE_ZYN_UI_DEPS = true | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
ifeq ($(HAVE_DGL),true) | |||||
BASE_FLAGS += -DHAVE_DGL | |||||
endif | |||||
ifeq ($(HAVE_PROJECTM),true) | |||||
BASE_FLAGS += -DHAVE_PROJECTM | |||||
endif | |||||
ifeq ($(HAVE_ZYN_DEPS),true) | |||||
BASE_FLAGS += -DHAVE_ZYN_DEPS | |||||
ifeq ($(HAVE_ZYN_UI_DEPS),true) | |||||
BASE_FLAGS += -DHAVE_ZYN_UI_DEPS | |||||
endif | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
ifeq ($(HAVE_DGL),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
ifeq ($(MACOS),true) | |||||
DGL_LIBS = -framework OpenGL -framework Cocoa | |||||
endif | |||||
ifeq ($(WIN32),true) | |||||
DGL_LIBS = -lopengl32 -lgdi32 | |||||
endif | |||||
else | |||||
DGL_FLAGS = $(shell pkg-config --cflags gl x11) | |||||
DGL_LIBS = $(shell pkg-config --libs gl x11) | |||||
endif | |||||
DGL_FLAGS += -DDGL_NAMESPACE=CarlaDGL -DDGL_FILE_BROWSER_DISABLED -DDGL_NO_SHARED_RESOURCES | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
ifeq ($(HAVE_PROJECTM),true) | |||||
PROJECTM_FLAGS = $(shell pkg-config --cflags libprojectM) | |||||
PROJECTM_LIBS = $(shell pkg-config --libs libprojectM) | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Flags for DPF Plugins | |||||
DPF_FLAGS = -I$(CWDE)/modules/distrho | |||||
ifeq ($(HAVE_DGL),true) | |||||
ifneq ($(MACOS_OR_WIN32),true) | |||||
DPF_FLAGS += $(shell pkg-config --cflags gl) | |||||
endif | |||||
DPF_FLAGS += -I$(CWDE)/modules/dgl -DDGL_NAMESPACE=CarlaDGL -DDGL_FILE_BROWSER_DISABLED -DDGL_NO_SHARED_RESOURCES | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Flags for ZynAddSubFX (DSP and UI separated) | |||||
ifeq ($(HAVE_ZYN_DEPS),true) | |||||
# Common flags | |||||
ZYN_BASE_FLAGS = $(shell pkg-config --cflags liblo mxml) | |||||
ZYN_BASE_FLAGS += -Iexternal/zynaddsubfx -Iexternal/zynaddsubfx/rtosc | |||||
ifneq ($(WIN32),true) | |||||
ZYN_BASE_FLAGS += -DHAVE_ASYNC | |||||
endif | |||||
ZYN_BASE_LIBS = $(shell pkg-config --libs liblo mxml) -lpthread | |||||
ZYN_BASE_LIBS += $(LIBDL_LIBS) | |||||
# DSP flags | |||||
ZYN_DSP_FLAGS = $(ZYN_BASE_FLAGS) | |||||
ZYN_DSP_FLAGS += $(shell pkg-config --cflags fftw3 zlib) | |||||
ZYN_DSP_LIBS = $(ZYN_BASE_LIBS) | |||||
ZYN_DSP_LIBS += $(shell pkg-config --libs fftw3 zlib) | |||||
ifeq ($(SKIP_ZYN_SYNTH),true) | |||||
BASE_FLAGS += -DSKIP_ZYN_SYNTH | |||||
else | |||||
# UI flags | |||||
ifeq ($(HAVE_ZYN_UI_DEPS),true) | |||||
# Common UI flags | |||||
ZYN_UI_FLAGS = $(ZYN_BASE_FLAGS) | |||||
ZYN_UI_LIBS = $(ZYN_BASE_LIBS) | |||||
# NTK or FLTK UI flags | |||||
ifeq ($(HAVE_NTK),true) | |||||
FLUID = ntk-fluid | |||||
ZYN_UI_FLAGS += $(shell pkg-config --cflags ntk_images ntk) -DNTK_GUI | |||||
ZYN_UI_LIBS += $(shell pkg-config --libs ntk_images ntk) | |||||
else # HAVE_NTK | |||||
FLUID = fluid | |||||
ZYN_UI_FLAGS += $(shell fltk-config --use-images --cxxflags) -DFLTK_GUI | |||||
ZYN_UI_LIBS += $(shell fltk-config --use-images --ldflags) | |||||
endif # HAVE_NTK | |||||
# UI extra flags | |||||
ifeq ($(HAVE_X11),true) | |||||
ZYN_UI_FLAGS += $(shell pkg-config --cflags x11) | |||||
ZYN_UI_LIBS += $(shell pkg-config --libs x11) | |||||
endif | |||||
ifeq ($(LINUX),true) | |||||
ZYN_UI_LIBS += -lrt | |||||
endif | |||||
else # HAVE_ZYN_UI_DEPS | |||||
ZYN_DSP_FLAGS += -DNO_UI | |||||
endif # SKIP_ZYN_SYNTH | |||||
endif # HAVE_ZYN_UI_DEPS | |||||
endif # HAVE_ZYN_DEPS | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
NATIVE_PLUGINS_LIBS += $(DGL_LIBS) | |||||
NATIVE_PLUGINS_LIBS += $(PROJECTM_LIBS) | |||||
NATIVE_PLUGINS_LIBS += $(ZYN_DSP_LIBS) | |||||
NATIVE_PLUGINS_LIBS += $(ZITA_DSP_LIBS) | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
ifeq ($(HAVE_DGL),true) | |||||
ALL_LIBS += $(MODULEDIR)/dgl.a | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
all: | |||||
install_external_plugins: | |||||
ifeq ($(HAVE_ZYN_DEPS),true) | |||||
ifeq ($(HAVE_ZYN_UI_DEPS),true) | |||||
# Create directories (zynaddsubfx) | |||||
install -d $(DESTDIR)$(DATADIR)/carla/resources/zynaddsubfx | |||||
# Install resources (zynaddsubfx) | |||||
install -m 644 \ | |||||
bin/resources/zynaddsubfx/*.png \ | |||||
$(DESTDIR)$(DATADIR)/carla/resources/zynaddsubfx | |||||
install -m 755 \ | |||||
bin/resources/zynaddsubfx-ui \ | |||||
$(DESTDIR)$(DATADIR)/carla/resources | |||||
endif | |||||
endif | |||||
features_print_external_plugins: | |||||
@printf -- "\n" | |||||
@printf -- "$(tS)---> External plugins: $(tE)\n" | |||||
ifeq ($(HAVE_DGL),true) | |||||
@printf -- "DPF Plugins: $(ANS_YES) (with UI)\n" | |||||
ifeq ($(HAVE_PROJECTM),true) | |||||
@printf -- "DPF ProM: $(ANS_YES)\n" | |||||
else | |||||
@printf -- "DPF ProM: $(ANS_NO) $(mS)missing libprojectM$(mE)\n" | |||||
endif | |||||
else | |||||
@printf -- "DPF Plugins: $(ANS_YES) (without UI)\n" | |||||
ifeq ($(HAVE_PROJECTM),true) | |||||
@printf -- "DPF ProM: $(ANS_NO) $(mS)missing OpenGL$(mE)\n" | |||||
else | |||||
@printf -- "DPF ProM: $(ANS_NO) $(mS)missing OpenGL and libprojectM$(mE)\n" | |||||
endif | |||||
endif | |||||
ifeq ($(HAVE_ZYN_DEPS),true) | |||||
ifeq ($(HAVE_ZYN_UI_DEPS),true) | |||||
ifeq ($(HAVE_NTK),true) | |||||
@printf -- "ZynAddSubFX: $(ANS_YES) (with NTK UI)\n" | |||||
else | |||||
@printf -- "ZynAddSubFX: $(ANS_YES) (with FLTK UI)\n" | |||||
endif | |||||
else | |||||
@printf -- "ZynAddSubFX: $(ANS_YES) (without UI) $(mS)FLTK or NTK missing$(mE)\n" | |||||
endif | |||||
else | |||||
@printf -- "ZynAddSubFX: $(ANS_NO) $(mS)liblo, fftw3, mxml or zlib missing$(mE)\n" | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,66 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 "CarlaDefines.h" | |||||
#include "CarlaNative.h" | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// DISTRHO plugins | |||||
extern void carla_register_native_plugin_distrho_3bandeq(void); | |||||
extern void carla_register_native_plugin_distrho_3bandsplitter(void); | |||||
extern void carla_register_native_plugin_distrho_kars(void); | |||||
extern void carla_register_native_plugin_distrho_nekobi(void); | |||||
extern void carla_register_native_plugin_distrho_pingpongpan(void); | |||||
extern void carla_register_native_plugin_distrho_prom(void); | |||||
// DISTRHO plugins (Juice) | |||||
extern void carla_register_native_plugin_distrho_vectorjuice(void); | |||||
extern void carla_register_native_plugin_distrho_wobblejuice(void); | |||||
// ZynAddSubFX | |||||
extern void carla_register_native_plugin_zynaddsubfx_fx(void); | |||||
extern void carla_register_native_plugin_zynaddsubfx_synth(void); | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void carla_register_all_native_external_plugins(void) | |||||
{ | |||||
// DISTRHO Plugins | |||||
carla_register_native_plugin_distrho_3bandeq(); | |||||
carla_register_native_plugin_distrho_3bandsplitter(); | |||||
carla_register_native_plugin_distrho_kars(); | |||||
carla_register_native_plugin_distrho_nekobi(); | |||||
carla_register_native_plugin_distrho_pingpongpan(); | |||||
#if defined(HAVE_DGL) && defined(HAVE_PROJECTM) | |||||
carla_register_native_plugin_distrho_prom(); | |||||
#endif | |||||
// DISTRHO plugins (Juice) | |||||
carla_register_native_plugin_distrho_vectorjuice(); | |||||
carla_register_native_plugin_distrho_wobblejuice(); | |||||
#ifdef HAVE_ZYN_DEPS | |||||
// ZynAddSubFX | |||||
carla_register_native_plugin_zynaddsubfx_fx(); | |||||
# ifndef SKIP_ZYN_SYNTH | |||||
carla_register_native_plugin_zynaddsubfx_synth(); | |||||
# endif | |||||
#endif | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,470 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 "CarlaNative.h" | |||||
#include "CarlaMIDI.h" | |||||
#include "CarlaUtils.hpp" | |||||
#ifndef CARLA_EXTERNAL_PLUGINS_INCLUDED_DIRECTLY | |||||
# define DESCFUNCS \ | |||||
nullptr, nullptr, nullptr, nullptr, nullptr, \ | |||||
nullptr, nullptr, nullptr, nullptr, nullptr, \ | |||||
nullptr, nullptr, nullptr, nullptr, nullptr, \ | |||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr | |||||
static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// DISTRHO Plugins | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_EQ, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 6, | |||||
/* paramOuts */ 0, | |||||
/* name */ "3 Band EQ", | |||||
/* label */ "3bandeq", | |||||
/* maker */ "falkTX, Michael Gruhn", | |||||
/* copyright */ "LGPL", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_EQ, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 6, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 6, | |||||
/* paramOuts */ 0, | |||||
/* name */ "3 Band Splitter", | |||||
/* label */ "3bandsplitter", | |||||
/* maker */ "falkTX, Michael Gruhn", | |||||
/* copyright */ "LGPL", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_SYNTH, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 0, | |||||
/* audioOuts */ 1, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 1, | |||||
/* paramOuts */ 0, | |||||
/* name */ "Kars", | |||||
/* label */ "kars", | |||||
/* maker */ "falkTX, Chris Cannam", | |||||
/* copyright */ "ISC", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_SYNTH, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH), | |||||
#endif | |||||
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES | |||||
|NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF), | |||||
/* audioIns */ 0, | |||||
/* audioOuts */ 1, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 8, | |||||
/* paramOuts */ 0, | |||||
/* name */ "Nekobi", | |||||
/* label */ "nekobi", | |||||
/* maker */ "falkTX, Sean Bolton and others", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "Ping Pong Pan", | |||||
/* label */ "pingpongpan", | |||||
/* maker */ "falkTX, Michael Gruhn", | |||||
/* copyright */ "LGPL", | |||||
DESCFUNCS | |||||
}, | |||||
#ifdef HAVE_DGL | |||||
#ifdef HAVE_PROJECTM | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 1, | |||||
/* audioOuts */ 1, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 0, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ProM", | |||||
/* label */ "prom", | |||||
/* maker */ "falkTX", | |||||
/* copyright */ "LGPL", | |||||
DESCFUNCS | |||||
}, | |||||
#endif // HAVE_PROJECTM | |||||
#endif // HAVE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// DISTRHO plugins (Juice) | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_DYNAMICS, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 6, | |||||
/* paramOuts */ 0, | |||||
/* name */ "WobbleJuice", | |||||
/* label */ "wobblejuice", | |||||
/* maker */ "Andre Sklenar", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 8, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 13, | |||||
/* paramOuts */ 4, | |||||
/* name */ "VectorJuice", | |||||
/* label */ "vectorjuice", | |||||
/* maker */ "Andre Sklenar", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// ZynAddSubFX | |||||
#ifdef HAVE_ZYN_DEPS | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_MODULATOR, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 11-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynAlienWah", | |||||
/* label */ "zynalienwah", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_MODULATOR, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 12-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynChorus", | |||||
/* label */ "zynchorus", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_MODULATOR, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 11-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynDistortion", | |||||
/* label */ "zyndistortion", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_FILTER, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 10-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynDynamicFilter", | |||||
/* label */ "zyndynamicfilter", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_DELAY, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 7-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynEcho", | |||||
/* label */ "zynecho", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_MODULATOR, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 15-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynPhaser", | |||||
/* label */ "zynphaser", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_DELAY, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_USES_PANNING | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 13-2, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynReverb", | |||||
/* label */ "zynreverb", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
# ifndef SKIP_ZYN_SYNTH | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_SYNTH, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH | |||||
# ifdef HAVE_ZYN_UI_DEPS | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
# endif | |||||
|NATIVE_PLUGIN_USES_MULTI_PROGS | |||||
|NATIVE_PLUGIN_USES_STATE), | |||||
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES | |||||
|NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH | |||||
|NATIVE_PLUGIN_SUPPORTS_PITCHBEND | |||||
|NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF), | |||||
/* audioIns */ 0, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 6, | |||||
/* paramOuts */ 0, | |||||
/* name */ "ZynAddSubFX", | |||||
/* label */ "zynaddsubfx", | |||||
/* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul", | |||||
/* copyright */ "GNU GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
# endif // ! SKIP_ZYN_SYNTH | |||||
#endif // HAVE_ZYN_DEPS | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Experimental plugins | |||||
#ifdef HAVE_EXPERIMENTAL_PLUGINS | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_MODULATOR, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS | |||||
|NATIVE_PLUGIN_USES_STATE), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 1, | |||||
/* audioOuts */ 1, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 6, | |||||
/* paramOuts */ 0, | |||||
/* name */ "AT1", | |||||
/* label */ "at1", | |||||
/* maker */ "falkTX, Fons Adriaensen", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_FILTER, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 6, | |||||
/* paramOuts */ 0, | |||||
/* name */ "BLS1", | |||||
/* label */ "bls1", | |||||
/* maker */ "falkTX, Fons Adriaensen", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_DELAY, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 4, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 10, | |||||
/* paramOuts */ 0, | |||||
/* name */ "REV1 (Ambisonic)", | |||||
/* label */ "rev1-ambisonic", | |||||
/* maker */ "falkTX, Fons Adriaensen", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
{ | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_DELAY, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 10, | |||||
/* paramOuts */ 0, | |||||
/* name */ "REV1 (Stereo)", | |||||
/* label */ "rev1-stereo", | |||||
/* maker */ "falkTX, Fons Adriaensen", | |||||
/* copyright */ "GPL v2+", | |||||
DESCFUNCS | |||||
}, | |||||
#endif // HAVE_EXPERIMENTAL_PLUGINS | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#ifndef CARLA_EXTERNAL_PLUGINS_INCLUDED_DIRECTLY | |||||
} | |||||
#endif |
@@ -0,0 +1,85 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-3bandeq/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaMathUtils.hpp" | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-3bandeq/DistrhoArtwork3BandEQ.cpp" | |||||
#include "distrho-3bandeq/DistrhoPlugin3BandEQ.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-3bandeq/DistrhoUI3BandEQ.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor _3bandeqDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_EQ, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ DistrhoPlugin3BandEQ::paramCount, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "3bandeq", | |||||
/* maker */ "falkTX, Michael Gruhn", | |||||
/* copyright */ "LGPL", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_3bandeq(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_3bandeq() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&_3bandeqDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,40 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_DISTRHOARTWORK3BANDEQ_HPP | |||||
#define BINARY_DISTRHOARTWORK3BANDEQ_HPP | |||||
namespace DistrhoArtwork3BandEQ | |||||
{ | |||||
extern const char* aboutData; | |||||
const unsigned int aboutDataSize = 172710; | |||||
const unsigned int aboutWidth = 303; | |||||
const unsigned int aboutHeight = 190; | |||||
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 = 437472; | |||||
const unsigned int backgroundWidth = 392; | |||||
const unsigned int backgroundHeight = 372; | |||||
extern const char* knobData; | |||||
const unsigned int knobDataSize = 15376; | |||||
const unsigned int knobWidth = 62; | |||||
const unsigned int knobHeight = 62; | |||||
extern const char* sliderData; | |||||
const unsigned int sliderDataSize = 6000; | |||||
const unsigned int sliderWidth = 50; | |||||
const unsigned int sliderHeight = 30; | |||||
} | |||||
#endif // BINARY_DISTRHOARTWORK3BANDEQ_HPP | |||||
@@ -0,0 +1,264 @@ | |||||
/* | |||||
* DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||||
* Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPlugin3BandEQ.hpp" | |||||
#include <cmath> | |||||
static const float kAMP_DB = 8.656170245f; | |||||
static const float kDC_ADD = 1e-30f; | |||||
static const float kPI = 3.141592654f; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoPlugin3BandEQ::DistrhoPlugin3BandEQ() | |||||
: Plugin(paramCount, 1, 0) // 1 program, 0 states | |||||
{ | |||||
// set default values | |||||
loadProgram(0); | |||||
// reset | |||||
deactivate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramLow: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Low"; | |||||
parameter.symbol = "low"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramMid: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Mid"; | |||||
parameter.symbol = "mid"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramHigh: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "High"; | |||||
parameter.symbol = "high"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramMaster: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Master"; | |||||
parameter.symbol = "master"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramLowMidFreq: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Low-Mid Freq"; | |||||
parameter.symbol = "low_mid"; | |||||
parameter.unit = "Hz"; | |||||
parameter.ranges.def = 440.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1000.0f; | |||||
break; | |||||
case paramMidHighFreq: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Mid-High Freq"; | |||||
parameter.symbol = "mid_high"; | |||||
parameter.unit = "Hz"; | |||||
parameter.ranges.def = 1000.0f; | |||||
parameter.ranges.min = 1000.0f; | |||||
parameter.ranges.max = 20000.0f; | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoPlugin3BandEQ::initProgramName(uint32_t index, String& programName) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
programName = "Default"; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float DistrhoPlugin3BandEQ::getParameterValue(uint32_t index) const | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramLow: | |||||
return fLow; | |||||
case paramMid: | |||||
return fMid; | |||||
case paramHigh: | |||||
return fHigh; | |||||
case paramMaster: | |||||
return fMaster; | |||||
case paramLowMidFreq: | |||||
return fLowMidFreq; | |||||
case paramMidHighFreq: | |||||
return fMidHighFreq; | |||||
default: | |||||
return 0.0f; | |||||
} | |||||
} | |||||
void DistrhoPlugin3BandEQ::setParameterValue(uint32_t index, float value) | |||||
{ | |||||
if (getSampleRate() <= 0.0) | |||||
return; | |||||
switch (index) | |||||
{ | |||||
case paramLow: | |||||
fLow = value; | |||||
lowVol = std::exp( (fLow/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramMid: | |||||
fMid = value; | |||||
midVol = std::exp( (fMid/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramHigh: | |||||
fHigh = value; | |||||
highVol = std::exp( (fHigh/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramMaster: | |||||
fMaster = value; | |||||
outVol = std::exp( (fMaster/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramLowMidFreq: | |||||
fLowMidFreq = std::fmin(value, fMidHighFreq); | |||||
freqLP = fLowMidFreq; | |||||
xLP = std::exp(-2.0f * kPI * freqLP / (float)getSampleRate()); | |||||
a0LP = 1.0f - xLP; | |||||
b1LP = -xLP; | |||||
break; | |||||
case paramMidHighFreq: | |||||
fMidHighFreq = std::fmax(value, fLowMidFreq); | |||||
freqHP = fMidHighFreq; | |||||
xHP = std::exp(-2.0f * kPI * freqHP / (float)getSampleRate()); | |||||
a0HP = 1.0f - xHP; | |||||
b1HP = -xHP; | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoPlugin3BandEQ::loadProgram(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fLow = 0.0f; | |||||
fMid = 0.0f; | |||||
fHigh = 0.0f; | |||||
fMaster = 0.0f; | |||||
fLowMidFreq = 220.0f; | |||||
fMidHighFreq = 2000.0f; | |||||
// Internal stuff | |||||
lowVol = midVol = highVol = outVol = 1.0f; | |||||
freqLP = 200.0f; | |||||
freqHP = 2000.0f; | |||||
// reset filter values | |||||
activate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void DistrhoPlugin3BandEQ::activate() | |||||
{ | |||||
const float sr = (float)getSampleRate(); | |||||
xLP = std::exp(-2.0f * kPI * freqLP / sr); | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
// don't ask me why, but this fixes a crash/exception below on windows... | |||||
printf("%f\n", -xLP); | |||||
#endif | |||||
a0LP = 1.0f - xLP; | |||||
b1LP = -xLP; | |||||
xHP = std::exp(-2.0f * kPI * freqHP / sr); | |||||
a0HP = 1.0f - xHP; | |||||
b1HP = -xHP; | |||||
} | |||||
void DistrhoPlugin3BandEQ::deactivate() | |||||
{ | |||||
out1LP = out2LP = out1HP = out2HP = 0.0f; | |||||
tmp1LP = tmp2LP = tmp1HP = tmp2HP = 0.0f; | |||||
} | |||||
void DistrhoPlugin3BandEQ::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]; | |||||
for (uint32_t i=0; i < frames; ++i) | |||||
{ | |||||
tmp1LP = a0LP * in1[i] - b1LP * tmp1LP + kDC_ADD; | |||||
tmp2LP = a0LP * in2[i] - b1LP * tmp2LP + kDC_ADD; | |||||
out1LP = tmp1LP - kDC_ADD; | |||||
out2LP = tmp2LP - kDC_ADD; | |||||
tmp1HP = a0HP * in1[i] - b1HP * tmp1HP + kDC_ADD; | |||||
tmp2HP = a0HP * in2[i] - b1HP * tmp2HP + kDC_ADD; | |||||
out1HP = in1[i] - tmp1HP - kDC_ADD; | |||||
out2HP = in2[i] - tmp2HP - kDC_ADD; | |||||
out1[i] = (out1LP*lowVol + (in1[i] - out1LP - out1HP)*midVol + out1HP*highVol) * outVol; | |||||
out2[i] = (out2LP*lowVol + (in2[i] - out2LP - out2HP)*midVol + out2HP*highVol) * outVol; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new DistrhoPlugin3BandEQ(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,123 @@ | |||||
/* | |||||
* DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||||
* Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_3BANDEQ_HPP_INCLUDED | |||||
#define DISTRHO_PLUGIN_3BANDEQ_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoPlugin3BandEQ : public Plugin | |||||
{ | |||||
public: | |||||
enum Parameters | |||||
{ | |||||
paramLow = 0, | |||||
paramMid, | |||||
paramHigh, | |||||
paramMaster, | |||||
paramLowMidFreq, | |||||
paramMidHighFreq, | |||||
paramCount | |||||
}; | |||||
DistrhoPlugin3BandEQ(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "3BandEQ"; | |||||
} | |||||
const char* getDescription() const override | |||||
{ | |||||
return "3 Band Equalizer, stereo version."; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "DISTRHO"; | |||||
} | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/Mini-Series"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "LGPL"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', '3', 'E', 'Q'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
void initProgramName(uint32_t index, String& programName) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
void loadProgram(uint32_t index) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void deactivate() override; | |||||
void run(const float** inputs, float** outputs, uint32_t frames) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
float fLow, fMid, fHigh, fMaster, fLowMidFreq, fMidHighFreq; | |||||
float lowVol, midVol, highVol, outVol; | |||||
float freqLP, freqHP; | |||||
float xLP, a0LP, b1LP; | |||||
float xHP, a0HP, b1HP; | |||||
float out1LP, out2LP, out1HP, out2HP; | |||||
float tmp1LP, tmp2LP, tmp1HP, tmp2HP; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoPlugin3BandEQ) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_PLUGIN_3BANDEQ_HPP_INCLUDED |
@@ -0,0 +1,32 @@ | |||||
/* | |||||
* DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "3 Band EQ" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandEQ" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||||
#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:EQPlugin" | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,211 @@ | |||||
/* | |||||
* DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPlugin3BandEQ.hpp" | |||||
#include "DistrhoUI3BandEQ.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
namespace Art = DistrhoArtwork3BandEQ; | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoUI3BandEQ::DistrhoUI3BandEQ() | |||||
: UI(Art::backgroundWidth, Art::backgroundHeight), | |||||
fImgBackground(Art::backgroundData, Art::backgroundWidth, Art::backgroundHeight, GL_BGR), | |||||
fAboutWindow(this) | |||||
{ | |||||
// about | |||||
Image aboutImage(Art::aboutData, Art::aboutWidth, Art::aboutHeight, GL_BGR); | |||||
fAboutWindow.setImage(aboutImage); | |||||
// sliders | |||||
Image sliderImage(Art::sliderData, Art::sliderWidth, Art::sliderHeight); | |||||
Point<int> sliderPosStart(57, 43); | |||||
Point<int> sliderPosEnd(57, 43 + 160); | |||||
// slider Low | |||||
fSliderLow = new ImageSlider(this, sliderImage); | |||||
fSliderLow->setId(DistrhoPlugin3BandEQ::paramLow); | |||||
fSliderLow->setInverted(true); | |||||
fSliderLow->setStartPos(sliderPosStart); | |||||
fSliderLow->setEndPos(sliderPosEnd); | |||||
fSliderLow->setRange(-24.0f, 24.0f); | |||||
fSliderLow->setCallback(this); | |||||
// slider Mid | |||||
sliderPosStart.setX(120); | |||||
sliderPosEnd.setX(120); | |||||
fSliderMid = new ImageSlider(this, sliderImage); | |||||
fSliderMid->setId(DistrhoPlugin3BandEQ::paramMid); | |||||
fSliderMid->setInverted(true); | |||||
fSliderMid->setStartPos(sliderPosStart); | |||||
fSliderMid->setEndPos(sliderPosEnd); | |||||
fSliderMid->setRange(-24.0f, 24.0f); | |||||
fSliderMid->setCallback(this); | |||||
// slider High | |||||
sliderPosStart.setX(183); | |||||
sliderPosEnd.setX(183); | |||||
fSliderHigh = new ImageSlider(this, sliderImage); | |||||
fSliderHigh->setId(DistrhoPlugin3BandEQ::paramHigh); | |||||
fSliderHigh->setInverted(true); | |||||
fSliderHigh->setStartPos(sliderPosStart); | |||||
fSliderHigh->setEndPos(sliderPosEnd); | |||||
fSliderHigh->setRange(-24.0f, 24.0f); | |||||
fSliderHigh->setCallback(this); | |||||
// slider Master | |||||
sliderPosStart.setX(287); | |||||
sliderPosEnd.setX(287); | |||||
fSliderMaster = new ImageSlider(this, sliderImage); | |||||
fSliderMaster->setId(DistrhoPlugin3BandEQ::paramMaster); | |||||
fSliderMaster->setInverted(true); | |||||
fSliderMaster->setStartPos(sliderPosStart); | |||||
fSliderMaster->setEndPos(sliderPosEnd); | |||||
fSliderMaster->setRange(-24.0f, 24.0f); | |||||
fSliderMaster->setCallback(this); | |||||
// knobs | |||||
Image knobImage(Art::knobData, Art::knobWidth, Art::knobHeight); | |||||
// knob Low-Mid | |||||
fKnobLowMid = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobLowMid->setId(DistrhoPlugin3BandEQ::paramLowMidFreq); | |||||
fKnobLowMid->setAbsolutePos(65, 269); | |||||
fKnobLowMid->setRange(0.0f, 1000.0f); | |||||
fKnobLowMid->setDefault(440.0f); | |||||
fKnobLowMid->setRotationAngle(270); | |||||
fKnobLowMid->setCallback(this); | |||||
// knob Mid-High | |||||
fKnobMidHigh = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobMidHigh->setId(DistrhoPlugin3BandEQ::paramMidHighFreq); | |||||
fKnobMidHigh->setAbsolutePos(159, 269); | |||||
fKnobMidHigh->setRange(1000.0f, 20000.0f); | |||||
fKnobMidHigh->setDefault(1000.0f); | |||||
fKnobMidHigh->setRotationAngle(270); | |||||
fKnobMidHigh->setCallback(this); | |||||
// about button | |||||
Image aboutImageNormal(Art::aboutButtonNormalData, Art::aboutButtonNormalWidth, Art::aboutButtonNormalHeight); | |||||
Image aboutImageHover(Art::aboutButtonHoverData, Art::aboutButtonHoverWidth, Art::aboutButtonHoverHeight); | |||||
fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||||
fButtonAbout->setAbsolutePos(264, 300); | |||||
fButtonAbout->setCallback(this); | |||||
// set default values | |||||
programLoaded(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void DistrhoUI3BandEQ::parameterChanged(uint32_t index, float value) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case DistrhoPlugin3BandEQ::paramLow: | |||||
fSliderLow->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandEQ::paramMid: | |||||
fSliderMid->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandEQ::paramHigh: | |||||
fSliderHigh->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandEQ::paramMaster: | |||||
fSliderMaster->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandEQ::paramLowMidFreq: | |||||
fKnobLowMid->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandEQ::paramMidHighFreq: | |||||
fKnobMidHigh->setValue(value); | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoUI3BandEQ::programLoaded(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fSliderLow->setValue(0.0f); | |||||
fSliderMid->setValue(0.0f); | |||||
fSliderHigh->setValue(0.0f); | |||||
fSliderMaster->setValue(0.0f); | |||||
fKnobLowMid->setValue(220.0f); | |||||
fKnobMidHigh->setValue(2000.0f); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void DistrhoUI3BandEQ::imageButtonClicked(ImageButton* button, int) | |||||
{ | |||||
if (button != fButtonAbout) | |||||
return; | |||||
fAboutWindow.exec(); | |||||
} | |||||
void DistrhoUI3BandEQ::imageKnobDragStarted(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), true); | |||||
} | |||||
void DistrhoUI3BandEQ::imageKnobDragFinished(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), false); | |||||
} | |||||
void DistrhoUI3BandEQ::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
{ | |||||
setParameterValue(knob->getId(), value); | |||||
} | |||||
void DistrhoUI3BandEQ::imageSliderDragStarted(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), true); | |||||
} | |||||
void DistrhoUI3BandEQ::imageSliderDragFinished(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), false); | |||||
} | |||||
void DistrhoUI3BandEQ::imageSliderValueChanged(ImageSlider* slider, float value) | |||||
{ | |||||
setParameterValue(slider->getId(), value); | |||||
} | |||||
void DistrhoUI3BandEQ::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new DistrhoUI3BandEQ(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,72 @@ | |||||
/* | |||||
* DISTRHO 3BandEQ Plugin, based on 3BandEQ by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_UI_3BANDEQ_HPP_INCLUDED | |||||
#define DISTRHO_UI_3BANDEQ_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
#include "ImageWidgets.hpp" | |||||
#include "DistrhoArtwork3BandEQ.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoUI3BandEQ : public UI, | |||||
public ImageButton::Callback, | |||||
public ImageKnob::Callback, | |||||
public ImageSlider::Callback | |||||
{ | |||||
public: | |||||
DistrhoUI3BandEQ(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
void programLoaded(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 imageSliderDragStarted(ImageSlider* slider) override; | |||||
void imageSliderDragFinished(ImageSlider* slider) override; | |||||
void imageSliderValueChanged(ImageSlider* slider, float value) override; | |||||
void onDisplay() override; | |||||
private: | |||||
Image fImgBackground; | |||||
ImageAboutWindow fAboutWindow; | |||||
ScopedPointer<ImageButton> fButtonAbout; | |||||
ScopedPointer<ImageKnob> fKnobLowMid, fKnobMidHigh; | |||||
ScopedPointer<ImageSlider> fSliderLow, fSliderMid, fSliderHigh, fSliderMaster; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUI3BandEQ) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_3BANDEQ_HPP_INCLUDED |
@@ -0,0 +1,85 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-3bandsplitter/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaMathUtils.hpp" | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-3bandsplitter/DistrhoArtwork3BandSplitter.cpp" | |||||
#include "distrho-3bandsplitter/DistrhoPlugin3BandSplitter.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-3bandsplitter/DistrhoUI3BandSplitter.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor _3bandsplitterDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_EQ, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ DistrhoPlugin3BandSplitter::paramCount, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "3bandsplitter", | |||||
/* maker */ "falkTX, Michael Gruhn", | |||||
/* copyright */ "LGPL", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_3bandsplitter(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_3bandsplitter() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&_3bandsplitterDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,40 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_DISTRHOARTWORK3BANDSPLITTER_HPP | |||||
#define BINARY_DISTRHOARTWORK3BANDSPLITTER_HPP | |||||
namespace DistrhoArtwork3BandSplitter | |||||
{ | |||||
extern const char* aboutData; | |||||
const unsigned int aboutDataSize = 172710; | |||||
const unsigned int aboutWidth = 303; | |||||
const unsigned int aboutHeight = 190; | |||||
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 = 437472; | |||||
const unsigned int backgroundWidth = 392; | |||||
const unsigned int backgroundHeight = 372; | |||||
extern const char* knobData; | |||||
const unsigned int knobDataSize = 15376; | |||||
const unsigned int knobWidth = 62; | |||||
const unsigned int knobHeight = 62; | |||||
extern const char* sliderData; | |||||
const unsigned int sliderDataSize = 6000; | |||||
const unsigned int sliderWidth = 50; | |||||
const unsigned int sliderHeight = 30; | |||||
} | |||||
#endif // BINARY_DISTRHOARTWORK3BANDSPLITTER_HPP | |||||
@@ -0,0 +1,272 @@ | |||||
/* | |||||
* DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||||
* Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPlugin3BandSplitter.hpp" | |||||
#include <cmath> | |||||
static const float kAMP_DB = 8.656170245f; | |||||
static const float kDC_ADD = 1e-30f; | |||||
static const float kPI = 3.141592654f; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoPlugin3BandSplitter::DistrhoPlugin3BandSplitter() | |||||
: Plugin(paramCount, 1, 0) // 1 program, 0 states | |||||
{ | |||||
// set default values | |||||
loadProgram(0); | |||||
// reset | |||||
deactivate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramLow: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Low"; | |||||
parameter.symbol = "low"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramMid: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Mid"; | |||||
parameter.symbol = "mid"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramHigh: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "High"; | |||||
parameter.symbol = "high"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramMaster: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Master"; | |||||
parameter.symbol = "master"; | |||||
parameter.unit = "dB"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -24.0f; | |||||
parameter.ranges.max = 24.0f; | |||||
break; | |||||
case paramLowMidFreq: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Low-Mid Freq"; | |||||
parameter.symbol = "low_mid"; | |||||
parameter.unit = "Hz"; | |||||
parameter.ranges.def = 440.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1000.0f; | |||||
break; | |||||
case paramMidHighFreq: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Mid-High Freq"; | |||||
parameter.symbol = "mid_high"; | |||||
parameter.unit = "Hz"; | |||||
parameter.ranges.def = 1000.0f; | |||||
parameter.ranges.min = 1000.0f; | |||||
parameter.ranges.max = 20000.0f; | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoPlugin3BandSplitter::initProgramName(uint32_t index, String& programName) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
programName = "Default"; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float DistrhoPlugin3BandSplitter::getParameterValue(uint32_t index) const | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramLow: | |||||
return fLow; | |||||
case paramMid: | |||||
return fMid; | |||||
case paramHigh: | |||||
return fHigh; | |||||
case paramMaster: | |||||
return fMaster; | |||||
case paramLowMidFreq: | |||||
return fLowMidFreq; | |||||
case paramMidHighFreq: | |||||
return fMidHighFreq; | |||||
default: | |||||
return 0.0f; | |||||
} | |||||
} | |||||
void DistrhoPlugin3BandSplitter::setParameterValue(uint32_t index, float value) | |||||
{ | |||||
if (getSampleRate() <= 0.0) | |||||
return; | |||||
switch (index) | |||||
{ | |||||
case paramLow: | |||||
fLow = value; | |||||
lowVol = std::exp( (fLow/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramMid: | |||||
fMid = value; | |||||
midVol = std::exp( (fMid/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramHigh: | |||||
fHigh = value; | |||||
highVol = std::exp( (fHigh/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramMaster: | |||||
fMaster = value; | |||||
outVol = std::exp( (fMaster/48.0f) * 48.0f / kAMP_DB); | |||||
break; | |||||
case paramLowMidFreq: | |||||
fLowMidFreq = std::fmin(value, fMidHighFreq); | |||||
freqLP = fLowMidFreq; | |||||
xLP = std::exp(-2.0f * kPI * freqLP / (float)getSampleRate()); | |||||
a0LP = 1.0f - xLP; | |||||
b1LP = -xLP; | |||||
break; | |||||
case paramMidHighFreq: | |||||
fMidHighFreq = std::fmax(value, fLowMidFreq); | |||||
freqHP = fMidHighFreq; | |||||
xHP = std::exp(-2.0f * kPI * freqHP / (float)getSampleRate()); | |||||
a0HP = 1.0f - xHP; | |||||
b1HP = -xHP; | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoPlugin3BandSplitter::loadProgram(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fLow = 0.0f; | |||||
fMid = 0.0f; | |||||
fHigh = 0.0f; | |||||
fMaster = 0.0f; | |||||
fLowMidFreq = 220.0f; | |||||
fMidHighFreq = 2000.0f; | |||||
// Internal stuff | |||||
lowVol = midVol = highVol = outVol = 1.0f; | |||||
freqLP = 200.0f; | |||||
freqHP = 2000.0f; | |||||
// reset filter values | |||||
activate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void DistrhoPlugin3BandSplitter::activate() | |||||
{ | |||||
const float sr = (float)getSampleRate(); | |||||
xLP = std::exp(-2.0f * kPI * freqLP / sr); | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
// don't ask me why, but this fixes a crash/exception below on windows... | |||||
printf("%f\n", -xLP); | |||||
#endif | |||||
a0LP = 1.0f - xLP; | |||||
b1LP = -xLP; | |||||
xHP = std::exp(-2.0f * kPI * freqHP / sr); | |||||
a0HP = 1.0f - xHP; | |||||
b1HP = -xHP; | |||||
} | |||||
void DistrhoPlugin3BandSplitter::deactivate() | |||||
{ | |||||
out1LP = out2LP = out1HP = out2HP = 0.0f; | |||||
tmp1LP = tmp2LP = tmp1HP = tmp2HP = 0.0f; | |||||
} | |||||
void DistrhoPlugin3BandSplitter::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* out3 = outputs[2]; | |||||
float* out4 = outputs[3]; | |||||
float* out5 = outputs[4]; | |||||
float* out6 = outputs[5]; | |||||
for (uint32_t i=0; i < frames; ++i) | |||||
{ | |||||
tmp1LP = a0LP * in1[i] - b1LP * tmp1LP + kDC_ADD; | |||||
tmp2LP = a0LP * in2[i] - b1LP * tmp2LP + kDC_ADD; | |||||
out1LP = tmp1LP - kDC_ADD; | |||||
out2LP = tmp2LP - kDC_ADD; | |||||
tmp1HP = a0HP * in1[i] - b1HP * tmp1HP + kDC_ADD; | |||||
tmp2HP = a0HP * in2[i] - b1HP * tmp2HP + kDC_ADD; | |||||
out1HP = in1[i] - tmp1HP - kDC_ADD; | |||||
out2HP = in2[i] - tmp2HP - kDC_ADD; | |||||
out6[i] = out2HP*highVol * outVol; | |||||
out5[i] = out1HP*highVol * outVol; | |||||
out4[i] = (in2[i] - out2LP - out2HP)*midVol * outVol; | |||||
out3[i] = (in1[i] - out1LP - out1HP)*midVol * outVol; | |||||
out2[i] = out2LP*lowVol * outVol; | |||||
out1[i] = out1LP*lowVol * outVol; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new DistrhoPlugin3BandSplitter(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,123 @@ | |||||
/* | |||||
* DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||||
* Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_3BANDSPLITTER_HPP_INCLUDED | |||||
#define DISTRHO_PLUGIN_3BANDSPLITTER_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoPlugin3BandSplitter : public Plugin | |||||
{ | |||||
public: | |||||
enum Parameters | |||||
{ | |||||
paramLow = 0, | |||||
paramMid, | |||||
paramHigh, | |||||
paramMaster, | |||||
paramLowMidFreq, | |||||
paramMidHighFreq, | |||||
paramCount | |||||
}; | |||||
DistrhoPlugin3BandSplitter(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "3BandSplitter"; | |||||
} | |||||
const char* getDescription() const override | |||||
{ | |||||
return "3 Band Equalizer, splitted output version."; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "DISTRHO"; | |||||
} | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/Mini-Series"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "LGPL"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', '3', 'E', 'S'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
void initProgramName(uint32_t index, String& programName) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
void loadProgram(uint32_t index) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void deactivate() override; | |||||
void run(const float** inputs, float** outputs, uint32_t frames) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
float fLow, fMid, fHigh, fMaster, fLowMidFreq, fMidHighFreq; | |||||
float lowVol, midVol, highVol, outVol; | |||||
float freqLP, freqHP; | |||||
float xLP, a0LP, b1LP; | |||||
float xHP, a0HP, b1HP; | |||||
float out1LP, out2LP, out1HP, out2HP; | |||||
float tmp1LP, tmp2LP, tmp1HP, tmp2HP; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoPlugin3BandSplitter) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_PLUGIN_3BANDSPLITTER_HPP_INCLUDED |
@@ -0,0 +1,32 @@ | |||||
/* | |||||
* DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "3 Band Splitter" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandSplitter" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 6 | |||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||||
#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:EQPlugin" | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,211 @@ | |||||
/* | |||||
* DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPlugin3BandSplitter.hpp" | |||||
#include "DistrhoUI3BandSplitter.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
namespace Art = DistrhoArtwork3BandSplitter; | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoUI3BandSplitter::DistrhoUI3BandSplitter() | |||||
: UI(Art::backgroundWidth, Art::backgroundHeight), | |||||
fImgBackground(Art::backgroundData, Art::backgroundWidth, Art::backgroundHeight, GL_BGR), | |||||
fAboutWindow(this) | |||||
{ | |||||
// about | |||||
Image aboutImage(Art::aboutData, Art::aboutWidth, Art::aboutHeight, GL_BGR); | |||||
fAboutWindow.setImage(aboutImage); | |||||
// sliders | |||||
Image sliderImage(Art::sliderData, Art::sliderWidth, Art::sliderHeight); | |||||
Point<int> sliderPosStart(57, 43); | |||||
Point<int> sliderPosEnd(57, 43 + 160); | |||||
// slider Low | |||||
fSliderLow = new ImageSlider(this, sliderImage); | |||||
fSliderLow->setId(DistrhoPlugin3BandSplitter::paramLow); | |||||
fSliderLow->setInverted(true); | |||||
fSliderLow->setStartPos(sliderPosStart); | |||||
fSliderLow->setEndPos(sliderPosEnd); | |||||
fSliderLow->setRange(-24.0f, 24.0f); | |||||
fSliderLow->setCallback(this); | |||||
// slider Mid | |||||
sliderPosStart.setX(120); | |||||
sliderPosEnd.setX(120); | |||||
fSliderMid = new ImageSlider(this, sliderImage); | |||||
fSliderMid->setId(DistrhoPlugin3BandSplitter::paramMid); | |||||
fSliderMid->setInverted(true); | |||||
fSliderMid->setStartPos(sliderPosStart); | |||||
fSliderMid->setEndPos(sliderPosEnd); | |||||
fSliderMid->setRange(-24.0f, 24.0f); | |||||
fSliderMid->setCallback(this); | |||||
// slider High | |||||
sliderPosStart.setX(183); | |||||
sliderPosEnd.setX(183); | |||||
fSliderHigh = new ImageSlider(this, sliderImage); | |||||
fSliderHigh->setId(DistrhoPlugin3BandSplitter::paramHigh); | |||||
fSliderHigh->setInverted(true); | |||||
fSliderHigh->setStartPos(sliderPosStart); | |||||
fSliderHigh->setEndPos(sliderPosEnd); | |||||
fSliderHigh->setRange(-24.0f, 24.0f); | |||||
fSliderHigh->setCallback(this); | |||||
// slider Master | |||||
sliderPosStart.setX(287); | |||||
sliderPosEnd.setX(287); | |||||
fSliderMaster = new ImageSlider(this, sliderImage); | |||||
fSliderMaster->setId(DistrhoPlugin3BandSplitter::paramMaster); | |||||
fSliderMaster->setInverted(true); | |||||
fSliderMaster->setStartPos(sliderPosStart); | |||||
fSliderMaster->setEndPos(sliderPosEnd); | |||||
fSliderMaster->setRange(-24.0f, 24.0f); | |||||
fSliderMaster->setCallback(this); | |||||
// knobs | |||||
Image knobImage(Art::knobData, Art::knobWidth, Art::knobHeight); | |||||
// knob Low-Mid | |||||
fKnobLowMid = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobLowMid->setId(DistrhoPlugin3BandSplitter::paramLowMidFreq); | |||||
fKnobLowMid->setAbsolutePos(65, 269); | |||||
fKnobLowMid->setRange(0.0f, 1000.0f); | |||||
fKnobLowMid->setDefault(440.0f); | |||||
fKnobLowMid->setRotationAngle(270); | |||||
fKnobLowMid->setCallback(this); | |||||
// knob Mid-High | |||||
fKnobMidHigh = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobMidHigh->setId(DistrhoPlugin3BandSplitter::paramMidHighFreq); | |||||
fKnobMidHigh->setAbsolutePos(159, 269); | |||||
fKnobMidHigh->setRange(1000.0f, 20000.0f); | |||||
fKnobMidHigh->setDefault(1000.0f); | |||||
fKnobMidHigh->setRotationAngle(270); | |||||
fKnobMidHigh->setCallback(this); | |||||
// about button | |||||
Image aboutImageNormal(Art::aboutButtonNormalData, Art::aboutButtonNormalWidth, Art::aboutButtonNormalHeight); | |||||
Image aboutImageHover(Art::aboutButtonHoverData, Art::aboutButtonHoverWidth, Art::aboutButtonHoverHeight); | |||||
fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||||
fButtonAbout->setAbsolutePos(264, 300); | |||||
fButtonAbout->setCallback(this); | |||||
// set default values | |||||
programLoaded(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void DistrhoUI3BandSplitter::parameterChanged(uint32_t index, float value) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case DistrhoPlugin3BandSplitter::paramLow: | |||||
fSliderLow->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandSplitter::paramMid: | |||||
fSliderMid->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandSplitter::paramHigh: | |||||
fSliderHigh->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandSplitter::paramMaster: | |||||
fSliderMaster->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandSplitter::paramLowMidFreq: | |||||
fKnobLowMid->setValue(value); | |||||
break; | |||||
case DistrhoPlugin3BandSplitter::paramMidHighFreq: | |||||
fKnobMidHigh->setValue(value); | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoUI3BandSplitter::programLoaded(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fSliderLow->setValue(0.0f); | |||||
fSliderMid->setValue(0.0f); | |||||
fSliderHigh->setValue(0.0f); | |||||
fSliderMaster->setValue(0.0f); | |||||
fKnobLowMid->setValue(220.0f); | |||||
fKnobMidHigh->setValue(2000.0f); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void DistrhoUI3BandSplitter::imageButtonClicked(ImageButton* button, int) | |||||
{ | |||||
if (button != fButtonAbout) | |||||
return; | |||||
fAboutWindow.exec(); | |||||
} | |||||
void DistrhoUI3BandSplitter::imageKnobDragStarted(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), true); | |||||
} | |||||
void DistrhoUI3BandSplitter::imageKnobDragFinished(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), false); | |||||
} | |||||
void DistrhoUI3BandSplitter::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
{ | |||||
setParameterValue(knob->getId(), value); | |||||
} | |||||
void DistrhoUI3BandSplitter::imageSliderDragStarted(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), true); | |||||
} | |||||
void DistrhoUI3BandSplitter::imageSliderDragFinished(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), false); | |||||
} | |||||
void DistrhoUI3BandSplitter::imageSliderValueChanged(ImageSlider* slider, float value) | |||||
{ | |||||
setParameterValue(slider->getId(), value); | |||||
} | |||||
void DistrhoUI3BandSplitter::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new DistrhoUI3BandSplitter(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,72 @@ | |||||
/* | |||||
* DISTRHO 3BandSplitter Plugin, based on 3BandSplitter by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_UI_3BANDSPLITTER_HPP_INCLUDED | |||||
#define DISTRHO_UI_3BANDSPLITTER_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
#include "ImageWidgets.hpp" | |||||
#include "DistrhoArtwork3BandSplitter.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoUI3BandSplitter : public UI, | |||||
public ImageButton::Callback, | |||||
public ImageKnob::Callback, | |||||
public ImageSlider::Callback | |||||
{ | |||||
public: | |||||
DistrhoUI3BandSplitter(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
void programLoaded(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 imageSliderDragStarted(ImageSlider* slider) override; | |||||
void imageSliderDragFinished(ImageSlider* slider) override; | |||||
void imageSliderValueChanged(ImageSlider* slider, float value) override; | |||||
void onDisplay() override; | |||||
private: | |||||
Image fImgBackground; | |||||
ImageAboutWindow fAboutWindow; | |||||
ScopedPointer<ImageButton> fButtonAbout; | |||||
ScopedPointer<ImageKnob> fKnobLowMid, fKnobMidHigh; | |||||
ScopedPointer<ImageSlider> fSliderLow, fSliderMid, fSliderHigh, fSliderMaster; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUI3BandSplitter) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_3BANDSPLITTER_HPP_INCLUDED |
@@ -0,0 +1,86 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-kars/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-kars/DistrhoArtworkKars.cpp" | |||||
#include "distrho-kars/DistrhoPluginKars.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-kars/DistrhoUIKars.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor karsDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_SYNTH, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ DistrhoPluginKars::paramCount, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "kars", | |||||
/* maker */ "falkTX, Chris Cannam", | |||||
/* copyright */ "ISC", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_kars(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_kars() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&karsDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,20 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_DISTRHOARTWORKKARS_HPP | |||||
#define BINARY_DISTRHOARTWORKKARS_HPP | |||||
namespace DistrhoArtworkKars | |||||
{ | |||||
extern const char* backgroundData; | |||||
const unsigned int backgroundDataSize = 379260; | |||||
const unsigned int backgroundWidth = 301; | |||||
const unsigned int backgroundHeight = 315; | |||||
extern const char* switchData; | |||||
const unsigned int switchDataSize = 61952; | |||||
const unsigned int switchWidth = 88; | |||||
const unsigned int switchHeight = 176; | |||||
} | |||||
#endif // BINARY_DISTRHOARTWORKKARS_HPP | |||||
@@ -0,0 +1,31 @@ | |||||
/* | |||||
* DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "Kars" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Kars" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||||
#define DISTRHO_PLUGIN_IS_SYNTH 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 0 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 1 | |||||
#define DISTRHO_PLUGIN_USES_MODGUI 1 | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,214 @@ | |||||
/* | |||||
* DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "DistrhoPluginKars.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoPluginKars::DistrhoPluginKars() | |||||
: Plugin(paramCount, 0, 0), // 0 programs, 0 states | |||||
fSustain(false), | |||||
fSampleRate(getSampleRate()), | |||||
fBlockStart(0) | |||||
{ | |||||
for (int i=kMaxNotes; --i >= 0;) | |||||
{ | |||||
fNotes[i].index = i; | |||||
fNotes[i].setSampleRate(fSampleRate); | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
parameter.hints = kParameterIsAutomable|kParameterIsBoolean; | |||||
parameter.name = "Sustain"; | |||||
parameter.symbol = "sustain"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float DistrhoPluginKars::getParameterValue(uint32_t index) const | |||||
{ | |||||
if (index != 0) | |||||
return 0.0f; | |||||
return fSustain ? 1.0f : 0.0f; | |||||
} | |||||
void DistrhoPluginKars::setParameterValue(uint32_t index, float value) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
fSustain = value > 0.5f; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void DistrhoPluginKars::activate() | |||||
{ | |||||
fBlockStart = 0; | |||||
for (int i=kMaxNotes; --i >= 0;) | |||||
{ | |||||
fNotes[i].on = kNoteNull; | |||||
fNotes[i].off = kNoteNull; | |||||
fNotes[i].velocity = 0; | |||||
} | |||||
} | |||||
void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) | |||||
{ | |||||
uint8_t note, velo; | |||||
float* out = outputs[0]; | |||||
for (uint32_t count, pos=0, curEventIndex=0; pos<frames;) | |||||
{ | |||||
for (;curEventIndex < midiEventCount && pos >= midiEvents[curEventIndex].frame; ++curEventIndex) | |||||
{ | |||||
if (midiEvents[curEventIndex].size > MidiEvent::kDataSize) | |||||
continue; | |||||
const uint8_t* data = midiEvents[curEventIndex].data; | |||||
const uint8_t status = data[0] & 0xF0; | |||||
switch (status) | |||||
{ | |||||
case 0x90: | |||||
note = data[1]; | |||||
velo = data[2]; | |||||
DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes | |||||
if (velo > 0) | |||||
{ | |||||
fNotes[note].on = fBlockStart + midiEvents[curEventIndex].frame; | |||||
fNotes[note].off = kNoteNull; | |||||
fNotes[note].velocity = velo; | |||||
break; | |||||
} | |||||
// fall through | |||||
case 0x80: | |||||
note = data[1]; | |||||
DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes | |||||
fNotes[note].off = fBlockStart + midiEvents[curEventIndex].frame; | |||||
break; | |||||
} | |||||
} | |||||
if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame < frames) | |||||
count = midiEvents[curEventIndex].frame - pos; | |||||
else | |||||
count = frames - pos; | |||||
std::memset(out+pos, 0, sizeof(float)*count); | |||||
//for (uint32_t i=0; i<count; ++i) | |||||
// out[pos + i] = 0.0f; | |||||
for (int i=kMaxNotes; --i >= 0;) | |||||
{ | |||||
if (fNotes[i].on != kNoteNull) | |||||
addSamples(out, i, pos, count); | |||||
} | |||||
pos += count; | |||||
} | |||||
fBlockStart += frames; | |||||
} | |||||
void DistrhoPluginKars::addSamples(float* out, int voice, uint32_t offset, uint32_t count) | |||||
{ | |||||
const uint32_t start = fBlockStart + offset; | |||||
Note& note(fNotes[voice]); | |||||
if (start < note.on) | |||||
return; | |||||
if (start == note.on) | |||||
{ | |||||
for (int i=note.sizei; --i >= 0;) | |||||
note.wavetable[i] = (float(rand()) / float(RAND_MAX)) * 2.0f - 1.0f; | |||||
} | |||||
const float vgain = float(note.velocity) / 127.0f; | |||||
bool decay; | |||||
float gain, sample; | |||||
uint32_t index, size; | |||||
for (uint32_t i=0, s=start-note.on; i<count; ++i, ++s) | |||||
{ | |||||
gain = vgain; | |||||
if ((! fSustain) && note.off != kNoteNull && note.off < i+start) | |||||
{ | |||||
// reuse index and size to save some performance. | |||||
// actual values are release and dist | |||||
index = 1 + uint32_t(0.01 * fSampleRate); // release, not index | |||||
size = i + start - note.off; // dist, not size | |||||
if (size > index) | |||||
{ | |||||
note.on = kNoteNull; | |||||
break; | |||||
} | |||||
gain = gain * float(index - size) / float(index); | |||||
} | |||||
size = uint32_t(note.sizei); | |||||
decay = s > size; | |||||
index = s % size; | |||||
sample = note.wavetable[index]; | |||||
if (decay) | |||||
{ | |||||
if (index == 0) | |||||
sample += note.wavetable[size-1]; | |||||
else | |||||
sample += note.wavetable[index-1]; | |||||
note.wavetable[index] = sample/2; | |||||
} | |||||
out[offset+i] += gain * sample; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new DistrhoPluginKars(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,152 @@ | |||||
/* | |||||
* DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_KARS_HPP_INCLUDED | |||||
#define DISTRHO_PLUGIN_KARS_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoPluginKars : public Plugin | |||||
{ | |||||
public: | |||||
static const int kMaxNotes = 128; | |||||
static const uint32_t kNoteNull = (uint32_t)-1; | |||||
enum Parameters | |||||
{ | |||||
paramSustain = 0, | |||||
paramCount | |||||
}; | |||||
DistrhoPluginKars(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "Kars"; | |||||
} | |||||
const char* getDescription() const override | |||||
{ | |||||
return "Simple karplus-strong plucked string synth."; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "falkTX"; | |||||
} | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/Kars"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "ISC"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', 'K', 'r', 's'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
bool fSustain; | |||||
double fSampleRate; | |||||
uint32_t fBlockStart; | |||||
struct Note { | |||||
uint32_t on; | |||||
uint32_t off; | |||||
uint8_t velocity; | |||||
float index; | |||||
float size; | |||||
int sizei; | |||||
float* wavetable; | |||||
Note() noexcept | |||||
: on(kNoteNull), | |||||
off(kNoteNull), | |||||
velocity(0), | |||||
index(0.0f), | |||||
size(0.0f), | |||||
wavetable(nullptr) {} | |||||
~Note() noexcept | |||||
{ | |||||
if (wavetable != nullptr) | |||||
{ | |||||
delete[] wavetable; | |||||
wavetable = nullptr; | |||||
} | |||||
} | |||||
void setSampleRate(const double sampleRate) | |||||
{ | |||||
if (wavetable != nullptr) | |||||
delete[] wavetable; | |||||
const float frequency = 440.0f * std::pow(2.0f, (index - 69.0f) / 12.0f); | |||||
size = sampleRate / frequency; | |||||
sizei = int(size)+1; | |||||
wavetable = new float[sizei]; | |||||
std::memset(wavetable, 0, sizeof(float)*static_cast<size_t>(sizei)); | |||||
} | |||||
} fNotes[kMaxNotes]; | |||||
void addSamples(float* out, int voice, uint32_t offset, uint32_t count); | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoPluginKars) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_PLUGIN_KARS_HPP_INCLUDED |
@@ -0,0 +1,77 @@ | |||||
/* | |||||
* DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "DistrhoPluginKars.hpp" | |||||
#include "DistrhoUIKars.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
namespace Art = DistrhoArtworkKars; | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoUIKars::DistrhoUIKars() | |||||
: UI(Art::backgroundWidth, Art::backgroundHeight), | |||||
fImgBackground(Art::backgroundData, Art::backgroundWidth, Art::backgroundHeight) | |||||
{ | |||||
// sustain switch | |||||
Image switchImageNormal(Art::switchData, Art::switchWidth, Art::switchHeight/2); | |||||
Image switchImageDown(Art::switchData+(Art::switchWidth*Art::switchHeight/2*4), Art::switchWidth, Art::switchHeight/2); | |||||
fSwitchSustain = new ImageSwitch(this, switchImageNormal, switchImageDown); | |||||
fSwitchSustain->setAbsolutePos(Art::backgroundWidth/2-Art::switchWidth/2, Art::backgroundHeight/2-Art::switchHeight/4); | |||||
fSwitchSustain->setId(DistrhoPluginKars::paramSustain); | |||||
fSwitchSustain->setCallback(this); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void DistrhoUIKars::parameterChanged(uint32_t index, float value) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
fSwitchSustain->setDown(value > 0.5f); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void DistrhoUIKars::imageSwitchClicked(ImageSwitch* imageSwitch, bool down) | |||||
{ | |||||
if (imageSwitch != fSwitchSustain) | |||||
return; | |||||
editParameter(DistrhoPluginKars::paramSustain, true); | |||||
setParameterValue(DistrhoPluginKars::paramSustain, down ? 1.0f : 0.0f); | |||||
editParameter(DistrhoPluginKars::paramSustain, false); | |||||
} | |||||
void DistrhoUIKars::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new DistrhoUIKars(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,60 @@ | |||||
/* | |||||
* DISTRHO Kars Plugin, based on karplong by Chris Cannam. | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_UI_KARS_HPP_INCLUDED | |||||
#define DISTRHO_UI_KARS_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
#include "ImageWidgets.hpp" | |||||
#include "DistrhoArtworkKars.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoUIKars : public UI, | |||||
public ImageSwitch::Callback | |||||
{ | |||||
public: | |||||
DistrhoUIKars(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
// ------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void imageSwitchClicked(ImageSwitch* imageSwitch, bool down) override; | |||||
void onDisplay() override; | |||||
private: | |||||
Image fImgBackground; | |||||
ScopedPointer<ImageSwitch> fSwitchSustain; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUIKars) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_KARS_HPP_INCLUDED |
@@ -0,0 +1,87 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-nekobi/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-nekobi/DistrhoArtworkNekobi.cpp" | |||||
#include "distrho-nekobi/DistrhoPluginNekobi.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-nekobi/DistrhoUINekobi.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor nekobiDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_SYNTH, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_IS_SYNTH), | |||||
#endif | |||||
/* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES | |||||
|NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF), | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ DistrhoPluginNekobi::paramCount, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "nekobi", | |||||
/* maker */ "falkTX, Sean Bolton and others", | |||||
/* copyright */ "GPL v2+", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_nekobi(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_nekobi() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&nekobiDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,90 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_DISTRHOARTWORKNEKOBI_HPP | |||||
#define BINARY_DISTRHOARTWORKNEKOBI_HPP | |||||
namespace DistrhoArtworkNekobi | |||||
{ | |||||
extern const char* aboutData; | |||||
const unsigned int aboutDataSize = 172710; | |||||
const unsigned int aboutWidth = 303; | |||||
const unsigned int aboutHeight = 190; | |||||
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 = 206064; | |||||
const unsigned int backgroundWidth = 636; | |||||
const unsigned int backgroundHeight = 108; | |||||
extern const char* claw1Data; | |||||
const unsigned int claw1DataSize = 4096; | |||||
const unsigned int claw1Width = 32; | |||||
const unsigned int claw1Height = 32; | |||||
extern const char* claw2Data; | |||||
const unsigned int claw2DataSize = 4096; | |||||
const unsigned int claw2Width = 32; | |||||
const unsigned int claw2Height = 32; | |||||
extern const char* knobData; | |||||
const unsigned int knobDataSize = 10000; | |||||
const unsigned int knobWidth = 50; | |||||
const unsigned int knobHeight = 50; | |||||
extern const char* run1Data; | |||||
const unsigned int run1DataSize = 4096; | |||||
const unsigned int run1Width = 32; | |||||
const unsigned int run1Height = 32; | |||||
extern const char* run2Data; | |||||
const unsigned int run2DataSize = 4096; | |||||
const unsigned int run2Width = 32; | |||||
const unsigned int run2Height = 32; | |||||
extern const char* run3Data; | |||||
const unsigned int run3DataSize = 4096; | |||||
const unsigned int run3Width = 32; | |||||
const unsigned int run3Height = 32; | |||||
extern const char* run4Data; | |||||
const unsigned int run4DataSize = 4096; | |||||
const unsigned int run4Width = 32; | |||||
const unsigned int run4Height = 32; | |||||
extern const char* scratch1Data; | |||||
const unsigned int scratch1DataSize = 4096; | |||||
const unsigned int scratch1Width = 32; | |||||
const unsigned int scratch1Height = 32; | |||||
extern const char* scratch2Data; | |||||
const unsigned int scratch2DataSize = 4096; | |||||
const unsigned int scratch2Width = 32; | |||||
const unsigned int scratch2Height = 32; | |||||
extern const char* sitData; | |||||
const unsigned int sitDataSize = 4096; | |||||
const unsigned int sitWidth = 32; | |||||
const unsigned int sitHeight = 32; | |||||
extern const char* sliderData; | |||||
const unsigned int sliderDataSize = 6084; | |||||
const unsigned int sliderWidth = 39; | |||||
const unsigned int sliderHeight = 39; | |||||
extern const char* tailData; | |||||
const unsigned int tailDataSize = 4096; | |||||
const unsigned int tailWidth = 32; | |||||
const unsigned int tailHeight = 32; | |||||
} | |||||
#endif // BINARY_DISTRHOARTWORKNEKOBI_HPP | |||||
@@ -0,0 +1,32 @@ | |||||
/* | |||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | |||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "Nekobi" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Nekobi" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||||
#define DISTRHO_PLUGIN_IS_SYNTH 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 0 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 1 | |||||
#define DISTRHO_PLUGIN_USES_MODGUI 1 | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,399 @@ | |||||
/* | |||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | |||||
* Copyright (C) 2004 Sean Bolton and others | |||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 LICENSE file. | |||||
*/ | |||||
#include "DistrhoPluginNekobi.hpp" | |||||
extern "C" { | |||||
#include "nekobee-src/nekobee_synth.c" | |||||
#include "nekobee-src/nekobee_voice.c" | |||||
#include "nekobee-src/nekobee_voice_render.c" | |||||
#include "nekobee-src/minblep_tables.c" | |||||
// ----------------------------------------------------------------------- | |||||
// mutual exclusion | |||||
bool dssp_voicelist_mutex_trylock(nekobee_synth_t* const synth) | |||||
{ | |||||
/* Attempt the mutex lock */ | |||||
if (pthread_mutex_trylock(&synth->voicelist_mutex) != 0) | |||||
{ | |||||
synth->voicelist_mutex_grab_failed = 1; | |||||
return false; | |||||
} | |||||
/* Clean up if a previous mutex grab failed */ | |||||
if (synth->voicelist_mutex_grab_failed) | |||||
{ | |||||
nekobee_synth_all_voices_off(synth); | |||||
synth->voicelist_mutex_grab_failed = 0; | |||||
} | |||||
return true; | |||||
} | |||||
bool dssp_voicelist_mutex_unlock(nekobee_synth_t* const synth) | |||||
{ | |||||
return (pthread_mutex_unlock(&synth->voicelist_mutex) == 0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// nekobee_handle_raw_event | |||||
void nekobee_handle_raw_event(nekobee_synth_t* const synth, const uint8_t size, const uint8_t* const data) | |||||
{ | |||||
if (size != 3) | |||||
return; | |||||
switch (data[0] & 0xf0) | |||||
{ | |||||
case 0x80: | |||||
nekobee_synth_note_off(synth, data[1], data[2]); | |||||
break; | |||||
case 0x90: | |||||
if (data[2] > 0) | |||||
nekobee_synth_note_on(synth, data[1], data[2]); | |||||
else | |||||
nekobee_synth_note_off(synth, data[1], 64); /* shouldn't happen, but... */ | |||||
break; | |||||
case 0xB0: | |||||
nekobee_synth_control_change(synth, data[1], data[2]); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
} /* extern "C" */ | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoPluginNekobi::DistrhoPluginNekobi() | |||||
: Plugin(paramCount, 0, 0) // 0 programs, 0 states | |||||
{ | |||||
nekobee_init_tables(); | |||||
// init synth | |||||
fSynth.sample_rate = getSampleRate(); | |||||
fSynth.deltat = 1.0f / (float)getSampleRate(); | |||||
fSynth.nugget_remains = 0; | |||||
fSynth.note_id = 0; | |||||
fSynth.polyphony = XSYNTH_DEFAULT_POLYPHONY; | |||||
fSynth.voices = XSYNTH_DEFAULT_POLYPHONY; | |||||
fSynth.monophonic = XSYNTH_MONO_MODE_ONCE; | |||||
fSynth.glide = 0; | |||||
fSynth.last_noteon_pitch = 0.0f; | |||||
fSynth.vcf_accent = 0.0f; | |||||
fSynth.vca_accent = 0.0f; | |||||
for (int i=0; i<8; ++i) | |||||
fSynth.held_keys[i] = -1; | |||||
fSynth.voice = nekobee_voice_new(); | |||||
fSynth.voicelist_mutex_grab_failed = 0; | |||||
pthread_mutex_init(&fSynth.voicelist_mutex, nullptr); | |||||
fSynth.channel_pressure = 0; | |||||
fSynth.pitch_wheel_sensitivity = 0; | |||||
fSynth.pitch_wheel = 0; | |||||
for (int i=0; i<128; ++i) | |||||
{ | |||||
fSynth.key_pressure[i] = 0; | |||||
fSynth.cc[i] = 0; | |||||
} | |||||
fSynth.cc[7] = 127; // full volume | |||||
fSynth.mod_wheel = 1.0f; | |||||
fSynth.pitch_bend = 1.0f; | |||||
fSynth.cc_volume = 1.0f; | |||||
// Default values | |||||
fParams.waveform = 0.0f; | |||||
fParams.tuning = 0.0f; | |||||
fParams.cutoff = 25.0f; | |||||
fParams.resonance = 25.0f; | |||||
fParams.envMod = 50.0f; | |||||
fParams.decay = 75.0f; | |||||
fParams.accent = 25.0f; | |||||
fParams.volume = 75.0f; | |||||
// Internal stuff | |||||
fSynth.waveform = 0.0f; | |||||
fSynth.tuning = 1.0f; | |||||
fSynth.cutoff = 5.0f; | |||||
fSynth.resonance = 0.8f; | |||||
fSynth.envmod = 0.3f; | |||||
fSynth.decay = 0.0002f; | |||||
fSynth.accent = 0.3f; | |||||
fSynth.volume = 0.75f; | |||||
// reset | |||||
deactivate(); | |||||
} | |||||
DistrhoPluginNekobi::~DistrhoPluginNekobi() | |||||
{ | |||||
std::free(fSynth.voice); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramWaveform: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Waveform"; | |||||
parameter.symbol = "waveform"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramTuning: | |||||
parameter.hints = kParameterIsAutomable; // was 0.5 <-> 2.0, log | |||||
parameter.name = "Tuning"; | |||||
parameter.symbol = "tuning"; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -12.0f; | |||||
parameter.ranges.max = 12.0f; | |||||
break; | |||||
case paramCutoff: | |||||
parameter.hints = kParameterIsAutomable; // modified x2.5 | |||||
parameter.name = "Cutoff"; | |||||
parameter.symbol = "cutoff"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 25.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
case paramResonance: | |||||
parameter.hints = kParameterIsAutomable; // modified x100 | |||||
parameter.name = "VCF Resonance"; | |||||
parameter.symbol = "resonance"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 25.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 95.0f; | |||||
break; | |||||
case paramEnvMod: | |||||
parameter.hints = kParameterIsAutomable; // modified x100 | |||||
parameter.name = "Env Mod"; | |||||
parameter.symbol = "env_mod"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 50.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
case paramDecay: | |||||
parameter.hints = kParameterIsAutomable; // was 0.000009 <-> 0.0005, log | |||||
parameter.name = "Decay"; | |||||
parameter.symbol = "decay"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 75.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
case paramAccent: | |||||
parameter.hints = kParameterIsAutomable; // modified x100 | |||||
parameter.name = "Accent"; | |||||
parameter.symbol = "accent"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 25.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
case paramVolume: | |||||
parameter.hints = kParameterIsAutomable; // modified x100 | |||||
parameter.name = "Volume"; | |||||
parameter.symbol = "volume"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 75.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float DistrhoPluginNekobi::getParameterValue(uint32_t index) const | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramWaveform: | |||||
return fParams.waveform; | |||||
case paramTuning: | |||||
return fParams.tuning; | |||||
case paramCutoff: | |||||
return fParams.cutoff; | |||||
case paramResonance: | |||||
return fParams.resonance; | |||||
case paramEnvMod: | |||||
return fParams.envMod; | |||||
case paramDecay: | |||||
return fParams.decay; | |||||
case paramAccent: | |||||
return fParams.accent; | |||||
case paramVolume: | |||||
return fParams.volume; | |||||
} | |||||
return 0.0f; | |||||
} | |||||
void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramWaveform: | |||||
fParams.waveform = value; | |||||
fSynth.waveform = value; | |||||
DISTRHO_SAFE_ASSERT(fSynth.waveform == 0.0f || fSynth.waveform == 1.0f); | |||||
break; | |||||
case paramTuning: | |||||
fParams.tuning = value; | |||||
fSynth.tuning = (value+12.0f)/24.0f * 1.5 + 0.5f; // FIXME: log? | |||||
DISTRHO_SAFE_ASSERT(fSynth.tuning >= 0.5f && fSynth.tuning <= 2.0f); | |||||
break; | |||||
case paramCutoff: | |||||
fParams.cutoff = value; | |||||
fSynth.cutoff = value/2.5f; | |||||
DISTRHO_SAFE_ASSERT(fSynth.cutoff >= 0.0f && fSynth.cutoff <= 40.0f); | |||||
break; | |||||
case paramResonance: | |||||
fParams.resonance = value; | |||||
fSynth.resonance = value/100.0f; | |||||
DISTRHO_SAFE_ASSERT(fSynth.resonance >= 0.0f && fSynth.resonance <= 0.95f); | |||||
break; | |||||
case paramEnvMod: | |||||
fParams.envMod = value; | |||||
fSynth.envmod = value/100.0f; | |||||
DISTRHO_SAFE_ASSERT(fSynth.envmod >= 0.0f && fSynth.envmod <= 1.0f); | |||||
break; | |||||
case paramDecay: | |||||
fParams.decay = value; | |||||
fSynth.decay = value/100.0f * 0.000491f + 0.000009f; // FIXME: log? | |||||
DISTRHO_SAFE_ASSERT(fSynth.decay >= 0.000009f && fSynth.decay <= 0.0005f); | |||||
break; | |||||
case paramAccent: | |||||
fParams.accent = value; | |||||
fSynth.accent = value/100.0f; | |||||
DISTRHO_SAFE_ASSERT(fSynth.accent >= 0.0f && fSynth.accent <= 1.0f); | |||||
break; | |||||
case paramVolume: | |||||
fParams.volume = value; | |||||
fSynth.volume = value/100.0f; | |||||
DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f); | |||||
break; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void DistrhoPluginNekobi::activate() | |||||
{ | |||||
fSynth.nugget_remains = 0; | |||||
fSynth.note_id = 0; | |||||
if (fSynth.voice != nullptr) | |||||
nekobee_synth_all_voices_off(&fSynth); | |||||
} | |||||
void DistrhoPluginNekobi::deactivate() | |||||
{ | |||||
if (fSynth.voice != nullptr) | |||||
nekobee_synth_all_voices_off(&fSynth); | |||||
} | |||||
void DistrhoPluginNekobi::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) | |||||
{ | |||||
uint32_t framesDone = 0; | |||||
uint32_t curEventIndex = 0; | |||||
uint32_t burstSize; | |||||
float* out = outputs[0]; | |||||
if (fSynth.voice == nullptr || ! dssp_voicelist_mutex_trylock(&fSynth)) | |||||
{ | |||||
std::memset(out, 0, sizeof(float)*frames); | |||||
return; | |||||
} | |||||
while (framesDone < frames) | |||||
{ | |||||
if (fSynth.nugget_remains == 0) | |||||
fSynth.nugget_remains = XSYNTH_NUGGET_SIZE; | |||||
/* process any ready events */ | |||||
while (curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame) | |||||
{ | |||||
if (midiEvents[curEventIndex].size > MidiEvent::kDataSize) | |||||
continue; | |||||
nekobee_handle_raw_event(&fSynth, midiEvents[curEventIndex].size, midiEvents[curEventIndex].data); | |||||
curEventIndex++; | |||||
} | |||||
/* calculate the sample count (burstSize) for the next nekobee_voice_render() call to be the smallest of: | |||||
* - control calculation quantization size (XSYNTH_NUGGET_SIZE, in samples) | |||||
* - the number of samples remaining in an already-begun nugget (synth->nugget_remains) | |||||
* - the number of samples until the next event is ready | |||||
* - the number of samples left in this run | |||||
*/ | |||||
burstSize = XSYNTH_NUGGET_SIZE; | |||||
/* we're still in the middle of a nugget, so reduce the burst size | |||||
* to end when the nugget ends */ | |||||
if (fSynth.nugget_remains < burstSize) | |||||
burstSize = fSynth.nugget_remains; | |||||
/* reduce burst size to end when next event is ready */ | |||||
if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame - framesDone < burstSize) | |||||
burstSize = midiEvents[curEventIndex].frame - framesDone; | |||||
/* reduce burst size to end at end of this run */ | |||||
if (frames - framesDone < burstSize) | |||||
burstSize = frames - framesDone; | |||||
/* render the burst */ | |||||
nekobee_synth_render_voices(&fSynth, out + framesDone, burstSize, (burstSize == fSynth.nugget_remains)); | |||||
framesDone += burstSize; | |||||
fSynth.nugget_remains -= burstSize; | |||||
} | |||||
dssp_voicelist_mutex_unlock(&fSynth); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new DistrhoPluginNekobi(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,131 @@ | |||||
/* | |||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | |||||
* Copyright (C) 2004 Sean Bolton and others | |||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_NEKOBI_HPP_INCLUDED | |||||
#define DISTRHO_PLUGIN_NEKOBI_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
extern "C" { | |||||
#include "nekobee-src/nekobee_synth.h" | |||||
} | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoPluginNekobi : public Plugin | |||||
{ | |||||
public: | |||||
enum Parameters | |||||
{ | |||||
paramWaveform = 0, | |||||
paramTuning, | |||||
paramCutoff, | |||||
paramResonance, | |||||
paramEnvMod, | |||||
paramDecay, | |||||
paramAccent, | |||||
paramVolume, | |||||
paramCount | |||||
}; | |||||
DistrhoPluginNekobi(); | |||||
~DistrhoPluginNekobi() override; | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "Nekobi"; | |||||
} | |||||
const char* getDescription() const override | |||||
{ | |||||
return "Simple single-oscillator synth based on the Roland TB-303."; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "Sean Bolton, falkTX"; | |||||
} | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/Nekobi"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "GPL v2+"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', 'N', 'e', 'k'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void deactivate() override; | |||||
void run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
struct ParamValues { | |||||
float waveform; | |||||
float tuning; | |||||
float cutoff; | |||||
float resonance; | |||||
float envMod; | |||||
float decay; | |||||
float accent; | |||||
float volume; | |||||
} fParams; | |||||
nekobee_synth_t fSynth; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoPluginNekobi) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_PLUGIN_NEKOBI_HPP_INCLUDED |
@@ -0,0 +1,231 @@ | |||||
/* | |||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | |||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 LICENSE file. | |||||
*/ | |||||
#include "DistrhoPluginNekobi.hpp" | |||||
#include "DistrhoUINekobi.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
namespace Art = DistrhoArtworkNekobi; | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoUINekobi::DistrhoUINekobi() | |||||
: UI(Art::backgroundWidth, Art::backgroundHeight), | |||||
fImgBackground(Art::backgroundData, Art::backgroundWidth, Art::backgroundHeight, GL_BGR), | |||||
fAboutWindow(this) | |||||
{ | |||||
// FIXME | |||||
fNeko.setTimerSpeed(5); | |||||
// about | |||||
Image aboutImage(Art::aboutData, Art::aboutWidth, Art::aboutHeight, GL_BGR); | |||||
fAboutWindow.setImage(aboutImage); | |||||
// slider | |||||
Image sliderImage(Art::sliderData, Art::sliderWidth, Art::sliderHeight); | |||||
fSliderWaveform = new ImageSlider(this, sliderImage); | |||||
fSliderWaveform->setId(DistrhoPluginNekobi::paramWaveform); | |||||
fSliderWaveform->setStartPos(133, 40); | |||||
fSliderWaveform->setEndPos(133, 60); | |||||
fSliderWaveform->setRange(0.0f, 1.0f); | |||||
fSliderWaveform->setStep(1.0f); | |||||
fSliderWaveform->setValue(0.0f); | |||||
fSliderWaveform->setCallback(this); | |||||
// knobs | |||||
Image knobImage(Art::knobData, Art::knobWidth, Art::knobHeight); | |||||
// knob Tuning | |||||
fKnobTuning = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobTuning->setId(DistrhoPluginNekobi::paramTuning); | |||||
fKnobTuning->setAbsolutePos(41, 43); | |||||
fKnobTuning->setRange(-12.0f, 12.0f); | |||||
fKnobTuning->setDefault(0.0f); | |||||
fKnobTuning->setValue(0.0f); | |||||
fKnobTuning->setRotationAngle(305); | |||||
fKnobTuning->setCallback(this); | |||||
// knob Cutoff | |||||
fKnobCutoff = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobCutoff->setId(DistrhoPluginNekobi::paramCutoff); | |||||
fKnobCutoff->setAbsolutePos(185, 43); | |||||
fKnobCutoff->setRange(0.0f, 100.0f); | |||||
fKnobCutoff->setDefault(25.0f); | |||||
fKnobCutoff->setValue(25.0f); | |||||
fKnobCutoff->setRotationAngle(305); | |||||
fKnobCutoff->setCallback(this); | |||||
// knob Resonance | |||||
fKnobResonance = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobResonance->setId(DistrhoPluginNekobi::paramResonance); | |||||
fKnobResonance->setAbsolutePos(257, 43); | |||||
fKnobResonance->setRange(0.0f, 95.0f); | |||||
fKnobResonance->setDefault(25.0f); | |||||
fKnobResonance->setValue(25.0f); | |||||
fKnobResonance->setRotationAngle(305); | |||||
fKnobResonance->setCallback(this); | |||||
// knob Env Mod | |||||
fKnobEnvMod = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobEnvMod->setId(DistrhoPluginNekobi::paramEnvMod); | |||||
fKnobEnvMod->setAbsolutePos(329, 43); | |||||
fKnobEnvMod->setRange(0.0f, 100.0f); | |||||
fKnobEnvMod->setDefault(50.0f); | |||||
fKnobEnvMod->setValue(50.0f); | |||||
fKnobEnvMod->setRotationAngle(305); | |||||
fKnobEnvMod->setCallback(this); | |||||
// knob Decay | |||||
fKnobDecay = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobDecay->setId(DistrhoPluginNekobi::paramDecay); | |||||
fKnobDecay->setAbsolutePos(400, 43); | |||||
fKnobDecay->setRange(0.0f, 100.0f); | |||||
fKnobDecay->setDefault(75.0f); | |||||
fKnobDecay->setValue(75.0f); | |||||
fKnobDecay->setRotationAngle(305); | |||||
fKnobDecay->setCallback(this); | |||||
// knob Accent | |||||
fKnobAccent = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobAccent->setId(DistrhoPluginNekobi::paramAccent); | |||||
fKnobAccent->setAbsolutePos(473, 43); | |||||
fKnobAccent->setRange(0.0f, 100.0f); | |||||
fKnobAccent->setDefault(25.0f); | |||||
fKnobAccent->setValue(25.0f); | |||||
fKnobAccent->setRotationAngle(305); | |||||
fKnobAccent->setCallback(this); | |||||
// knob Volume | |||||
fKnobVolume = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobVolume->setId(DistrhoPluginNekobi::paramVolume); | |||||
fKnobVolume->setAbsolutePos(545, 43); | |||||
fKnobVolume->setRange(0.0f, 100.0f); | |||||
fKnobVolume->setDefault(75.0f); | |||||
fKnobVolume->setValue(75.0f); | |||||
fKnobVolume->setRotationAngle(305); | |||||
fKnobVolume->setCallback(this); | |||||
// about button | |||||
Image aboutImageNormal(Art::aboutButtonNormalData, Art::aboutButtonNormalWidth, Art::aboutButtonNormalHeight); | |||||
Image aboutImageHover(Art::aboutButtonHoverData, Art::aboutButtonHoverWidth, Art::aboutButtonHoverHeight); | |||||
fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||||
fButtonAbout->setAbsolutePos(505, 5); | |||||
fButtonAbout->setCallback(this); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void DistrhoUINekobi::parameterChanged(uint32_t index, float value) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case DistrhoPluginNekobi::paramTuning: | |||||
fKnobTuning->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramWaveform: | |||||
fSliderWaveform->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramCutoff: | |||||
fKnobCutoff->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramResonance: | |||||
fKnobResonance->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramEnvMod: | |||||
fKnobEnvMod->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramDecay: | |||||
fKnobDecay->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramAccent: | |||||
fKnobAccent->setValue(value); | |||||
break; | |||||
case DistrhoPluginNekobi::paramVolume: | |||||
fKnobVolume->setValue(value); | |||||
break; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// UI Callbacks | |||||
void DistrhoUINekobi::uiIdle() | |||||
{ | |||||
if (fNeko.idle()) | |||||
repaint(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void DistrhoUINekobi::imageButtonClicked(ImageButton* button, int) | |||||
{ | |||||
if (button != fButtonAbout) | |||||
return; | |||||
fAboutWindow.exec(); | |||||
} | |||||
void DistrhoUINekobi::imageKnobDragStarted(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), true); | |||||
} | |||||
void DistrhoUINekobi::imageKnobDragFinished(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), false); | |||||
} | |||||
void DistrhoUINekobi::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
{ | |||||
setParameterValue(knob->getId(), value); | |||||
} | |||||
void DistrhoUINekobi::imageSliderDragStarted(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), true); | |||||
} | |||||
void DistrhoUINekobi::imageSliderDragFinished(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), false); | |||||
} | |||||
void DistrhoUINekobi::imageSliderValueChanged(ImageSlider* slider, float value) | |||||
{ | |||||
setParameterValue(slider->getId(), value); | |||||
} | |||||
void DistrhoUINekobi::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
fNeko.draw(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new DistrhoUINekobi(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,86 @@ | |||||
/* | |||||
* DISTRHO Nekobi Plugin, based on Nekobee by Sean Bolton and others. | |||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_UI_NEKOBI_HPP_INCLUDED | |||||
#define DISTRHO_UI_NEKOBI_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
#include "ImageWidgets.hpp" | |||||
#include "DistrhoArtworkNekobi.hpp" | |||||
#include "NekoWidget.hpp" | |||||
using DGL_NAMESPACE::ImageAboutWindow; | |||||
using DGL_NAMESPACE::ImageButton; | |||||
using DGL_NAMESPACE::ImageKnob; | |||||
using DGL_NAMESPACE::ImageSlider; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoUINekobi : public UI, | |||||
public ImageButton::Callback, | |||||
public ImageKnob::Callback, | |||||
public ImageSlider::Callback | |||||
{ | |||||
public: | |||||
DistrhoUINekobi(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
// ------------------------------------------------------------------- | |||||
// UI Callbacks | |||||
void 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 imageSliderDragStarted(ImageSlider* slider) override; | |||||
void imageSliderDragFinished(ImageSlider* slider) override; | |||||
void imageSliderValueChanged(ImageSlider* slider, float value) override; | |||||
void onDisplay() override; | |||||
private: | |||||
Image fImgBackground; | |||||
ImageAboutWindow fAboutWindow; | |||||
NekoWidget fNeko; | |||||
ScopedPointer<ImageButton> fButtonAbout; | |||||
ScopedPointer<ImageSlider> fSliderWaveform; | |||||
ScopedPointer<ImageKnob> fKnobTuning, fKnobCutoff, fKnobResonance; | |||||
ScopedPointer<ImageKnob> fKnobEnvMod, fKnobDecay, fKnobAccent, fKnobVolume; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUINekobi) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_NEKOBI_HPP_INCLUDED |
@@ -0,0 +1,202 @@ | |||||
/* | |||||
* Neko widget animation | |||||
* Copyright (C) 2013-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 LICENSE file. | |||||
*/ | |||||
#ifndef NEKO_WIDGET_HPP_INCLUDED | |||||
#define NEKO_WIDGET_HPP_INCLUDED | |||||
#include "DistrhoArtworkNekobi.hpp" | |||||
#include "Image.hpp" | |||||
#include "Widget.hpp" | |||||
#include <cstdlib> // rand | |||||
using DGL_NAMESPACE::Image; | |||||
// ----------------------------------------------------------------------- | |||||
class NekoWidget | |||||
{ | |||||
public: | |||||
NekoWidget() | |||||
: fPos(0), | |||||
fTimer(0), | |||||
fTimerSpeed(20), | |||||
fCurAction(kActionNone), | |||||
fCurImage(&fImages.sit) | |||||
{ | |||||
// load images | |||||
{ | |||||
using namespace DistrhoArtworkNekobi; | |||||
#define JOIN(a, b) a ## b | |||||
#define LOAD_IMAGE(NAME) fImages.NAME.loadFromMemory(JOIN(NAME, Data), JOIN(NAME, Width), JOIN(NAME, Height)); | |||||
LOAD_IMAGE(sit) | |||||
LOAD_IMAGE(tail) | |||||
LOAD_IMAGE(claw1) | |||||
LOAD_IMAGE(claw2) | |||||
LOAD_IMAGE(scratch1) | |||||
LOAD_IMAGE(scratch2) | |||||
LOAD_IMAGE(run1) | |||||
LOAD_IMAGE(run2) | |||||
LOAD_IMAGE(run3) | |||||
LOAD_IMAGE(run4) | |||||
#undef JOIN | |||||
#undef LOAD_IMAGE | |||||
} | |||||
} | |||||
void draw() | |||||
{ | |||||
int x = fPos+108; | |||||
int y = -2; | |||||
if (fCurImage == &fImages.claw1 || fCurImage == &fImages.claw2) | |||||
{ | |||||
x += 2; | |||||
y += 12; | |||||
} | |||||
fCurImage->drawAt(x, y); | |||||
} | |||||
// returns true if needs repaint | |||||
bool idle() | |||||
{ | |||||
if (++fTimer % fTimerSpeed != 0) // target is 20ms | |||||
return false; | |||||
if (fTimer == fTimerSpeed*9) | |||||
{ | |||||
if (fCurAction == kActionNone) | |||||
fCurAction = static_cast<Action>(std::rand() % kActionCount); | |||||
else | |||||
fCurAction = kActionNone; | |||||
fTimer = 0; | |||||
} | |||||
switch (fCurAction) | |||||
{ | |||||
case kActionNone: | |||||
if (fCurImage == &fImages.sit) | |||||
fCurImage = &fImages.tail; | |||||
else | |||||
fCurImage = &fImages.sit; | |||||
break; | |||||
case kActionClaw: | |||||
if (fCurImage == &fImages.claw1) | |||||
fCurImage = &fImages.claw2; | |||||
else | |||||
fCurImage = &fImages.claw1; | |||||
break; | |||||
case kActionScratch: | |||||
if (fCurImage == &fImages.scratch1) | |||||
fCurImage = &fImages.scratch2; | |||||
else | |||||
fCurImage = &fImages.scratch1; | |||||
break; | |||||
case kActionRunRight: | |||||
if (fTimer == 0 && fPos > 20*9) | |||||
{ | |||||
// run the other way | |||||
--fTimer; | |||||
fCurAction = kActionRunLeft; | |||||
idle(); | |||||
break; | |||||
} | |||||
fPos += 20; | |||||
if (fCurImage == &fImages.run1) | |||||
fCurImage = &fImages.run2; | |||||
else | |||||
fCurImage = &fImages.run1; | |||||
break; | |||||
case kActionRunLeft: | |||||
if (fTimer == 0 && fPos < 20*9) | |||||
{ | |||||
// run the other way | |||||
--fTimer; | |||||
fCurAction = kActionRunRight; | |||||
idle(); | |||||
break; | |||||
} | |||||
fPos -= 20; | |||||
if (fCurImage == &fImages.run3) | |||||
fCurImage = &fImages.run4; | |||||
else | |||||
fCurImage = &fImages.run3; | |||||
break; | |||||
case kActionCount: | |||||
break; | |||||
} | |||||
return true; | |||||
} | |||||
void setTimerSpeed(int speed) | |||||
{ | |||||
fTimer = 0; | |||||
fTimerSpeed = speed; | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
enum Action { | |||||
kActionNone, // bounce tail | |||||
kActionClaw, | |||||
kActionScratch, | |||||
kActionRunRight, | |||||
kActionRunLeft, | |||||
kActionCount | |||||
}; | |||||
struct Images { | |||||
Image sit; | |||||
Image tail; | |||||
Image claw1; | |||||
Image claw2; | |||||
Image scratch1; | |||||
Image scratch2; | |||||
Image run1; | |||||
Image run2; | |||||
Image run3; | |||||
Image run4; | |||||
} fImages; | |||||
int fPos; | |||||
int fTimer; | |||||
int fTimerSpeed; | |||||
Action fCurAction; | |||||
Image* fCurImage; | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
#endif // NEKO_WIDGET_HPP_INCLUDED |
@@ -0,0 +1,77 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
* | |||||
* Copyright (C) 2004 Sean Bolton and others. | |||||
* | |||||
* Portions of this file may have come from Chris Cannam and Steve | |||||
* Harris's public domain DSSI example code. | |||||
* | |||||
* 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 (at your option) 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. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this program; if not, write to the Free | |||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||||
* MA 02111-1307, USA. | |||||
*/ | |||||
#ifndef _XSYNTH_H | |||||
#define _XSYNTH_H | |||||
/* ==== debugging ==== */ | |||||
/* XSYNTH_DEBUG bits */ | |||||
#define XDB_DSSI 1 /* DSSI interface */ | |||||
#define XDB_AUDIO 2 /* audio output */ | |||||
#define XDB_NOTE 4 /* note on/off, voice allocation */ | |||||
#define XDB_DATA 8 /* plugin patchbank handling */ | |||||
#define GDB_MAIN 16 /* GUI main program flow */ | |||||
#define GDB_OSC 32 /* GUI OSC handling */ | |||||
#define GDB_IO 64 /* GUI patch file input/output */ | |||||
#define GDB_GUI 128 /* GUI GUI callbacks, updating, etc. */ | |||||
/* If you want debug information, define XSYNTH_DEBUG to the XDB_* bits you're | |||||
* interested in getting debug information about, bitwise-ORed together. | |||||
* Otherwise, leave it undefined. */ | |||||
// #define XSYNTH_DEBUG (1+8+16+32+64) | |||||
//#define XSYNTH_DEBUG GDB_GUI + GDB_OSC | |||||
// #define XSYNTH_DEBUG XDB_DSSI | |||||
#ifdef XSYNTH_DEBUG | |||||
#include <stdio.h> | |||||
#define XSYNTH_DEBUG_INIT(x) | |||||
#define XDB_MESSAGE(type, fmt...) { if (XSYNTH_DEBUG & type) fprintf(stderr, "nekobee-dssi.so" fmt); } | |||||
#define GDB_MESSAGE(type, fmt...) { if (XSYNTH_DEBUG & type) fprintf(stderr, "nekobee_gtk" fmt); } | |||||
// -FIX-: | |||||
// #include "message_buffer.h" | |||||
// #define XSYNTH_DEBUG_INIT(x) mb_init(x) | |||||
// #define XDB_MESSAGE(type, fmt...) { \- | |||||
// if (XSYNTH_DEBUG & type) { \- | |||||
// char _m[256]; \- | |||||
// snprintf(_m, 255, fmt); \- | |||||
// add_message(_m); \- | |||||
// } \- | |||||
// } | |||||
#else /* !XSYNTH_DEBUG */ | |||||
#define XDB_MESSAGE(type, fmt...) | |||||
#define GDB_MESSAGE(type, fmt...) | |||||
#define XSYNTH_DEBUG_INIT(x) | |||||
#endif /* XSYNTH_DEBUG */ | |||||
/* ==== end of debugging ==== */ | |||||
#define XSYNTH_MAX_POLYPHONY 1 | |||||
#define XSYNTH_DEFAULT_POLYPHONY 1 | |||||
#endif /* _XSYNTH_H */ |
@@ -0,0 +1,237 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
* | |||||
* Copyright (C) 2004 Sean Bolton and others. | |||||
* | |||||
* Portions of this file may have come from Steve Brookes' | |||||
* nekobee, copyright (C) 1999 S. J. Brookes. | |||||
* Portions of this file may have come from Peter Hanappe's | |||||
* Fluidsynth, copyright (C) 2003 Peter Hanappe and others. | |||||
* Portions of this file may have come from Chris Cannam and Steve | |||||
* Harris's public domain DSSI example code. | |||||
* | |||||
* 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 (at your option) 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. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this program; if not, write to the Free | |||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||||
* MA 02111-1307, USA. | |||||
*/ | |||||
#include <stdlib.h> | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include <math.h> | |||||
#include <pthread.h> | |||||
#include "nekobee.h" | |||||
#include "nekobee_synth.h" | |||||
#include "nekobee_voice.h" | |||||
/* | |||||
* nekobee_synth_all_voices_off | |||||
* | |||||
* stop processing all notes immediately | |||||
*/ | |||||
void | |||||
nekobee_synth_all_voices_off(nekobee_synth_t *synth) | |||||
{ | |||||
int i; | |||||
nekobee_voice_t *voice; | |||||
for (i = 0; i < synth->voices; i++) { | |||||
//voice = synth->voice[i]; | |||||
voice = synth->voice; | |||||
if (_PLAYING(voice)) { | |||||
nekobee_voice_off(voice); | |||||
} | |||||
} | |||||
for (i = 0; i < 8; i++) synth->held_keys[i] = -1; | |||||
} | |||||
/* | |||||
* nekobee_synth_note_off | |||||
* | |||||
* handle a note off message | |||||
*/ | |||||
void | |||||
nekobee_synth_note_off(nekobee_synth_t *synth, unsigned char key, unsigned char rvelocity) | |||||
{ | |||||
int i, count = 0; | |||||
nekobee_voice_t *voice; | |||||
for (i = 0; i < synth->voices; i++) { | |||||
voice = synth->voice; | |||||
if (_PLAYING(voice)) { | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_synth_note_off: key %d rvel %d voice %d note id %d\n", key, rvelocity, i, voice->note_id); | |||||
nekobee_voice_note_off(synth, voice, key, 64); | |||||
count++; | |||||
} | |||||
} | |||||
if (!count) | |||||
nekobee_voice_remove_held_key(synth, key); | |||||
return; | |||||
(void)rvelocity; | |||||
} | |||||
/* | |||||
* nekobee_synth_all_notes_off | |||||
* | |||||
* put all notes into the released state | |||||
*/ | |||||
void | |||||
nekobee_synth_all_notes_off(nekobee_synth_t* synth) | |||||
{ | |||||
int i; | |||||
nekobee_voice_t *voice; | |||||
/* reset the sustain controller */ | |||||
synth->cc[MIDI_CTL_SUSTAIN] = 0; | |||||
for (i = 0; i < synth->voices; i++) { | |||||
//voice = synth->voice[i]; | |||||
voice = synth->voice; | |||||
if (_ON(voice) || _SUSTAINED(voice)) { | |||||
nekobee_voice_release_note(synth, voice); | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* nekobee_synth_note_on | |||||
*/ | |||||
void | |||||
nekobee_synth_note_on(nekobee_synth_t *synth, unsigned char key, unsigned char velocity) | |||||
{ | |||||
nekobee_voice_t* voice; | |||||
voice = synth->voice; | |||||
if (_PLAYING(synth->voice)) { | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_synth_note_on: retriggering mono voice on new key %d\n", key); | |||||
} | |||||
voice->note_id = synth->note_id++; | |||||
nekobee_voice_note_on(synth, voice, key, velocity); | |||||
} | |||||
/* | |||||
* nekobee_synth_update_volume | |||||
*/ | |||||
void | |||||
nekobee_synth_update_volume(nekobee_synth_t* synth) | |||||
{ | |||||
synth->cc_volume = (float)(synth->cc[MIDI_CTL_MSB_MAIN_VOLUME] * 128 + | |||||
synth->cc[MIDI_CTL_LSB_MAIN_VOLUME]) / 16256.0f; | |||||
if (synth->cc_volume > 1.0f) | |||||
synth->cc_volume = 1.0f; | |||||
/* don't need to check if any playing voices need updating, because it's global */ | |||||
} | |||||
/* | |||||
* nekobee_synth_control_change | |||||
*/ | |||||
void | |||||
nekobee_synth_control_change(nekobee_synth_t *synth, unsigned int param, signed int value) | |||||
{ | |||||
synth->cc[param] = value; | |||||
switch (param) { | |||||
case MIDI_CTL_MSB_MAIN_VOLUME: | |||||
case MIDI_CTL_LSB_MAIN_VOLUME: | |||||
nekobee_synth_update_volume(synth); | |||||
break; | |||||
case MIDI_CTL_ALL_SOUNDS_OFF: | |||||
nekobee_synth_all_voices_off(synth); | |||||
break; | |||||
case MIDI_CTL_RESET_CONTROLLERS: | |||||
nekobee_synth_init_controls(synth); | |||||
break; | |||||
case MIDI_CTL_ALL_NOTES_OFF: | |||||
nekobee_synth_all_notes_off(synth); | |||||
break; | |||||
/* what others should we respond to? */ | |||||
/* these we ignore (let the host handle): | |||||
* BANK_SELECT_MSB | |||||
* BANK_SELECT_LSB | |||||
* DATA_ENTRY_MSB | |||||
* NRPN_MSB | |||||
* NRPN_LSB | |||||
* RPN_MSB | |||||
* RPN_LSB | |||||
* -FIX- no! we need RPN (0, 0) Pitch Bend Sensitivity! | |||||
*/ | |||||
} | |||||
} | |||||
/* | |||||
* nekobee_synth_init_controls | |||||
*/ | |||||
void | |||||
nekobee_synth_init_controls(nekobee_synth_t *synth) | |||||
{ | |||||
int i; | |||||
for (i = 0; i < 128; i++) { | |||||
synth->cc[i] = 0; | |||||
} | |||||
synth->cc[7] = 127; /* full volume */ | |||||
nekobee_synth_update_volume(synth); | |||||
} | |||||
/* | |||||
* nekobee_synth_render_voices | |||||
*/ | |||||
void | |||||
nekobee_synth_render_voices(nekobee_synth_t *synth, float *out, unsigned long sample_count, | |||||
int do_control_update) | |||||
{ | |||||
unsigned long i; | |||||
float res, wow; | |||||
/* clear the buffer */ | |||||
for (i = 0; i < sample_count; i++) | |||||
out[i] = 0.0f; | |||||
// we can do anything that must be updated all the time here | |||||
// this is called even when a voice isn't playing | |||||
// approximate a log scale | |||||
res = 1-synth->resonance; | |||||
wow = res*res; | |||||
wow = wow/10.0f; | |||||
// as the resonance is increased, "wow" slows down the accent attack | |||||
if ((synth->voice->velocity>90) && (synth->vcf_accent < synth->voice->vcf_eg)) { | |||||
synth->vcf_accent=(0.985-wow)*synth->vcf_accent+(0.015+wow)*synth->voice->vcf_eg; | |||||
} else { | |||||
synth->vcf_accent=(0.985-wow)*synth->vcf_accent; // or just decay | |||||
} | |||||
if (synth->voice->velocity>90) { | |||||
synth->vca_accent=0.95*synth->vca_accent+0.05; // ramp up accent on with a time constant | |||||
} else { | |||||
synth->vca_accent=0.95*synth->vca_accent; // accent off with time constant | |||||
} | |||||
#if defined(XSYNTH_DEBUG) && (XSYNTH_DEBUG & XDB_AUDIO) | |||||
out[0] += 0.10f; /* add a 'buzz' to output so there's something audible even when quiescent */ | |||||
#endif /* defined(XSYNTH_DEBUG) && (XSYNTH_DEBUG & XDB_AUDIO) */ | |||||
if (_PLAYING(synth->voice)) { | |||||
nekobee_voice_render(synth, synth->voice, out, sample_count, do_control_update); | |||||
} | |||||
} |
@@ -0,0 +1,132 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
* | |||||
* Copyright (C) 2004 Sean Bolton and others. | |||||
* | |||||
* Portions of this file may have come from Peter Hanappe's | |||||
* Fluidsynth, copyright (C) 2003 Peter Hanappe and others. | |||||
* Portions of this file may have come from alsa-lib, copyright | |||||
* and licensed under the LGPL v2.1. | |||||
* | |||||
* 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 (at your option) 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. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this program; if not, write to the Free | |||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||||
* MA 02111-1307, USA. | |||||
*/ | |||||
#ifndef _XSYNTH_SYNTH_H | |||||
#define _XSYNTH_SYNTH_H | |||||
#include <pthread.h> | |||||
#include "nekobee.h" | |||||
#include "nekobee_types.h" | |||||
#define XSYNTH_MONO_MODE_OFF 0 | |||||
#define XSYNTH_MONO_MODE_ON 1 | |||||
#define XSYNTH_MONO_MODE_ONCE 2 | |||||
#define XSYNTH_MONO_MODE_BOTH 3 | |||||
#define XSYNTH_GLIDE_MODE_LEGATO 0 | |||||
#define XSYNTH_GLIDE_MODE_INITIAL 1 | |||||
#define XSYNTH_GLIDE_MODE_ALWAYS 2 | |||||
#define XSYNTH_GLIDE_MODE_LEFTOVER 3 | |||||
#define XSYNTH_GLIDE_MODE_OFF 4 | |||||
/* | |||||
* nekobee_synth_t | |||||
*/ | |||||
struct _nekobee_synth_t { | |||||
/* output */ | |||||
unsigned long sample_rate; | |||||
float deltat; /* 1 / sample_rate */ | |||||
unsigned long nugget_remains; | |||||
/* voice tracking and data */ | |||||
unsigned int note_id; /* incremented for every new note, used for voice-stealing prioritization */ | |||||
int polyphony; /* requested polyphony, must be <= XSYNTH_MAX_POLYPHONY */ | |||||
int voices; /* current polyphony, either requested polyphony above or 1 while in monophonic mode */ | |||||
int monophonic; /* true if operating in monophonic mode */ | |||||
int glide; /* current glide mode */ | |||||
float last_noteon_pitch; /* glide start pitch for non-legato modes */ | |||||
signed char held_keys[8]; /* for monophonic key tracking, an array of note-ons, most recently received first */ | |||||
float vcf_accent; /* used to emulate the circuit that sweeps the vcf at full resonance */ | |||||
float vca_accent; /* used to smooth the accent pulse, removing the click */ | |||||
//nekobee_voice_t *voice[XSYNTH_MAX_POLYPHONY]; | |||||
nekobee_voice_t *voice; | |||||
pthread_mutex_t voicelist_mutex; | |||||
int voicelist_mutex_grab_failed; | |||||
/* current non-paramter-mapped controller values */ | |||||
unsigned char key_pressure[128]; | |||||
unsigned char cc[128]; /* controller values */ | |||||
unsigned char channel_pressure; | |||||
unsigned char pitch_wheel_sensitivity; /* in semitones */ | |||||
int pitch_wheel; /* range is -8192 - 8191 */ | |||||
/* translated controller values */ | |||||
float mod_wheel; /* filter cutoff multiplier, off = 1.0, full on = 0.0 */ | |||||
float pitch_bend; /* frequency multiplier, product of wheel setting and sensitivity, center = 1.0 */ | |||||
float cc_volume; /* volume multiplier, 0.0 to 1.0 */ | |||||
/* patch parameters */ | |||||
float tuning; | |||||
float waveform; | |||||
float cutoff; | |||||
float resonance; | |||||
float envmod; | |||||
float decay; | |||||
float accent; | |||||
float volume; | |||||
}; | |||||
void nekobee_synth_all_voices_off(nekobee_synth_t *synth); | |||||
void nekobee_synth_note_off(nekobee_synth_t *synth, unsigned char key, | |||||
unsigned char rvelocity); | |||||
void nekobee_synth_all_notes_off(nekobee_synth_t *synth); | |||||
void nekobee_synth_note_on(nekobee_synth_t *synth, unsigned char key, | |||||
unsigned char velocity); | |||||
void nekobee_synth_control_change(nekobee_synth_t *synth, unsigned int param, | |||||
signed int value); | |||||
void nekobee_synth_init_controls(nekobee_synth_t *synth); | |||||
void nekobee_synth_render_voices(nekobee_synth_t *synth, float *out, | |||||
unsigned long sample_count, | |||||
int do_control_update); | |||||
/* these come right out of alsa/asoundef.h */ | |||||
#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ | |||||
#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ | |||||
#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ | |||||
#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ | |||||
#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ | |||||
#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ | |||||
#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ | |||||
#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ | |||||
#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ | |||||
// nekobee defines | |||||
#define MIDI_CTL_TUNING 0x4b // impossible | |||||
#define MIDI_CTL_WAVEFORM 0x46 // select waveform | |||||
#define MIDI_CTL_CUTOFF 0x4a // VCF Cutoff | |||||
#define MIDI_CTL_RESONANCE 0x47 // VCF Resonance | |||||
#define MIDI_CTL_ENVMOD 0x01 // cheat and use modwheel | |||||
#define MIDI_CTL_DECAY 0x48 // Decay time (well release really) | |||||
#define MIDI_CTL_ACCENT 0x4c // impossible | |||||
#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ | |||||
#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ | |||||
#define MIDI_CTL_ALL_NOTES_OFF 0x7b /**< All notes off */ | |||||
#define XSYNTH_SYNTH_SUSTAINED(_s) ((_s)->cc[MIDI_CTL_SUSTAIN] >= 64) | |||||
#endif /* _XSYNTH_SYNTH_H */ |
@@ -0,0 +1,30 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
* | |||||
* Copyright (C) 2004 Sean Bolton and others. | |||||
* | |||||
* 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 (at your option) 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. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this library; if not, write to the Free | |||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||||
* MA 02111-1307, USA. | |||||
*/ | |||||
#ifndef _XSYNTH_TYPES_H | |||||
#define _XSYNTH_TYPES_H | |||||
#include <stddef.h> | |||||
typedef struct _nekobee_synth_t nekobee_synth_t; | |||||
typedef struct _nekobee_voice_t nekobee_voice_t; | |||||
typedef struct _nekobee_patch_t nekobee_patch_t; | |||||
#endif /* _XSYNTH_TYPES_H */ |
@@ -0,0 +1,256 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
* | |||||
* Copyright (C) 2004 Sean Bolton and others. | |||||
* | |||||
* Portions of this file may have come from Steve Brookes' | |||||
* nekobee, copyright (C) 1999 S. J. Brookes. | |||||
* Portions of this file may have come from Peter Hanappe's | |||||
* Fluidsynth, copyright (C) 2003 Peter Hanappe and others. | |||||
* | |||||
* 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 (at your option) 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. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this program; if not, write to the Free | |||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||||
* MA 02111-1307, USA. | |||||
*/ | |||||
#define _BSD_SOURCE 1 | |||||
#define _SVID_SOURCE 1 | |||||
#define _ISOC99_SOURCE 1 | |||||
#include <stdlib.h> | |||||
#include "nekobee_types.h" | |||||
#include "nekobee.h" | |||||
#include "nekobee_synth.h" | |||||
#include "nekobee_voice.h" | |||||
/* | |||||
* nekobee_voice_new | |||||
*/ | |||||
nekobee_voice_t * | |||||
nekobee_voice_new() | |||||
{ | |||||
nekobee_voice_t *voice; | |||||
voice = (nekobee_voice_t *)calloc(sizeof(nekobee_voice_t), 1); | |||||
if (voice) { | |||||
voice->status = XSYNTH_VOICE_OFF; | |||||
} | |||||
return voice; | |||||
} | |||||
/* | |||||
* nekobee_voice_note_on | |||||
*/ | |||||
void | |||||
nekobee_voice_note_on(nekobee_synth_t *synth, nekobee_voice_t *voice, | |||||
unsigned char key, unsigned char velocity) | |||||
{ | |||||
int i; | |||||
voice->key = key; | |||||
voice->velocity = velocity; | |||||
if (!synth->monophonic || !(_ON(voice) || _SUSTAINED(voice))) { | |||||
// brand-new voice, or monophonic voice in release phase; set everything up | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_voice_note_on in polyphonic/new section: key %d, mono %d, old status %d\n", key, synth->monophonic, voice->status); | |||||
voice->target_pitch = nekobee_pitch[key]; | |||||
if (synth->held_keys[0] >= 0) { | |||||
voice->prev_pitch = nekobee_pitch[synth->held_keys[0]]; | |||||
} else { | |||||
voice->prev_pitch = voice->target_pitch; | |||||
} | |||||
if (!_PLAYING(voice)) { | |||||
voice->lfo_pos = 0.0f; | |||||
voice->vca_eg = 0.0f; | |||||
voice->vcf_eg = 0.0f; | |||||
voice->delay1 = 0.0f; | |||||
voice->delay2 = 0.0f; | |||||
voice->delay3 = 0.0f; | |||||
voice->delay4 = 0.0f; | |||||
voice->c5 = 0.0f; | |||||
voice->osc_index = 0; | |||||
voice->osc1.last_waveform = -1; | |||||
voice->osc1.pos = 0.0f; | |||||
} | |||||
voice->vca_eg_phase = 0; | |||||
voice->vcf_eg_phase = 0; | |||||
// nekobee_voice_update_pressure_mod(synth, voice); | |||||
} else { | |||||
/* synth is monophonic, and we're modifying a playing voice */ | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_voice_note_on in monophonic section: old key %d => new key %d\n", synth->held_keys[0], key); | |||||
/* set new pitch */ | |||||
voice->target_pitch = nekobee_pitch[key]; | |||||
if (synth->glide == XSYNTH_GLIDE_MODE_INITIAL || | |||||
synth->glide == XSYNTH_GLIDE_MODE_OFF) | |||||
voice->prev_pitch = voice->target_pitch; | |||||
/* if in 'on' or 'both' modes, and key has changed, then re-trigger EGs */ | |||||
if ((synth->monophonic == XSYNTH_MONO_MODE_ON || | |||||
synth->monophonic == XSYNTH_MONO_MODE_BOTH) && | |||||
(synth->held_keys[0] < 0 || synth->held_keys[0] != key)) { | |||||
voice->vca_eg_phase = 0; | |||||
voice->vcf_eg_phase = 0; | |||||
} | |||||
/* all other variables stay what they are */ | |||||
} | |||||
synth->last_noteon_pitch = voice->target_pitch; | |||||
/* add new key to the list of held keys */ | |||||
/* check if new key is already in the list; if so, move it to the | |||||
* top of the list, otherwise shift the other keys down and add it | |||||
* to the top of the list. */ | |||||
for (i = 0; i < 7; i++) { | |||||
if (synth->held_keys[i] == key) | |||||
break; | |||||
} | |||||
for (; i > 0; i--) { | |||||
synth->held_keys[i] = synth->held_keys[i - 1]; | |||||
} | |||||
synth->held_keys[0] = key; | |||||
if (!_PLAYING(voice)) { | |||||
nekobee_voice_start_voice(voice); | |||||
} else if (!_ON(voice)) { /* must be XSYNTH_VOICE_SUSTAINED or XSYNTH_VOICE_RELEASED */ | |||||
voice->status = XSYNTH_VOICE_ON; | |||||
} | |||||
} | |||||
/* | |||||
* nekobee_voice_set_release_phase | |||||
*/ | |||||
static inline void | |||||
nekobee_voice_set_release_phase(nekobee_voice_t *voice) | |||||
{ | |||||
voice->vca_eg_phase = 2; | |||||
voice->vcf_eg_phase = 2; | |||||
} | |||||
/* | |||||
* nekobee_voice_remove_held_key | |||||
*/ | |||||
inline void | |||||
nekobee_voice_remove_held_key(nekobee_synth_t *synth, unsigned char key) | |||||
{ | |||||
int i; | |||||
/* check if this key is in list of held keys; if so, remove it and | |||||
* shift the other keys up */ | |||||
for (i = 7; i >= 0; i--) { | |||||
if (synth->held_keys[i] == key) | |||||
break; | |||||
} | |||||
if (i >= 0) { | |||||
for (; i < 7; i++) { | |||||
synth->held_keys[i] = synth->held_keys[i + 1]; | |||||
} | |||||
synth->held_keys[7] = -1; | |||||
} | |||||
} | |||||
/* | |||||
* nekobee_voice_note_off | |||||
*/ | |||||
void | |||||
nekobee_voice_note_off(nekobee_synth_t *synth, nekobee_voice_t *voice, | |||||
unsigned char key, unsigned char rvelocity) | |||||
{ | |||||
unsigned char previous_top_key; | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_set_note_off: called for voice %p, key %d\n", voice, key); | |||||
/* save release velocity */ | |||||
voice->velocity = rvelocity; | |||||
previous_top_key = synth->held_keys[0]; | |||||
/* remove this key from list of held keys */ | |||||
nekobee_voice_remove_held_key(synth, key); | |||||
if (synth->held_keys[0] >= 0) { | |||||
/* still some keys held */ | |||||
if (synth->held_keys[0] != previous_top_key) { | |||||
/* most-recently-played key has changed */ | |||||
voice->key = synth->held_keys[0]; | |||||
XDB_MESSAGE(XDB_NOTE, " note-off in monophonic section: changing pitch to %d\n", voice->key); | |||||
voice->target_pitch = nekobee_pitch[voice->key]; | |||||
if (synth->glide == XSYNTH_GLIDE_MODE_INITIAL || | |||||
synth->glide == XSYNTH_GLIDE_MODE_OFF) | |||||
voice->prev_pitch = voice->target_pitch; | |||||
/* if mono mode is 'both', re-trigger EGs */ | |||||
if (synth->monophonic == XSYNTH_MONO_MODE_BOTH && !_RELEASED(voice)) { | |||||
voice->vca_eg_phase = 0; | |||||
voice->vcf_eg_phase = 0; | |||||
} | |||||
} | |||||
} else { /* no keys still held */ | |||||
if (XSYNTH_SYNTH_SUSTAINED(synth)) { | |||||
/* no more keys in list, but we're sustained */ | |||||
XDB_MESSAGE(XDB_NOTE, " note-off in monophonic section: sustained with no held keys\n"); | |||||
if (!_RELEASED(voice)) | |||||
voice->status = XSYNTH_VOICE_SUSTAINED; | |||||
} else { /* not sustained */ | |||||
/* no more keys in list, so turn off note */ | |||||
XDB_MESSAGE(XDB_NOTE, " note-off in monophonic section: turning off voice %p\n", voice); | |||||
nekobee_voice_set_release_phase(voice); | |||||
voice->status = XSYNTH_VOICE_RELEASED; | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* nekobee_voice_release_note | |||||
*/ | |||||
void | |||||
nekobee_voice_release_note(nekobee_synth_t *synth, nekobee_voice_t *voice) | |||||
{ | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_voice_release_note: turning off voice %p\n", voice); | |||||
if (_ON(voice)) { | |||||
/* dummy up a release velocity */ | |||||
voice->rvelocity = 64; | |||||
} | |||||
nekobee_voice_set_release_phase(voice); | |||||
voice->status = XSYNTH_VOICE_RELEASED; | |||||
return; | |||||
(void)synth; | |||||
} |
@@ -0,0 +1,183 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
* | |||||
* Copyright (C) 2004 Sean Bolton and others. | |||||
* | |||||
* Portions of this file may have come from Steve Brookes' | |||||
* nekobee, copyright (C) 1999 S. J. Brookes. | |||||
* Portions of this file may have come from Peter Hanappe's | |||||
* Fluidsynth, copyright (C) 2003 Peter Hanappe and others. | |||||
* | |||||
* 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 (at your option) 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. | |||||
* | |||||
* You should have received a copy of the GNU General Public | |||||
* License along with this program; if not, write to the Free | |||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||||
* MA 02111-1307, USA. | |||||
*/ | |||||
#ifndef _XSYNTH_VOICE_H | |||||
#define _XSYNTH_VOICE_H | |||||
#include <string.h> | |||||
#include "nekobee_types.h" | |||||
/* maximum size of a rendering burst */ | |||||
#define XSYNTH_NUGGET_SIZE 64 | |||||
/* minBLEP constants */ | |||||
/* minBLEP table oversampling factor (must be a power of two): */ | |||||
#define MINBLEP_PHASES 64 | |||||
/* MINBLEP_PHASES minus one: */ | |||||
#define MINBLEP_PHASE_MASK 63 | |||||
/* length in samples of (truncated) step discontinuity delta: */ | |||||
#define STEP_DD_PULSE_LENGTH 72 | |||||
/* length in samples of (truncated) slope discontinuity delta: */ | |||||
#define SLOPE_DD_PULSE_LENGTH 71 | |||||
/* the longer of the two above: */ | |||||
#define LONGEST_DD_PULSE_LENGTH STEP_DD_PULSE_LENGTH | |||||
/* MINBLEP_BUFFER_LENGTH must be at least XSYNTH_NUGGET_SIZE plus | |||||
* LONGEST_DD_PULSE_LENGTH, and not less than twice LONGEST_DD_PULSE_LENGTH: */ | |||||
#define MINBLEP_BUFFER_LENGTH 512 | |||||
/* delay between start of DD pulse and the discontinuity, in samples: */ | |||||
#define DD_SAMPLE_DELAY 4 | |||||
struct _nekobee_patch_t | |||||
{ | |||||
float tuning; | |||||
unsigned char waveform; | |||||
float cutoff; | |||||
float resonance; | |||||
float envmod; | |||||
float decay; | |||||
float accent; | |||||
float volume; | |||||
}; | |||||
enum nekobee_voice_status | |||||
{ | |||||
XSYNTH_VOICE_OFF, /* silent: is not processed by render loop */ | |||||
XSYNTH_VOICE_ON, /* has not received a note off event */ | |||||
XSYNTH_VOICE_SUSTAINED, /* has received note off, but sustain controller is on */ | |||||
XSYNTH_VOICE_RELEASED /* had note off, not sustained, in final decay phase of envelopes */ | |||||
}; | |||||
struct blosc | |||||
{ | |||||
int last_waveform, /* persistent */ | |||||
waveform, /* comes from LADSPA port each cycle */ | |||||
bp_high; /* persistent */ | |||||
float pos, /* persistent */ | |||||
pw; /* comes from LADSPA port each cycle */ | |||||
}; | |||||
/* | |||||
* nekobee_voice_t | |||||
*/ | |||||
struct _nekobee_voice_t | |||||
{ | |||||
unsigned int note_id; | |||||
unsigned char status; | |||||
unsigned char key; | |||||
unsigned char velocity; | |||||
unsigned char rvelocity; /* the note-off velocity */ | |||||
/* translated controller values */ | |||||
float pressure; /* filter resonance multiplier, off = 1.0, full on = 0.0 */ | |||||
/* persistent voice state */ | |||||
float prev_pitch, | |||||
target_pitch, | |||||
lfo_pos; | |||||
struct blosc osc1; | |||||
float vca_eg, | |||||
vcf_eg, | |||||
accent_slug, | |||||
delay1, | |||||
delay2, | |||||
delay3, | |||||
delay4, | |||||
c5; | |||||
unsigned char vca_eg_phase, | |||||
vcf_eg_phase; | |||||
int osc_index; /* shared index into osc_audio */ | |||||
float osc_audio[MINBLEP_BUFFER_LENGTH]; | |||||
float freqcut_buf[XSYNTH_NUGGET_SIZE]; | |||||
float vca_buf[XSYNTH_NUGGET_SIZE]; | |||||
}; | |||||
#define _PLAYING(voice) ((voice)->status != XSYNTH_VOICE_OFF) | |||||
#define _ON(voice) ((voice)->status == XSYNTH_VOICE_ON) | |||||
#define _SUSTAINED(voice) ((voice)->status == XSYNTH_VOICE_SUSTAINED) | |||||
#define _RELEASED(voice) ((voice)->status == XSYNTH_VOICE_RELEASED) | |||||
#define _AVAILABLE(voice) ((voice)->status == XSYNTH_VOICE_OFF) | |||||
extern float nekobee_pitch[128]; | |||||
typedef struct { float value, delta; } float_value_delta; | |||||
extern float_value_delta step_dd_table[]; | |||||
extern float slope_dd_table[]; | |||||
/* nekobee_voice.c */ | |||||
nekobee_voice_t *nekobee_voice_new(); | |||||
void nekobee_voice_note_on(nekobee_synth_t *synth, | |||||
nekobee_voice_t *voice, | |||||
unsigned char key, | |||||
unsigned char velocity); | |||||
void nekobee_voice_remove_held_key(nekobee_synth_t *synth, | |||||
unsigned char key); | |||||
void nekobee_voice_note_off(nekobee_synth_t *synth, | |||||
nekobee_voice_t *voice, | |||||
unsigned char key, | |||||
unsigned char rvelocity); | |||||
void nekobee_voice_release_note(nekobee_synth_t *synth, | |||||
nekobee_voice_t *voice); | |||||
void nekobee_voice_set_ports(nekobee_synth_t *synth, | |||||
nekobee_patch_t *patch); | |||||
void nekobee_voice_update_pressure_mod(nekobee_synth_t *synth, | |||||
nekobee_voice_t *voice); | |||||
/* nekobee_voice_render.c */ | |||||
void nekobee_init_tables(void); | |||||
void nekobee_voice_render(nekobee_synth_t *synth, nekobee_voice_t *voice, | |||||
float *out, unsigned long sample_count, | |||||
int do_control_update); | |||||
/* inline functions */ | |||||
/* | |||||
* nekobee_voice_off | |||||
* | |||||
* Purpose: Turns off a voice immediately, meaning that it is not processed | |||||
* anymore by the render loop. | |||||
*/ | |||||
static inline void | |||||
nekobee_voice_off(nekobee_voice_t* voice) | |||||
{ | |||||
voice->status = XSYNTH_VOICE_OFF; | |||||
/* silence the oscillator buffer for the next use */ | |||||
memset(voice->osc_audio, 0, MINBLEP_BUFFER_LENGTH * sizeof(float)); | |||||
/* -FIX- decrement active voice count? */ | |||||
} | |||||
/* | |||||
* nekobee_voice_start_voice | |||||
*/ | |||||
static inline void | |||||
nekobee_voice_start_voice(nekobee_voice_t *voice) | |||||
{ | |||||
voice->status = XSYNTH_VOICE_ON; | |||||
/* -FIX- increment active voice count? */ | |||||
} | |||||
#endif /* _XSYNTH_VOICE_H */ |
@@ -0,0 +1,414 @@ | |||||
/* nekobee DSSI software synthesizer plugin | |||||
*/ | |||||
#define _BSD_SOURCE 1 | |||||
#define _SVID_SOURCE 1 | |||||
#define _ISOC99_SOURCE 1 | |||||
#include <math.h> | |||||
#include "nekobee.h" | |||||
#include "nekobee_synth.h" | |||||
#include "nekobee_voice.h" | |||||
#ifndef M_PI | |||||
#define M_PI 3.14159265358979323846 | |||||
#endif | |||||
#define M_2PI_F (2.0f * (float)M_PI) | |||||
#define M_PI_F (float)M_PI | |||||
#define VCF_FREQ_MAX (0.825f) /* original filters only stable to this frequency */ | |||||
static int tables_initialized = 0; | |||||
float nekobee_pitch[128]; | |||||
#define pitch_ref_note 69 | |||||
#define volume_to_amplitude_scale 128 | |||||
static float volume_to_amplitude_table[4 + volume_to_amplitude_scale + 2]; | |||||
static float velocity_to_attenuation[128]; | |||||
static float qdB_to_amplitude_table[4 + 256 + 0]; | |||||
void | |||||
nekobee_init_tables(void) | |||||
{ | |||||
int i; | |||||
float pexp; | |||||
float volume, volume_exponent; | |||||
float ol, amp; | |||||
if (tables_initialized) | |||||
return; | |||||
/* MIDI note to pitch */ | |||||
for (i = 0; i < 128; ++i) { | |||||
pexp = (float)(i - pitch_ref_note) / 12.0f; | |||||
nekobee_pitch[i] = powf(2.0f, pexp); | |||||
} | |||||
/* volume to amplitude | |||||
* | |||||
* This generates a curve which is: | |||||
* volume_to_amplitude_table[128 + 4] = 0.25 * 3.16... ~= -2dB | |||||
* volume_to_amplitude_table[64 + 4] = 0.25 * 1.0 ~= -12dB | |||||
* volume_to_amplitude_table[32 + 4] = 0.25 * 0.316... ~= -22dB | |||||
* volume_to_amplitude_table[16 + 4] = 0.25 * 0.1 ~= -32dB | |||||
* etc. | |||||
*/ | |||||
volume_exponent = 1.0f / (2.0f * log10f(2.0f)); | |||||
for (i = 0; i <= volume_to_amplitude_scale; i++) { | |||||
volume = (float)i / (float)volume_to_amplitude_scale; | |||||
volume_to_amplitude_table[i + 4] = powf(2.0f * volume, volume_exponent) / 4.0f; | |||||
} | |||||
volume_to_amplitude_table[ -1 + 4] = 0.0f; | |||||
volume_to_amplitude_table[129 + 4] = volume_to_amplitude_table[128 + 4]; | |||||
/* velocity to attenuation | |||||
* | |||||
* Creates the velocity to attenuation lookup table, for converting | |||||
* velocities [1, 127] to full-velocity-sensitivity attenuation in | |||||
* quarter decibels. Modeled after my TX-7's velocity response.*/ | |||||
velocity_to_attenuation[0] = 253.9999f; | |||||
for (i = 1; i < 127; i++) { | |||||
if (i >= 10) { | |||||
ol = (powf(((float)i / 127.0f), 0.32f) - 1.0f) * 100.0f; | |||||
amp = powf(2.0f, ol / 8.0f); | |||||
} else { | |||||
ol = (powf(((float)10 / 127.0f), 0.32f) - 1.0f) * 100.0f; | |||||
amp = powf(2.0f, ol / 8.0f) * (float)i / 10.0f; | |||||
} | |||||
velocity_to_attenuation[i] = log10f(amp) * -80.0f; | |||||
} | |||||
velocity_to_attenuation[127] = 0.0f; | |||||
/* quarter-decibel attenuation to amplitude */ | |||||
qdB_to_amplitude_table[-1 + 4] = 1.0f; | |||||
for (i = 0; i <= 255; i++) { | |||||
qdB_to_amplitude_table[i + 4] = powf(10.0f, (float)i / -80.0f); | |||||
} | |||||
tables_initialized = 1; | |||||
} | |||||
static inline float | |||||
volume(float level) | |||||
{ | |||||
unsigned char segment; | |||||
float fract; | |||||
level *= (float)volume_to_amplitude_scale; | |||||
segment = lrintf(level - 0.5f); | |||||
fract = level - (float)segment; | |||||
return volume_to_amplitude_table[segment + 4] + fract * | |||||
(volume_to_amplitude_table[segment + 5] - | |||||
volume_to_amplitude_table[segment + 4]); | |||||
} | |||||
static inline float | |||||
qdB_to_amplitude(float qdB) | |||||
{ | |||||
int i = lrintf(qdB - 0.5f); | |||||
float f = qdB - (float)i; | |||||
return qdB_to_amplitude_table[i + 4] + f * | |||||
(qdB_to_amplitude_table[i + 5] - | |||||
qdB_to_amplitude_table[i + 4]); | |||||
} | |||||
void blosc_place_step_dd(float *buffer, int index, float phase, float w, float scale){ | |||||
float r; | |||||
int i; | |||||
r = MINBLEP_PHASES * phase / w; | |||||
i = lrintf(r - 0.5f); | |||||
r -= (float)i; | |||||
i &= MINBLEP_PHASE_MASK; /* port changes can cause i to be out-of-range */ | |||||
/* This would be better than the above, but more expensive: | |||||
* while (i < 0) { | |||||
* i += MINBLEP_PHASES; | |||||
* index++; | |||||
* } | |||||
*/ | |||||
while (i < MINBLEP_PHASES * STEP_DD_PULSE_LENGTH) { | |||||
buffer[index] += scale * (step_dd_table[i].value + r * step_dd_table[i].delta); | |||||
i += MINBLEP_PHASES; | |||||
index++; | |||||
} | |||||
} | |||||
void vco(unsigned long sample_count, nekobee_voice_t *voice, struct blosc *osc, | |||||
int index, float w) | |||||
{ | |||||
unsigned long sample; | |||||
float pos = osc->pos; | |||||
float pw, gain, halfgain, out; | |||||
pw=0.46f; | |||||
gain=1.0f; | |||||
halfgain=gain*0.5f; | |||||
int bp_high = osc->bp_high; | |||||
out=(bp_high ? halfgain : -halfgain); | |||||
switch (osc->waveform) | |||||
{ | |||||
default: | |||||
case 0: { | |||||
for (sample = 0; sample < sample_count; sample++) { | |||||
pos += w; | |||||
if (bp_high) { | |||||
if (pos >= pw) { | |||||
blosc_place_step_dd(voice->osc_audio, index, pos - pw, w, -gain); | |||||
bp_high = 0; | |||||
out = -halfgain; | |||||
} | |||||
if (pos >= 1.0f) { | |||||
pos -= 1.0f; | |||||
blosc_place_step_dd(voice->osc_audio, index, pos, w, gain); | |||||
bp_high = 1; | |||||
out = halfgain; | |||||
} | |||||
} else { | |||||
if (pos >= 1.0f) { | |||||
pos -= 1.0f; | |||||
blosc_place_step_dd(voice->osc_audio, index, pos, w, gain); | |||||
bp_high = 1; | |||||
out = halfgain; | |||||
} | |||||
if (bp_high && pos >= pw) { | |||||
blosc_place_step_dd(voice->osc_audio, index, pos - pw, w, -gain); | |||||
bp_high = 0; | |||||
out = -halfgain; | |||||
} | |||||
} | |||||
voice->osc_audio[index + DD_SAMPLE_DELAY] += out; | |||||
index++; | |||||
} | |||||
osc->pos = pos; | |||||
osc->bp_high = bp_high; | |||||
break; | |||||
} | |||||
case 1: // sawtooth wave | |||||
{ | |||||
for (sample=0; sample < sample_count; sample++) { | |||||
pos += w; | |||||
if (pos >= 1.0f) { | |||||
pos -= 1.0f; | |||||
blosc_place_step_dd(voice->osc_audio, index, pos, w, gain); | |||||
} | |||||
voice->osc_audio[index + DD_SAMPLE_DELAY] += gain * (0.5f - pos); | |||||
index++; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
osc->pos=pos; | |||||
} | |||||
static inline void | |||||
vcf_4pole(nekobee_voice_t *voice, unsigned long sample_count, | |||||
float *in, float *out, float *cutoff, float qres, float *amp) | |||||
{ | |||||
unsigned long sample; | |||||
float freqcut, freqcut2, highpass, | |||||
delay1 = voice->delay1, | |||||
delay2 = voice->delay2, | |||||
delay3 = voice->delay3, | |||||
delay4 = voice->delay4; | |||||
qres = 2.0f - qres * 1.995f; | |||||
for (sample = 0; sample < sample_count; sample++) { | |||||
/* Hal Chamberlin's state variable filter */ | |||||
freqcut = cutoff[sample] * 2.0f; | |||||
freqcut2 = cutoff[sample] * 4.0f; | |||||
if (freqcut > VCF_FREQ_MAX) freqcut = VCF_FREQ_MAX; | |||||
if (freqcut2 > VCF_FREQ_MAX) freqcut2 = VCF_FREQ_MAX; | |||||
delay2 = delay2 + freqcut * delay1; /* delay2/4 = lowpass output */ | |||||
highpass = in[sample] - delay2 - qres * delay1; | |||||
delay1 = freqcut * highpass + delay1; /* delay1/3 = bandpass output */ | |||||
delay4 = delay4 + freqcut2 * delay3; | |||||
highpass = delay2 - delay4 - qres * delay3; | |||||
delay3 = freqcut2 * highpass + delay3; | |||||
/* mix filter output into output buffer */ | |||||
out[sample] += 0.1*atan(3*delay4 * amp[sample]); | |||||
} | |||||
voice->delay1 = delay1; | |||||
voice->delay2 = delay2; | |||||
voice->delay3 = delay3; | |||||
voice->delay4 = delay4; | |||||
voice->c5 = 0.0f; | |||||
} | |||||
/* | |||||
* nekobee_voice_render | |||||
* | |||||
* generate the actual sound data for this voice | |||||
*/ | |||||
void | |||||
nekobee_voice_render(nekobee_synth_t *synth, nekobee_voice_t *voice, | |||||
float *out, unsigned long sample_count, | |||||
int do_control_update) | |||||
{ | |||||
unsigned long sample; | |||||
/* state variables saved in voice */ | |||||
float lfo_pos = voice->lfo_pos, | |||||
vca_eg = voice->vca_eg, | |||||
vcf_eg = voice->vcf_eg; | |||||
unsigned char vca_eg_phase = voice->vca_eg_phase, | |||||
vcf_eg_phase = voice->vcf_eg_phase; | |||||
int osc_index = voice->osc_index; | |||||
/* temporary variables used in calculating voice */ | |||||
float fund_pitch; | |||||
float deltat = synth->deltat; | |||||
float freq, cutoff, vcf_amt; | |||||
float vcf_acc_amt; | |||||
/* set up synthesis variables from patch */ | |||||
float omega; | |||||
float vca_eg_amp = qdB_to_amplitude(velocity_to_attenuation[voice->velocity] * 0); | |||||
float vca_eg_rate_level[3], vca_eg_one_rate[3]; | |||||
float vcf_eg_amp = qdB_to_amplitude(velocity_to_attenuation[voice->velocity] * 0); | |||||
float vcf_eg_rate_level[3], vcf_eg_one_rate[3]; | |||||
float qres = synth->resonance; | |||||
float vol_out = volume(synth->volume); | |||||
float velocity = (voice->velocity); | |||||
float vcf_egdecay = synth->decay; | |||||
fund_pitch = 0.1f*voice->target_pitch +0.9 * voice->prev_pitch; /* glide */ | |||||
if (do_control_update) { | |||||
voice->prev_pitch = fund_pitch; /* save pitch for next time */ | |||||
} | |||||
fund_pitch *= 440.0f; | |||||
omega = synth->tuning * fund_pitch; | |||||
// if we have triggered ACCENT | |||||
// we need a shorter decay | |||||
// we should probably have something like this in the note on code | |||||
// that could trigger an ACCENT light | |||||
if (velocity>90) { | |||||
vcf_egdecay=.0005; | |||||
} | |||||
// VCA - In a real 303, it is set for around 2 seconds | |||||
vca_eg_rate_level[0] = 0.1f * vca_eg_amp; // instant on attack | |||||
vca_eg_one_rate[0] = 0.9f; // very fast | |||||
vca_eg_rate_level[1] = 0.0f; // sustain is zero | |||||
vca_eg_one_rate[1] = 1.0f - 0.00001f; // decay time is very slow | |||||
vca_eg_rate_level[2] = 0.0f; // decays to zero | |||||
vca_eg_one_rate[2] = 0.975f; // very fast release | |||||
// VCF - funny things go on with the accent | |||||
vcf_eg_rate_level[0] = 0.1f * vcf_eg_amp; | |||||
vcf_eg_one_rate[0] = 1-0.1f; //0.9f; | |||||
vcf_eg_rate_level[1] = 0.0f; // vcf_egdecay * *(synth->vcf_eg_sustain_level) * vcf_eg_amp; | |||||
vcf_eg_one_rate[1] = 1.0f - vcf_egdecay; | |||||
vcf_eg_rate_level[2] = 0.0f; | |||||
vcf_eg_one_rate[2] = 0.9995f; // 1.0f - *(synth->vcf_eg_release_time); | |||||
vca_eg_amp *= 0.99f; | |||||
vcf_eg_amp *= 0.99f; | |||||
freq = M_PI_F * deltat * fund_pitch * synth->mod_wheel; /* now (0 to 1) * pi */ | |||||
cutoff = 0.008f * synth->cutoff; | |||||
// 303 always has slight VCF mod | |||||
vcf_amt = 0.05f+(synth->envmod*0.75); | |||||
/* copy some things so oscillator functions can see them */ | |||||
voice->osc1.waveform = lrintf(synth->waveform); | |||||
// work out how much the accent will affect the filter | |||||
vcf_acc_amt=.333f+ (synth->resonance/1.5f); | |||||
for (sample = 0; sample < sample_count; sample++) { | |||||
vca_eg = vca_eg_rate_level[vca_eg_phase] + vca_eg_one_rate[vca_eg_phase] * vca_eg; | |||||
vcf_eg = vcf_eg_rate_level[vcf_eg_phase] + vcf_eg_one_rate[vcf_eg_phase] * vcf_eg; | |||||
voice->freqcut_buf[sample] = (cutoff + (vcf_amt * vcf_eg/2.0f) + (synth->vcf_accent * synth->accent*0.5f)); | |||||
voice->vca_buf[sample] = vca_eg * vol_out*(1.0f + synth->accent*synth->vca_accent); | |||||
if (!vca_eg_phase && vca_eg > vca_eg_amp) vca_eg_phase = 1; /* flip from attack to decay */ | |||||
if (!vcf_eg_phase && vcf_eg > vcf_eg_amp) vcf_eg_phase = 1; /* flip from attack to decay */ | |||||
} | |||||
// oscillator | |||||
vco(sample_count, voice, &voice->osc1, osc_index, deltat * omega); | |||||
// VCF and VCA | |||||
vcf_4pole(voice, sample_count, voice->osc_audio + osc_index, out, voice->freqcut_buf, qres, voice->vca_buf); | |||||
osc_index += sample_count; | |||||
if (do_control_update) { | |||||
/* do those things should be done only once per control-calculation | |||||
* interval ("nugget"), such as voice check-for-dead, pitch envelope | |||||
* calculations, volume envelope phase transition checks, etc. */ | |||||
/* check if we've decayed to nothing, turn off voice if so */ | |||||
if (vca_eg_phase == 2 && voice->vca_buf[sample_count - 1] < 6.26e-6f) { | |||||
// sound has completed its release phase (>96dB below volume '5' max) | |||||
XDB_MESSAGE(XDB_NOTE, " nekobee_voice_render check for dead: killing note id %d\n", voice->note_id); | |||||
nekobee_voice_off(voice); | |||||
return; // we're dead now, so return | |||||
} | |||||
/* already saved prev_pitch above */ | |||||
/* check oscillator audio buffer index, shift buffer if necessary */ | |||||
if (osc_index > MINBLEP_BUFFER_LENGTH - (XSYNTH_NUGGET_SIZE + LONGEST_DD_PULSE_LENGTH)) { | |||||
memcpy(voice->osc_audio, voice->osc_audio + osc_index, | |||||
LONGEST_DD_PULSE_LENGTH * sizeof (float)); | |||||
memset(voice->osc_audio + LONGEST_DD_PULSE_LENGTH, 0, | |||||
(MINBLEP_BUFFER_LENGTH - LONGEST_DD_PULSE_LENGTH) * sizeof (float)); | |||||
osc_index = 0; | |||||
} | |||||
} | |||||
/* save things for next time around */ | |||||
voice->lfo_pos = lfo_pos; | |||||
voice->vca_eg = vca_eg; | |||||
voice->vca_eg_phase = vca_eg_phase; | |||||
voice->vcf_eg = vcf_eg; | |||||
voice->vcf_eg_phase = vcf_eg_phase; | |||||
voice->osc_index = osc_index; | |||||
return; | |||||
(void)freq; | |||||
(void)vcf_acc_amt; | |||||
} |
@@ -0,0 +1,85 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-pingpongpan/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaMathUtils.hpp" | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-pingpongpan/DistrhoArtworkPingPongPan.cpp" | |||||
#include "distrho-pingpongpan/DistrhoPluginPingPongPan.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-pingpongpan/DistrhoUIPingPongPan.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor pingpongpanDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ DistrhoPluginPingPongPan::paramCount, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "pingpongpan", | |||||
/* maker */ "falkTX, Michael Gruhn", | |||||
/* copyright */ "LGPL", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_pingpongpan(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_pingpongpan() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&pingpongpanDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,35 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_DISTRHOARTWORKPINGPONGPAN_HPP | |||||
#define BINARY_DISTRHOARTWORKPINGPONGPAN_HPP | |||||
namespace DistrhoArtworkPingPongPan | |||||
{ | |||||
extern const char* aboutData; | |||||
const unsigned int aboutDataSize = 172710; | |||||
const unsigned int aboutWidth = 303; | |||||
const unsigned int aboutHeight = 190; | |||||
extern const char* aboutButtonHoverData; | |||||
const unsigned int aboutButtonHoverDataSize = 7600; | |||||
const unsigned int aboutButtonHoverWidth = 95; | |||||
const unsigned int aboutButtonHoverHeight = 20; | |||||
extern const char* aboutButtonNormalData; | |||||
const unsigned int aboutButtonNormalDataSize = 7600; | |||||
const unsigned int aboutButtonNormalWidth = 95; | |||||
const unsigned int aboutButtonNormalHeight = 20; | |||||
extern const char* backgroundData; | |||||
const unsigned int backgroundDataSize = 157080; | |||||
const unsigned int backgroundWidth = 308; | |||||
const unsigned int backgroundHeight = 170; | |||||
extern const char* knobData; | |||||
const unsigned int knobDataSize = 17956; | |||||
const unsigned int knobWidth = 67; | |||||
const unsigned int knobHeight = 67; | |||||
} | |||||
#endif // BINARY_DISTRHOARTWORKPINGPONGPAN_HPP | |||||
@@ -0,0 +1,33 @@ | |||||
/* | |||||
* DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "Ping Pong Pan" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/PingPongPan" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||||
#define DISTRHO_PLUGIN_USES_MODGUI 1 | |||||
#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:SpatialPlugin" | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,161 @@ | |||||
/* | |||||
* DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||||
* Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPluginPingPongPan.hpp" | |||||
#include <cmath> | |||||
static const float k2PI = 6.283185307f; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoPluginPingPongPan::DistrhoPluginPingPongPan() | |||||
: Plugin(paramCount, 1, 0) // 1 program, 0 states | |||||
{ | |||||
// set default values | |||||
loadProgram(0); | |||||
// reset | |||||
deactivate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void DistrhoPluginPingPongPan::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramFreq: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Frequency"; | |||||
parameter.symbol = "freq"; | |||||
parameter.ranges.def = 50.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
case paramWidth: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Width"; | |||||
parameter.symbol = "width"; | |||||
parameter.unit = "%"; | |||||
parameter.ranges.def = 75.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoPluginPingPongPan::initProgramName(uint32_t index, String& programName) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
programName = "Default"; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float DistrhoPluginPingPongPan::getParameterValue(uint32_t index) const | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramFreq: | |||||
return fFreq; | |||||
case paramWidth: | |||||
return fWidth; | |||||
default: | |||||
return 0.0f; | |||||
} | |||||
} | |||||
void DistrhoPluginPingPongPan::setParameterValue(uint32_t index, float value) | |||||
{ | |||||
if (getSampleRate() <= 0.0) | |||||
return; | |||||
switch (index) | |||||
{ | |||||
case paramFreq: | |||||
fFreq = value; | |||||
waveSpeed = (k2PI * fFreq / 100.0f)/(float)getSampleRate(); | |||||
break; | |||||
case paramWidth: | |||||
fWidth = value; | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoPluginPingPongPan::loadProgram(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fFreq = 50.0f; | |||||
fWidth = 75.0f; | |||||
// reset filter values | |||||
activate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void DistrhoPluginPingPongPan::activate() | |||||
{ | |||||
waveSpeed = (k2PI * fFreq / 100.0f)/(float)getSampleRate(); | |||||
} | |||||
void DistrhoPluginPingPongPan::deactivate() | |||||
{ | |||||
wavePos = 0.0f; | |||||
} | |||||
void DistrhoPluginPingPongPan::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]; | |||||
for (uint32_t i=0; i < frames; ++i) | |||||
{ | |||||
pan = std::fmin(std::fmax(std::sin(wavePos) * (fWidth/100.0f), -1.0f), 1.0f); | |||||
if ((wavePos += waveSpeed) >= k2PI) | |||||
wavePos -= k2PI; | |||||
out1[i] = in1[i] * (pan > 0.0f ? 1.0f-pan : 1.0f); | |||||
out2[i] = in2[i] * (pan < 0.0f ? 1.0f+pan : 1.0f); | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new DistrhoPluginPingPongPan(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,114 @@ | |||||
/* | |||||
* DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||||
* Copyright (C) 2007 Michael Gruhn <michael-gruhn@web.de> | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_PINGPONGPAN_HPP_INCLUDED | |||||
#define DISTRHO_PLUGIN_PINGPONGPAN_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoPluginPingPongPan : public Plugin | |||||
{ | |||||
public: | |||||
enum Parameters | |||||
{ | |||||
paramFreq = 0, | |||||
paramWidth, | |||||
paramCount | |||||
}; | |||||
DistrhoPluginPingPongPan(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "PingPongPan"; | |||||
} | |||||
const char* getDescription() const override | |||||
{ | |||||
return "Ping Pong Panning."; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "DISTRHO"; | |||||
} | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/Mini-Series"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "LGPL"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', 'P', 'P', 'P'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
void initProgramName(uint32_t index, String& programName) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
void loadProgram(uint32_t index) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void deactivate() override; | |||||
void run(const float** inputs, float** outputs, uint32_t frames) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
float fFreq; | |||||
float fWidth; | |||||
float waveSpeed; | |||||
float pan, wavePos; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoPluginPingPongPan) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_PLUGIN_PINGPONGPAN_HPP_INCLUDED |
@@ -0,0 +1,133 @@ | |||||
/* | |||||
* DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPluginPingPongPan.hpp" | |||||
#include "DistrhoUIPingPongPan.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
namespace Art = DistrhoArtworkPingPongPan; | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoUIPingPongPan::DistrhoUIPingPongPan() | |||||
: UI(Art::backgroundWidth, Art::backgroundHeight), | |||||
fImgBackground(Art::backgroundData, Art::backgroundWidth, Art::backgroundHeight, GL_BGR), | |||||
fAboutWindow(this) | |||||
{ | |||||
// about | |||||
Image imageAbout(Art::aboutData, Art::aboutWidth, Art::aboutHeight, GL_BGR); | |||||
fAboutWindow.setImage(imageAbout); | |||||
// knobs | |||||
Image knobImage(Art::knobData, Art::knobWidth, Art::knobHeight); | |||||
// knob Low-Mid | |||||
fKnobFreq = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobFreq->setId(DistrhoPluginPingPongPan::paramFreq); | |||||
fKnobFreq->setAbsolutePos(60, 58); | |||||
fKnobFreq->setRange(0.0f, 100.0f); | |||||
fKnobFreq->setDefault(50.0f); | |||||
fKnobFreq->setRotationAngle(270); | |||||
fKnobFreq->setCallback(this); | |||||
// knob Mid-High | |||||
fKnobWidth = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobWidth->setId(DistrhoPluginPingPongPan::paramWidth); | |||||
fKnobWidth->setAbsolutePos(182, 58); | |||||
fKnobWidth->setRange(0.0f, 100.0f); | |||||
fKnobWidth->setDefault(75.0f); | |||||
fKnobWidth->setRotationAngle(270); | |||||
fKnobWidth->setCallback(this); | |||||
// about button | |||||
Image aboutImageNormal(Art::aboutButtonNormalData, Art::aboutButtonNormalWidth, Art::aboutButtonNormalHeight); | |||||
Image aboutImageHover(Art::aboutButtonHoverData, Art::aboutButtonHoverWidth, Art::aboutButtonHoverHeight); | |||||
fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||||
fButtonAbout->setAbsolutePos(183, 8); | |||||
fButtonAbout->setCallback(this); | |||||
// set default values | |||||
programLoaded(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void DistrhoUIPingPongPan::parameterChanged(uint32_t index, float value) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case DistrhoPluginPingPongPan::paramFreq: | |||||
fKnobFreq->setValue(value); | |||||
break; | |||||
case DistrhoPluginPingPongPan::paramWidth: | |||||
fKnobWidth->setValue(value); | |||||
break; | |||||
} | |||||
} | |||||
void DistrhoUIPingPongPan::programLoaded(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fKnobFreq->setValue(50.0f); | |||||
fKnobWidth->setValue(75.0f); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void DistrhoUIPingPongPan::imageButtonClicked(ImageButton* button, int) | |||||
{ | |||||
if (button != fButtonAbout) | |||||
return; | |||||
fAboutWindow.exec(); | |||||
} | |||||
void DistrhoUIPingPongPan::imageKnobDragStarted(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), true); | |||||
} | |||||
void DistrhoUIPingPongPan::imageKnobDragFinished(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), false); | |||||
} | |||||
void DistrhoUIPingPongPan::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
{ | |||||
setParameterValue(knob->getId(), value); | |||||
} | |||||
void DistrhoUIPingPongPan::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new DistrhoUIPingPongPan(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,67 @@ | |||||
/* | |||||
* DISTRHO PingPongPan Plugin, based on PingPongPan by Michael Gruhn | |||||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_UI_PINGPONGPAN_HPP_INCLUDED | |||||
#define DISTRHO_UI_PINGPONGPAN_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
#include "ImageWidgets.hpp" | |||||
#include "DistrhoArtworkPingPongPan.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoUIPingPongPan : public UI, | |||||
public ImageButton::Callback, | |||||
public ImageKnob::Callback | |||||
{ | |||||
public: | |||||
DistrhoUIPingPongPan(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
void programLoaded(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; | |||||
ScopedPointer<ImageButton> fButtonAbout; | |||||
ScopedPointer<ImageKnob> fKnobFreq, fKnobWidth; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUIPingPongPan) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_PINGPONGPAN_HPP_INCLUDED |
@@ -0,0 +1,67 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-prom/DistrhoPluginProM.cpp" | |||||
#include "distrho-prom/DistrhoUIProM.cpp" | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#include "DistrhoUIMain.cpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor promDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID), | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 0, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "prom", | |||||
/* maker */ "falkTX", | |||||
/* copyright */ "LGPL", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_prom(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_prom() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&promDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,33 @@ | |||||
/* | |||||
* DISTRHO ProM Plugin | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "ProM" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/ProM" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 1 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 1 | |||||
// required by projectM | |||||
#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 | |||||
#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,84 @@ | |||||
/* | |||||
* DISTRHO ProM Plugin | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPluginProM.hpp" | |||||
#include "libprojectM/projectM.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoPluginProM::DistrhoPluginProM() | |||||
: Plugin(0, 0, 0), | |||||
fPM(nullptr) | |||||
{ | |||||
} | |||||
DistrhoPluginProM::~DistrhoPluginProM() | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(fPM == nullptr); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void DistrhoPluginProM::initParameter(uint32_t, Parameter&) | |||||
{ | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float DistrhoPluginProM::getParameterValue(uint32_t) const | |||||
{ | |||||
return 0.0f; | |||||
} | |||||
void DistrhoPluginProM::setParameterValue(uint32_t, float) | |||||
{ | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void DistrhoPluginProM::run(const float** inputs, float** outputs, uint32_t frames) | |||||
{ | |||||
const float* in = inputs[0]; | |||||
float* out = outputs[0]; | |||||
if (out != in) | |||||
std::memcpy(out, in, sizeof(float)*frames); | |||||
const MutexLocker csm(fMutex); | |||||
if (fPM == nullptr) | |||||
return; | |||||
if (PCM* const pcm = const_cast<PCM*>(fPM->pcm())) | |||||
pcm->addPCMfloat(in, frames); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new DistrhoPluginProM(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,106 @@ | |||||
/* | |||||
* DISTRHO ProM Plugin | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_PROM_HPP_INCLUDED | |||||
#define DISTRHO_PLUGIN_PROM_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
#include "extra/Mutex.hpp" | |||||
class projectM; | |||||
class DistrhoUIProM; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoPluginProM : public Plugin | |||||
{ | |||||
public: | |||||
DistrhoPluginProM(); | |||||
~DistrhoPluginProM() override; | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "ProM"; | |||||
} | |||||
const char* getDescription() const override | |||||
{ | |||||
return "ProjectM visualizer."; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "DISTRHO"; | |||||
} | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/ProM"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "LGPL"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', 'P', 'r', 'M'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t, Parameter&) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t) const override; | |||||
void setParameterValue(uint32_t, float) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void run(const float** inputs, float** outputs, uint32_t frames) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
Mutex fMutex; | |||||
projectM* fPM; | |||||
friend class DistrhoUIProM; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoPluginProM) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_PLUGIN_PROM_HPP_INCLUDED |
@@ -0,0 +1,304 @@ | |||||
/* | |||||
* DISTRHO ProM Plugin | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#include "DistrhoPluginProM.hpp" | |||||
#include "DistrhoUIProM.hpp" | |||||
#include "libprojectM/projectM.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
#if 0 | |||||
static const projectM::Settings kSettings = { | |||||
/* meshX */ 32, | |||||
/* meshY */ 24, | |||||
/* fps */ 35, | |||||
/* textureSize */ 1024, | |||||
/* windowWidth */ 512, | |||||
/* windowHeight */ 512, | |||||
/* presetURL */ "/usr/share/projectM/presets", | |||||
/* titleFontURL */ "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", | |||||
/* menuFontURL */ "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", | |||||
/* smoothPresetDuration */ 5, | |||||
/* presetDuration */ 30, | |||||
/* beatSensitivity */ 10.0f, | |||||
/* aspectCorrection */ true, | |||||
/* easterEgg */ 1.0f, | |||||
/* shuffleEnabled */ true, | |||||
/* softCutRatingsEnabled */ false | |||||
}; | |||||
#endif | |||||
// ----------------------------------------------------------------------- | |||||
DistrhoUIProM::DistrhoUIProM() | |||||
: UI(512, 512) | |||||
{ | |||||
} | |||||
DistrhoUIProM::~DistrhoUIProM() | |||||
{ | |||||
if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer()) | |||||
{ | |||||
const MutexLocker csm(dspPtr->fMutex); | |||||
dspPtr->fPM = nullptr; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void DistrhoUIProM::parameterChanged(uint32_t, float) | |||||
{ | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// UI Callbacks | |||||
void DistrhoUIProM::uiIdle() | |||||
{ | |||||
if (fPM == nullptr) | |||||
return; | |||||
repaint(); | |||||
if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer()) | |||||
{ | |||||
if (dspPtr->fPM != nullptr) | |||||
return; | |||||
const MutexLocker csm(dspPtr->fMutex); | |||||
dspPtr->fPM = fPM; | |||||
} | |||||
} | |||||
void DistrhoUIProM::uiReshape(uint width, uint height) | |||||
{ | |||||
glEnable(GL_BLEND); | |||||
glEnable(GL_LINE_SMOOTH); | |||||
glEnable(GL_POINT_SMOOTH); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glShadeModel(GL_SMOOTH); | |||||
glMatrixMode(GL_TEXTURE); | |||||
glLoadIdentity(); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0, width, height, 0, 0.0f, 1.0f); | |||||
glViewport(0, 0, width, height); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
glDrawBuffer(GL_BACK); | |||||
glReadBuffer(GL_BACK); | |||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |||||
glLineStipple(2, 0xAAAA); | |||||
if (fPM == nullptr) | |||||
//fPM = new projectM(kSettings); | |||||
fPM = new projectM("/usr/share/projectM/config.inp"); | |||||
fPM->projectM_resetGL(width, height); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void DistrhoUIProM::onDisplay() | |||||
{ | |||||
if (fPM == nullptr) | |||||
return; | |||||
fPM->renderFrame(); | |||||
} | |||||
bool DistrhoUIProM::onKeyboard(const KeyboardEvent& ev) | |||||
{ | |||||
if (fPM == nullptr) | |||||
return false; | |||||
if (ev.press && (ev.key == '1' || ev.key == '+' || ev.key == '-')) | |||||
{ | |||||
if (ev.key == '1') | |||||
{ | |||||
if (getWidth() != 512 || getHeight() != 512) | |||||
setSize(512, 512); | |||||
} | |||||
else if (ev.key == '+') | |||||
{ | |||||
/**/ if (getWidth() < 1100 && getHeight() < 1100) | |||||
setSize(getWidth()+100, getHeight()+100); | |||||
else if (getWidth() != 1100 || getHeight() != 1100) | |||||
setSize(1100, 1100); | |||||
} | |||||
else if (ev.key == '-') | |||||
{ | |||||
/**/ if (getWidth() >= 200 && getHeight() >= 200) | |||||
setSize(getWidth()-100, getHeight()-100); | |||||
else if (getWidth() != 100 || getHeight() != 100) | |||||
setSize(100, 100); | |||||
} | |||||
return true; | |||||
} | |||||
projectMKeycode pmKey = PROJECTM_K_NONE; | |||||
projectMModifier pmMod = PROJECTM_KMOD_LSHIFT; | |||||
if ((ev.key >= PROJECTM_K_0 && ev.key <= PROJECTM_K_9) || | |||||
(ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z) || | |||||
(ev.key >= PROJECTM_K_a && ev.key <= PROJECTM_K_z)) | |||||
{ | |||||
pmKey = static_cast<projectMKeycode>(ev.key); | |||||
} | |||||
else | |||||
{ | |||||
switch (ev.key) | |||||
{ | |||||
case DGL_NAMESPACE::kCharBackspace: | |||||
pmKey = PROJECTM_K_BACKSPACE; | |||||
break; | |||||
case DGL_NAMESPACE::kCharEscape: | |||||
pmKey = PROJECTM_K_ESCAPE; | |||||
break; | |||||
case DGL_NAMESPACE::kCharDelete: | |||||
pmKey = PROJECTM_K_DELETE; | |||||
break; | |||||
} | |||||
} | |||||
if (pmKey == PROJECTM_K_NONE) | |||||
return false; | |||||
if (ev.mod & DGL_NAMESPACE::kModifierControl) | |||||
pmMod = PROJECTM_KMOD_LCTRL; | |||||
fPM->key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey, pmMod); | |||||
return true; | |||||
} | |||||
bool DistrhoUIProM::onSpecial(const SpecialEvent& ev) | |||||
{ | |||||
if (fPM == nullptr) | |||||
return false; | |||||
projectMKeycode pmKey = PROJECTM_K_NONE; | |||||
projectMModifier pmMod = PROJECTM_KMOD_LSHIFT; | |||||
switch (ev.key) | |||||
{ | |||||
case DGL_NAMESPACE::kKeyF1: | |||||
pmKey = PROJECTM_K_F1; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF2: | |||||
pmKey = PROJECTM_K_F2; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF3: | |||||
pmKey = PROJECTM_K_F3; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF4: | |||||
pmKey = PROJECTM_K_F4; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF5: | |||||
pmKey = PROJECTM_K_F5; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF6: | |||||
pmKey = PROJECTM_K_F6; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF7: | |||||
pmKey = PROJECTM_K_F7; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF8: | |||||
pmKey = PROJECTM_K_F8; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF9: | |||||
pmKey = PROJECTM_K_F9; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF10: | |||||
pmKey = PROJECTM_K_F10; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF11: | |||||
pmKey = PROJECTM_K_F11; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyF12: | |||||
pmKey = PROJECTM_K_F12; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyLeft: | |||||
pmKey = PROJECTM_K_LEFT; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyUp: | |||||
pmKey = PROJECTM_K_UP; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyRight: | |||||
pmKey = PROJECTM_K_RIGHT; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyDown: | |||||
pmKey = PROJECTM_K_DOWN; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyPageUp: | |||||
pmKey = PROJECTM_K_PAGEUP; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyPageDown: | |||||
pmKey = PROJECTM_K_PAGEDOWN; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyHome: | |||||
pmKey = PROJECTM_K_HOME; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyEnd: | |||||
pmKey = PROJECTM_K_END; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyInsert: | |||||
pmKey = PROJECTM_K_INSERT; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyShift: | |||||
pmKey = PROJECTM_K_LSHIFT; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyControl: | |||||
pmKey = PROJECTM_K_LCTRL; | |||||
break; | |||||
case DGL_NAMESPACE::kKeyAlt: | |||||
case DGL_NAMESPACE::kKeySuper: | |||||
break; | |||||
} | |||||
if (pmKey == PROJECTM_K_NONE) | |||||
return false; | |||||
if (ev.mod & DGL_NAMESPACE::kModifierControl) | |||||
pmMod = PROJECTM_KMOD_LCTRL; | |||||
fPM->key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey, pmMod); | |||||
return true; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new DistrhoUIProM(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,63 @@ | |||||
/* | |||||
* DISTRHO ProM Plugin | |||||
* Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* 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 Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef DISTRHO_UI_PROM_HPP_INCLUDED | |||||
#define DISTRHO_UI_PROM_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
class projectM; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class DistrhoUIProM : public UI | |||||
{ | |||||
public: | |||||
DistrhoUIProM(); | |||||
~DistrhoUIProM() override; | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t, float) override; | |||||
// ------------------------------------------------------------------- | |||||
// UI Callbacks | |||||
void uiIdle() override; | |||||
void uiReshape(uint width, uint height) override; | |||||
// ------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void onDisplay() override; | |||||
bool onKeyboard(const KeyboardEvent&) override; | |||||
bool onSpecial(const SpecialEvent&) override; | |||||
private: | |||||
ScopedPointer<projectM> fPM; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUIProM) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_PROM_HPP_INCLUDED |
@@ -0,0 +1,87 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-vectorjuice/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaMathUtils.hpp" | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-vectorjuice/VectorJuicePlugin.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-vectorjuice/VectorJuiceArtwork.cpp" | |||||
#include "distrho-vectorjuice/VectorJuiceUI.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor vectorjuiceDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ 13, | |||||
/* paramOuts */ 4, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "vectorjuice", | |||||
/* maker */ "Andre Sklenar", | |||||
/* copyright */ "GPL v2+", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_vectorjuice(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_vectorjuice() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&vectorjuiceDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,36 @@ | |||||
/* | |||||
* Vector 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 "VectorJuice" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_SYNTH 0 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 8 | |||||
#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:VectorJuice" | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,55 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_VECTORJUICEARTWORK_HPP | |||||
#define BINARY_VECTORJUICEARTWORK_HPP | |||||
namespace VectorJuiceArtwork | |||||
{ | |||||
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 = 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* orbitData; | |||||
const unsigned int orbitDataSize = 4096; | |||||
const unsigned int orbitWidth = 32; | |||||
const unsigned int orbitHeight = 32; | |||||
extern const char* roundletData; | |||||
const unsigned int roundletDataSize = 2500; | |||||
const unsigned int roundletWidth = 25; | |||||
const unsigned int roundletHeight = 25; | |||||
extern const char* sliderData; | |||||
const unsigned int sliderDataSize = 2600; | |||||
const unsigned int sliderWidth = 26; | |||||
const unsigned int sliderHeight = 25; | |||||
extern const char* subOrbitData; | |||||
const unsigned int subOrbitDataSize = 3364; | |||||
const unsigned int subOrbitWidth = 29; | |||||
const unsigned int subOrbitHeight = 29; | |||||
} | |||||
#endif // BINARY_VECTORJUICEARTWORK_HPP | |||||
@@ -0,0 +1,391 @@ | |||||
/* | |||||
* Vector 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 "VectorJuicePlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
VectorJuicePlugin::VectorJuicePlugin() | |||||
: Plugin(paramCount, 1, 0) // 1 program, 0 states | |||||
{ | |||||
// set default values | |||||
loadProgram(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void VectorJuicePlugin::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramX: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "X"; | |||||
parameter.symbol = "x"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramY: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Y"; | |||||
parameter.symbol = "y"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramOrbitSizeX: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Orbit Size X"; | |||||
parameter.symbol = "sizex"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramOrbitSizeY: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Orbit Size Y"; | |||||
parameter.symbol = "sizey"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramOrbitSpeedX: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Orbit Speed X"; | |||||
parameter.symbol = "speedx"; | |||||
parameter.ranges.def = 4.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 128.0f; | |||||
break; | |||||
case paramOrbitSpeedY: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Orbit Speed Y"; | |||||
parameter.symbol = "speedy"; | |||||
parameter.ranges.def = 4.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 128.0f; | |||||
break; | |||||
case paramSubOrbitSize: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "SubOrbit Size"; | |||||
parameter.symbol = "subsize"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramSubOrbitSpeed: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "SubOrbit Speed"; | |||||
parameter.symbol = "subspeed"; | |||||
parameter.ranges.def = 32.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 128.0f; | |||||
break; | |||||
case paramSubOrbitSmooth: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "SubOrbit Wave"; | |||||
parameter.symbol = "subwave"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramOrbitWaveX: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Orbit Wave X"; | |||||
parameter.symbol = "wavex"; | |||||
parameter.ranges.def = 3.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 4.0f; | |||||
break; | |||||
case paramOrbitWaveY: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Orbit Wave Y"; | |||||
parameter.symbol = "wavey"; | |||||
parameter.ranges.def = 3.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 4.0f; | |||||
break; | |||||
case paramOrbitPhaseX: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Orbit Phase X"; | |||||
parameter.symbol = "phasex"; | |||||
parameter.ranges.def = 1.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 4.0f; | |||||
break; | |||||
case paramOrbitPhaseY: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Orbit Phase Y"; | |||||
parameter.symbol = "phasey"; | |||||
parameter.ranges.def = 1.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 4.0f; | |||||
break; | |||||
case paramOrbitOutX: | |||||
parameter.hints = kParameterIsOutput; | |||||
parameter.name = "Orbit X"; | |||||
parameter.symbol = "orx"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramOrbitOutY: | |||||
parameter.hints = kParameterIsOutput; | |||||
parameter.name = "Orbit Y"; | |||||
parameter.symbol = "ory"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramSubOrbitOutX: | |||||
parameter.hints = kParameterIsOutput; | |||||
parameter.name = "SubOrbit X"; | |||||
parameter.symbol = "sorx"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
case paramSubOrbitOutY: | |||||
parameter.hints = kParameterIsOutput; | |||||
parameter.name = "SubOrbit Y"; | |||||
parameter.symbol = "sory"; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
} | |||||
} | |||||
void VectorJuicePlugin::initProgramName(uint32_t index, String& programName) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
programName = "Default"; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float VectorJuicePlugin::getParameterValue(uint32_t index) const | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramX: | |||||
return x; | |||||
case paramY: | |||||
return y; | |||||
case paramOrbitSizeX: | |||||
return orbitSizeX; | |||||
case paramOrbitSizeY: | |||||
return orbitSizeY; | |||||
case paramOrbitSpeedX: | |||||
return orbitSpeedX; | |||||
case paramOrbitSpeedY: | |||||
return orbitSpeedY; | |||||
case paramSubOrbitSize: | |||||
return subOrbitSize; | |||||
case paramSubOrbitSpeed: | |||||
return subOrbitSpeed; | |||||
case paramSubOrbitSmooth: | |||||
return subOrbitSmooth; | |||||
case paramOrbitWaveX: | |||||
return orbitWaveX; | |||||
case paramOrbitWaveY: | |||||
return orbitWaveY; | |||||
case paramOrbitPhaseX: | |||||
return orbitPhaseY; | |||||
case paramOrbitPhaseY: | |||||
return orbitPhaseY; | |||||
case paramOrbitOutX: | |||||
return orbitX; | |||||
case paramOrbitOutY: | |||||
return orbitY; | |||||
case paramSubOrbitOutX: | |||||
return subOrbitX; | |||||
case paramSubOrbitOutY: | |||||
return subOrbitY; | |||||
default: | |||||
return 0.0f; | |||||
} | |||||
} | |||||
void VectorJuicePlugin::setParameterValue(uint32_t index, float value) | |||||
{ | |||||
bool resetPhase = false; | |||||
switch (index) | |||||
{ | |||||
case paramX: | |||||
x = value; | |||||
break; | |||||
case paramY: | |||||
y = value; | |||||
break; | |||||
case paramOrbitSizeX: | |||||
orbitSizeX = value; | |||||
break; | |||||
case paramOrbitSizeY: | |||||
orbitSizeY = value; | |||||
break; | |||||
case paramOrbitSpeedX: | |||||
orbitSpeedX = value; | |||||
resetPhase = true; | |||||
break; | |||||
case paramOrbitSpeedY: | |||||
orbitSpeedY = value; | |||||
resetPhase = true; | |||||
break; | |||||
case paramSubOrbitSize: | |||||
subOrbitSize = value; | |||||
break; | |||||
case paramSubOrbitSpeed: | |||||
subOrbitSpeed = value; | |||||
resetPhase = true; | |||||
break; | |||||
case paramSubOrbitSmooth: | |||||
subOrbitSmooth = value; | |||||
break; | |||||
case paramOrbitWaveX: | |||||
orbitWaveX = value; | |||||
break; | |||||
case paramOrbitWaveY: | |||||
orbitWaveY = value; | |||||
break; | |||||
case paramOrbitPhaseX: | |||||
orbitPhaseX = value; | |||||
resetPhase = true; | |||||
break; | |||||
case paramOrbitPhaseY: | |||||
orbitPhaseY = value; | |||||
resetPhase = true; | |||||
break; | |||||
} | |||||
if (resetPhase) | |||||
{ | |||||
sinePosX = 0; | |||||
sinePosY = 0; | |||||
sinePos = 0; | |||||
} | |||||
} | |||||
void VectorJuicePlugin::loadProgram(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
/* Default parameter values */ | |||||
x = 0.5f; | |||||
y = 0.5f; | |||||
orbitSizeX = 0.5f; | |||||
orbitSizeY = 0.5f; | |||||
orbitSpeedX = 4.0f; | |||||
orbitSpeedY = 4.0f; | |||||
subOrbitSize = 0.5f; | |||||
subOrbitSpeed = 32.0f; | |||||
subOrbitSmooth = 0.5f; | |||||
orbitWaveX = 3.0f; | |||||
orbitWaveY = 3.0f; | |||||
orbitPhaseX = 1.0f; | |||||
orbitPhaseY = 1.0f; | |||||
/* reset filter values */ | |||||
activate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void VectorJuicePlugin::activate() | |||||
{ | |||||
/* Default variable values */ | |||||
orbitX=orbitY=orbitTX=orbitTY=0.5; | |||||
subOrbitX=subOrbitY=subOrbitTX=subOrbitTY=0; | |||||
interpolationDivider=200; | |||||
bar=tickX=tickY=percentageX=percentageY=tickOffsetX=0; | |||||
tickOffsetY=sinePosX=sinePosY=tick=percentage=tickOffset=sinePos=0; | |||||
waveBlend=0; | |||||
//parameter smoothing | |||||
for (int i=0; i<2; i++) { | |||||
sA[i] = 0.99f; | |||||
sB[i] = 1.f - sA[i]; | |||||
sZ[i] = 0; | |||||
} | |||||
} | |||||
void VectorJuicePlugin::run(const float** inputs, float** outputs, uint32_t frames) | |||||
{ | |||||
float out1, out2, tX, tY; | |||||
for (uint32_t i=0; i<frames; i++) { | |||||
//1.41421 -> 1 | |||||
//<0 = 0 | |||||
animate(); | |||||
tX = subOrbitX; | |||||
tY = subOrbitY; | |||||
out1 = inputs[0][i]*tN(1-std::sqrt((tX*tX)+(tY*tY))); | |||||
out2 = inputs[1][i]*tN(1-std::sqrt((tX*tX)+(tY*tY))); | |||||
out1 += inputs[2][i]*tN(1-std::sqrt(((1-tX)*(1-tX))+(tY*tY))); | |||||
out2 += inputs[3][i]*tN(1-std::sqrt(((1-tX)*(1-tX))+(tY*tY))); | |||||
out1 += inputs[4][i]*tN(1-std::sqrt(((1-tX)*(1-tX))+((1-tY)*(1-tY)))); | |||||
out2 += inputs[5][i]*tN(1-std::sqrt(((1-tX)*(1-tX))+((1-tY)*(1-tY)))); | |||||
out1 += inputs[6][i]*tN(1-std::sqrt((tX*tX)+((1-tY)*(1-tY)))); | |||||
out2 += inputs[7][i]*tN(1-std::sqrt((tX*tX)+((1-tY)*(1-tY)))); | |||||
outputs[0][i] = out1; | |||||
outputs[1][i] = out2; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new VectorJuicePlugin(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,236 @@ | |||||
/* | |||||
* Vector 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 VECTORJUICEPLUGIN_HPP_INCLUDED | |||||
#define VECTORJUICEPLUGIN_HPP_INCLUDED | |||||
#include "DistrhoPlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class VectorJuicePlugin : public Plugin | |||||
{ | |||||
public: | |||||
enum Parameters | |||||
{ | |||||
paramX = 0, | |||||
paramY, | |||||
paramOrbitSizeX, | |||||
paramOrbitSizeY, | |||||
paramOrbitSpeedX, | |||||
paramOrbitSpeedY, | |||||
paramSubOrbitSize, | |||||
paramSubOrbitSpeed, | |||||
paramSubOrbitSmooth, | |||||
paramOrbitWaveX, | |||||
paramOrbitWaveY, | |||||
paramOrbitPhaseX, | |||||
paramOrbitPhaseY, | |||||
paramOrbitOutX, | |||||
paramOrbitOutY, | |||||
paramSubOrbitOutX, | |||||
paramSubOrbitOutY, | |||||
paramCount | |||||
}; | |||||
float smoothParameter(float in, int axis) { | |||||
sZ[axis] = (in * sB[axis]) + (sZ[axis] * sA[axis]); | |||||
return sZ[axis]; | |||||
} | |||||
float getSinePhase(float x) { | |||||
return (-std::sin(x)); | |||||
} | |||||
float getSawPhase(float x) { | |||||
return (-(2/M_PI *std::atan(1/std::tan(x/2)))); | |||||
} | |||||
float getRevSawPhase(float x) { | |||||
return ((2/M_PI *std::atan(1/std::tan(x/2)))); | |||||
} | |||||
float getSquarePhase(float x) { | |||||
return (std::round((std::sin(x)+1)/2)-0.5)*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; | |||||
} | |||||
} | |||||
float tN(float x) | |||||
{ | |||||
if (x>0) return x; | |||||
else return 0; | |||||
} | |||||
void animate() | |||||
{ | |||||
//sync orbit with frame, bpm | |||||
const TimePosition& time(getTimePosition()); | |||||
bar = ((120.0/(time.bbt.valid ? time.bbt.beatsPerMinute : 120.0))*(getSampleRate())); | |||||
int multiplier = 16;//2000*4; | |||||
tickX = bar/(std::round(orbitSpeedX))*multiplier; | |||||
tickY = bar/(std::round(orbitSpeedY))*multiplier; | |||||
tick = bar/(std::round(subOrbitSpeed))*multiplier; | |||||
if (time.playing) | |||||
{ | |||||
/* if rolling then sync to timepos */ | |||||
tickOffsetX = time.frame-std::floor(time.frame/tickX)*tickX; | |||||
tickOffsetY = time.frame-std::floor(time.frame/tickY)*tickY; | |||||
tickOffset = time.frame-std::floor(time.frame/tick)*tick; | |||||
percentageX = tickOffsetX/tickX; | |||||
percentageY = tickOffsetY/tickY; | |||||
percentage = tickOffset/tick; | |||||
sinePosX = (M_PI*2)*percentageX; | |||||
sinePosY = (M_PI*2)*percentageY; | |||||
sinePos = (M_PI*2)*percentage; | |||||
} else { | |||||
/* else just keep on wobblin' */ | |||||
sinePosX += (2*M_PI)/(tickX); | |||||
sinePosY += (2*M_PI)/(tickY); | |||||
sinePos += (M_PI)/(tick); | |||||
if (sinePosX>2*M_PI) { | |||||
sinePosX = 0; | |||||
} | |||||
if (sinePosY>2*M_PI) { | |||||
sinePosY = 0; | |||||
} | |||||
if (sinePos>2*M_PI) { | |||||
sinePos = 0; | |||||
} | |||||
} | |||||
//0..1 | |||||
//0..3 | |||||
//0, 1, 2, 3 | |||||
//* 0.25 | |||||
//0, 0.25, 0.5, 0.75 | |||||
float tempPhaseX = std::round(orbitPhaseX)*0.25-0.25; | |||||
float tempPhaseY = std::round(orbitPhaseY)*0.25-0.25; | |||||
orbitX = x+getBlendedPhase(sinePosX + tempPhaseX*(2*M_PI), std::round(orbitWaveX))*(orbitSizeX/2); | |||||
orbitY = y+getBlendedPhase(sinePosY+M_PI/2 + tempPhaseY*(2*M_PI), std::round(orbitWaveY))*(orbitSizeY/2); | |||||
subOrbitX = smoothParameter(orbitX+getBlendedPhase(sinePos, 3)*(subOrbitSize/3), 0); | |||||
subOrbitY = smoothParameter(orbitY+getBlendedPhase(sinePos+M_PI/2, 3)*(subOrbitSize/3), 1); | |||||
if (orbitX<0) orbitX=0; | |||||
if (orbitX>1) orbitX=1; | |||||
if (orbitY<0) orbitY=0; | |||||
if (orbitY>1) orbitY=1; | |||||
if (subOrbitX<0) subOrbitX=0; | |||||
if (subOrbitX>1) subOrbitX=1; | |||||
if (subOrbitY<0) subOrbitY=0; | |||||
if (subOrbitY>1) subOrbitY=1; | |||||
} | |||||
VectorJuicePlugin(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "VectorJuice"; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "Andre Sklenar"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "GPL v2+"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return 0x1000; | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('V', 'e', 'c', 'J'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
void initProgramName(uint32_t index, String& programName) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
void loadProgram(uint32_t index) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void run(const float** inputs, float** outputs, uint32_t frames) override; | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
float x, y; | |||||
float orbitX, orbitY; | |||||
float orbitTX, orbitTY; //targetX and targetY for interpolation | |||||
float subOrbitX, subOrbitY; | |||||
float subOrbitTX, subOrbitTY; | |||||
float subOrbitSpeed, subOrbitSize, orbitSpeedX, orbitSpeedY; | |||||
float orbitSizeX, orbitSizeY; | |||||
float interpolationDivider; | |||||
float bar, tickX, tickY, percentageX, percentageY, tickOffsetX, tickOffsetY; | |||||
float sinePosX, sinePosY, tick, percentage, tickOffset, sinePos; | |||||
float orbitWaveX, orbitWaveY, subOrbitSmooth, waveBlend; | |||||
float orbitPhaseX, orbitPhaseY; | |||||
//parameter smoothing, for subOrbitX and subOrbitY | |||||
float sA[2], sB[2], sZ[2]; | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // VECTORJUICE_HPP_INCLUDED |
@@ -0,0 +1,461 @@ | |||||
/* | |||||
* Vector 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 "VectorJuicePlugin.hpp" | |||||
#include "VectorJuiceUI.hpp" | |||||
using DGL_NAMESPACE::Point; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
VectorJuiceUI::VectorJuiceUI() | |||||
: UI(), | |||||
fAboutWindow(this) | |||||
{ | |||||
setSize(VectorJuiceArtwork::backgroundWidth, VectorJuiceArtwork::backgroundHeight); | |||||
// xy params | |||||
paramX = paramY = 0.5f; | |||||
// orbit params | |||||
orbitX = orbitY = subOrbitX = subOrbitY = 0.5f; | |||||
// set the XY canvas area | |||||
fDragging = false; | |||||
fDragValid = false; | |||||
fLastX = fLastY = 0; | |||||
fCanvasArea.setPos(22+12, 49+12); | |||||
fCanvasArea.setSize(368-24, 368-24); | |||||
// background | |||||
fImgBackground = Image(VectorJuiceArtwork::backgroundData, VectorJuiceArtwork::backgroundWidth, VectorJuiceArtwork::backgroundHeight, GL_BGR); | |||||
//roundlet | |||||
fImgRoundlet = Image(VectorJuiceArtwork::roundletData, VectorJuiceArtwork::roundletWidth, VectorJuiceArtwork::roundletHeight); | |||||
//orbit | |||||
fImgOrbit = Image(VectorJuiceArtwork::orbitData, VectorJuiceArtwork::orbitWidth, VectorJuiceArtwork::orbitHeight); | |||||
//subOrbit | |||||
fImgSubOrbit = Image(VectorJuiceArtwork::subOrbitData, VectorJuiceArtwork::subOrbitWidth, VectorJuiceArtwork::subOrbitHeight); | |||||
// about | |||||
Image aboutImage(VectorJuiceArtwork::aboutData, VectorJuiceArtwork::aboutWidth, VectorJuiceArtwork::aboutHeight, GL_BGR); | |||||
fAboutWindow.setImage(aboutImage); | |||||
// about button | |||||
Image aboutImageNormal(VectorJuiceArtwork::aboutButtonNormalData, VectorJuiceArtwork::aboutButtonNormalWidth, VectorJuiceArtwork::aboutButtonNormalHeight); | |||||
Image aboutImageHover(VectorJuiceArtwork::aboutButtonHoverData, VectorJuiceArtwork::aboutButtonHoverWidth, VectorJuiceArtwork::aboutButtonHoverHeight); | |||||
fButtonAbout = new ImageButton(this, aboutImageNormal, aboutImageHover, aboutImageHover); | |||||
fButtonAbout->setAbsolutePos(599, 17); | |||||
fButtonAbout->setCallback(this); | |||||
// knobs | |||||
Image knobImage(VectorJuiceArtwork::knobData, VectorJuiceArtwork::knobWidth, VectorJuiceArtwork::knobHeight); | |||||
// knob KnobOrbitSizeX | |||||
fKnobOrbitSizeX = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobOrbitSizeX->setId(VectorJuicePlugin::paramOrbitSizeX); | |||||
fKnobOrbitSizeX->setAbsolutePos(423, 73); | |||||
fKnobOrbitSizeX->setRotationAngle(270); | |||||
fKnobOrbitSizeX->setRange(0.0f, 1.0f); | |||||
fKnobOrbitSizeX->setDefault(0.5f); | |||||
fKnobOrbitSizeX->setCallback(this); | |||||
// knob KnobOrbitSizeY | |||||
fKnobOrbitSizeY = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobOrbitSizeY->setId(VectorJuicePlugin::paramOrbitSizeY); | |||||
fKnobOrbitSizeY->setAbsolutePos(516, 73); | |||||
fKnobOrbitSizeY->setRotationAngle(270); | |||||
fKnobOrbitSizeY->setRange(0.0f, 1.0f); | |||||
fKnobOrbitSizeY->setDefault(0.5f); | |||||
fKnobOrbitSizeY->setCallback(this); | |||||
// knob KnobOrbitSpeedX | |||||
fKnobOrbitSpeedX = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobOrbitSpeedX->setId(VectorJuicePlugin::paramOrbitSpeedX); | |||||
fKnobOrbitSpeedX->setAbsolutePos(423, 185); | |||||
fKnobOrbitSpeedX->setRotationAngle(270); | |||||
fKnobOrbitSpeedX->setStep(1.0f); | |||||
fKnobOrbitSpeedX->setRange(1.0f, 128.0f); | |||||
fKnobOrbitSpeedX->setDefault(4.0f); | |||||
fKnobOrbitSpeedX->setCallback(this); | |||||
// knob KnobOrbitSpeedY | |||||
fKnobOrbitSpeedY = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobOrbitSpeedY->setId(VectorJuicePlugin::paramOrbitSpeedY); | |||||
fKnobOrbitSpeedY->setAbsolutePos(516, 185); | |||||
fKnobOrbitSpeedY->setRotationAngle(270); | |||||
fKnobOrbitSpeedY->setStep(1.0f); | |||||
fKnobOrbitSpeedY->setRange(1.0f, 128.0f); | |||||
fKnobOrbitSpeedY->setDefault(4.0f); | |||||
fKnobOrbitSpeedY->setCallback(this); | |||||
// knob KnobSubOrbitSize | |||||
fKnobSubOrbitSize = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobSubOrbitSize->setId(VectorJuicePlugin::paramSubOrbitSize); | |||||
fKnobSubOrbitSize->setAbsolutePos(620, 73); | |||||
fKnobSubOrbitSize->setRange(0.0f, 1.0f); | |||||
fKnobSubOrbitSize->setRotationAngle(270); | |||||
fKnobSubOrbitSize->setDefault(0.5f); | |||||
fKnobSubOrbitSize->setCallback(this); | |||||
// knob KnobSubOrbitSpeed | |||||
fKnobSubOrbitSpeed = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobSubOrbitSpeed->setId(VectorJuicePlugin::paramSubOrbitSpeed); | |||||
fKnobSubOrbitSpeed->setAbsolutePos(620, 185); | |||||
fKnobSubOrbitSpeed->setRotationAngle(270); | |||||
fKnobSubOrbitSpeed->setStep(1.0f); | |||||
fKnobSubOrbitSpeed->setRange(1.0f, 128.0f); | |||||
fKnobSubOrbitSpeed->setDefault(32.0f); | |||||
fKnobSubOrbitSpeed->setCallback(this); | |||||
// knob KnobSubOrbitSmooth | |||||
fKnobSubOrbitSmooth = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobSubOrbitSmooth->setId(VectorJuicePlugin::paramSubOrbitSmooth); | |||||
fKnobSubOrbitSmooth->setAbsolutePos(620, 297); | |||||
fKnobSubOrbitSmooth->setRotationAngle(270); | |||||
fKnobSubOrbitSmooth->setRange(0.0f, 1.0f); | |||||
fKnobSubOrbitSmooth->setDefault(0.5f); | |||||
fKnobSubOrbitSmooth->setCallback(this); | |||||
// sliders | |||||
Image sliderImage(VectorJuiceArtwork::sliderData, VectorJuiceArtwork::sliderWidth, VectorJuiceArtwork::sliderHeight); | |||||
Point<int> sliderPosStart(410, 284); | |||||
Point<int> sliderPosEnd(410+48, 284); | |||||
// slider OrbitWaveX | |||||
fSliderOrbitWaveX = new ImageSlider(this, sliderImage); | |||||
fSliderOrbitWaveX->setId(VectorJuicePlugin::paramOrbitWaveX); | |||||
fSliderOrbitWaveX->setStartPos(sliderPosStart); | |||||
fSliderOrbitWaveX->setEndPos(sliderPosEnd); | |||||
fSliderOrbitWaveX->setRange(1.0f, 4.0f); | |||||
fSliderOrbitWaveX->setStep(1.0f); | |||||
fSliderOrbitWaveX->setCallback(this); | |||||
// slider OrbitWaveY | |||||
sliderPosStart.setX(503); | |||||
sliderPosEnd.setX(503+48); | |||||
fSliderOrbitWaveY = new ImageSlider(this, sliderImage); | |||||
fSliderOrbitWaveY->setId(VectorJuicePlugin::paramOrbitWaveY); | |||||
fSliderOrbitWaveY->setStartPos(sliderPosStart); | |||||
fSliderOrbitWaveY->setEndPos(sliderPosEnd); | |||||
fSliderOrbitWaveY->setRange(1.0f, 4.0f); | |||||
fSliderOrbitWaveY->setStep(1.0f); | |||||
fSliderOrbitWaveY->setCallback(this); | |||||
// slider OrbitPhaseX | |||||
sliderPosStart.setX(410); | |||||
sliderPosStart.setY(345); | |||||
sliderPosEnd.setX(410+48); | |||||
sliderPosEnd.setY(345); | |||||
fSliderOrbitPhaseX = new ImageSlider(this, sliderImage); | |||||
fSliderOrbitPhaseX->setId(VectorJuicePlugin::paramOrbitPhaseX); | |||||
fSliderOrbitPhaseX->setStartPos(sliderPosStart); | |||||
fSliderOrbitPhaseX->setEndPos(sliderPosEnd); | |||||
fSliderOrbitPhaseX->setRange(1.0f, 4.0f); | |||||
fSliderOrbitPhaseX->setStep(1.0f); | |||||
fSliderOrbitPhaseX->setCallback(this); | |||||
// slider OrbitPhaseY | |||||
sliderPosStart.setX(503); | |||||
sliderPosEnd.setX(503+48); | |||||
fSliderOrbitPhaseY = new ImageSlider(this, sliderImage); | |||||
fSliderOrbitPhaseY->setId(VectorJuicePlugin::paramOrbitPhaseY); | |||||
fSliderOrbitPhaseY->setStartPos(sliderPosStart); | |||||
fSliderOrbitPhaseY->setEndPos(sliderPosEnd); | |||||
fSliderOrbitPhaseY->setRange(1.0f, 4.0f); | |||||
fSliderOrbitPhaseY->setStep(1.0f); | |||||
fSliderOrbitPhaseY->setCallback(this); | |||||
// set default values | |||||
programLoaded(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void VectorJuiceUI::parameterChanged(uint32_t index, float value) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case VectorJuicePlugin::paramX: | |||||
if (paramX != value) | |||||
{ | |||||
paramX = value; | |||||
fDragValid = false; | |||||
repaint(); | |||||
} | |||||
break; | |||||
case VectorJuicePlugin::paramY: | |||||
if (paramY != value) | |||||
{ | |||||
paramY = value; | |||||
fDragValid = false; | |||||
repaint(); | |||||
} | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitSizeX: | |||||
fKnobOrbitSizeX->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitSizeY: | |||||
fKnobOrbitSizeY->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitSpeedX: | |||||
fKnobOrbitSpeedX->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitSpeedY: | |||||
fKnobOrbitSpeedY->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramSubOrbitSize: | |||||
fKnobSubOrbitSize->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramSubOrbitSpeed: | |||||
fKnobSubOrbitSpeed->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramSubOrbitSmooth: | |||||
fKnobSubOrbitSmooth->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitWaveX: | |||||
fSliderOrbitWaveX->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitWaveY: | |||||
fSliderOrbitWaveY->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitPhaseX: | |||||
fSliderOrbitPhaseX->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitPhaseY: | |||||
fSliderOrbitPhaseY->setValue(value); | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitOutX: | |||||
if (orbitX != value) | |||||
{ | |||||
orbitX = value; | |||||
repaint(); | |||||
} | |||||
break; | |||||
case VectorJuicePlugin::paramOrbitOutY: | |||||
if (orbitY != value) | |||||
{ | |||||
orbitY = value; | |||||
repaint(); | |||||
} | |||||
break; | |||||
case VectorJuicePlugin::paramSubOrbitOutX: | |||||
if (subOrbitX != value) | |||||
{ | |||||
subOrbitX = value; | |||||
repaint(); | |||||
} | |||||
break; | |||||
case VectorJuicePlugin::paramSubOrbitOutY: | |||||
if (subOrbitY != value) | |||||
{ | |||||
subOrbitY = value; | |||||
repaint(); | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
void VectorJuiceUI::programLoaded(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
paramX = paramY = 0.5f; | |||||
fKnobOrbitSizeX->setValue(0.5f); | |||||
fKnobOrbitSizeY->setValue(0.5f); | |||||
fKnobOrbitSpeedX->setValue(4.0f); | |||||
fKnobOrbitSpeedY->setValue(4.0f); | |||||
fKnobSubOrbitSize->setValue(0.5f); | |||||
fKnobSubOrbitSpeed->setValue(32.0f); | |||||
fKnobSubOrbitSmooth->setValue(0.5f); | |||||
fSliderOrbitWaveX->setValue(3.0f); | |||||
fSliderOrbitWaveY->setValue(3.0f); | |||||
fSliderOrbitPhaseX->setValue(1.0f); | |||||
fSliderOrbitPhaseY->setValue(1.0f); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Widget Callbacks | |||||
void VectorJuiceUI::imageButtonClicked(ImageButton* button, int) | |||||
{ | |||||
if (button != fButtonAbout) | |||||
return; | |||||
fAboutWindow.exec(); | |||||
} | |||||
void VectorJuiceUI::imageKnobDragStarted(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), true); | |||||
} | |||||
void VectorJuiceUI::imageKnobDragFinished(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), false); | |||||
} | |||||
void VectorJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
{ | |||||
setParameterValue(knob->getId(), value); | |||||
} | |||||
void VectorJuiceUI::imageSliderDragStarted(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), true); | |||||
} | |||||
void VectorJuiceUI::imageSliderDragFinished(ImageSlider* slider) | |||||
{ | |||||
editParameter(slider->getId(), false); | |||||
} | |||||
void VectorJuiceUI::imageSliderValueChanged(ImageSlider* slider, float value) | |||||
{ | |||||
setParameterValue(slider->getId(), value); | |||||
} | |||||
void VectorJuiceUI::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
// get x, y mapped to XY area | |||||
int x = fCanvasArea.getX() + paramX*fCanvasArea.getWidth() - fImgRoundlet.getWidth()/2; | |||||
int y = fCanvasArea.getY() + paramY*fCanvasArea.getHeight() - fImgRoundlet.getHeight()/2; | |||||
int nOrbitX = fCanvasArea.getX()+((orbitX)*fCanvasArea.getWidth())-15; | |||||
int nOrbitY = fCanvasArea.getY()+((orbitY)*fCanvasArea.getWidth())-15; | |||||
int nSubOrbitX = fCanvasArea.getX()+(subOrbitX*fCanvasArea.getWidth())-15; | |||||
int nSubOrbitY = fCanvasArea.getY()+(subOrbitY*fCanvasArea.getWidth())-14; | |||||
//draw lines, just for fun | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glColor4f(0.0f, 1.0f, 0.0f, 0.05f); | |||||
glLineWidth(4); | |||||
glBegin(GL_LINES); | |||||
glVertex2i(x+ fImgRoundlet.getWidth()/2, y+ fImgRoundlet.getHeight()/2); | |||||
glVertex2i(nOrbitX+15, nOrbitY+15); | |||||
glEnd(); | |||||
glBegin(GL_LINES); | |||||
glVertex2i(nOrbitX+15, nOrbitY+15); | |||||
glVertex2i(nSubOrbitX+15, nSubOrbitY+14); | |||||
glEnd(); | |||||
// reset color | |||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
// draw roundlet and orbits | |||||
fImgRoundlet.drawAt(x, y); | |||||
fImgOrbit.drawAt(nOrbitX, nOrbitY); | |||||
fImgSubOrbit.drawAt(nSubOrbitX, nSubOrbitY); | |||||
} | |||||
bool VectorJuiceUI::onMouse(const MouseEvent& ev) | |||||
{ | |||||
if (ev.button != 1) | |||||
return false; | |||||
if (ev.press) | |||||
{ | |||||
if (! fCanvasArea.contains(ev.pos)) | |||||
return false; | |||||
fDragging = true; | |||||
fDragValid = true; | |||||
fLastX = ev.pos.getX(); | |||||
fLastY = ev.pos.getY(); | |||||
return true; | |||||
} | |||||
else if (fDragging) | |||||
{ | |||||
fDragging = false; | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool VectorJuiceUI::onMotion(const MotionEvent& ev) | |||||
{ | |||||
if (! fDragging) | |||||
return false; | |||||
const int x = ev.pos.getX(); | |||||
const int y = ev.pos.getY(); | |||||
if (! fDragValid) | |||||
{ | |||||
fDragValid = true; | |||||
fLastX = x; | |||||
fLastY = y; | |||||
} | |||||
const int movedX = fLastX - x; | |||||
const int movedY = fLastY - y; | |||||
fLastX = x; | |||||
fLastY = y; | |||||
float newX = paramX; | |||||
float newY = paramY; | |||||
newX -= float(movedX)/fCanvasArea.getWidth(); | |||||
newY -= float(movedY)/fCanvasArea.getHeight(); | |||||
if (newX < 0.0f) | |||||
newX = 0.0f; | |||||
else if (newX > 1.0f) | |||||
newX = 1.0f; | |||||
if (newY < 0.0f) | |||||
newY = 0.0f; | |||||
else if (newY > 1.0f) | |||||
newY = 1.0f; | |||||
if (newX != paramX) | |||||
{ | |||||
paramX = newX; | |||||
setParameterValue(VectorJuicePlugin::paramX, paramX); | |||||
repaint(); | |||||
} | |||||
if (newY != paramY) | |||||
{ | |||||
paramY = newY; | |||||
setParameterValue(VectorJuicePlugin::paramY, paramY); | |||||
repaint(); | |||||
} | |||||
return true; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new VectorJuiceUI(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,99 @@ | |||||
/* | |||||
* Vector 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 VECTORJUICEUI_HPP_INCLUDED | |||||
#define VECTORJUICEUI_HPP_INCLUDED | |||||
#include "DistrhoUI.hpp" | |||||
#include "ImageWidgets.hpp" | |||||
#include "VectorJuiceArtwork.hpp" | |||||
using DGL_NAMESPACE::Image; | |||||
using DGL_NAMESPACE::ImageAboutWindow; | |||||
using DGL_NAMESPACE::ImageButton; | |||||
using DGL_NAMESPACE::ImageKnob; | |||||
using DGL_NAMESPACE::ImageSlider; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class VectorJuiceUI : public UI, | |||||
public ImageButton::Callback, | |||||
public ImageKnob::Callback, | |||||
public ImageSlider::Callback | |||||
{ | |||||
public: | |||||
VectorJuiceUI(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
void programLoaded(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 imageSliderDragStarted(ImageSlider* slider) override; | |||||
void imageSliderDragFinished(ImageSlider* slider) override; | |||||
void imageSliderValueChanged(ImageSlider* slider, float value) override; | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
private: | |||||
float paramX, paramY; | |||||
Image fImgBackground; | |||||
Image fImgRoundlet; | |||||
Image fImgOrbit; | |||||
Image fImgSubOrbit; | |||||
ImageAboutWindow fAboutWindow; | |||||
ScopedPointer<ImageButton> fButtonAbout; | |||||
//knobs | |||||
ScopedPointer<ImageKnob> fKnobOrbitSpeedX, fKnobOrbitSpeedY, fKnobOrbitSizeX, fKnobOrbitSizeY; | |||||
ScopedPointer<ImageKnob> fKnobSubOrbitSpeed, fKnobSubOrbitSize, fKnobSubOrbitSmooth; | |||||
//sliders | |||||
ScopedPointer<ImageSlider> fSliderOrbitWaveX, fSliderOrbitWaveY; | |||||
ScopedPointer<ImageSlider> fSliderOrbitPhaseX, fSliderOrbitPhaseY; | |||||
// needed for XY canvas handling | |||||
bool fDragging; | |||||
bool fDragValid; | |||||
int fLastX; | |||||
int fLastY; | |||||
DGL_NAMESPACE::Rectangle<int> fCanvasArea; | |||||
float orbitX, orbitY, subOrbitX, subOrbitY; | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // VECTORJUICEUI_HPP_INCLUDED |
@@ -0,0 +1,87 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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. | |||||
*/ | |||||
// config fix | |||||
#include "distrho-wobblejuice/DistrhoPluginInfo.h" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#include "CarlaMathUtils.hpp" | |||||
#include "CarlaJuceUtils.hpp" | |||||
// Plugin Code | |||||
#include "distrho-wobblejuice/WobbleJuiceArtwork.cpp" | |||||
#include "distrho-wobblejuice/WobbleJuicePlugin.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "distrho-wobblejuice/WobbleJuiceUI.cpp" | |||||
#endif | |||||
// DISTRHO Code | |||||
#define DISTRHO_PLUGIN_TARGET_CARLA | |||||
#include "DistrhoPluginMain.cpp" | |||||
#ifdef HAVE_DGL | |||||
#include "DistrhoUIMain.cpp" | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor wobblejuiceDesc = { | |||||
/* category */ NATIVE_PLUGIN_CATEGORY_DYNAMICS, | |||||
#ifdef HAVE_DGL | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_HAS_UI | |||||
|NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||||
|NATIVE_PLUGIN_USES_PARENT_ID | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#else | |||||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||||
|NATIVE_PLUGIN_USES_TIME), | |||||
#endif | |||||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||||
/* midiIns */ 0, | |||||
/* midiOuts */ 0, | |||||
/* paramIns */ WobbleJuicePlugin::paramCount, | |||||
/* paramOuts */ 0, | |||||
/* name */ DISTRHO_PLUGIN_NAME, | |||||
/* label */ "wobblejuice", | |||||
/* maker */ "Andre Sklenar", | |||||
/* copyright */ "GPL v2+", | |||||
PluginDescriptorFILL(PluginCarla) | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_wobblejuice(); | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_distrho_wobblejuice() | |||||
{ | |||||
USE_NAMESPACE_DISTRHO | |||||
carla_register_native_plugin(&wobblejuiceDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -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,243 @@ | |||||
/* | |||||
* 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 | |||||
loadProgram(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Init | |||||
void WobbleJuicePlugin::initParameter(uint32_t index, Parameter& parameter) | |||||
{ | |||||
switch (index) | |||||
{ | |||||
case paramDivision: | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.name = "Division"; | |||||
parameter.symbol = "div"; | |||||
parameter.unit = "x"; | |||||
parameter.ranges.def = 4.0f; | |||||
parameter.ranges.min = 1.0f; | |||||
parameter.ranges.max = 16.0f; | |||||
break; | |||||
case paramReso: | |||||
parameter.hints = kParameterIsAutomable; | |||||
parameter.name = "Resonance"; | |||||
parameter.symbol = "reso"; | |||||
parameter.unit = ""; | |||||
parameter.ranges.def = 0.1f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 0.2f; | |||||
break; | |||||
case paramRange: | |||||
parameter.hints = kParameterIsAutomable; | |||||
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 = kParameterIsAutomable; | |||||
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 = kParameterIsAutomable; | |||||
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 = kParameterIsAutomable; | |||||
parameter.name = "Drive"; | |||||
parameter.symbol = "drv"; | |||||
parameter.unit = ""; | |||||
parameter.ranges.def = 0.5f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 1.0f; | |||||
break; | |||||
} | |||||
} | |||||
void WobbleJuicePlugin::initProgramName(uint32_t index, String& programName) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
programName = "Default"; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Internal data | |||||
float WobbleJuicePlugin::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::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::loadProgram(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.0f; | |||||
currentPhaseR=posL=posR=cutoffL=cutoffR=0.0f; | |||||
waveType=2.0f; | |||||
/* reset filter values */ | |||||
activate(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Process | |||||
void WobbleJuicePlugin::activate() | |||||
{ | |||||
sinePos = 0.0; | |||||
} | |||||
void WobbleJuicePlugin::run(const float** inputs, float** outputs, uint32_t frames) | |||||
{ | |||||
//fetch the timepos struct from host; | |||||
const TimePosition& time(getTimePosition()); | |||||
/* sample count for one bar */ | |||||
bar = ((120.0/(time.bbt.valid ? time.bbt.beatsPerMinute : 120.0))*(getSampleRate())); //ONE, two, three, four | |||||
tick = bar/(std::round(division)); //size of one target wob | |||||
phaseOffset = phase*M_PI; //2pi = 1 whole cycle | |||||
/* if rolling then sync to timepos */ | |||||
if (time.playing) | |||||
{ | |||||
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 just keep on wobblin' */ | |||||
else | |||||
{ | |||||
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, getSampleRate(), drive); | |||||
filterR.recalc(cutoffR, reso*4, 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(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Information | |||||
const char* getLabel() const noexcept override | |||||
{ | |||||
return "WobbleJuice"; | |||||
} | |||||
const char* getMaker() const noexcept override | |||||
{ | |||||
return "Andre Sklenar"; | |||||
} | |||||
const char* getLicense() const noexcept override | |||||
{ | |||||
return "GPL v2+"; | |||||
} | |||||
uint32_t getVersion() const noexcept override | |||||
{ | |||||
return 0x1000; | |||||
} | |||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('W', 'b', 'l', 'J'); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Init | |||||
void initParameter(uint32_t index, Parameter& parameter) override; | |||||
void initProgramName(uint32_t index, String& programName) override; | |||||
// ------------------------------------------------------------------- | |||||
// Internal data | |||||
float getParameterValue(uint32_t index) const override; | |||||
void setParameterValue(uint32_t index, float value) override; | |||||
void loadProgram(uint32_t index) override; | |||||
// ------------------------------------------------------------------- | |||||
// Process | |||||
void activate() override; | |||||
void run(const 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; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WobbleJuicePlugin) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // WOBBLEJUICE_HPP_INCLUDED |
@@ -0,0 +1,189 @@ | |||||
/* | |||||
* 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" | |||||
#include "WobbleJuiceUI.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
WobbleJuiceUI::WobbleJuiceUI() | |||||
: UI(), | |||||
fAboutWindow(this) | |||||
{ | |||||
setSize(WobbleJuiceArtwork::backgroundWidth, WobbleJuiceArtwork::backgroundHeight); | |||||
// background | |||||
fImgBackground = Image(WobbleJuiceArtwork::backgroundData, WobbleJuiceArtwork::backgroundWidth, WobbleJuiceArtwork::backgroundHeight, GL_BGR); | |||||
// about | |||||
Image aboutImage(WobbleJuiceArtwork::aboutData, WobbleJuiceArtwork::aboutWidth, WobbleJuiceArtwork::aboutHeight, GL_BGR); | |||||
fAboutWindow.setImage(aboutImage); | |||||
// knobs | |||||
Image knobImage(WobbleJuiceArtwork::knobData, WobbleJuiceArtwork::knobWidth, WobbleJuiceArtwork::knobHeight); | |||||
// knob Division | |||||
fKnobDivision = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobDivision->setId(WobbleJuicePlugin::paramDivision); | |||||
fKnobDivision->setAbsolutePos(222, 74); | |||||
fKnobDivision->setRotationAngle(270); | |||||
fKnobDivision->setRange(1.0f, 16.0f); | |||||
fKnobDivision->setDefault(4.0f); | |||||
fKnobDivision->setStep(1.0f); | |||||
fKnobDivision->setCallback(this); | |||||
// knob Resonance | |||||
fKnobResonance = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobResonance->setId(WobbleJuicePlugin::paramReso); | |||||
fKnobResonance->setAbsolutePos(222, 199); | |||||
fKnobResonance->setRotationAngle(270); | |||||
fKnobResonance->setRange(0.0f, 0.2f); | |||||
fKnobResonance->setDefault(0.1f); | |||||
fKnobResonance->setCallback(this); | |||||
// knob Range | |||||
fKnobRange = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobRange->setId(WobbleJuicePlugin::paramRange); | |||||
fKnobRange->setAbsolutePos(77, 199); | |||||
fKnobRange->setRotationAngle(270); | |||||
fKnobRange->setRange(500.0f, 16000.0f); | |||||
fKnobRange->setDefault(16000.0f); | |||||
fKnobRange->setCallback(this); | |||||
// knob Phase | |||||
fKnobPhase = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobPhase->setId(WobbleJuicePlugin::paramPhase); | |||||
fKnobPhase->setAbsolutePos(362, 74); | |||||
fKnobPhase->setRotationAngle(270); | |||||
fKnobPhase->setRange(-1.0f, 1.0f); | |||||
fKnobPhase->setDefault(0.0f); | |||||
fKnobPhase->setCallback(this); | |||||
// knob Wave | |||||
fKnobWave = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobWave->setId(WobbleJuicePlugin::paramWave); | |||||
fKnobWave->setAbsolutePos(77, 74); | |||||
fKnobWave->setRotationAngle(270); | |||||
fKnobWave->setRange(1.0f, 4.0f); | |||||
fKnobWave->setDefault(2.0f); | |||||
fKnobWave->setCallback(this); | |||||
// knob Drive | |||||
fKnobDrive = new ImageKnob(this, knobImage, ImageKnob::Vertical); | |||||
fKnobDrive->setId(WobbleJuicePlugin::paramDrive); | |||||
fKnobDrive->setAbsolutePos(362, 199); | |||||
fKnobDrive->setRotationAngle(270); | |||||
fKnobDrive->setRange(0.0f, 1.0f); | |||||
fKnobDrive->setDefault(0.5f); | |||||
fKnobDrive->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->setAbsolutePos(390, 20); | |||||
fButtonAbout->setCallback(this); | |||||
// set default values | |||||
programLoaded(0); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void WobbleJuiceUI::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::programLoaded(uint32_t index) | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
// Default values | |||||
fKnobDivision->setValue(4.0f); | |||||
fKnobResonance->setValue(0.1f); | |||||
fKnobRange->setValue(16000.0f); | |||||
fKnobPhase->setValue(0.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) | |||||
{ | |||||
editParameter(knob->getId(), true); | |||||
} | |||||
void WobbleJuiceUI::imageKnobDragFinished(ImageKnob* knob) | |||||
{ | |||||
editParameter(knob->getId(), false); | |||||
} | |||||
void WobbleJuiceUI::imageKnobValueChanged(ImageKnob* knob, float value) | |||||
{ | |||||
setParameterValue(knob->getId(), value); | |||||
} | |||||
void WobbleJuiceUI::onDisplay() | |||||
{ | |||||
fImgBackground.draw(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
UI* createUI() | |||||
{ | |||||
return new WobbleJuiceUI(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,75 @@ | |||||
/* | |||||
* 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 "ImageWidgets.hpp" | |||||
#include "WobbleJuiceArtwork.hpp" | |||||
using DGL_NAMESPACE::Image; | |||||
using DGL_NAMESPACE::ImageAboutWindow; | |||||
using DGL_NAMESPACE::ImageButton; | |||||
using DGL_NAMESPACE::ImageKnob; | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
class WobbleJuiceUI : public UI, | |||||
public ImageButton::Callback, | |||||
public ImageKnob::Callback | |||||
{ | |||||
public: | |||||
WobbleJuiceUI(); | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// DSP Callbacks | |||||
void parameterChanged(uint32_t index, float value) override; | |||||
void programLoaded(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; | |||||
ScopedPointer<ImageButton> fButtonAbout; | |||||
ScopedPointer<ImageKnob> fKnobDivision, fKnobResonance, fKnobRange; | |||||
ScopedPointer<ImageKnob> fKnobPhase, fKnobWave, fKnobDrive; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WobbleJuiceUI) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
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, const 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 |
@@ -0,0 +1,598 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 "CarlaDefines.h" | |||||
#define PLUGINVERSION | |||||
#define SOURCE_DIR "/usr/share/zynaddsubfx/examples" | |||||
#undef override | |||||
// ignore some compiler warnings | |||||
#if defined(__clang__) | |||||
# pragma clang diagnostic push | |||||
# pragma clang diagnostic ignored "-Winconsistent-missing-override" | |||||
# pragma clang diagnostic ignored "-Wunused-private-field" | |||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wliteral-suffix" | |||||
# if __GNUC__ >= 6 | |||||
# pragma GCC diagnostic ignored "-Wshift-negative-value" | |||||
# pragma GCC diagnostic ignored "-Wmisleading-indentation" | |||||
# endif | |||||
#endif | |||||
// base c-style headers | |||||
#include "zynaddsubfx/tlsf/tlsf.h" | |||||
#include "zynaddsubfx/rtosc/rtosc.h" | |||||
#ifdef SKIP_ZYN_SYNTH | |||||
# define PRId64 P_INT64 | |||||
# define PRIi64 P_INT64 | |||||
# define PRIx64 P_UINT64 | |||||
# define PRId32 "%d" | |||||
# define PRIi32 "%i" | |||||
# define PRIx32 "%x" | |||||
#endif | |||||
// C-code includes | |||||
extern "C" { | |||||
#include "zynaddsubfx/tlsf/tlsf.c" | |||||
#undef TLSF_64BIT | |||||
#undef tlsf_decl | |||||
#undef tlsf_fls_sizet | |||||
#undef tlsf_cast | |||||
#undef tlsf_min | |||||
#undef tlsf_max | |||||
#undef tlsf_assert | |||||
#undef _tlsf_glue2 | |||||
#undef _tlsf_glue | |||||
#undef tlsf_static_assert | |||||
#undef tlsf_insist | |||||
#include "zynaddsubfx/rtosc/dispatch.c" | |||||
#include "zynaddsubfx/rtosc/rtosc.c" | |||||
#ifdef CARLA_OS_WIN | |||||
# include "zynaddsubfx/rtosc/pretty-format.c" | |||||
#endif | |||||
} | |||||
// rtosc includes | |||||
#include "zynaddsubfx/rtosc/cpp/automations.cpp" | |||||
#include "zynaddsubfx/rtosc/cpp/midimapper.cpp" | |||||
#include "zynaddsubfx/rtosc/cpp/miditable.cpp" | |||||
#undef RTOSC_INVALID_MIDI | |||||
#undef MAX_UNHANDLED_PATH | |||||
#include "zynaddsubfx/rtosc/cpp/ports.cpp" | |||||
#undef __builtin_expect | |||||
#include "zynaddsubfx/rtosc/cpp/subtree-serialize.cpp" | |||||
#include "zynaddsubfx/rtosc/cpp/thread-link.cpp" | |||||
#undef off_t | |||||
#include "zynaddsubfx/rtosc/cpp/undo-history.cpp" | |||||
// zynaddsubfx includes | |||||
#include "zynaddsubfx/version.cpp" | |||||
#ifndef SKIP_ZYN_SYNTH | |||||
#include "zynaddsubfx/Containers/MultiPseudoStack.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Containers/NotePool.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Containers/ScratchString.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Bank.cpp" | |||||
#undef INSTRUMENT_EXTENSION | |||||
#undef FORCE_BANK_DIR_FILE | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#define INSTRUMENT_EXTENSION INSTRUMENT_EXTENSION_DB | |||||
#include "zynaddsubfx/Misc/BankDb.cpp" | |||||
#undef INSTRUMENT_EXTENSION | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/CallbackRepeater.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Config.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Master.cpp" | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Microtonal.cpp" | |||||
#undef MAX_LINE_SIZE | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/MiddleWare.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Part.cpp" | |||||
#undef CLONE | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/PresetExtractor.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Recorder.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/WavFile.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/ADnoteParameters.cpp" | |||||
#undef EXPAND | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/Controller.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/EnvelopeParams.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/LFOParams.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/PADnoteParameters.cpp" | |||||
#undef PC | |||||
#undef P_C | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/SUBnoteParameters.cpp" | |||||
#undef doPaste | |||||
#undef doPPaste | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/ADnote.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/Envelope.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/LFO.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/ModFilter.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/OscilGen.cpp" | |||||
#undef PC | |||||
#undef DIFF | |||||
#undef PRESERVE | |||||
#undef RESTORE | |||||
#undef FUNC | |||||
#undef FILTER | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/PADnote.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/Resonance.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/SUBnote.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/SynthNote.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Synth/WatchPoint.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/UI/ConnectionDummy.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/globals.cpp" | |||||
#endif // ! SKIP_ZYN_SYNTH | |||||
#include "zynaddsubfx/DSP/AnalogFilter.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/DSP/FFTwrapper.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/DSP/Filter.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/DSP/FormantFilter.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/DSP/SVFilter.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/DSP/Unison.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Alienwah.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Chorus.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Distorsion.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/DynamicFilter.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Echo.cpp" | |||||
#undef MAX_DELAY | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Effect.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/EffectLFO.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/EffectMgr.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/EQ.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Phaser.cpp" | |||||
#undef PHASER_LFO_SHAPE | |||||
#undef ONE_ | |||||
#undef ZERO_ | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Effects/Reverb.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Allocator.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/Util.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/WaveShapeSmps.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Misc/XMLwrapper.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/FilterParams.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/Presets.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/PresetsArray.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#include "zynaddsubfx/Params/PresetsStore.cpp" | |||||
#undef rBegin | |||||
#undef rObject | |||||
#undef rStdString | |||||
#undef rStdStringCb | |||||
#undef rChangeCb | |||||
#define rChangeCb | |||||
#if defined(__clang__) | |||||
# pragma clang diagnostic pop | |||||
#elif defined(__GNUC__) && (__GNUC__ >= 6) | |||||
# pragma GCC diagnostic pop | |||||
#endif | |||||
#ifndef SKIP_ZYN_SYNTH | |||||
// Dummy variables and functions for linking purposes | |||||
namespace zyncarla { | |||||
class WavFile; | |||||
namespace Nio { | |||||
void masterSwap(Master*){} | |||||
bool setSource(std::string){return true;} | |||||
bool setSink(std::string){return true;} | |||||
std::set<std::string> getSources(void){return std::set<std::string>();} | |||||
std::set<std::string> getSinks(void){return std::set<std::string>();} | |||||
std::string getSource(void){return "";} | |||||
std::string getSink(void){return "";} | |||||
void waveNew(WavFile*){} | |||||
void waveStart(){} | |||||
void waveStop(){} | |||||
} | |||||
} | |||||
#endif // ! SKIP_ZYN_SYNTH | |||||
#ifdef CARLA_OS_WIN | |||||
rtosc_version rtosc_current_version() | |||||
{ | |||||
return ((rtosc_version) { 0, 0, 0 } ); | |||||
} | |||||
void rtosc_version_print_to_12byte_str(const rtosc_version* v, | |||||
char* _12bytes) | |||||
{ | |||||
snprintf(_12bytes, 12, "%u.%u.%u", | |||||
(unsigned)v->major, (unsigned)v->minor, (unsigned)v->revision); | |||||
} | |||||
#endif |
@@ -0,0 +1,273 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* 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 "CarlaString.hpp" | |||||
#include "CarlaPipeUtils.hpp" | |||||
#define PLUGINVERSION | |||||
#define SOURCE_DIR "/usr/share/zynaddsubfx" | |||||
#undef override | |||||
#ifdef NTK_GUI | |||||
# include <dlfcn.h> | |||||
static CarlaString getResourceDir() | |||||
{ | |||||
Dl_info exeInfo; | |||||
dladdr((void*)getResourceDir, &exeInfo); | |||||
CarlaString filename(exeInfo.dli_fname); | |||||
return filename.truncate(filename.rfind("-ui")); | |||||
} | |||||
CarlaString gUiPixmapPath(getResourceDir()); | |||||
#endif | |||||
// base c-style headers | |||||
#include "zynaddsubfx/rtosc/rtosc.h" | |||||
// rtosc c includes | |||||
extern "C" { | |||||
#include "zynaddsubfx/rtosc/dispatch.c" | |||||
#include "zynaddsubfx/rtosc/rtosc.c" | |||||
} | |||||
// ignore some compiler warnings | |||||
#if defined(__clang__) | |||||
# pragma clang diagnostic push | |||||
# pragma clang diagnostic ignored "-Winconsistent-missing-override" | |||||
# pragma clang diagnostic ignored "-Wunused-private-field" | |||||
#elif defined(__GNUC__) && (__GNUC__ >= 6) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wmisleading-indentation" | |||||
# if (__GNUC__ >= 7) | |||||
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" | |||||
# endif | |||||
#endif | |||||
// rtosc c++ includes | |||||
#include "zynaddsubfx/rtosc/cpp/midimapper.cpp" | |||||
#include "zynaddsubfx/rtosc/cpp/miditable.cpp" | |||||
#undef RTOSC_INVALID_MIDI | |||||
#undef MAX_UNHANDLED_PATH | |||||
#include "zynaddsubfx/rtosc/cpp/ports.cpp" | |||||
#undef __builtin_expect | |||||
#include "zynaddsubfx/rtosc/cpp/subtree-serialize.cpp" | |||||
#include "zynaddsubfx/rtosc/cpp/thread-link.cpp" | |||||
#undef off_t | |||||
#undef static | |||||
#include "zynaddsubfx/rtosc/cpp/undo-history.cpp" | |||||
// zynaddsubfx ui includes | |||||
#include "zynaddsubfx/UI/NioUI.cpp" | |||||
#include "zynaddsubfx/UI/WidgetPDial.cpp" | |||||
#include "zynaddsubfx/UI/ADnoteUI.cpp" | |||||
#include "zynaddsubfx/UI/BankUI.cpp" | |||||
#include "zynaddsubfx/UI/BankView.cpp" | |||||
#include "zynaddsubfx/UI/ConfigUI.cpp" | |||||
// #include "zynaddsubfx/UI/Connection.cpp" | |||||
#include "zynaddsubfx/UI/EffUI.cpp" | |||||
#include "zynaddsubfx/UI/EnvelopeFreeEdit.cpp" | |||||
#include "zynaddsubfx/UI/EnvelopeUI.cpp" | |||||
#include "zynaddsubfx/UI/FilterUI.cpp" | |||||
#include "zynaddsubfx/UI/Fl_EQGraph.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Button.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Check.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Choice.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Counter.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Dial.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_DialF.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Input.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_ListView.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Numeric_Input.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Output.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Pane.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Roller.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Slider.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_TSlider.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Value.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_VSlider.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Osc_Widget.cpp" | |||||
#include "zynaddsubfx/UI/Fl_Resonance_Graph.cpp" | |||||
#include "zynaddsubfx/UI/FormantFilterGraph.cpp" | |||||
#include "zynaddsubfx/UI/LFOUI.cpp" | |||||
#include "zynaddsubfx/UI/MasterUI.cpp" | |||||
#include "zynaddsubfx/UI/MicrotonalUI.cpp" | |||||
#include "zynaddsubfx/UI/OscilGenUI.cpp" | |||||
#include "zynaddsubfx/UI/PADnoteUI.cpp" | |||||
#include "zynaddsubfx/UI/PartNameButton.cpp" | |||||
#include "zynaddsubfx/UI/PartUI.cpp" | |||||
#include "zynaddsubfx/UI/PresetsUI.cpp" | |||||
#include "zynaddsubfx/UI/ResonanceUI.cpp" | |||||
#include "zynaddsubfx/UI/SUBnoteUI.cpp" | |||||
#include "zynaddsubfx/UI/TipWin.cpp" | |||||
#include "zynaddsubfx/UI/VirKeyboard.cpp" | |||||
#include "zynaddsubfx/UI/guimain.cpp" | |||||
#if defined(__clang__) | |||||
# pragma clang diagnostic pop | |||||
#elif defined(__GNUC__) && (__GNUC__ >= 6) | |||||
# pragma GCC diagnostic pop | |||||
#endif | |||||
class ZynPipeClient : public CarlaPipeClient | |||||
{ | |||||
public: | |||||
ZynPipeClient() noexcept | |||||
: CarlaPipeClient(), | |||||
fQuitReceived(false) {} | |||||
~ZynPipeClient() noexcept override | |||||
{ | |||||
if (fQuitReceived) | |||||
return; | |||||
writeExitingMessageAndWait(); | |||||
} | |||||
protected: | |||||
bool msgReceived(const char* const msg) noexcept override | |||||
{ | |||||
if (std::strcmp(msg, "control") == 0) | |||||
{ | |||||
uint index; | |||||
float value; | |||||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); | |||||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true); | |||||
// TODO | |||||
return true; | |||||
} | |||||
if (std::strcmp(msg, "program") == 0) | |||||
{ | |||||
uint i; | |||||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(i), true); | |||||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(i), true); | |||||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(i), true); | |||||
return true; | |||||
} | |||||
if (std::strcmp(msg, "show") == 0) | |||||
{ | |||||
try { | |||||
GUI::raiseUi(gui, "/show", "i", 1); | |||||
} CARLA_SAFE_EXCEPTION("msgReceived show"); | |||||
return true; | |||||
} | |||||
if (std::strcmp(msg, "hide") == 0) | |||||
{ | |||||
try { | |||||
GUI::raiseUi(gui, "/hide", ""); | |||||
} CARLA_SAFE_EXCEPTION("msgReceived hide"); | |||||
return true; | |||||
} | |||||
if (std::strcmp(msg, "focus") == 0) | |||||
{ | |||||
try { | |||||
GUI::raiseUi(gui, "/focus", ""); | |||||
} CARLA_SAFE_EXCEPTION("msgReceived focus"); | |||||
return true; | |||||
} | |||||
if (std::strcmp(msg, "uiTitle") == 0) | |||||
{ | |||||
const char* uiTitle; | |||||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uiTitle), true); | |||||
try { | |||||
GUI::raiseUi(gui, "/ui/title", "s", uiTitle); | |||||
} CARLA_SAFE_EXCEPTION("msgReceived uiTitle"); | |||||
return true; | |||||
} | |||||
if (std::strcmp(msg, "quit") == 0) | |||||
{ | |||||
fQuitReceived = true; | |||||
try { | |||||
GUI::raiseUi(gui, "/close-ui", ""); | |||||
} CARLA_SAFE_EXCEPTION("msgReceived quit"); | |||||
return true; | |||||
} | |||||
carla_stderr("ZynPipeClient::msgReceived : %s", msg); | |||||
return false; | |||||
} | |||||
private: | |||||
bool fQuitReceived; | |||||
}; | |||||
int main(int argc, const char* argv[]) | |||||
{ | |||||
ZynPipeClient pipe; | |||||
const char* uiTitle = nullptr; | |||||
if (argc > 1) | |||||
{ | |||||
sendtourl = argv[1]; | |||||
uiTitle = argv[2]; | |||||
if (! pipe.initPipeClient(argv)) | |||||
return 1; | |||||
server = lo_server_new_with_proto(NULL, LO_UDP, liblo_error_cb); | |||||
lo_server_add_method(server, NULL, NULL, handler_function, 0); | |||||
} | |||||
std::thread lo_watch(watch_lo); | |||||
gui = GUI::createUi(new UI_Interface(), &Pexitprogram); | |||||
if (argc == 1) | |||||
{ | |||||
// testing only | |||||
GUI::raiseUi(gui, "/show", "i", 1); | |||||
} | |||||
else | |||||
{ | |||||
// full thing | |||||
isPlugin = true; | |||||
MasterUI::menu_mastermenu[11].hide(); // file -> nio settings | |||||
} | |||||
if (uiTitle != nullptr && uiTitle[0] != '\0') | |||||
GUI::raiseUi(gui, "/ui/title", "s", uiTitle); | |||||
for (; Pexitprogram == 0;) | |||||
{ | |||||
pipe.idlePipe(); | |||||
GUI::tickUi(gui); | |||||
for (; lo_buffer.hasNext();) | |||||
raiseUi(gui, lo_buffer.read()); | |||||
} | |||||
GUI::destroyUi(gui); | |||||
gui = nullptr; | |||||
lo_watch.join(); | |||||
return 0; | |||||
} | |||||
#include "CarlaPipeUtils.cpp" | |||||
#include "water/misc/Time.cpp" | |||||
// -------------------------------------------------------------------------------------------- |
@@ -0,0 +1,121 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
MultiPseudoStack.cpp - Multiple-Writer Lock Free Datastructure | |||||
Copyright (C) 2016 Mark McCurry | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include "MultiPseudoStack.h" | |||||
#include <cassert> | |||||
#include <cstdio> | |||||
#define INVALID ((int32_t)0xffffffff) | |||||
#define MAX ((int32_t)0x7fffffff) | |||||
namespace zyncarla { | |||||
QueueListItem::QueueListItem(void) | |||||
:memory(0), size(0) | |||||
{ | |||||
} | |||||
LockFreeQueue::LockFreeQueue(qli_t *data_, int n) | |||||
:data(data_), elms(n), next_r(0), next_w(0), avail(0) | |||||
{ | |||||
tag = new std::atomic<uint32_t>[n]; | |||||
for(int i=0; i<n; ++i) | |||||
tag[i] = INVALID; | |||||
} | |||||
LockFreeQueue::~LockFreeQueue(void) | |||||
{ | |||||
delete [] tag; | |||||
} | |||||
qli_t *LockFreeQueue::read(void) { | |||||
retry: | |||||
int8_t free_elms = avail.load(); | |||||
if(free_elms <= 0) | |||||
return 0; | |||||
int32_t next_tag = next_r.load(); | |||||
int32_t next_next_tag = (next_tag+1)&MAX; | |||||
assert(next_tag != INVALID); | |||||
for(int i=0; i<elms; ++i) { | |||||
uint32_t elm_tag = tag[i].load(); | |||||
//attempt to remove tagged element | |||||
//if and only if it's next | |||||
if(((uint32_t)next_tag) == elm_tag) { | |||||
if(!tag[i].compare_exchange_strong(elm_tag, INVALID)) | |||||
goto retry; | |||||
//Ok, now there is no element that can be removed from the list | |||||
//Effectively there's mutual exclusion over other readers here | |||||
//Set the next element | |||||
int sane_read = next_r.compare_exchange_strong(next_tag, next_next_tag); | |||||
assert(sane_read && "No double read on a single tag"); | |||||
//Decrement available elements | |||||
int32_t free_elms_next = avail.load(); | |||||
while(!avail.compare_exchange_strong(free_elms_next, free_elms_next-1)); | |||||
//printf("r%d ", free_elms_next-1); | |||||
return &data[i]; | |||||
} | |||||
} | |||||
goto retry; | |||||
} | |||||
//Insert Node Q | |||||
void LockFreeQueue::write(qli_t *Q) { | |||||
retry: | |||||
if(!Q) | |||||
return; | |||||
int32_t write_tag = next_w.load(); | |||||
int32_t next_write_tag = (write_tag+1)&MAX; | |||||
if(!next_w.compare_exchange_strong(write_tag, next_write_tag)) | |||||
goto retry; | |||||
uint32_t invalid_tag = INVALID; | |||||
//Update tag | |||||
int sane_write = tag[Q-data].compare_exchange_strong(invalid_tag, write_tag); | |||||
assert(sane_write); | |||||
//Increment available elements | |||||
int32_t free_elms = avail.load(); | |||||
while(!avail.compare_exchange_strong(free_elms, free_elms+1)) | |||||
assert(free_elms <= 32); | |||||
//printf("w%d ", free_elms+1); | |||||
} | |||||
MultiQueue::MultiQueue(void) | |||||
:pool(new qli_t[32]), m_free(pool, 32), m_msgs(pool, 32) | |||||
{ | |||||
//32 instances of 2kBi memory chunks | |||||
for(int i=0; i<32; ++i) { | |||||
qli_t &ptr = pool[i]; | |||||
ptr.size = 2048; | |||||
ptr.memory = new char[2048]; | |||||
free(&ptr); | |||||
} | |||||
} | |||||
MultiQueue::~MultiQueue(void) | |||||
{ | |||||
for(int i=0; i<32; ++i) | |||||
delete [] pool[i].memory; | |||||
delete [] pool; | |||||
} | |||||
} |
@@ -0,0 +1,66 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
MultiPseudoStack.h - Multiple-Writer Lock Free Datastructure | |||||
Copyright (C) 2016 Mark McCurry | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#pragma once | |||||
#include <atomic> | |||||
#include <cassert> | |||||
namespace zyncarla { | |||||
//XXX rename this thing | |||||
typedef struct QueueListItem qli_t; | |||||
struct QueueListItem | |||||
{ | |||||
QueueListItem(void); | |||||
char *memory; | |||||
uint32_t size; | |||||
}; | |||||
//Many reader many writer | |||||
class LockFreeQueue | |||||
{ | |||||
qli_t *const data; | |||||
const int elms; | |||||
std::atomic<uint32_t> *tag; | |||||
std::atomic<int32_t> next_r; | |||||
std::atomic<int32_t> next_w; | |||||
std::atomic<int32_t> avail; | |||||
public: | |||||
LockFreeQueue(qli_t *data_, int n); | |||||
~LockFreeQueue(void); | |||||
qli_t *read(void); | |||||
void write(qli_t *Q); | |||||
}; | |||||
/* | |||||
* Many reader Many writer capiable queue | |||||
* - lock free | |||||
* - allocation free (post initialization) | |||||
*/ | |||||
class MultiQueue | |||||
{ | |||||
qli_t *pool; | |||||
LockFreeQueue m_free; | |||||
LockFreeQueue m_msgs; | |||||
public: | |||||
MultiQueue(void); | |||||
~MultiQueue(void); | |||||
void dump(void); | |||||
qli_t *alloc(void) { return m_free.read(); } | |||||
void free(qli_t *q) { m_free.write(q); } | |||||
void write(qli_t *q) { m_msgs.write(q); } | |||||
qli_t *read(void) { return m_msgs.read(); } | |||||
}; | |||||
} |
@@ -0,0 +1,436 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
NotePool.cpp - Pool of Synthesizer Engines And Note Instances | |||||
Copyright (C) 2016 Mark McCurry | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include "NotePool.h" | |||||
#include "../Misc/Allocator.h" | |||||
#include "../Synth/SynthNote.h" | |||||
#include <cstring> | |||||
#include <cassert> | |||||
#include <iostream> | |||||
#define SUSTAIN_BIT 0x04 | |||||
#define NOTE_MASK 0x03 | |||||
namespace zyncarla { | |||||
enum NoteStatus { | |||||
KEY_OFF = 0x00, | |||||
KEY_PLAYING = 0x01, | |||||
KEY_RELEASED_AND_SUSTAINED = 0x02, | |||||
KEY_RELEASED = 0x03 | |||||
}; | |||||
NotePool::NotePool(void) | |||||
:needs_cleaning(0) | |||||
{ | |||||
memset(ndesc, 0, sizeof(ndesc)); | |||||
memset(sdesc, 0, sizeof(sdesc)); | |||||
} | |||||
bool NotePool::NoteDescriptor::playing(void) const | |||||
{ | |||||
return (status&NOTE_MASK) == KEY_PLAYING; | |||||
} | |||||
bool NotePool::NoteDescriptor::sustained(void) const | |||||
{ | |||||
return (status&NOTE_MASK) == KEY_RELEASED_AND_SUSTAINED; | |||||
} | |||||
bool NotePool::NoteDescriptor::released(void) const | |||||
{ | |||||
return (status&NOTE_MASK) == KEY_RELEASED; | |||||
} | |||||
bool NotePool::NoteDescriptor::off(void) const | |||||
{ | |||||
return (status&NOTE_MASK) == KEY_OFF; | |||||
} | |||||
void NotePool::NoteDescriptor::setStatus(uint8_t s) | |||||
{ | |||||
status &= ~NOTE_MASK; | |||||
status |= (NOTE_MASK&s); | |||||
} | |||||
void NotePool::NoteDescriptor::doSustain(void) | |||||
{ | |||||
setStatus(KEY_RELEASED_AND_SUSTAINED); | |||||
} | |||||
bool NotePool::NoteDescriptor::canSustain(void) const | |||||
{ | |||||
return !(status & SUSTAIN_BIT); | |||||
} | |||||
void NotePool::NoteDescriptor::makeUnsustainable(void) | |||||
{ | |||||
status |= SUSTAIN_BIT; | |||||
} | |||||
NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n) | |||||
{ | |||||
const int off_d1 = &n-ndesc; | |||||
int off_d2 = 0; | |||||
assert(off_d1 <= POLYPHONY); | |||||
for(int i=0; i<off_d1; ++i) | |||||
off_d2 += ndesc[i].size; | |||||
return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size}; | |||||
} | |||||
bool NotePool::NoteDescriptor::operator==(NoteDescriptor nd) | |||||
{ | |||||
return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status; | |||||
} | |||||
//return either the first unused descriptor or the last valid descriptor which | |||||
//matches note/sendto | |||||
static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato, | |||||
NotePool::NoteDescriptor *ndesc) | |||||
{ | |||||
int desc_id = 0; | |||||
for(int i=0; i<POLYPHONY; ++i, ++desc_id) | |||||
if(ndesc[desc_id].off()) | |||||
break; | |||||
if(desc_id != 0) { | |||||
auto &nd = ndesc[desc_id-1]; | |||||
if(nd.age == 0 && nd.note == note && nd.sendto == sendto | |||||
&& nd.playing() && nd.legatoMirror == legato && nd.canSustain()) | |||||
return desc_id-1; | |||||
} | |||||
//Out of free descriptors | |||||
if(desc_id >= POLYPHONY || !ndesc[desc_id].off()) { | |||||
return -1; | |||||
} | |||||
return desc_id; | |||||
} | |||||
NotePool::activeDescIter NotePool::activeDesc(void) | |||||
{ | |||||
cleanup(); | |||||
return activeDescIter{*this}; | |||||
} | |||||
NotePool::constActiveDescIter NotePool::activeDesc(void) const | |||||
{ | |||||
const_cast<NotePool*>(this)->cleanup(); | |||||
return constActiveDescIter{*this}; | |||||
} | |||||
int NotePool::usedNoteDesc(void) const | |||||
{ | |||||
if(needs_cleaning) | |||||
const_cast<NotePool*>(this)->cleanup(); | |||||
int cnt = 0; | |||||
for(int i=0; i<POLYPHONY; ++i) | |||||
cnt += (ndesc[i].size != 0); | |||||
return cnt; | |||||
} | |||||
int NotePool::usedSynthDesc(void) const | |||||
{ | |||||
if(needs_cleaning) | |||||
const_cast<NotePool*>(this)->cleanup(); | |||||
int cnt = 0; | |||||
for(int i=0; i<POLYPHONY*EXPECTED_USAGE; ++i) | |||||
cnt += (bool)sdesc[i].note; | |||||
return cnt; | |||||
} | |||||
void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato) | |||||
{ | |||||
//Get first free note descriptor | |||||
int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc); | |||||
assert(desc_id != -1); | |||||
ndesc[desc_id].note = note; | |||||
ndesc[desc_id].sendto = sendto; | |||||
ndesc[desc_id].size += 1; | |||||
ndesc[desc_id].status = KEY_PLAYING; | |||||
ndesc[desc_id].legatoMirror = legato; | |||||
//Get first free synth descriptor | |||||
int sdesc_id = 0; | |||||
while(sdesc[sdesc_id].note && sdesc_id < POLYPHONY*EXPECTED_USAGE) | |||||
sdesc_id++; | |||||
assert(sdesc_id < POLYPHONY*EXPECTED_USAGE); | |||||
sdesc[sdesc_id] = desc; | |||||
}; | |||||
void NotePool::upgradeToLegato(void) | |||||
{ | |||||
for(auto &d:activeDesc()) | |||||
if(d.playing()) | |||||
for(auto &s:activeNotes(d)) | |||||
insertLegatoNote(d.note, d.sendto, s); | |||||
} | |||||
void NotePool::insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc) | |||||
{ | |||||
assert(desc.note); | |||||
try { | |||||
desc.note = desc.note->cloneLegato(); | |||||
insertNote(note, sendto, desc, true); | |||||
} catch (std::bad_alloc &ba) { | |||||
std::cerr << "failed to insert legato note: " << ba.what() << std::endl; | |||||
} | |||||
}; | |||||
//There should only be one pair of notes which are still playing | |||||
void NotePool::applyLegato(LegatoParams &par) | |||||
{ | |||||
for(auto &desc:activeDesc()) { | |||||
desc.note = par.midinote; | |||||
for(auto &synth:activeNotes(desc)) | |||||
try { | |||||
synth.note->legatonote(par); | |||||
} catch (std::bad_alloc& ba) { | |||||
std::cerr << "failed to create legato note: " << ba.what() << std::endl; | |||||
} | |||||
} | |||||
} | |||||
void NotePool::makeUnsustainable(uint8_t note) | |||||
{ | |||||
for(auto &desc:activeDesc()) { | |||||
if(desc.note == note) { | |||||
desc.makeUnsustainable(); | |||||
if(desc.sustained()) | |||||
release(desc); | |||||
} | |||||
} | |||||
} | |||||
bool NotePool::full(void) const | |||||
{ | |||||
for(int i=0; i<POLYPHONY; ++i) | |||||
if(ndesc[i].off()) | |||||
return false; | |||||
return true; | |||||
} | |||||
bool NotePool::synthFull(int sdesc_count) const | |||||
{ | |||||
int actually_free=sizeof(sdesc)/sizeof(sdesc[0]); | |||||
for(const auto &desc:activeDesc()) { | |||||
actually_free -= desc.size; | |||||
} | |||||
return actually_free < sdesc_count; | |||||
} | |||||
//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING | |||||
bool NotePool::existsRunningNote(void) const | |||||
{ | |||||
//printf("runing note # =%d\n", getRunningNotes()); | |||||
return getRunningNotes(); | |||||
} | |||||
int NotePool::getRunningNotes(void) const | |||||
{ | |||||
bool running[256] = {0}; | |||||
for(auto &desc:activeDesc()) { | |||||
//printf("note!(%d)\n", desc.note); | |||||
if(desc.playing() || desc.sustained()) | |||||
running[desc.note] = true; | |||||
} | |||||
int running_count = 0; | |||||
for(int i=0; i<256; ++i) | |||||
running_count += running[i]; | |||||
return running_count; | |||||
} | |||||
void NotePool::enforceKeyLimit(int limit) | |||||
{ | |||||
int notes_to_kill = getRunningNotes() - limit; | |||||
if(notes_to_kill <= 0) | |||||
return; | |||||
NoteDescriptor *to_kill = NULL; | |||||
unsigned oldest = 0; | |||||
for(auto &nd : activeDesc()) { | |||||
if(to_kill == NULL) { | |||||
//There must be something to kill | |||||
oldest = nd.age; | |||||
to_kill = &nd; | |||||
} else if(to_kill->released() && nd.playing()) { | |||||
//Prefer to kill off a running note | |||||
oldest = nd.age; | |||||
to_kill = &nd; | |||||
} else if(nd.age > oldest && !(to_kill->playing() && nd.released())) { | |||||
//Get an older note when it doesn't move from running to released | |||||
oldest = nd.age; | |||||
to_kill = &nd; | |||||
} | |||||
} | |||||
if(to_kill) { | |||||
auto &tk = *to_kill; | |||||
if(tk.released() || tk.sustained()) | |||||
kill(*to_kill); | |||||
else | |||||
entomb(*to_kill); | |||||
} | |||||
} | |||||
void NotePool::releasePlayingNotes(void) | |||||
{ | |||||
for(auto &d:activeDesc()) { | |||||
if(d.playing() || d.sustained()) { | |||||
d.setStatus(KEY_RELEASED); | |||||
for(auto s:activeNotes(d)) | |||||
s.note->releasekey(); | |||||
} | |||||
} | |||||
} | |||||
void NotePool::release(NoteDescriptor &d) | |||||
{ | |||||
d.setStatus(KEY_RELEASED); | |||||
for(auto s:activeNotes(d)) | |||||
s.note->releasekey(); | |||||
} | |||||
void NotePool::killAllNotes(void) | |||||
{ | |||||
for(auto &d:activeDesc()) | |||||
kill(d); | |||||
} | |||||
void NotePool::killNote(uint8_t note) | |||||
{ | |||||
for(auto &d:activeDesc()) { | |||||
if(d.note == note) | |||||
kill(d); | |||||
} | |||||
} | |||||
void NotePool::kill(NoteDescriptor &d) | |||||
{ | |||||
d.setStatus(KEY_OFF); | |||||
for(auto &s:activeNotes(d)) | |||||
kill(s); | |||||
} | |||||
void NotePool::kill(SynthDescriptor &s) | |||||
{ | |||||
//printf("Kill synth...\n"); | |||||
s.note->memory.dealloc(s.note); | |||||
needs_cleaning = true; | |||||
} | |||||
void NotePool::entomb(NoteDescriptor &d) | |||||
{ | |||||
d.setStatus(KEY_RELEASED); | |||||
for(auto &s:activeNotes(d)) | |||||
s.note->entomb(); | |||||
} | |||||
const char *getStatus(int status_bits) | |||||
{ | |||||
switch(status_bits) | |||||
{ | |||||
case 0: return "OFF "; | |||||
case 1: return "PLAY"; | |||||
case 2: return "SUST"; | |||||
case 3: return "RELA"; | |||||
default: return "INVD"; | |||||
} | |||||
} | |||||
void NotePool::cleanup(void) | |||||
{ | |||||
if(!needs_cleaning) | |||||
return; | |||||
needs_cleaning = false; | |||||
int new_length[POLYPHONY] = {0}; | |||||
int cur_length[POLYPHONY] = {0}; | |||||
//printf("Cleanup Start\n"); | |||||
//dump(); | |||||
//Identify the current length of all segments | |||||
//and the lengths discarding invalid entries | |||||
int last_valid_desc = 0; | |||||
for(int i=0; i<POLYPHONY; ++i) | |||||
if(!ndesc[i].off()) | |||||
last_valid_desc = i; | |||||
//Find the real numbers of allocated notes | |||||
{ | |||||
int cum_old = 0; | |||||
for(int i=0; i<=last_valid_desc; ++i) { | |||||
cur_length[i] = ndesc[i].size; | |||||
for(int j=0; j<ndesc[i].size; ++j) | |||||
new_length[i] += (bool)sdesc[cum_old++].note; | |||||
} | |||||
} | |||||
//Move the note descriptors | |||||
{ | |||||
int cum_new = 0; | |||||
for(int i=0; i<=last_valid_desc; ++i) { | |||||
ndesc[i].size = new_length[i]; | |||||
if(new_length[i] != 0) | |||||
ndesc[cum_new++] = ndesc[i]; | |||||
else | |||||
ndesc[i].setStatus(KEY_OFF); | |||||
} | |||||
memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new)); | |||||
} | |||||
//Move the synth descriptors | |||||
{ | |||||
int total_notes=0; | |||||
for(int i=0; i<=last_valid_desc; ++i) | |||||
total_notes+=cur_length[i]; | |||||
int cum_new = 0; | |||||
for(int i=0; i<total_notes; ++i) | |||||
if(sdesc[i].note) | |||||
sdesc[cum_new++] = sdesc[i]; | |||||
memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new)); | |||||
} | |||||
//printf("Cleanup Done\n"); | |||||
//dump(); | |||||
} | |||||
void NotePool::dump(void) | |||||
{ | |||||
printf("NotePool::dump<\n"); | |||||
const char *format = | |||||
" Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n"; | |||||
int note_id=0; | |||||
int descriptor_id=0; | |||||
for(auto &d:activeDesc()) { | |||||
descriptor_id += 1; | |||||
for(auto &s:activeNotes(d)) { | |||||
note_id += 1; | |||||
printf(format, | |||||
note_id, descriptor_id, | |||||
d.age, d.note, d.sendto, | |||||
getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note); | |||||
} | |||||
} | |||||
printf(">NotePool::dump\n"); | |||||
} | |||||
} |
@@ -0,0 +1,151 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
NotePool.h - Pool of Synthesizer Engines And Note Instances | |||||
Copyright (C) 2016 Mark McCurry | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#pragma once | |||||
#include <stdint.h> | |||||
#include <functional> | |||||
#include "../globals.h" | |||||
//Expected upper bound of synths given that max polyphony is hit | |||||
#define EXPECTED_USAGE 3 | |||||
namespace zyncarla { | |||||
struct LegatoParams; | |||||
class NotePool | |||||
{ | |||||
public: | |||||
typedef uint8_t note_t; | |||||
//Currently this wastes a ton of bits due ot the legatoMirror flag | |||||
struct NoteDescriptor { | |||||
//acceptable overlap after 2 minutes | |||||
//run time at 48kHz 8 samples per buffer | |||||
//19 bit minimum | |||||
uint32_t age; | |||||
uint8_t note; | |||||
uint8_t sendto; | |||||
//max of 16 kit elms and 3 kit items per | |||||
uint8_t size; | |||||
uint8_t status; | |||||
bool legatoMirror; | |||||
bool operator==(NoteDescriptor); | |||||
//status checks | |||||
bool playing(void) const; | |||||
bool off(void) const; | |||||
bool sustained(void) const; | |||||
bool released(void) const; | |||||
//status transitions | |||||
void setStatus(uint8_t s); | |||||
void doSustain(void); | |||||
bool canSustain(void) const; | |||||
void makeUnsustainable(void); | |||||
}; | |||||
//To be pedantic this wastes 2 or 6 bytes per descriptor | |||||
//depending on 32bit/64bit alignment rules | |||||
struct SynthDescriptor { | |||||
SynthNote *note; | |||||
uint8_t type; | |||||
uint8_t kit; | |||||
}; | |||||
//Pool of notes | |||||
NoteDescriptor ndesc[POLYPHONY]; | |||||
SynthDescriptor sdesc[POLYPHONY*EXPECTED_USAGE]; | |||||
bool needs_cleaning; | |||||
//Iterators | |||||
struct activeNotesIter { | |||||
SynthDescriptor *begin() {return _b;}; | |||||
SynthDescriptor *end() {return _e;}; | |||||
SynthDescriptor *_b; | |||||
SynthDescriptor *_e; | |||||
}; | |||||
struct activeDescIter { | |||||
activeDescIter(NotePool &_np):np(_np) | |||||
{ | |||||
int off=0; | |||||
for(int i=0; i<POLYPHONY; ++i, ++off) | |||||
if(np.ndesc[i].status == 0) | |||||
break; | |||||
_end = np.ndesc+off; | |||||
} | |||||
NoteDescriptor *begin() {return np.ndesc;}; | |||||
NoteDescriptor *end() { return _end; }; | |||||
NoteDescriptor *_end; | |||||
NotePool &np; | |||||
}; | |||||
struct constActiveDescIter { | |||||
constActiveDescIter(const NotePool &_np):np(_np) | |||||
{ | |||||
int off=0; | |||||
for(int i=0; i<POLYPHONY; ++i, ++off) | |||||
if(np.ndesc[i].status == 0) | |||||
break; | |||||
_end = np.ndesc+off; | |||||
} | |||||
const NoteDescriptor *begin() const {return np.ndesc;}; | |||||
const NoteDescriptor *end() const { return _end; }; | |||||
const NoteDescriptor *_end; | |||||
const NotePool &np; | |||||
}; | |||||
activeNotesIter activeNotes(NoteDescriptor &n); | |||||
activeDescIter activeDesc(void); | |||||
constActiveDescIter activeDesc(void) const; | |||||
//Counts of descriptors used for tests | |||||
int usedNoteDesc(void) const; | |||||
int usedSynthDesc(void) const; | |||||
NotePool(void); | |||||
//Operations | |||||
void insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato=false); | |||||
void insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc); | |||||
void upgradeToLegato(void); | |||||
void applyLegato(LegatoParams &par); | |||||
void makeUnsustainable(uint8_t note); | |||||
bool full(void) const; | |||||
bool synthFull(int sdesc_count) const; | |||||
//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING | |||||
bool existsRunningNote(void) const; | |||||
int getRunningNotes(void) const; | |||||
void enforceKeyLimit(int limit); | |||||
void releasePlayingNotes(void); | |||||
void releaseNote(note_t note); | |||||
void release(NoteDescriptor &d); | |||||
void killAllNotes(void); | |||||
void killNote(note_t note); | |||||
void kill(NoteDescriptor &d); | |||||
void kill(SynthDescriptor &s); | |||||
void entomb(NoteDescriptor &d); | |||||
void cleanup(void); | |||||
void dump(void); | |||||
}; | |||||
} |
@@ -0,0 +1,43 @@ | |||||
#include "ScratchString.h" | |||||
#include <cstring> | |||||
#include <cstdio> | |||||
namespace zyncarla { | |||||
ScratchString::ScratchString(void) | |||||
{ | |||||
memset(c_str, 0, sizeof(c_str)); | |||||
} | |||||
ScratchString::ScratchString(int num) | |||||
{ | |||||
snprintf(c_str, SCRATCH_SIZE, "%d", num); | |||||
} | |||||
ScratchString::ScratchString(unsigned char num) | |||||
{ | |||||
snprintf(c_str, SCRATCH_SIZE, "%d", num); | |||||
} | |||||
ScratchString::ScratchString(const char *str) | |||||
{ | |||||
if(str) | |||||
strncpy(c_str, str, SCRATCH_SIZE); | |||||
else | |||||
memset(c_str, 0, sizeof(c_str)); | |||||
} | |||||
ScratchString ScratchString::operator+(const ScratchString s) | |||||
{ | |||||
ScratchString ss; | |||||
strncpy(ss.c_str, c_str, SCRATCH_SIZE); | |||||
strncat(ss.c_str, s.c_str, SCRATCH_SIZE-strlen(c_str)); | |||||
return ss; | |||||
} | |||||
//ScratchString::operator const char*() const | |||||
//{ | |||||
// return c_str; | |||||
//} | |||||
} |
@@ -0,0 +1,22 @@ | |||||
#pragma once | |||||
#define SCRATCH_SIZE 128 | |||||
namespace zyncarla { | |||||
//Fixed Size String Substitute | |||||
struct ScratchString | |||||
{ | |||||
ScratchString(void); | |||||
ScratchString(int num); | |||||
ScratchString(unsigned char num); | |||||
ScratchString(const char *str); | |||||
ScratchString operator+(const ScratchString s); | |||||
//operator const char*() const; | |||||
char c_str[SCRATCH_SIZE]; | |||||
}; | |||||
} | |||||
@@ -0,0 +1,429 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
AnalogFilter.cpp - Several analog filters (lowpass, highpass...) | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Copyright (C) 2010-2010 Mark McCurry | |||||
Author: Nasca Octavian Paul | |||||
Mark McCurry | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cstring> //memcpy | |||||
#include <cmath> | |||||
#include <cassert> | |||||
#include "../Misc/Util.h" | |||||
#include "AnalogFilter.h" | |||||
namespace zyncarla { | |||||
AnalogFilter::AnalogFilter(unsigned char Ftype, | |||||
float Ffreq, | |||||
float Fq, | |||||
unsigned char Fstages, | |||||
unsigned int srate, int bufsize) | |||||
:Filter(srate, bufsize), | |||||
type(Ftype), | |||||
stages(Fstages), | |||||
freq(Ffreq), | |||||
q(Fq), | |||||
gain(1.0), | |||||
abovenq(false), | |||||
oldabovenq(false) | |||||
{ | |||||
for(int i = 0; i < 3; ++i) | |||||
coeff.c[i] = coeff.d[i] = oldCoeff.c[i] = oldCoeff.d[i] = 0.0f; | |||||
if(stages >= MAX_FILTER_STAGES) | |||||
stages = MAX_FILTER_STAGES; | |||||
cleanup(); | |||||
firsttime = false; | |||||
setfreq_and_q(Ffreq, Fq); | |||||
firsttime = true; | |||||
coeff.d[0] = 0; //this is not used | |||||
outgain = 1.0f; | |||||
} | |||||
AnalogFilter::~AnalogFilter() | |||||
{} | |||||
void AnalogFilter::cleanup() | |||||
{ | |||||
for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) { | |||||
history[i].x1 = 0.0f; | |||||
history[i].x2 = 0.0f; | |||||
history[i].y1 = 0.0f; | |||||
history[i].y2 = 0.0f; | |||||
oldHistory[i] = history[i]; | |||||
} | |||||
needsinterpolation = false; | |||||
} | |||||
AnalogFilter::Coeff AnalogFilter::computeCoeff(int type, float cutoff, float q, | |||||
int stages, float gain, float fs, int &order) | |||||
{ | |||||
AnalogFilter::Coeff coeff; | |||||
bool zerocoefs = false; //this is used if the freq is too high | |||||
const float samplerate_f = fs; | |||||
const float halfsamplerate_f = fs/2; | |||||
//do not allow frequencies bigger than samplerate/2 | |||||
float freq = cutoff; | |||||
if(freq > (halfsamplerate_f - 500.0f)) { | |||||
freq = halfsamplerate_f - 500.0f; | |||||
zerocoefs = true; | |||||
} | |||||
if(freq < 0.1f) | |||||
freq = 0.1f; | |||||
//do not allow bogus Q | |||||
if(q < 0.0f) | |||||
q = 0.0f; | |||||
float tmpq, tmpgain; | |||||
if(stages == 0) { | |||||
tmpq = q; | |||||
tmpgain = gain; | |||||
} else { | |||||
tmpq = (q > 1.0f) ? powf(q, 1.0f / (stages + 1)) : q; | |||||
tmpgain = powf(gain, 1.0f / (stages + 1)); | |||||
} | |||||
//Alias Terms | |||||
float *c = coeff.c; | |||||
float *d = coeff.d; | |||||
//General Constants | |||||
const float omega = 2 * PI * freq / samplerate_f; | |||||
const float sn = sinf(omega), cs = cosf(omega); | |||||
float alpha, beta; | |||||
//most of theese are implementations of | |||||
//the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson | |||||
//The original location of the Cookbook is: | |||||
//http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt | |||||
float tmp; | |||||
float tgp1; | |||||
float tgm1; | |||||
switch(type) { | |||||
case 0: //LPF 1 pole | |||||
if(!zerocoefs) | |||||
tmp = expf(-2.0f * PI * freq / samplerate_f); | |||||
else | |||||
tmp = 0.0f; | |||||
c[0] = 1.0f - tmp; | |||||
c[1] = 0.0f; | |||||
c[2] = 0.0f; | |||||
d[1] = tmp; | |||||
d[2] = 0.0f; | |||||
order = 1; | |||||
break; | |||||
case 1: //HPF 1 pole | |||||
if(!zerocoefs) | |||||
tmp = expf(-2.0f * PI * freq / samplerate_f); | |||||
else | |||||
tmp = 0.0f; | |||||
c[0] = (1.0f + tmp) / 2.0f; | |||||
c[1] = -(1.0f + tmp) / 2.0f; | |||||
c[2] = 0.0f; | |||||
d[1] = tmp; | |||||
d[2] = 0.0f; | |||||
order = 1; | |||||
break; | |||||
case 2: //LPF 2 poles | |||||
if(!zerocoefs) { | |||||
alpha = sn / (2.0f * tmpq); | |||||
tmp = 1 + alpha; | |||||
c[1] = (1.0f - cs) / tmp; | |||||
c[0] = c[2] = c[1] / 2.0f; | |||||
d[1] = -2.0f * cs / tmp * -1.0f; | |||||
d[2] = (1.0f - alpha) / tmp * -1.0f; | |||||
} | |||||
else { | |||||
c[0] = 1.0f; | |||||
c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
} | |||||
order = 2; | |||||
break; | |||||
case 3: //HPF 2 poles | |||||
if(!zerocoefs) { | |||||
alpha = sn / (2.0f * tmpq); | |||||
tmp = 1 + alpha; | |||||
c[0] = (1.0f + cs) / 2.0f / tmp; | |||||
c[1] = -(1.0f + cs) / tmp; | |||||
c[2] = (1.0f + cs) / 2.0f / tmp; | |||||
d[1] = -2.0f * cs / tmp * -1.0f; | |||||
d[2] = (1.0f - alpha) / tmp * -1.0f; | |||||
} | |||||
else | |||||
c[0] = c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
order = 2; | |||||
break; | |||||
case 4: //BPF 2 poles | |||||
if(!zerocoefs) { | |||||
alpha = sn / (2.0f * tmpq); | |||||
tmp = 1.0f + alpha; | |||||
c[0] = alpha / tmp *sqrtf(tmpq + 1.0f); | |||||
c[1] = 0.0f; | |||||
c[2] = -alpha / tmp *sqrtf(tmpq + 1.0f); | |||||
d[1] = -2.0f * cs / tmp * -1.0f; | |||||
d[2] = (1.0f - alpha) / tmp * -1.0f; | |||||
} | |||||
else | |||||
c[0] = c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
order = 2; | |||||
break; | |||||
case 5: //NOTCH 2 poles | |||||
if(!zerocoefs) { | |||||
alpha = sn / (2.0f * sqrtf(tmpq)); | |||||
tmp = 1.0f + alpha; | |||||
c[0] = 1.0f / tmp; | |||||
c[1] = -2.0f * cs / tmp; | |||||
c[2] = 1.0f / tmp; | |||||
d[1] = -2.0f * cs / tmp * -1.0f; | |||||
d[2] = (1.0f - alpha) / tmp * -1.0f; | |||||
} | |||||
else { | |||||
c[0] = 1.0f; | |||||
c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
} | |||||
order = 2; | |||||
break; | |||||
case 6: //PEAK (2 poles) | |||||
if(!zerocoefs) { | |||||
tmpq *= 3.0f; | |||||
alpha = sn / (2.0f * tmpq); | |||||
tmp = 1.0f + alpha / tmpgain; | |||||
c[0] = (1.0f + alpha * tmpgain) / tmp; | |||||
c[1] = (-2.0f * cs) / tmp; | |||||
c[2] = (1.0f - alpha * tmpgain) / tmp; | |||||
d[1] = -2.0f * cs / tmp * -1.0f; | |||||
d[2] = (1.0f - alpha / tmpgain) / tmp * -1.0f; | |||||
} | |||||
else { | |||||
c[0] = 1.0f; | |||||
c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
} | |||||
order = 2; | |||||
break; | |||||
case 7: //Low Shelf - 2 poles | |||||
if(!zerocoefs) { | |||||
tmpq = sqrtf(tmpq); | |||||
beta = sqrtf(tmpgain) / tmpq; | |||||
tgp1 = tmpgain + 1.0f; | |||||
tgm1 = tmpgain - 1.0f; | |||||
tmp = tgp1 + tgm1 * cs + beta * sn; | |||||
c[0] = tmpgain * (tgp1 - tgm1 * cs + beta * sn) / tmp; | |||||
c[1] = 2.0f * tmpgain * (tgm1 - tgp1 * cs) / tmp; | |||||
c[2] = tmpgain * (tgp1 - tgm1 * cs - beta * sn) / tmp; | |||||
d[1] = -2.0f * (tgm1 + tgp1 * cs) / tmp * -1.0f; | |||||
d[2] = (tgp1 + tgm1 * cs - beta * sn) / tmp * -1.0f; | |||||
} | |||||
else { | |||||
c[0] = tmpgain; | |||||
c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
} | |||||
order = 2; | |||||
break; | |||||
case 8: //High Shelf - 2 poles | |||||
if(!zerocoefs) { | |||||
tmpq = sqrtf(tmpq); | |||||
beta = sqrtf(tmpgain) / tmpq; | |||||
tgp1 = tmpgain + 1.0f; | |||||
tgm1 = tmpgain - 1.0f; | |||||
tmp = tgp1 - tgm1 * cs + beta * sn; | |||||
c[0] = tmpgain * (tgp1 + tgm1 * cs + beta * sn) / tmp; | |||||
c[1] = -2.0f * tmpgain * (tgm1 + tgp1 * cs) / tmp; | |||||
c[2] = tmpgain * (tgp1 + tgm1 * cs - beta * sn) / tmp; | |||||
d[1] = 2.0f * (tgm1 - tgp1 * cs) / tmp * -1.0f; | |||||
d[2] = (tgp1 - tgm1 * cs - beta * sn) / tmp * -1.0f; | |||||
} | |||||
else { | |||||
c[0] = 1.0f; | |||||
c[1] = c[2] = d[1] = d[2] = 0.0f; | |||||
} | |||||
order = 2; | |||||
break; | |||||
default: //wrong type | |||||
assert(false && "wrong type for a filter"); | |||||
break; | |||||
} | |||||
return coeff; | |||||
} | |||||
void AnalogFilter::computefiltercoefs(void) | |||||
{ | |||||
coeff = AnalogFilter::computeCoeff(type, freq, q, stages, gain, | |||||
samplerate_f, order); | |||||
} | |||||
void AnalogFilter::setfreq(float frequency) | |||||
{ | |||||
if(frequency < 0.1f) | |||||
frequency = 0.1f; | |||||
float rap = freq / frequency; | |||||
if(rap < 1.0f) | |||||
rap = 1.0f / rap; | |||||
oldabovenq = abovenq; | |||||
abovenq = frequency > (halfsamplerate_f - 500.0f); | |||||
bool nyquistthresh = (abovenq ^ oldabovenq); | |||||
//if the frequency is changed fast, it needs interpolation | |||||
if((rap > 3.0f) || nyquistthresh) { //(now, filter and coeficients backup) | |||||
oldCoeff = coeff; | |||||
for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) | |||||
oldHistory[i] = history[i]; | |||||
if(!firsttime) | |||||
needsinterpolation = true; | |||||
} | |||||
freq = frequency; | |||||
computefiltercoefs(); | |||||
firsttime = false; | |||||
} | |||||
void AnalogFilter::setfreq_and_q(float frequency, float q_) | |||||
{ | |||||
q = q_; | |||||
setfreq(frequency); | |||||
} | |||||
void AnalogFilter::setq(float q_) | |||||
{ | |||||
q = q_; | |||||
computefiltercoefs(); | |||||
} | |||||
void AnalogFilter::settype(int type_) | |||||
{ | |||||
type = type_; | |||||
computefiltercoefs(); | |||||
} | |||||
void AnalogFilter::setgain(float dBgain) | |||||
{ | |||||
gain = dB2rap(dBgain); | |||||
computefiltercoefs(); | |||||
} | |||||
void AnalogFilter::setstages(int stages_) | |||||
{ | |||||
if(stages_ >= MAX_FILTER_STAGES) | |||||
stages_ = MAX_FILTER_STAGES - 1; | |||||
if(stages_ != stages) { | |||||
stages = stages_; | |||||
cleanup(); | |||||
computefiltercoefs(); | |||||
} | |||||
} | |||||
inline void AnalogBiquadFilterA(const float coeff[5], float &src, float work[4]) | |||||
{ | |||||
work[3] = src*coeff[0] | |||||
+ work[0]*coeff[1] | |||||
+ work[1]*coeff[2] | |||||
+ work[2]*coeff[3] | |||||
+ work[3]*coeff[4]; | |||||
work[1] = src; | |||||
src = work[3]; | |||||
} | |||||
inline void AnalogBiquadFilterB(const float coeff[5], float &src, float work[4]) | |||||
{ | |||||
work[2] = src*coeff[0] | |||||
+ work[1]*coeff[1] | |||||
+ work[0]*coeff[2] | |||||
+ work[3]*coeff[3] | |||||
+ work[2]*coeff[4]; | |||||
work[0] = src; | |||||
src = work[2]; | |||||
} | |||||
void AnalogFilter::singlefilterout(float *smp, fstage &hist, | |||||
const Coeff &coeff) | |||||
{ | |||||
assert((buffersize % 8) == 0); | |||||
if(order == 1) { //First order filter | |||||
for(int i = 0; i < buffersize; ++i) { | |||||
float y0 = smp[i] * coeff.c[0] + hist.x1 * coeff.c[1] | |||||
+ hist.y1 * coeff.d[1]; | |||||
hist.y1 = y0; | |||||
hist.x1 = smp[i]; | |||||
smp[i] = y0; | |||||
} | |||||
} else if(order == 2) {//Second order filter | |||||
const float coeff_[5] = {coeff.c[0], coeff.c[1], coeff.c[2], coeff.d[1], coeff.d[2]}; | |||||
float work[4] = {hist.x1, hist.x2, hist.y1, hist.y2}; | |||||
for(int i = 0; i < buffersize; i+=8) { | |||||
AnalogBiquadFilterA(coeff_, smp[i + 0], work); | |||||
AnalogBiquadFilterB(coeff_, smp[i + 1], work); | |||||
AnalogBiquadFilterA(coeff_, smp[i + 2], work); | |||||
AnalogBiquadFilterB(coeff_, smp[i + 3], work); | |||||
AnalogBiquadFilterA(coeff_, smp[i + 4], work); | |||||
AnalogBiquadFilterB(coeff_, smp[i + 5], work); | |||||
AnalogBiquadFilterA(coeff_, smp[i + 6], work); | |||||
AnalogBiquadFilterB(coeff_, smp[i + 7], work); | |||||
} | |||||
hist.x1 = work[0]; | |||||
hist.x2 = work[1]; | |||||
hist.y1 = work[2]; | |||||
hist.y2 = work[3]; | |||||
} | |||||
} | |||||
void AnalogFilter::filterout(float *smp) | |||||
{ | |||||
for(int i = 0; i < stages + 1; ++i) | |||||
singlefilterout(smp, history[i], coeff); | |||||
if(needsinterpolation) { | |||||
//Merge Filter at old coeff with new coeff | |||||
float ismp[buffersize]; | |||||
memcpy(ismp, smp, bufferbytes); | |||||
for(int i = 0; i < stages + 1; ++i) | |||||
singlefilterout(ismp, oldHistory[i], oldCoeff); | |||||
for(int i = 0; i < buffersize; ++i) { | |||||
float x = (float)i / buffersize_f; | |||||
smp[i] = ismp[i] * (1.0f - x) + smp[i] * x; | |||||
} | |||||
needsinterpolation = false; | |||||
} | |||||
for(int i = 0; i < buffersize; ++i) | |||||
smp[i] *= outgain; | |||||
} | |||||
float AnalogFilter::H(float freq) | |||||
{ | |||||
float fr = freq / samplerate_f * PI * 2.0f; | |||||
float x = coeff.c[0], y = 0.0f; | |||||
for(int n = 1; n < 3; ++n) { | |||||
x += cosf(n * fr) * coeff.c[n]; | |||||
y -= sinf(n * fr) * coeff.c[n]; | |||||
} | |||||
float h = x * x + y * y; | |||||
x = 1.0f; | |||||
y = 0.0f; | |||||
for(int n = 1; n < 3; ++n) { | |||||
x -= cosf(n * fr) * coeff.d[n]; | |||||
y += sinf(n * fr) * coeff.d[n]; | |||||
} | |||||
h = h / (x * x + y * y); | |||||
return powf(h, (stages + 1.0f) / 2.0f); | |||||
} | |||||
} |
@@ -0,0 +1,84 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Analog Filter.h - Several analog filters (lowpass, highpass...) | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Copyright (C) 2010-2010 Mark McCurry | |||||
Author: Nasca Octavian Paul | |||||
Mark McCurry | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef ANALOG_FILTER_H | |||||
#define ANALOG_FILTER_H | |||||
#include "../globals.h" | |||||
#include "Filter.h" | |||||
namespace zyncarla { | |||||
/**Implementation of Several analog filters (lowpass, highpass...) | |||||
* Implemented with IIR filters | |||||
* Coefficients generated with "Cookbook formulae for audio EQ"*/ | |||||
class AnalogFilter:public Filter | |||||
{ | |||||
public: | |||||
AnalogFilter(unsigned char Ftype, float Ffreq, float Fq, | |||||
unsigned char Fstages, unsigned int srate, int bufsize); | |||||
~AnalogFilter(); | |||||
void filterout(float *smp); | |||||
void setfreq(float frequency); | |||||
void setfreq_and_q(float frequency, float q_); | |||||
void setq(float q_); | |||||
void settype(int type_); | |||||
void setgain(float dBgain); | |||||
void setstages(int stages_); | |||||
void cleanup(); | |||||
float H(float freq); //Obtains the response for a given frequency | |||||
struct Coeff { | |||||
float c[3], //Feed Forward | |||||
d[3]; //Feed Back | |||||
} coeff, oldCoeff; | |||||
static Coeff computeCoeff(int type, float cutoff, float q, int stages, | |||||
float gain, float fs, int &order); | |||||
private: | |||||
struct fstage { | |||||
float x1, x2; //Input History | |||||
float y1, y2; //Output History | |||||
} history[MAX_FILTER_STAGES + 1], oldHistory[MAX_FILTER_STAGES + 1]; | |||||
//old coeffs are used for interpolation when paremeters change quickly | |||||
//Apply IIR filter to Samples, with coefficients, and past history | |||||
void singlefilterout(float *smp, fstage &hist, const Coeff &coeff); | |||||
//Update coeff and order | |||||
void computefiltercoefs(void); | |||||
int type; //The type of the filter (LPF1,HPF1,LPF2,HPF2...) | |||||
int stages; //how many times the filter is applied (0->1,1->2,etc.) | |||||
float freq; //Frequency given in Hz | |||||
float q; //Q factor (resonance or Q factor) | |||||
float gain; //the gain of the filter (if are shelf/peak) filters | |||||
int order; //the order of the filter (number of poles) | |||||
bool needsinterpolation, //Interpolation between coeff changes | |||||
firsttime; //First Iteration of filter | |||||
bool abovenq, //if the frequency is above the nyquist | |||||
oldabovenq; //if the last time was above nyquist | |||||
//(used to see if it needs interpolation) | |||||
}; | |||||
} | |||||
#endif |
@@ -0,0 +1,97 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
FFTwrapper.c - A wrapper for Fast Fourier Transforms | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cmath> | |||||
#include <cassert> | |||||
#include <cstring> | |||||
#include <pthread.h> | |||||
#include "FFTwrapper.h" | |||||
namespace zyncarla { | |||||
static pthread_mutex_t *mutex = NULL; | |||||
FFTwrapper::FFTwrapper(int fftsize_) | |||||
{ | |||||
//first one will spawn the mutex (yeah this may be a race itself) | |||||
if(!mutex) { | |||||
mutex = new pthread_mutex_t; | |||||
pthread_mutex_init(mutex, NULL); | |||||
} | |||||
fftsize = fftsize_; | |||||
time = new fftw_real[fftsize]; | |||||
fft = new fftw_complex[fftsize + 1]; | |||||
pthread_mutex_lock(mutex); | |||||
planfftw = fftw_plan_dft_r2c_1d(fftsize, | |||||
time, | |||||
fft, | |||||
FFTW_ESTIMATE); | |||||
planfftw_inv = fftw_plan_dft_c2r_1d(fftsize, | |||||
fft, | |||||
time, | |||||
FFTW_ESTIMATE); | |||||
pthread_mutex_unlock(mutex); | |||||
} | |||||
FFTwrapper::~FFTwrapper() | |||||
{ | |||||
pthread_mutex_lock(mutex); | |||||
fftw_destroy_plan(planfftw); | |||||
fftw_destroy_plan(planfftw_inv); | |||||
pthread_mutex_unlock(mutex); | |||||
delete [] time; | |||||
delete [] fft; | |||||
} | |||||
void FFTwrapper::smps2freqs(const float *smps, fft_t *freqs) | |||||
{ | |||||
//Load data | |||||
for(int i = 0; i < fftsize; ++i) | |||||
time[i] = static_cast<double>(smps[i]); | |||||
//DFT | |||||
fftw_execute(planfftw); | |||||
//Grab data | |||||
memcpy((void *)freqs, (const void *)fft, fftsize * sizeof(double)); | |||||
} | |||||
void FFTwrapper::freqs2smps(const fft_t *freqs, float *smps) | |||||
{ | |||||
//Load data | |||||
memcpy((void *)fft, (const void *)freqs, fftsize * sizeof(double)); | |||||
//clear unused freq channel | |||||
fft[fftsize / 2][0] = 0.0f; | |||||
fft[fftsize / 2][1] = 0.0f; | |||||
//IDFT | |||||
fftw_execute(planfftw_inv); | |||||
//Grab data | |||||
for(int i = 0; i < fftsize; ++i) | |||||
smps[i] = static_cast<float>(time[i]); | |||||
} | |||||
void FFT_cleanup() | |||||
{ | |||||
fftw_cleanup(); | |||||
pthread_mutex_destroy(mutex); | |||||
delete mutex; | |||||
mutex = NULL; | |||||
} | |||||
} |
@@ -0,0 +1,66 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
FFTwrapper.h - A wrapper for Fast Fourier Transforms | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef FFT_WRAPPER_H | |||||
#define FFT_WRAPPER_H | |||||
#include <fftw3.h> | |||||
#include <complex> | |||||
#include "../globals.h" | |||||
namespace zyncarla { | |||||
/**A wrapper for the FFTW library (Fast Fourier Transforms)*/ | |||||
class FFTwrapper | |||||
{ | |||||
public: | |||||
/**Constructor | |||||
* @param fftsize The size of samples to be fed to fftw*/ | |||||
FFTwrapper(int fftsize_); | |||||
/**Destructor*/ | |||||
~FFTwrapper(); | |||||
/**Convert Samples to Frequencies using Fourier Transform | |||||
* @param smps Pointer to Samples to be converted; has length fftsize_ | |||||
* @param freqs Structure FFTFREQS which stores the frequencies*/ | |||||
void smps2freqs(const float *smps, fft_t *freqs); | |||||
void freqs2smps(const fft_t *freqs, float *smps); | |||||
private: | |||||
int fftsize; | |||||
fftw_real *time; | |||||
fftw_complex *fft; | |||||
fftw_plan planfftw, planfftw_inv; | |||||
}; | |||||
/* | |||||
* The "std::polar" template has no clear definition for the range of | |||||
* the input parameters, and some C++ standard library implementations | |||||
* don't accept negative amplitude among others. Define our own | |||||
* FFTpolar template, which works like we expect it to. | |||||
*/ | |||||
template<class _Tp> | |||||
std::complex<_Tp> | |||||
FFTpolar(const _Tp& __rho, const _Tp& __theta = _Tp(0)) | |||||
{ | |||||
_Tp __x = __rho * cos(__theta); | |||||
if (std::isnan(__x)) | |||||
__x = 0; | |||||
_Tp __y = __rho * sin(__theta); | |||||
if (std::isnan(__y)) | |||||
__y = 0; | |||||
return std::complex<_Tp>(__x, __y); | |||||
} | |||||
void FFT_cleanup(); | |||||
} | |||||
#endif |
@@ -0,0 +1,71 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Filter.cpp - Filters, uses analog,formant,etc. filters | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cmath> | |||||
#include <cstdio> | |||||
#include <cassert> | |||||
#include "Filter.h" | |||||
#include "AnalogFilter.h" | |||||
#include "FormantFilter.h" | |||||
#include "SVFilter.h" | |||||
#include "../Params/FilterParams.h" | |||||
#include "../Misc/Allocator.h" | |||||
namespace zyncarla { | |||||
Filter::Filter(unsigned int srate, int bufsize) | |||||
: outgain(1.0f), | |||||
samplerate(srate), | |||||
buffersize(bufsize) | |||||
{ | |||||
alias(); | |||||
} | |||||
Filter *Filter::generate(Allocator &memory, const FilterParams *pars, | |||||
unsigned int srate, int bufsize) | |||||
{ | |||||
assert(srate != 0); | |||||
assert(bufsize != 0); | |||||
unsigned char Ftype = pars->Ptype; | |||||
unsigned char Fstages = pars->Pstages; | |||||
Filter *filter; | |||||
switch(pars->Pcategory) { | |||||
case 1: | |||||
filter = memory.alloc<FormantFilter>(pars, &memory, srate, bufsize); | |||||
break; | |||||
case 2: | |||||
filter = memory.alloc<SVFilter>(Ftype, 1000.0f, pars->getq(), Fstages, srate, bufsize); | |||||
filter->outgain = dB2rap(pars->getgain()); | |||||
if(filter->outgain > 1.0f) | |||||
filter->outgain = sqrt(filter->outgain); | |||||
break; | |||||
default: | |||||
filter = memory.alloc<AnalogFilter>(Ftype, 1000.0f, pars->getq(), Fstages, srate, bufsize); | |||||
if((Ftype >= 6) && (Ftype <= 8)) | |||||
filter->setgain(pars->getgain()); | |||||
else | |||||
filter->outgain = dB2rap(pars->getgain()); | |||||
break; | |||||
} | |||||
return filter; | |||||
} | |||||
float Filter::getrealfreq(float freqpitch) | |||||
{ | |||||
return powf(2.0f, freqpitch + 9.96578428f); //log2(1000)=9.95748f | |||||
} | |||||
} |
@@ -0,0 +1,60 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Filter.h - Filters, uses analog,formant,etc. filters | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef FILTER_H | |||||
#define FILTER_H | |||||
#include "../globals.h" | |||||
namespace zyncarla { | |||||
class Filter | |||||
{ | |||||
public: | |||||
static float getrealfreq(float freqpitch); | |||||
static Filter *generate(Allocator &memory, const FilterParams *pars, | |||||
unsigned int srate, int bufsize); | |||||
Filter(unsigned int srate, int bufsize); | |||||
virtual ~Filter() {} | |||||
virtual void filterout(float *smp) = 0; | |||||
virtual void setfreq(float frequency) = 0; | |||||
virtual void setfreq_and_q(float frequency, float q_) = 0; | |||||
virtual void setq(float q_) = 0; | |||||
virtual void setgain(float dBgain) = 0; | |||||
protected: | |||||
float outgain; | |||||
// current setup | |||||
unsigned int samplerate; | |||||
int buffersize; | |||||
// alias for above terms | |||||
float samplerate_f; | |||||
float halfsamplerate_f; | |||||
float buffersize_f; | |||||
int bufferbytes; | |||||
inline void alias() | |||||
{ | |||||
samplerate_f = samplerate; | |||||
halfsamplerate_f = samplerate_f / 2.0f; | |||||
buffersize_f = buffersize; | |||||
bufferbytes = buffersize * sizeof(float); | |||||
} | |||||
}; | |||||
} | |||||
#endif |
@@ -0,0 +1,221 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
FormantFilter.cpp - formant filters | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cmath> | |||||
#include <cstdio> | |||||
#include "../Misc/Util.h" | |||||
#include "../Misc/Allocator.h" | |||||
#include "FormantFilter.h" | |||||
#include "AnalogFilter.h" | |||||
#include "../Params/FilterParams.h" | |||||
namespace zyncarla { | |||||
FormantFilter::FormantFilter(const FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize) | |||||
:Filter(srate, bufsize), memory(*alloc) | |||||
{ | |||||
numformants = pars->Pnumformants; | |||||
for(int i = 0; i < numformants; ++i) | |||||
formant[i] = memory.alloc<AnalogFilter>(4 /*BPF*/, 1000.0f, 10.0f, pars->Pstages, srate, bufsize); | |||||
cleanup(); | |||||
for(int j = 0; j < FF_MAX_VOWELS; ++j) | |||||
for(int i = 0; i < numformants; ++i) { | |||||
formantpar[j][i].freq = pars->getformantfreq( | |||||
pars->Pvowels[j].formants[i].freq); | |||||
formantpar[j][i].amp = pars->getformantamp( | |||||
pars->Pvowels[j].formants[i].amp); | |||||
formantpar[j][i].q = pars->getformantq( | |||||
pars->Pvowels[j].formants[i].q); | |||||
} | |||||
for(int i = 0; i < FF_MAX_FORMANTS; ++i) | |||||
oldformantamp[i] = 1.0f; | |||||
for(int i = 0; i < numformants; ++i) { | |||||
currentformants[i].freq = 1000.0f; | |||||
currentformants[i].amp = 1.0f; | |||||
currentformants[i].q = 2.0f; | |||||
} | |||||
formantslowness = powf(1.0f - (pars->Pformantslowness / 128.0f), 3.0f); | |||||
sequencesize = pars->Psequencesize; | |||||
if(sequencesize == 0) | |||||
sequencesize = 1; | |||||
for(int k = 0; k < sequencesize; ++k) | |||||
sequence[k].nvowel = pars->Psequence[k].nvowel; | |||||
vowelclearness = powf(10.0f, (pars->Pvowelclearness - 32.0f) / 48.0f); | |||||
sequencestretch = powf(0.1f, (pars->Psequencestretch - 32.0f) / 48.0f); | |||||
if(pars->Psequencereversed) | |||||
sequencestretch *= -1.0f; | |||||
outgain = dB2rap(pars->getgain()); | |||||
oldinput = -1.0f; | |||||
Qfactor = pars->getq(); | |||||
oldQfactor = Qfactor; | |||||
firsttime = 1; | |||||
} | |||||
FormantFilter::~FormantFilter() | |||||
{ | |||||
for(int i = 0; i < numformants; ++i) | |||||
memory.dealloc(formant[i]); | |||||
} | |||||
void FormantFilter::cleanup() | |||||
{ | |||||
for(int i = 0; i < numformants; ++i) | |||||
formant[i]->cleanup(); | |||||
} | |||||
inline float log_2(float x) | |||||
{ | |||||
return logf(x) / logf(2.0f); | |||||
} | |||||
void FormantFilter::setpos(float frequency) | |||||
{ | |||||
int p1, p2; | |||||
//Convert form real freq[Hz] | |||||
const float input = log_2(frequency) - 9.96578428f; //log2(1000)=9.95748f. | |||||
if(firsttime != 0) | |||||
slowinput = input; | |||||
else | |||||
slowinput = slowinput | |||||
* (1.0f - formantslowness) + input * formantslowness; | |||||
if((fabsf(oldinput - input) < 0.001f) && (fabsf(slowinput - input) < 0.001f) | |||||
&& (fabsf(Qfactor - oldQfactor) < 0.001f)) { | |||||
// oldinput=input; daca setez asta, o sa faca probleme la schimbari foarte lente | |||||
firsttime = 0; | |||||
return; | |||||
} | |||||
else | |||||
oldinput = input; | |||||
float pos = input * sequencestretch; | |||||
pos -= floorf(pos); | |||||
F2I(pos * sequencesize, p2); | |||||
p1 = p2 - 1; | |||||
if(p1 < 0) | |||||
p1 += sequencesize; | |||||
pos = pos * sequencesize; | |||||
pos -= floorf(pos); | |||||
pos = | |||||
(atanf((pos * 2.0f | |||||
- 1.0f) | |||||
* vowelclearness) / atanf(vowelclearness) + 1.0f) * 0.5f; | |||||
p1 = sequence[p1].nvowel; | |||||
p2 = sequence[p2].nvowel; | |||||
if(firsttime != 0) { | |||||
for(int i = 0; i < numformants; ++i) { | |||||
currentformants[i].freq = | |||||
formantpar[p1][i].freq | |||||
* (1.0f - pos) + formantpar[p2][i].freq * pos; | |||||
currentformants[i].amp = | |||||
formantpar[p1][i].amp | |||||
* (1.0f - pos) + formantpar[p2][i].amp * pos; | |||||
currentformants[i].q = | |||||
formantpar[p1][i].q * (1.0f - pos) + formantpar[p2][i].q * pos; | |||||
formant[i]->setfreq_and_q(currentformants[i].freq, | |||||
currentformants[i].q * Qfactor); | |||||
oldformantamp[i] = currentformants[i].amp; | |||||
} | |||||
firsttime = 0; | |||||
} | |||||
else | |||||
for(int i = 0; i < numformants; ++i) { | |||||
currentformants[i].freq = | |||||
currentformants[i].freq * (1.0f - formantslowness) | |||||
+ (formantpar[p1][i].freq | |||||
* (1.0f - pos) + formantpar[p2][i].freq * pos) | |||||
* formantslowness; | |||||
currentformants[i].amp = | |||||
currentformants[i].amp * (1.0f - formantslowness) | |||||
+ (formantpar[p1][i].amp * (1.0f - pos) | |||||
+ formantpar[p2][i].amp * pos) * formantslowness; | |||||
currentformants[i].q = currentformants[i].q | |||||
* (1.0f - formantslowness) | |||||
+ (formantpar[p1][i].q * (1.0f - pos) | |||||
+ formantpar[p2][i].q | |||||
* pos) * formantslowness; | |||||
formant[i]->setfreq_and_q(currentformants[i].freq, | |||||
currentformants[i].q * Qfactor); | |||||
} | |||||
oldQfactor = Qfactor; | |||||
} | |||||
void FormantFilter::setfreq(float frequency) | |||||
{ | |||||
setpos(frequency); | |||||
} | |||||
void FormantFilter::setq(float q_) | |||||
{ | |||||
Qfactor = q_; | |||||
for(int i = 0; i < numformants; ++i) | |||||
formant[i]->setq(Qfactor * currentformants[i].q); | |||||
} | |||||
void FormantFilter::setgain(float /*dBgain*/) | |||||
{} | |||||
void FormantFilter::setfreq_and_q(float frequency, float q_) | |||||
{ | |||||
Qfactor = q_; | |||||
setpos(frequency); | |||||
} | |||||
void FormantFilter::filterout(float *smp) | |||||
{ | |||||
float inbuffer[buffersize]; | |||||
memcpy(inbuffer, smp, bufferbytes); | |||||
memset(smp, 0, bufferbytes); | |||||
for(int j = 0; j < numformants; ++j) { | |||||
float tmpbuf[buffersize]; | |||||
for(int i = 0; i < buffersize; ++i) | |||||
tmpbuf[i] = inbuffer[i] * outgain; | |||||
formant[j]->filterout(tmpbuf); | |||||
if(ABOVE_AMPLITUDE_THRESHOLD(oldformantamp[j], currentformants[j].amp)) | |||||
for(int i = 0; i < buffersize; ++i) | |||||
smp[i] += tmpbuf[i] | |||||
* INTERPOLATE_AMPLITUDE(oldformantamp[j], | |||||
currentformants[j].amp, | |||||
i, | |||||
buffersize); | |||||
else | |||||
for(int i = 0; i < buffersize; ++i) | |||||
smp[i] += tmpbuf[i] * currentformants[j].amp; | |||||
oldformantamp[j] = currentformants[j].amp; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,61 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
FormantFilter.h - formant filter | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef FORMANT_FILTER_H | |||||
#define FORMANT_FILTER_H | |||||
#include "../globals.h" | |||||
#include "Filter.h" | |||||
namespace zyncarla { | |||||
class FormantFilter:public Filter | |||||
{ | |||||
public: | |||||
FormantFilter(const FilterParams *pars, Allocator *alloc, unsigned int srate, int bufsize); | |||||
~FormantFilter(); | |||||
void filterout(float *smp); | |||||
void setfreq(float frequency); | |||||
void setfreq_and_q(float frequency, float q_); | |||||
void setq(float q_); | |||||
void setgain(float dBgain); | |||||
void cleanup(void); | |||||
private: | |||||
void setpos(float input); | |||||
class AnalogFilter * formant[FF_MAX_FORMANTS]; | |||||
struct { | |||||
float freq, amp, q; //frequency,amplitude,Q | |||||
} formantpar[FF_MAX_VOWELS][FF_MAX_FORMANTS], | |||||
currentformants[FF_MAX_FORMANTS]; | |||||
struct { | |||||
unsigned char nvowel; | |||||
} sequence [FF_MAX_SEQUENCE]; | |||||
float oldformantamp[FF_MAX_FORMANTS]; | |||||
int sequencesize, numformants, firsttime; | |||||
float oldinput, slowinput; | |||||
float Qfactor, formantslowness, oldQfactor; | |||||
float vowelclearness, sequencestretch; | |||||
Allocator &memory; | |||||
}; | |||||
} | |||||
#endif |
@@ -0,0 +1,235 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
SVFilter.cpp - Several state-variable filters | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cmath> | |||||
#include <cstdio> | |||||
#include <cstring> | |||||
#include <cassert> | |||||
#include "../Misc/Util.h" | |||||
#include "SVFilter.h" | |||||
#define errx(...) {} | |||||
#define warnx(...) {} | |||||
#ifndef errx | |||||
#include <err.h> | |||||
#endif | |||||
namespace zyncarla { | |||||
SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq, | |||||
unsigned char Fstages, unsigned int srate, int bufsize) | |||||
:Filter(srate, bufsize), | |||||
type(Ftype), | |||||
stages(Fstages), | |||||
freq(Ffreq), | |||||
q(Fq), | |||||
gain(1.0f), | |||||
needsinterpolation(false), | |||||
firsttime(true) | |||||
{ | |||||
if(stages >= MAX_FILTER_STAGES) | |||||
stages = MAX_FILTER_STAGES; | |||||
outgain = 1.0f; | |||||
cleanup(); | |||||
setfreq_and_q(Ffreq, Fq); | |||||
} | |||||
SVFilter::~SVFilter() | |||||
{} | |||||
void SVFilter::cleanup() | |||||
{ | |||||
for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) | |||||
st[i].low = st[i].high = st[i].band = st[i].notch = 0.0f; | |||||
oldabovenq = false; | |||||
abovenq = false; | |||||
} | |||||
SVFilter::response::response(float b0, float b1, float b2, | |||||
float a0, float a1 ,float a2) | |||||
{ | |||||
a[0] = a0; | |||||
a[1] = a1; | |||||
a[2] = a2; | |||||
b[0] = b0; | |||||
b[1] = b1; | |||||
b[2] = b2; | |||||
} | |||||
SVFilter::response SVFilter::computeResponse(int type, | |||||
float freq, float pq, int stages, float gain, float fs) | |||||
{ | |||||
typedef SVFilter::response res; | |||||
float f = freq / fs * 4.0; | |||||
if(f > 0.99999f) | |||||
f = 0.99999f; | |||||
float q = 1.0f - atanf(sqrtf(pq)) * 2.0f / PI; | |||||
q = powf(q, 1.0f / (stages + 1)); | |||||
float qrt = sqrtf(q); | |||||
float g = powf(gain, 1.0 / (stages + 1)); | |||||
if(type == 0) { //Low | |||||
return res{0, g*f*f*qrt, 0, | |||||
1, (q*f+f*f-2), (1-q*f)}; | |||||
} | |||||
if(type == 1) {//High | |||||
//g *= qrt/(1+f*q); | |||||
g *= qrt; | |||||
return res{g, -2*g, g, | |||||
//1, (f*f-2*f*q-2)/(1+f*q), 1}; | |||||
1, (q*f+f*f-2), (1-q*f)}; | |||||
} | |||||
if(type == 2) {//Band | |||||
g *= f*qrt; | |||||
return res{g, -g, 0, | |||||
1, (q*f+f*f-2), (1-q*f)}; | |||||
} | |||||
if(type == 3 || true) {//Notch | |||||
g *= qrt; | |||||
return res{g, -2*g+g*f*f, g, | |||||
1, (q*f+f*f-2), (1-q*f)}; | |||||
} | |||||
} | |||||
void SVFilter::computefiltercoefs(void) | |||||
{ | |||||
par.f = freq / samplerate_f * 4.0f; | |||||
if(par.f > 0.99999f) | |||||
par.f = 0.99999f; | |||||
par.q = 1.0f - atanf(sqrtf(q)) * 2.0f / PI; | |||||
par.q = powf(par.q, 1.0f / (stages + 1)); | |||||
par.q_sqrt = sqrtf(par.q); | |||||
} | |||||
void SVFilter::setfreq(float frequency) | |||||
{ | |||||
if(frequency < 0.1f) | |||||
frequency = 0.1f; | |||||
float rap = freq / frequency; | |||||
if(rap < 1.0f) | |||||
rap = 1.0f / rap; | |||||
oldabovenq = abovenq; | |||||
abovenq = frequency > (samplerate_f / 2 - 500.0f); | |||||
bool nyquistthresh = (abovenq ^ oldabovenq); | |||||
//if the frequency is changed fast, it needs interpolation | |||||
if((rap > 3.0f) || nyquistthresh) { //(now, filter and coefficients backup) | |||||
if(!firsttime) | |||||
needsinterpolation = true; | |||||
ipar = par; | |||||
} | |||||
freq = frequency; | |||||
computefiltercoefs(); | |||||
firsttime = false; | |||||
} | |||||
void SVFilter::setfreq_and_q(float frequency, float q_) | |||||
{ | |||||
q = q_; | |||||
setfreq(frequency); | |||||
} | |||||
void SVFilter::setq(float q_) | |||||
{ | |||||
q = q_; | |||||
computefiltercoefs(); | |||||
} | |||||
void SVFilter::settype(int type_) | |||||
{ | |||||
type = type_; | |||||
computefiltercoefs(); | |||||
} | |||||
void SVFilter::setgain(float dBgain) | |||||
{ | |||||
gain = dB2rap(dBgain); | |||||
computefiltercoefs(); | |||||
} | |||||
void SVFilter::setstages(int stages_) | |||||
{ | |||||
if(stages_ >= MAX_FILTER_STAGES) | |||||
stages_ = MAX_FILTER_STAGES - 1; | |||||
stages = stages_; | |||||
cleanup(); | |||||
computefiltercoefs(); | |||||
} | |||||
void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par) | |||||
{ | |||||
float *out = NULL; | |||||
switch(type) { | |||||
case 0: | |||||
out = &x.low; | |||||
break; | |||||
case 1: | |||||
out = &x.high; | |||||
break; | |||||
case 2: | |||||
out = &x.band; | |||||
break; | |||||
case 3: | |||||
out = &x.notch; | |||||
break; | |||||
default: | |||||
out = &x.low; | |||||
warnx("Impossible SVFilter type encountered [%d]", type); | |||||
} | |||||
for(int i = 0; i < buffersize; ++i) { | |||||
x.low = x.low + par.f * x.band; | |||||
x.high = par.q_sqrt * smp[i] - x.low - par.q * x.band; | |||||
x.band = par.f * x.high + x.band; | |||||
x.notch = x.high + x.low; | |||||
smp[i] = *out; | |||||
} | |||||
} | |||||
// simplifying the responses | |||||
// xl = xl*z(-1) + pf*xb*z(-1) | |||||
// xh = pq1*x - xl - pq*xb*z(-1) | |||||
// xb = pf*xh + xb*z(-1) | |||||
// xn = xh + xl | |||||
// | |||||
// xl = pf*xb*z(-1)/(1-z(-1)) | |||||
// xb = pf*xh/(1-z(-1)) | |||||
// xl = pf*pfxh*z(-1)/(1-z(-1))^2 | |||||
void SVFilter::filterout(float *smp) | |||||
{ | |||||
for(int i = 0; i < stages + 1; ++i) | |||||
singlefilterout(smp, st[i], par); | |||||
if(needsinterpolation) { | |||||
float ismp[buffersize]; | |||||
memcpy(ismp, smp, bufferbytes); | |||||
for(int i = 0; i < stages + 1; ++i) | |||||
singlefilterout(ismp, st[i], ipar); | |||||
for(int i = 0; i < buffersize; ++i) { | |||||
float x = i / buffersize_f; | |||||
smp[i] = ismp[i] * (1.0f - x) + smp[i] * x; | |||||
} | |||||
needsinterpolation = false; | |||||
} | |||||
for(int i = 0; i < buffersize; ++i) | |||||
smp[i] *= outgain; | |||||
} | |||||
} |
@@ -0,0 +1,74 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
SV Filter.h - Several state-variable filters | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef SV_FILTER_H | |||||
#define SV_FILTER_H | |||||
#include "../globals.h" | |||||
#include "Filter.h" | |||||
namespace zyncarla { | |||||
class SVFilter:public Filter | |||||
{ | |||||
public: | |||||
SVFilter(unsigned char Ftype, | |||||
float Ffreq, | |||||
float Fq, | |||||
unsigned char Fstages, | |||||
unsigned int srate, int bufsize); | |||||
~SVFilter(); | |||||
void filterout(float *smp); | |||||
void setfreq(float frequency); | |||||
void setfreq_and_q(float frequency, float q_); | |||||
void setq(float q_); | |||||
void settype(int type_); | |||||
void setgain(float dBgain); | |||||
void setstages(int stages_); | |||||
void cleanup(); | |||||
struct response { | |||||
response(float b0, float b1, float b2, | |||||
float a0, float a1 ,float a2); | |||||
float a[3]; | |||||
float b[3]; | |||||
}; | |||||
static response computeResponse(int type, | |||||
float freq, float pq, int stages, float g, float fs); | |||||
private: | |||||
struct fstage { | |||||
float low, high, band, notch; | |||||
} st[MAX_FILTER_STAGES + 1]; | |||||
struct parameters { | |||||
float f, q, q_sqrt; | |||||
} par, ipar; | |||||
void singlefilterout(float *smp, fstage &x, parameters &par); | |||||
void computefiltercoefs(void); | |||||
int type; // The type of the filter (LPF1,HPF1,LPF2,HPF2...) | |||||
int stages; // how many times the filter is applied (0->1,1->2,etc.) | |||||
float freq; // Frequency given in Hz | |||||
float q; // Q factor (resonance or Q factor) | |||||
float gain; // the gain of the filter (if are shelf/peak) filters | |||||
bool abovenq, //if the frequency is above the nyquist | |||||
oldabovenq; | |||||
bool needsinterpolation, firsttime; | |||||
}; | |||||
} | |||||
#endif |
@@ -0,0 +1,202 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Unison.cpp - Unison effect (multivoice chorus) | |||||
Copyright (C) 2002-2009 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cmath> | |||||
#include <cstring> | |||||
#include "../Misc/Allocator.h" | |||||
#include "Unison.h" | |||||
#include "globals.h" | |||||
#define errx(...) {} | |||||
#define warnx(...) {} | |||||
#ifndef errx | |||||
#include <err.h> | |||||
#endif | |||||
namespace zyncarla { | |||||
Unison::Unison(Allocator *alloc_, int update_period_samples_, float max_delay_sec_, float srate_f) | |||||
:unison_size(0), | |||||
base_freq(1.0f), | |||||
uv(NULL), | |||||
update_period_samples(update_period_samples_), | |||||
update_period_sample_k(0), | |||||
max_delay((int)(srate_f * max_delay_sec_) + 1), | |||||
delay_k(0), | |||||
first_time(false), | |||||
delay_buffer(NULL), | |||||
unison_amplitude_samples(0.0f), | |||||
unison_bandwidth_cents(10.0f), | |||||
samplerate_f(srate_f), | |||||
alloc(*alloc_) | |||||
{ | |||||
if(max_delay < 10) | |||||
max_delay = 10; | |||||
delay_buffer = alloc.valloc<float>(max_delay); | |||||
memset(delay_buffer, 0, max_delay * sizeof(float)); | |||||
setSize(1); | |||||
} | |||||
Unison::~Unison() { | |||||
alloc.devalloc(delay_buffer); | |||||
alloc.devalloc(uv); | |||||
} | |||||
void Unison::setSize(int new_size) | |||||
{ | |||||
if(new_size < 1) | |||||
new_size = 1; | |||||
unison_size = new_size; | |||||
alloc.devalloc(uv); | |||||
uv = alloc.valloc<UnisonVoice>(unison_size); | |||||
first_time = true; | |||||
updateParameters(); | |||||
} | |||||
void Unison::setBaseFrequency(float freq) | |||||
{ | |||||
base_freq = freq; | |||||
updateParameters(); | |||||
} | |||||
void Unison::setBandwidth(float bandwidth) | |||||
{ | |||||
if(bandwidth < 0) | |||||
bandwidth = 0.0f; | |||||
if(bandwidth > 1200.0f) | |||||
bandwidth = 1200.0f; | |||||
/* If the bandwidth is too small, the audio may cancel itself out | |||||
* (due to the sign change of the outputs) | |||||
* TODO figure out the acceptable lower bound and codify it | |||||
*/ | |||||
unison_bandwidth_cents = bandwidth; | |||||
updateParameters(); | |||||
} | |||||
void Unison::updateParameters(void) | |||||
{ | |||||
if(!uv) | |||||
return; | |||||
float increments_per_second = samplerate_f | |||||
/ (float) update_period_samples; | |||||
// printf("#%g, %g\n",increments_per_second,base_freq); | |||||
for(int i = 0; i < unison_size; ++i) { | |||||
float base = powf(UNISON_FREQ_SPAN, SYNTH_T::numRandom() * 2.0f - 1.0f); | |||||
uv[i].relative_amplitude = base; | |||||
float period = base / base_freq; | |||||
float m = 4.0f / (period * increments_per_second); | |||||
if(SYNTH_T::numRandom() < 0.5f) | |||||
m = -m; | |||||
uv[i].step = m; | |||||
// printf("%g %g\n",uv[i].relative_amplitude,period); | |||||
} | |||||
float max_speed = powf(2.0f, unison_bandwidth_cents / 1200.0f); | |||||
unison_amplitude_samples = 0.125f * (max_speed - 1.0f) | |||||
* samplerate_f / base_freq; | |||||
//If functions exceed this limit, they should have requested a bigguer delay | |||||
//and thus are buggy | |||||
if(unison_amplitude_samples >= max_delay - 1) { | |||||
warnx("BUG: Unison amplitude samples too big"); | |||||
warnx("Unision max_delay should be larger"); | |||||
unison_amplitude_samples = max_delay - 2; | |||||
} | |||||
updateUnisonData(); | |||||
} | |||||
void Unison::process(int bufsize, float *inbuf, float *outbuf) | |||||
{ | |||||
if(!uv) | |||||
return; | |||||
if(!outbuf) | |||||
outbuf = inbuf; | |||||
float volume = 1.0f / sqrtf(unison_size); | |||||
float xpos_step = 1.0f / (float) update_period_samples; | |||||
float xpos = (float) update_period_sample_k * xpos_step; | |||||
for(int i = 0; i < bufsize; ++i) { | |||||
if(update_period_sample_k++ >= update_period_samples) { | |||||
updateUnisonData(); | |||||
update_period_sample_k = 0; | |||||
xpos = 0.0f; | |||||
} | |||||
xpos += xpos_step; | |||||
float in = inbuf[i], out = 0.0f; | |||||
float sign = 1.0f; | |||||
for(int k = 0; k < unison_size; ++k) { | |||||
float vpos = uv[k].realpos1 * (1.0f - xpos) + uv[k].realpos2 * xpos; //optimize | |||||
float pos = (float)(delay_k + max_delay) - vpos - 1.0f; | |||||
int posi; | |||||
F2I(pos, posi); //optimize! | |||||
int posi_next = posi + 1; | |||||
if(posi >= max_delay) | |||||
posi -= max_delay; | |||||
if(posi_next >= max_delay) | |||||
posi_next -= max_delay; | |||||
float posf = pos - floorf(pos); | |||||
out += ((1.0f - posf) * delay_buffer[posi] + posf | |||||
* delay_buffer[posi_next]) * sign; | |||||
sign = -sign; | |||||
} | |||||
outbuf[i] = out * volume; | |||||
// printf("%d %g\n",i,outbuf[i]); | |||||
delay_buffer[delay_k] = in; | |||||
delay_k = (++delay_k < max_delay) ? delay_k : 0; | |||||
} | |||||
} | |||||
void Unison::updateUnisonData() | |||||
{ | |||||
if(!uv) | |||||
return; | |||||
for(int k = 0; k < unison_size; ++k) { | |||||
float pos = uv[k].position; | |||||
float step = uv[k].step; | |||||
pos += step; | |||||
if(pos <= -1.0f) { | |||||
pos = -1.0f; | |||||
step = -step; | |||||
} | |||||
else | |||||
if(pos >= 1.0f) { | |||||
pos = 1.0f; | |||||
step = -step; | |||||
} | |||||
float vibratto_val = (pos - 0.333333333f * pos * pos * pos) * 1.5f; //make the vibratto lfo smoother | |||||
//Relative amplitude is utilized, so the delay may be larger than the | |||||
//whole buffer, if the buffer is too small, this indicates a buggy call | |||||
//to Unison() | |||||
float newval = 1.0f + 0.5f | |||||
* (vibratto_val + 1.0f) * unison_amplitude_samples | |||||
* uv[k].relative_amplitude; | |||||
if(first_time) | |||||
uv[k].realpos1 = uv[k].realpos2 = newval; | |||||
else { | |||||
uv[k].realpos1 = uv[k].realpos2; | |||||
uv[k].realpos2 = newval; | |||||
} | |||||
uv[k].position = pos; | |||||
uv[k].step = step; | |||||
} | |||||
first_time = false; | |||||
} | |||||
} |
@@ -0,0 +1,76 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Unison.h - Unison effect (multivoice chorus) | |||||
Copyright (C) 2002-2009 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef UNISON_H | |||||
#define UNISON_H | |||||
#include "../Misc/Util.h" | |||||
//how much the unison frequencies varies (always >= 1.0) | |||||
#define UNISON_FREQ_SPAN 2.0f | |||||
namespace zyncarla { | |||||
class Allocator; | |||||
class Unison | |||||
{ | |||||
public: | |||||
Unison(Allocator *alloc_, int update_period_samples_, float max_delay_sec_, float srate_f); | |||||
~Unison(); | |||||
void setSize(int new_size); | |||||
void setBaseFrequency(float freq); | |||||
void setBandwidth(float bandwidth_cents); | |||||
void process(int bufsize, float *inbuf, float *outbuf = NULL); | |||||
private: | |||||
void updateParameters(void); | |||||
void updateUnisonData(void); | |||||
int unison_size; | |||||
float base_freq; | |||||
struct UnisonVoice { | |||||
float step; //base LFO | |||||
float position; | |||||
float realpos1; //the position regarding samples | |||||
float realpos2; | |||||
float relative_amplitude; | |||||
float lin_fpos; | |||||
float lin_ffreq; | |||||
UnisonVoice() { | |||||
position = RND * 1.8f - 0.9f; | |||||
realpos1 = 0.0f; | |||||
realpos2 = 0.0f; | |||||
step = 0.0f; | |||||
relative_amplitude = 1.0f; | |||||
} | |||||
} *uv; | |||||
int update_period_samples; | |||||
int update_period_sample_k; | |||||
int max_delay, delay_k; | |||||
bool first_time; | |||||
float *delay_buffer; | |||||
float unison_amplitude_samples; | |||||
float unison_bandwidth_cents; | |||||
// current setup | |||||
float samplerate_f; | |||||
Allocator &alloc; | |||||
}; | |||||
} | |||||
#endif |
@@ -0,0 +1,272 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Alienwah.cpp - "AlienWah" effect | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#include <cmath> | |||||
#include <rtosc/port-sugar.h> | |||||
#include <rtosc/ports.h> | |||||
#include "../Misc/Allocator.h" | |||||
#include "Alienwah.h" | |||||
namespace zyncarla { | |||||
using std::complex; | |||||
#define rObject Alienwah | |||||
#define rBegin [](const char *msg, rtosc::RtData &d) { | |||||
#define rEnd } | |||||
rtosc::Ports Alienwah::ports = { | |||||
{"preset::i", rProp(parameter) | |||||
rOptions(wah 1, wah 2, wah 3, wah 4) | |||||
rDoc("Instrument Presets"), 0, | |||||
rBegin; | |||||
rObject *o = (rObject*)d.obj; | |||||
if(rtosc_narguments(msg)) | |||||
o->setpreset(rtosc_argument(msg, 0).i); | |||||
else | |||||
d.reply(d.loc, "i", o->Ppreset); | |||||
rEnd}, | |||||
rEffParVol(rDefault(127), rPresetsAt(3, 93)), | |||||
rEffParPan(), | |||||
rEffPar(Pfreq, 2, rShort("freq") rPresets(70, 73, 63, 25), | |||||
"Effect Frequency"), | |||||
rEffPar(Pfreqrnd, 3, rShort("rand"), rPreset(1, 106) rDefault(0), | |||||
"Frequency Randomness"), | |||||
rEffPar(PLFOtype, 4, rShort("shape"), | |||||
rOptions(sine, triangle), rPresets(sine, sine, triangle, triangle), | |||||
"LFO Shape"), | |||||
rEffPar(PStereo, 5, rShort("stereo"), rPresets(62, 101, 100, 66), | |||||
"Stereo Mode"), | |||||
rEffPar(Pdepth, 6, rShort("depth"), rPresets(60, 60, 112, 101), | |||||
"LFO Depth"), | |||||
rEffPar(Pfeedback, 7, rShort("fb"), rPreset(3, 11), rDefault(105), | |||||
"Feedback"), | |||||
rEffPar(Pdelay, 8, rLinear(1,100), rPresets(25, 17, 31, 47), | |||||
rShort("delay"), "Delay"), | |||||
rEffPar(Plrcross, 9, rShort("l/r"), rDefault(0), "Left/Right Crossover"), | |||||
rEffPar(Pphase, 10, rShort("phase"), rDefault(64), rPreset(2, 42), | |||||
rPreset(3, 86), "Phase"), | |||||
}; | |||||
#undef rBegin | |||||
#undef rEnd | |||||
#undef rObject | |||||
Alienwah::Alienwah(EffectParams pars) | |||||
:Effect(pars), | |||||
lfo(pars.srate, pars.bufsize), | |||||
oldl(NULL), | |||||
oldr(NULL) | |||||
{ | |||||
setpreset(Ppreset); | |||||
cleanup(); | |||||
oldclfol = complex<float>(fb, 0.0f); | |||||
oldclfor = complex<float>(fb, 0.0f); | |||||
} | |||||
Alienwah::~Alienwah() | |||||
{ | |||||
memory.devalloc(oldl); | |||||
memory.devalloc(oldr); | |||||
} | |||||
//Apply the effect | |||||
void Alienwah::out(const Stereo<float *> &smp) | |||||
{ | |||||
float lfol, lfor; //Left/Right LFOs | |||||
complex<float> clfol, clfor; | |||||
/**\todo Rework, as optimization can be used when the new complex type is | |||||
* utilized. | |||||
* Before all calculations needed to be done with individual float, | |||||
* but now they can be done together*/ | |||||
lfo.effectlfoout(&lfol, &lfor); | |||||
lfol *= depth * PI * 2.0f; | |||||
lfor *= depth * PI * 2.0f; | |||||
clfol = complex<float>(cosf(lfol + phase) * fb, sinf(lfol + phase) * fb); //rework | |||||
clfor = complex<float>(cosf(lfor + phase) * fb, sinf(lfor + phase) * fb); //rework | |||||
for(int i = 0; i < buffersize; ++i) { | |||||
float x = ((float) i) / buffersize_f; | |||||
float x1 = 1.0f - x; | |||||
//left | |||||
complex<float> tmp = clfol * x + oldclfol * x1; | |||||
complex<float> out = tmp * oldl[oldk]; | |||||
out += (1 - fabs(fb)) * smp.l[i] * pangainL; | |||||
oldl[oldk] = out; | |||||
float l = out.real() * 10.0f * (fb + 0.1f); | |||||
//right | |||||
tmp = clfor * x + oldclfor * x1; | |||||
out = tmp * oldr[oldk]; | |||||
out += (1 - fabs(fb)) * smp.r[i] * pangainR; | |||||
oldr[oldk] = out; | |||||
float r = out.real() * 10.0f * (fb + 0.1f); | |||||
if(++oldk >= Pdelay) | |||||
oldk = 0; | |||||
//LRcross | |||||
efxoutl[i] = l * (1.0f - lrcross) + r * lrcross; | |||||
efxoutr[i] = r * (1.0f - lrcross) + l * lrcross; | |||||
} | |||||
oldclfol = clfol; | |||||
oldclfor = clfor; | |||||
} | |||||
//Cleanup the effect | |||||
void Alienwah::cleanup(void) | |||||
{ | |||||
for(int i = 0; i < Pdelay; ++i) { | |||||
oldl[i] = complex<float>(0.0f, 0.0f); | |||||
oldr[i] = complex<float>(0.0f, 0.0f); | |||||
} | |||||
oldk = 0; | |||||
} | |||||
//Parameter control | |||||
void Alienwah::setdepth(unsigned char _Pdepth) | |||||
{ | |||||
Pdepth = _Pdepth; | |||||
depth = Pdepth / 127.0f; | |||||
} | |||||
void Alienwah::setfb(unsigned char _Pfb) | |||||
{ | |||||
Pfb = _Pfb; | |||||
fb = fabs((Pfb - 64.0f) / 64.1f); | |||||
fb = sqrtf(fb); | |||||
if(fb < 0.4f) | |||||
fb = 0.4f; | |||||
if(Pfb < 64) | |||||
fb = -fb; | |||||
} | |||||
void Alienwah::setvolume(unsigned char _Pvolume) | |||||
{ | |||||
Pvolume = _Pvolume; | |||||
outvolume = Pvolume / 127.0f; | |||||
if(insertion == 0) | |||||
volume = 1.0f; | |||||
else | |||||
volume = outvolume; | |||||
} | |||||
void Alienwah::setphase(unsigned char _Pphase) | |||||
{ | |||||
Pphase = _Pphase; | |||||
phase = (Pphase - 64.0f) / 64.0f * PI; | |||||
} | |||||
void Alienwah::setdelay(unsigned char _Pdelay) | |||||
{ | |||||
memory.devalloc(oldl); | |||||
memory.devalloc(oldr); | |||||
Pdelay = limit<int>(_Pdelay, 1, MAX_ALIENWAH_DELAY); | |||||
oldl = memory.valloc<complex<float>>(Pdelay); | |||||
oldr = memory.valloc<complex<float>>(Pdelay); | |||||
cleanup(); | |||||
} | |||||
void Alienwah::setpreset(unsigned char npreset) | |||||
{ | |||||
const int PRESET_SIZE = 11; | |||||
const int NUM_PRESETS = 4; | |||||
unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { | |||||
//AlienWah1 | |||||
{127, 64, 70, 0, 0, 62, 60, 105, 25, 0, 64}, | |||||
//AlienWah2 | |||||
{127, 64, 73, 106, 0, 101, 60, 105, 17, 0, 64}, | |||||
//AlienWah3 | |||||
{127, 64, 63, 0, 1, 100, 112, 105, 31, 0, 42}, | |||||
//AlienWah4 | |||||
{93, 64, 25, 0, 1, 66, 101, 11, 47, 0, 86} | |||||
}; | |||||
if(npreset >= NUM_PRESETS) | |||||
npreset = NUM_PRESETS - 1; | |||||
for(int n = 0; n < PRESET_SIZE; ++n) | |||||
changepar(n, presets[npreset][n]); | |||||
if(insertion == 0) | |||||
changepar(0, presets[npreset][0] / 2); //lower the volume if this is system effect | |||||
Ppreset = npreset; | |||||
} | |||||
void Alienwah::changepar(int npar, unsigned char value) | |||||
{ | |||||
switch(npar) { | |||||
case 0: | |||||
setvolume(value); | |||||
break; | |||||
case 1: | |||||
setpanning(value); | |||||
break; | |||||
case 2: | |||||
lfo.Pfreq = value; | |||||
lfo.updateparams(); | |||||
break; | |||||
case 3: | |||||
lfo.Prandomness = value; | |||||
lfo.updateparams(); | |||||
break; | |||||
case 4: | |||||
lfo.PLFOtype = value; | |||||
lfo.updateparams(); | |||||
break; | |||||
case 5: | |||||
lfo.Pstereo = value; | |||||
lfo.updateparams(); | |||||
break; | |||||
case 6: | |||||
setdepth(value); | |||||
break; | |||||
case 7: | |||||
setfb(value); | |||||
break; | |||||
case 8: | |||||
setdelay(value); | |||||
break; | |||||
case 9: | |||||
setlrcross(value); | |||||
break; | |||||
case 10: | |||||
setphase(value); | |||||
break; | |||||
} | |||||
} | |||||
unsigned char Alienwah::getpar(int npar) const | |||||
{ | |||||
switch(npar) { | |||||
case 0: return Pvolume; | |||||
case 1: return Ppanning; | |||||
case 2: return lfo.Pfreq; | |||||
case 3: return lfo.Prandomness; | |||||
case 4: return lfo.PLFOtype; | |||||
case 5: return lfo.Pstereo; | |||||
case 6: return Pdepth; | |||||
case 7: return Pfb; | |||||
case 8: return Pdelay; | |||||
case 9: return Plrcross; | |||||
case 10: return Pphase; | |||||
default: return 0; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,65 @@ | |||||
/* | |||||
ZynAddSubFX - a software synthesizer | |||||
Alienwah.h - "AlienWah" effect | |||||
Copyright (C) 2002-2005 Nasca Octavian Paul | |||||
Author: Nasca Octavian Paul | |||||
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 (at your option) any later version. | |||||
*/ | |||||
#ifndef ALIENWAH_H | |||||
#define ALIENWAH_H | |||||
#include "Effect.h" | |||||
#include "EffectLFO.h" | |||||
#include <complex> | |||||
#define MAX_ALIENWAH_DELAY 100 | |||||
namespace zyncarla { | |||||
/**"AlienWah" Effect*/ | |||||
class Alienwah:public Effect | |||||
{ | |||||
public: | |||||
Alienwah(EffectParams pars); | |||||
~Alienwah(); | |||||
void out(const Stereo<float *> &smp); | |||||
void setpreset(unsigned char npreset); | |||||
void changepar(int npar, unsigned char value); | |||||
unsigned char getpar(int npar) const; | |||||
void cleanup(void); | |||||
static rtosc::Ports ports; | |||||
private: | |||||
//Alienwah Parameters | |||||
EffectLFO lfo; //lfo-ul Alienwah | |||||
unsigned char Pvolume; | |||||
unsigned char Pdepth; //the depth of the Alienwah | |||||
unsigned char Pfb; //feedback | |||||
unsigned char Pdelay; | |||||
unsigned char Pphase; | |||||
//Control Parameters | |||||
void setvolume(unsigned char _Pvolume); | |||||
void setdepth(unsigned char _Pdepth); | |||||
void setfb(unsigned char _Pfb); | |||||
void setdelay(unsigned char _Pdelay); | |||||
void setphase(unsigned char _Pphase); | |||||
//Internal Values | |||||
float fb, depth, phase; | |||||
std::complex<float> *oldl, *oldr; | |||||
std::complex<float> oldclfol, oldclfor; | |||||
int oldk; | |||||
}; | |||||
} | |||||
#endif |