Browse Source

Initial commit

pull/1/head
falkTX 7 years ago
commit
db21d6f7e3
100 changed files with 83912 additions and 0 deletions
  1. +171
    -0
      Makefile
  2. +233
    -0
      Makefile.mk
  3. +66
    -0
      _all.c
  4. +470
    -0
      _data.cpp
  5. +85
    -0
      distrho-3bandeq.cpp
  6. +10107
    -0
      distrho-3bandeq/DistrhoArtwork3BandEQ.cpp
  7. +40
    -0
      distrho-3bandeq/DistrhoArtwork3BandEQ.hpp
  8. +264
    -0
      distrho-3bandeq/DistrhoPlugin3BandEQ.cpp
  9. +123
    -0
      distrho-3bandeq/DistrhoPlugin3BandEQ.hpp
  10. +32
    -0
      distrho-3bandeq/DistrhoPluginInfo.h
  11. +211
    -0
      distrho-3bandeq/DistrhoUI3BandEQ.cpp
  12. +72
    -0
      distrho-3bandeq/DistrhoUI3BandEQ.hpp
  13. +85
    -0
      distrho-3bandsplitter.cpp
  14. +10107
    -0
      distrho-3bandsplitter/DistrhoArtwork3BandSplitter.cpp
  15. +40
    -0
      distrho-3bandsplitter/DistrhoArtwork3BandSplitter.hpp
  16. +272
    -0
      distrho-3bandsplitter/DistrhoPlugin3BandSplitter.cpp
  17. +123
    -0
      distrho-3bandsplitter/DistrhoPlugin3BandSplitter.hpp
  18. +32
    -0
      distrho-3bandsplitter/DistrhoPluginInfo.h
  19. +211
    -0
      distrho-3bandsplitter/DistrhoUI3BandSplitter.cpp
  20. +72
    -0
      distrho-3bandsplitter/DistrhoUI3BandSplitter.hpp
  21. +86
    -0
      distrho-kars.cpp
  22. +5264
    -0
      distrho-kars/DistrhoArtworkKars.cpp
  23. +20
    -0
      distrho-kars/DistrhoArtworkKars.hpp
  24. +31
    -0
      distrho-kars/DistrhoPluginInfo.h
  25. +214
    -0
      distrho-kars/DistrhoPluginKars.cpp
  26. +152
    -0
      distrho-kars/DistrhoPluginKars.hpp
  27. +77
    -0
      distrho-kars/DistrhoUIKars.cpp
  28. +60
    -0
      distrho-kars/DistrhoUIKars.hpp
  29. +87
    -0
      distrho-nekobi.cpp
  30. +6890
    -0
      distrho-nekobi/DistrhoArtworkNekobi.cpp
  31. +90
    -0
      distrho-nekobi/DistrhoArtworkNekobi.hpp
  32. +32
    -0
      distrho-nekobi/DistrhoPluginInfo.h
  33. +399
    -0
      distrho-nekobi/DistrhoPluginNekobi.cpp
  34. +131
    -0
      distrho-nekobi/DistrhoPluginNekobi.hpp
  35. +231
    -0
      distrho-nekobi/DistrhoUINekobi.cpp
  36. +86
    -0
      distrho-nekobi/DistrhoUINekobi.hpp
  37. +202
    -0
      distrho-nekobi/NekoWidget.hpp
  38. +1779
    -0
      distrho-nekobi/nekobee-src/minblep_tables.c
  39. +77
    -0
      distrho-nekobi/nekobee-src/nekobee.h
  40. +237
    -0
      distrho-nekobi/nekobee-src/nekobee_synth.c
  41. +132
    -0
      distrho-nekobi/nekobee-src/nekobee_synth.h
  42. +30
    -0
      distrho-nekobi/nekobee-src/nekobee_types.h
  43. +256
    -0
      distrho-nekobi/nekobee-src/nekobee_voice.c
  44. +183
    -0
      distrho-nekobi/nekobee-src/nekobee_voice.h
  45. +414
    -0
      distrho-nekobi/nekobee-src/nekobee_voice_render.c
  46. +85
    -0
      distrho-pingpongpan.cpp
  47. +5651
    -0
      distrho-pingpongpan/DistrhoArtworkPingPongPan.cpp
  48. +35
    -0
      distrho-pingpongpan/DistrhoArtworkPingPongPan.hpp
  49. +33
    -0
      distrho-pingpongpan/DistrhoPluginInfo.h
  50. +161
    -0
      distrho-pingpongpan/DistrhoPluginPingPongPan.cpp
  51. +114
    -0
      distrho-pingpongpan/DistrhoPluginPingPongPan.hpp
  52. +133
    -0
      distrho-pingpongpan/DistrhoUIPingPongPan.cpp
  53. +67
    -0
      distrho-pingpongpan/DistrhoUIPingPongPan.hpp
  54. +67
    -0
      distrho-prom.cpp
  55. +33
    -0
      distrho-prom/DistrhoPluginInfo.h
  56. +84
    -0
      distrho-prom/DistrhoPluginProM.cpp
  57. +106
    -0
      distrho-prom/DistrhoPluginProM.hpp
  58. +304
    -0
      distrho-prom/DistrhoUIProM.cpp
  59. +63
    -0
      distrho-prom/DistrhoUIProM.hpp
  60. +87
    -0
      distrho-vectorjuice.cpp
  61. +36
    -0
      distrho-vectorjuice/DistrhoPluginInfo.h
  62. +18123
    -0
      distrho-vectorjuice/VectorJuiceArtwork.cpp
  63. +55
    -0
      distrho-vectorjuice/VectorJuiceArtwork.hpp
  64. +391
    -0
      distrho-vectorjuice/VectorJuicePlugin.cpp
  65. +236
    -0
      distrho-vectorjuice/VectorJuicePlugin.hpp
  66. +461
    -0
      distrho-vectorjuice/VectorJuiceUI.cpp
  67. +99
    -0
      distrho-vectorjuice/VectorJuiceUI.hpp
  68. +87
    -0
      distrho-wobblejuice.cpp
  69. +36
    -0
      distrho-wobblejuice/DistrhoPluginInfo.h
  70. +10312
    -0
      distrho-wobblejuice/WobbleJuiceArtwork.cpp
  71. +35
    -0
      distrho-wobblejuice/WobbleJuiceArtwork.hpp
  72. +243
    -0
      distrho-wobblejuice/WobbleJuicePlugin.cpp
  73. +142
    -0
      distrho-wobblejuice/WobbleJuicePlugin.hpp
  74. +189
    -0
      distrho-wobblejuice/WobbleJuiceUI.cpp
  75. +75
    -0
      distrho-wobblejuice/WobbleJuiceUI.hpp
  76. +76
    -0
      distrho-wobblejuice/moogVCF.hxx
  77. +1502
    -0
      zynaddsubfx-fx.cpp
  78. +598
    -0
      zynaddsubfx-src.cpp
  79. +1092
    -0
      zynaddsubfx-synth.cpp
  80. +273
    -0
      zynaddsubfx-ui.cpp
  81. +121
    -0
      zynaddsubfx/Containers/MultiPseudoStack.cpp
  82. +66
    -0
      zynaddsubfx/Containers/MultiPseudoStack.h
  83. +436
    -0
      zynaddsubfx/Containers/NotePool.cpp
  84. +151
    -0
      zynaddsubfx/Containers/NotePool.h
  85. +43
    -0
      zynaddsubfx/Containers/ScratchString.cpp
  86. +22
    -0
      zynaddsubfx/Containers/ScratchString.h
  87. +429
    -0
      zynaddsubfx/DSP/AnalogFilter.cpp
  88. +84
    -0
      zynaddsubfx/DSP/AnalogFilter.h
  89. +97
    -0
      zynaddsubfx/DSP/FFTwrapper.cpp
  90. +66
    -0
      zynaddsubfx/DSP/FFTwrapper.h
  91. +71
    -0
      zynaddsubfx/DSP/Filter.cpp
  92. +60
    -0
      zynaddsubfx/DSP/Filter.h
  93. +221
    -0
      zynaddsubfx/DSP/FormantFilter.cpp
  94. +61
    -0
      zynaddsubfx/DSP/FormantFilter.h
  95. +235
    -0
      zynaddsubfx/DSP/SVFilter.cpp
  96. +74
    -0
      zynaddsubfx/DSP/SVFilter.h
  97. +202
    -0
      zynaddsubfx/DSP/Unison.cpp
  98. +76
    -0
      zynaddsubfx/DSP/Unison.h
  99. +272
    -0
      zynaddsubfx/Effects/Alienwah.cpp
  100. +65
    -0
      zynaddsubfx/Effects/Alienwah.h

+ 171
- 0
Makefile View File

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

# ---------------------------------------------------------------------------------------------------------------------

+ 233
- 0
Makefile.mk View File

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

# ---------------------------------------------------------------------------------------------------------------------

+ 66
- 0
_all.c View File

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

// --------------------------------------------------------------------------------------------------------------------

+ 470
- 0
_data.cpp View File

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

+ 85
- 0
distrho-3bandeq.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 10107
- 0
distrho-3bandeq/DistrhoArtwork3BandEQ.cpp
File diff suppressed because it is too large
View File


+ 40
- 0
distrho-3bandeq/DistrhoArtwork3BandEQ.hpp View File

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


+ 264
- 0
distrho-3bandeq/DistrhoPlugin3BandEQ.cpp View File

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

+ 123
- 0
distrho-3bandeq/DistrhoPlugin3BandEQ.hpp View File

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

+ 32
- 0
distrho-3bandeq/DistrhoPluginInfo.h View File

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

+ 211
- 0
distrho-3bandeq/DistrhoUI3BandEQ.cpp View File

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

+ 72
- 0
distrho-3bandeq/DistrhoUI3BandEQ.hpp View File

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

+ 85
- 0
distrho-3bandsplitter.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 10107
- 0
distrho-3bandsplitter/DistrhoArtwork3BandSplitter.cpp
File diff suppressed because it is too large
View File


+ 40
- 0
distrho-3bandsplitter/DistrhoArtwork3BandSplitter.hpp View File

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


+ 272
- 0
distrho-3bandsplitter/DistrhoPlugin3BandSplitter.cpp View File

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

+ 123
- 0
distrho-3bandsplitter/DistrhoPlugin3BandSplitter.hpp View File

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

+ 32
- 0
distrho-3bandsplitter/DistrhoPluginInfo.h View File

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

+ 211
- 0
distrho-3bandsplitter/DistrhoUI3BandSplitter.cpp View File

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

+ 72
- 0
distrho-3bandsplitter/DistrhoUI3BandSplitter.hpp View File

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

+ 86
- 0
distrho-kars.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 5264
- 0
distrho-kars/DistrhoArtworkKars.cpp
File diff suppressed because it is too large
View File


+ 20
- 0
distrho-kars/DistrhoArtworkKars.hpp View File

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


+ 31
- 0
distrho-kars/DistrhoPluginInfo.h View File

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

+ 214
- 0
distrho-kars/DistrhoPluginKars.cpp View File

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

+ 152
- 0
distrho-kars/DistrhoPluginKars.hpp View File

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

+ 77
- 0
distrho-kars/DistrhoUIKars.cpp View File

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

+ 60
- 0
distrho-kars/DistrhoUIKars.hpp View File

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

+ 87
- 0
distrho-nekobi.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 6890
- 0
distrho-nekobi/DistrhoArtworkNekobi.cpp
File diff suppressed because it is too large
View File


+ 90
- 0
distrho-nekobi/DistrhoArtworkNekobi.hpp View File

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


+ 32
- 0
distrho-nekobi/DistrhoPluginInfo.h View File

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

+ 399
- 0
distrho-nekobi/DistrhoPluginNekobi.cpp View File

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

+ 131
- 0
distrho-nekobi/DistrhoPluginNekobi.hpp View File

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

+ 231
- 0
distrho-nekobi/DistrhoUINekobi.cpp View File

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

+ 86
- 0
distrho-nekobi/DistrhoUINekobi.hpp View File

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

+ 202
- 0
distrho-nekobi/NekoWidget.hpp View File

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

+ 1779
- 0
distrho-nekobi/nekobee-src/minblep_tables.c
File diff suppressed because it is too large
View File


+ 77
- 0
distrho-nekobi/nekobee-src/nekobee.h View File

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

+ 237
- 0
distrho-nekobi/nekobee-src/nekobee_synth.c View File

@@ -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);
}
}

+ 132
- 0
distrho-nekobi/nekobee-src/nekobee_synth.h View File

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

+ 30
- 0
distrho-nekobi/nekobee-src/nekobee_types.h View File

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

+ 256
- 0
distrho-nekobi/nekobee-src/nekobee_voice.c View File

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

+ 183
- 0
distrho-nekobi/nekobee-src/nekobee_voice.h View File

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

+ 414
- 0
distrho-nekobi/nekobee-src/nekobee_voice_render.c View File

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

+ 85
- 0
distrho-pingpongpan.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 5651
- 0
distrho-pingpongpan/DistrhoArtworkPingPongPan.cpp
File diff suppressed because it is too large
View File


+ 35
- 0
distrho-pingpongpan/DistrhoArtworkPingPongPan.hpp View File

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


+ 33
- 0
distrho-pingpongpan/DistrhoPluginInfo.h View File

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

+ 161
- 0
distrho-pingpongpan/DistrhoPluginPingPongPan.cpp View File

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

+ 114
- 0
distrho-pingpongpan/DistrhoPluginPingPongPan.hpp View File

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

+ 133
- 0
distrho-pingpongpan/DistrhoUIPingPongPan.cpp View File

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

+ 67
- 0
distrho-pingpongpan/DistrhoUIPingPongPan.hpp View File

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

+ 67
- 0
distrho-prom.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 33
- 0
distrho-prom/DistrhoPluginInfo.h View File

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

+ 84
- 0
distrho-prom/DistrhoPluginProM.cpp View File

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

+ 106
- 0
distrho-prom/DistrhoPluginProM.hpp View File

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

+ 304
- 0
distrho-prom/DistrhoUIProM.cpp View File

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

+ 63
- 0
distrho-prom/DistrhoUIProM.hpp View File

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

+ 87
- 0
distrho-vectorjuice.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 36
- 0
distrho-vectorjuice/DistrhoPluginInfo.h View File

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

+ 18123
- 0
distrho-vectorjuice/VectorJuiceArtwork.cpp
File diff suppressed because it is too large
View File


+ 55
- 0
distrho-vectorjuice/VectorJuiceArtwork.hpp View File

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


+ 391
- 0
distrho-vectorjuice/VectorJuicePlugin.cpp View File

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

+ 236
- 0
distrho-vectorjuice/VectorJuicePlugin.hpp View File

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

+ 461
- 0
distrho-vectorjuice/VectorJuiceUI.cpp View File

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

+ 99
- 0
distrho-vectorjuice/VectorJuiceUI.hpp View File

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

+ 87
- 0
distrho-wobblejuice.cpp View File

@@ -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);
}

// -----------------------------------------------------------------------

+ 36
- 0
distrho-wobblejuice/DistrhoPluginInfo.h View File

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

+ 10312
- 0
distrho-wobblejuice/WobbleJuiceArtwork.cpp
File diff suppressed because it is too large
View File


+ 35
- 0
distrho-wobblejuice/WobbleJuiceArtwork.hpp View File

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


+ 243
- 0
distrho-wobblejuice/WobbleJuicePlugin.cpp View File

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

+ 142
- 0
distrho-wobblejuice/WobbleJuicePlugin.hpp View File

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

+ 189
- 0
distrho-wobblejuice/WobbleJuiceUI.cpp View File

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

+ 75
- 0
distrho-wobblejuice/WobbleJuiceUI.hpp View File

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

+ 76
- 0
distrho-wobblejuice/moogVCF.hxx View File

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

+ 1502
- 0
zynaddsubfx-fx.cpp
File diff suppressed because it is too large
View File


+ 598
- 0
zynaddsubfx-src.cpp View File

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

+ 1092
- 0
zynaddsubfx-synth.cpp
File diff suppressed because it is too large
View File


+ 273
- 0
zynaddsubfx-ui.cpp View File

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

// --------------------------------------------------------------------------------------------

+ 121
- 0
zynaddsubfx/Containers/MultiPseudoStack.cpp View File

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

}

+ 66
- 0
zynaddsubfx/Containers/MultiPseudoStack.h View File

@@ -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(); }
};

}

+ 436
- 0
zynaddsubfx/Containers/NotePool.cpp View File

@@ -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");
}

}

+ 151
- 0
zynaddsubfx/Containers/NotePool.h View File

@@ -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);
};

}

+ 43
- 0
zynaddsubfx/Containers/ScratchString.cpp View File

@@ -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;
//}

}

+ 22
- 0
zynaddsubfx/Containers/ScratchString.h View File

@@ -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];
};

}


+ 429
- 0
zynaddsubfx/DSP/AnalogFilter.cpp View File

@@ -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);
}

}

+ 84
- 0
zynaddsubfx/DSP/AnalogFilter.h View File

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

+ 97
- 0
zynaddsubfx/DSP/FFTwrapper.cpp View File

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

}

+ 66
- 0
zynaddsubfx/DSP/FFTwrapper.h View File

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

+ 71
- 0
zynaddsubfx/DSP/Filter.cpp View File

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

}

+ 60
- 0
zynaddsubfx/DSP/Filter.h View File

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

+ 221
- 0
zynaddsubfx/DSP/FormantFilter.cpp View File

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

}

+ 61
- 0
zynaddsubfx/DSP/FormantFilter.h View File

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

+ 235
- 0
zynaddsubfx/DSP/SVFilter.cpp View File

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

}

+ 74
- 0
zynaddsubfx/DSP/SVFilter.h View File

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

+ 202
- 0
zynaddsubfx/DSP/Unison.cpp View File

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

}

+ 76
- 0
zynaddsubfx/DSP/Unison.h View File

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

+ 272
- 0
zynaddsubfx/Effects/Alienwah.cpp View File

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

}

+ 65
- 0
zynaddsubfx/Effects/Alienwah.h View File

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

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save