diff --git a/examples/ImguiSimpleGain/CParamSmooth.hpp b/examples/ImguiSimpleGain/CParamSmooth.hpp new file mode 100644 index 00000000..b2b96ce0 --- /dev/null +++ b/examples/ImguiSimpleGain/CParamSmooth.hpp @@ -0,0 +1,41 @@ +/** + * One-pole LPF for smooth parameter changes + * + * https://www.musicdsp.org/en/latest/Filters/257-1-pole-lpf-for-smooth-parameter-changes.html + */ + +#ifndef C_PARAM_SMOOTH_H +#define C_PARAM_SMOOTH_H + +#include + +#define TWO_PI 6.283185307179586476925286766559f + +class CParamSmooth { +public: + CParamSmooth(float smoothingTimeMs, float samplingRate) + : t(smoothingTimeMs) + { + setSampleRate(samplingRate); + } + + ~CParamSmooth() { } + + void setSampleRate(float samplingRate) { + if (samplingRate != fs) { + fs = samplingRate; + a = exp(-TWO_PI / (t * 0.001f * samplingRate)); + b = 1.0f - a; + z = 0.0f; + } + } + + inline float process(float in) { + return z = (in * b) + (z * a); + } +private: + float a, b, t, z; + double fs = 0.0; +}; + +#endif // #ifndef C_PARAM_SMOOTH_H diff --git a/examples/ImguiSimpleGain/DistrhoPluginInfo.h b/examples/ImguiSimpleGain/DistrhoPluginInfo.h new file mode 100644 index 00000000..0deddd7b --- /dev/null +++ b/examples/ImguiSimpleGain/DistrhoPluginInfo.h @@ -0,0 +1,145 @@ +/* + * Simple Gain audio effect for DISTRHO Plugin Framework (DPF) + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2021 Jean Pierre Cimalando + * Copyright (C) 2021 Filipe Coelho + * + * 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. + */ + +/** + The plugin name.@n + This is used to identify your plugin before a Plugin instance can be created. + @note This macro is required. + */ +#define DISTRHO_PLUGIN_NAME "ImguiSimpleGain" + +/** + Number of audio inputs the plugin has. + @note This macro is required. + */ +#define DISTRHO_PLUGIN_NUM_INPUTS 2 + +/** + Number of audio outputs the plugin has. + @note This macro is required. + */ +#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 + +/** + The plugin URI when exporting in LV2 format. + @note This macro is required. + */ +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/examples/imguisimplegain" + +/** + Wherever the plugin has a custom %UI. + @see DISTRHO_UI_USE_NANOVG + @see UI + */ +#define DISTRHO_PLUGIN_HAS_UI 1 + +/** + Wherever the plugin processing is realtime-safe.@n + TODO - list rtsafe requirements + */ +#define DISTRHO_PLUGIN_IS_RT_SAFE 1 + +/** + Wherever the plugin is a synth.@n + @ref DISTRHO_PLUGIN_WANT_MIDI_INPUT is automatically enabled when this is too. + @see DISTRHO_PLUGIN_WANT_MIDI_INPUT + */ +#define DISTRHO_PLUGIN_IS_SYNTH 0 + +/** + Enable direct access between the %UI and plugin code. + @see UI::getPluginInstancePointer() + @note DO NOT USE THIS UNLESS STRICTLY NECESSARY!! + Try to avoid it at all costs! + */ +#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 + +/** + Wherever the plugin introduces latency during audio or midi processing. + @see Plugin::setLatency(uint32_t) + */ +#define DISTRHO_PLUGIN_WANT_LATENCY 0 + +/** + Wherever the plugin wants MIDI input.@n + This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. + */ +#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 0 + +/** + Wherever the plugin wants MIDI output. + @see Plugin::writeMidiEvent(const MidiEvent&) + */ +#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 + +/** + Wherever the plugin provides its own internal programs. + @see Plugin::initProgramName(uint32_t, String&) + @see Plugin::loadProgram(uint32_t) + */ +#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 + +/** + Wherever the plugin uses internal non-parameter data. + @see Plugin::initState(uint32_t, String&, String&) + @see Plugin::setState(const char*, const char*) + */ +#define DISTRHO_PLUGIN_WANT_STATE 0 + +/** + Wherever the plugin wants time position information from the host. + @see Plugin::getTimePosition() + */ +#define DISTRHO_PLUGIN_WANT_TIMEPOS 0 + +/** + Wherever the %UI uses NanoVG for drawing instead of the default raw OpenGL calls.@n + When enabled your %UI instance will subclass @ref NanoWidget instead of @ref Widget. + */ +#define DISTRHO_UI_USE_NANOVG 0 + +/** + The %UI URI when exporting in LV2 format.@n + By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix. + */ +#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" + +/** + Wherever the %UI uses a custom toolkit implementation based on OpenGL.@n + When enabled, the macros @ref DISTRHO_UI_CUSTOM_INCLUDE_PATH and @ref DISTRHO_UI_CUSTOM_WIDGET_TYPE are required. + */ +#define DISTRHO_UI_USE_CUSTOM 1 + +/** + The include path to the header file used by the custom toolkit implementation. + This path must be relative to dpf/distrho/DistrhoUI.hpp + @see DISTRHO_UI_USE_CUSTOM + */ +#define DISTRHO_UI_CUSTOM_INCLUDE_PATH "ImGuiUI.hpp" + +/** + The top-level-widget typedef to use for the custom toolkit. + This widget class MUST be a subclass of DGL TopLevelWindow class. + It is recommended that you keep this widget class inside the DGL namespace, + and define widget type as e.g. DGL_NAMESPACE::MyCustomTopLevelWidget. + @see DISTRHO_UI_USE_CUSTOM + */ +#define DISTRHO_UI_CUSTOM_WIDGET_TYPE DGL_NAMESPACE::ImGuiUI + +#define DISTRHO_UI_USER_RESIZABLE 1 diff --git a/examples/ImguiSimpleGain/ImGuiSrc.cpp b/examples/ImguiSimpleGain/ImGuiSrc.cpp new file mode 100644 index 00000000..ad4c106c --- /dev/null +++ b/examples/ImguiSimpleGain/ImGuiSrc.cpp @@ -0,0 +1,35 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2021 Jean Pierre Cimalando + * + * 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 +#if !defined(IMGUI_GL2) && !defined(IMGUI_GL3) +# define IMGUI_GL2 1 +#endif +#if defined(IMGUI_GL2) +# include +#elif defined(IMGUI_GL3) +# include +#endif + +#include +#include +#include +#include +#if defined(IMGUI_GL2) +#include +#elif defined(IMGUI_GL3) +#include +#endif diff --git a/examples/ImguiSimpleGain/ImGuiUI.cpp b/examples/ImguiSimpleGain/ImGuiUI.cpp new file mode 100644 index 00000000..629ba259 --- /dev/null +++ b/examples/ImguiSimpleGain/ImGuiUI.cpp @@ -0,0 +1,316 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2021 Jean Pierre Cimalando + * + * 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 "Application.hpp" + +#include + +#include "ImGuiUI.hpp" +#include +#if !defined(IMGUI_GL2) && !defined(IMGUI_GL3) +# define IMGUI_GL2 1 +#endif +#if defined(IMGUI_GL2) +# include +#elif defined(IMGUI_GL3) +# include +#endif +#include +#include + +START_NAMESPACE_DGL + +struct ImGuiUI::Impl +{ + explicit Impl(ImGuiUI* self); + ~Impl(); + + void setupGL(); + void cleanupGL(); + + // perhaps DPF will implement this in the future + float getScaleFactor() const { return 1.0f; } + + static int mouseButtonToImGui(int button); + + ImGuiUI* fSelf = nullptr; + ImGuiContext* fContext = nullptr; + Color fBackgroundColor{0.25f, 0.25f, 0.25f}; + int fRepaintIntervalMs = 15; + + using Clock = std::chrono::steady_clock; + Clock::time_point fLastRepainted; + bool fWasEverPainted = false; +}; + +ImGuiUI::ImGuiUI(Window& windowToMapTo) + : TopLevelWidget(windowToMapTo), + fImpl(new ImGuiUI::Impl(this)) +{ + getApp().addIdleCallback(this); +} + +ImGuiUI::~ImGuiUI() +{ + delete fImpl; +} + +void ImGuiUI::setBackgroundColor(Color color) +{ + fImpl->fBackgroundColor = color; +} + +void ImGuiUI::setRepaintInterval(int intervalMs) +{ + fImpl->fRepaintIntervalMs = intervalMs; +} + +void ImGuiUI::onDisplay() +{ + ImGui::SetCurrentContext(fImpl->fContext); + +#if defined(IMGUI_GL2) + ImGui_ImplOpenGL2_NewFrame(); +#elif defined(IMGUI_GL3) + ImGui_ImplOpenGL3_NewFrame(); +#endif + + ImGui::NewFrame(); + onImGuiDisplay(); + ImGui::Render(); + + ImGuiIO &io = ImGui::GetIO(); + + glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); + + Color backgroundColor = fImpl->fBackgroundColor; + glClearColor( + backgroundColor.red, backgroundColor.green, + backgroundColor.blue, backgroundColor.alpha); + glClear(GL_COLOR_BUFFER_BIT); + glLoadIdentity(); + +#if defined(IMGUI_GL2) + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); +#elif defined(IMGUI_GL3) + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +#endif + + fImpl->fLastRepainted = Impl::Clock::now(); + fImpl->fWasEverPainted = true; +} + +bool ImGuiUI::onKeyboard(const KeyboardEvent& event) +{ + ImGui::SetCurrentContext(fImpl->fContext); + ImGuiIO &io = ImGui::GetIO(); + + if (event.press) + io.AddInputCharacter(event.key); + + int imGuiKey = event.key; + if (imGuiKey >= 0 && imGuiKey < 128) + { + if (imGuiKey >= 'a' && imGuiKey <= 'z') + imGuiKey = imGuiKey - 'a' + 'A'; + io.KeysDown[imGuiKey] = event.press; + } + + return io.WantCaptureKeyboard; +} + +bool ImGuiUI::onSpecial(const SpecialEvent& event) +{ + ImGui::SetCurrentContext(fImpl->fContext); + ImGuiIO &io = ImGui::GetIO(); + + int imGuiKey = IM_ARRAYSIZE(io.KeysDown) - event.key; + io.KeysDown[imGuiKey] = event.press; + + switch (event.key) + { + case kKeyShift: + io.KeyShift = event.press; + break; + case kKeyControl: + io.KeyCtrl = event.press; + break; + case kKeyAlt: + io.KeyAlt = event.press; + break; + case kKeySuper: + io.KeySuper = event.press; + break; + default: + break; + } + + return io.WantCaptureKeyboard; +} + +bool ImGuiUI::onMouse(const MouseEvent& event) +{ + ImGui::SetCurrentContext(fImpl->fContext); + ImGuiIO &io = ImGui::GetIO(); + + int imGuiButton = Impl::mouseButtonToImGui(event.button); + if (imGuiButton != -1) + io.MouseDown[imGuiButton] = event.press; + + return io.WantCaptureMouse; +} + +bool ImGuiUI::onMotion(const MotionEvent& event) +{ + ImGui::SetCurrentContext(fImpl->fContext); + ImGuiIO &io = ImGui::GetIO(); + + const float scaleFactor = fImpl->getScaleFactor(); + io.MousePos.x = std::round(scaleFactor * event.pos.getX()); + io.MousePos.y = std::round(scaleFactor * event.pos.getY()); + + return false; +} + +bool ImGuiUI::onScroll(const ScrollEvent& event) +{ + ImGui::SetCurrentContext(fImpl->fContext); + ImGuiIO &io = ImGui::GetIO(); + + io.MouseWheel += event.delta.getY(); + io.MouseWheelH += event.delta.getX(); + + return io.WantCaptureMouse; +} + +void ImGuiUI::onResize(const ResizeEvent& event) +{ + TopLevelWidget::onResize(event); + + const uint width = event.size.getWidth(); + const uint height = event.size.getHeight(); + + ImGui::SetCurrentContext(fImpl->fContext); + ImGuiIO &io = ImGui::GetIO(); + + const float scaleFactor = fImpl->getScaleFactor(); + io.DisplaySize.x = std::round(scaleFactor * width); + io.DisplaySize.y = std::round(scaleFactor * height); +} + +void ImGuiUI::idleCallback() +{ + bool shouldRepaint; + + if (fImpl->fWasEverPainted) + { + Impl::Clock::duration elapsed = + Impl::Clock::now() - fImpl->fLastRepainted; + std::chrono::milliseconds elapsedMs = + std::chrono::duration_cast(elapsed); + shouldRepaint = elapsedMs.count() > fImpl->fRepaintIntervalMs; + } + else + { + shouldRepaint = true; + } + + if (shouldRepaint) + repaint(); +} + +ImGuiUI::Impl::Impl(ImGuiUI* self) + : fSelf(self) +{ + setupGL(); +} + +ImGuiUI::Impl::~Impl() +{ + cleanupGL(); +} + +void ImGuiUI::Impl::setupGL() +{ + DISTRHO_SAFE_ASSERT_RETURN(glewInit() == 0,); + + IMGUI_CHECKVERSION(); + fContext = ImGui::CreateContext(); + ImGui::SetCurrentContext(fContext); + + ImGuiIO &io = ImGui::GetIO(); + const float scaleFactor = getScaleFactor(); + io.DisplaySize.x = std::round(scaleFactor * fSelf->getWidth()); + io.DisplaySize.y = std::round(scaleFactor * fSelf->getHeight()); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.IniFilename = nullptr; + + io.KeyMap[ImGuiKey_Tab] = '\t'; + io.KeyMap[ImGuiKey_LeftArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyLeft; + io.KeyMap[ImGuiKey_RightArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyRight; + io.KeyMap[ImGuiKey_UpArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyUp; + io.KeyMap[ImGuiKey_DownArrow] = IM_ARRAYSIZE(io.KeysDown) - kKeyDown; + io.KeyMap[ImGuiKey_PageUp] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageUp; + io.KeyMap[ImGuiKey_PageDown] = IM_ARRAYSIZE(io.KeysDown) - kKeyPageDown; + io.KeyMap[ImGuiKey_Home] = IM_ARRAYSIZE(io.KeysDown) - kKeyHome; + io.KeyMap[ImGuiKey_End] = IM_ARRAYSIZE(io.KeysDown) - kKeyEnd; + io.KeyMap[ImGuiKey_Insert] = IM_ARRAYSIZE(io.KeysDown) - kKeyInsert; + io.KeyMap[ImGuiKey_Delete] = 127; + io.KeyMap[ImGuiKey_Backspace] = '\b'; + io.KeyMap[ImGuiKey_Space] = ' '; + io.KeyMap[ImGuiKey_Enter] = '\r'; + io.KeyMap[ImGuiKey_Escape] = 27; + io.KeyMap[ImGuiKey_A] = 'A'; + io.KeyMap[ImGuiKey_C] = 'C'; + io.KeyMap[ImGuiKey_V] = 'V'; + io.KeyMap[ImGuiKey_X] = 'X'; + io.KeyMap[ImGuiKey_Y] = 'Y'; + io.KeyMap[ImGuiKey_Z] = 'Z'; + +#if defined(IMGUI_GL2) + ImGui_ImplOpenGL2_Init(); +#elif defined(IMGUI_GL3) + ImGui_ImplOpenGL3_Init(); +#endif +} + +void ImGuiUI::Impl::cleanupGL() +{ + ImGui::SetCurrentContext(fContext); +#if defined(IMGUI_GL2) + ImGui_ImplOpenGL2_Shutdown(); +#elif defined(IMGUI_GL3) + ImGui_ImplOpenGL3_Shutdown(); +#endif + ImGui::DestroyContext(fContext); +} + +int ImGuiUI::Impl::mouseButtonToImGui(int button) +{ + switch (button) + { + default: + return -1; + case 1: + return 0; + case 2: + return 2; + case 3: + return 1; + } +} + +END_NAMESPACE_DGL diff --git a/examples/ImguiSimpleGain/ImGuiUI.hpp b/examples/ImguiSimpleGain/ImGuiUI.hpp new file mode 100644 index 00000000..589d3bef --- /dev/null +++ b/examples/ImguiSimpleGain/ImGuiUI.hpp @@ -0,0 +1,56 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2021 Jean Pierre Cimalando + * + * 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. + */ + +#pragma once + +#include "TopLevelWidget.hpp" +#include "Color.hpp" + +#ifndef DGL_OPENGL +# error ImGUI is only available in OpenGL mode +#endif + +START_NAMESPACE_DGL + +/** + ImGui user interface class. +*/ +class ImGuiUI : public TopLevelWidget, + public IdleCallback { +public: + ImGuiUI(Window& windowToMapTo); + ~ImGuiUI() override; + void setBackgroundColor(Color color); + void setRepaintInterval(int intervalMs); + +protected: + virtual void onImGuiDisplay() = 0; + + virtual void onDisplay() override; + virtual bool onKeyboard(const KeyboardEvent& event) override; + virtual bool onSpecial(const SpecialEvent& event) override; + virtual bool onMouse(const MouseEvent& event) override; + virtual bool onMotion(const MotionEvent& event) override; + virtual bool onScroll(const ScrollEvent& event) override; + virtual void onResize(const ResizeEvent& event) override; + virtual void idleCallback() override; + +private: + struct Impl; + Impl* fImpl; +}; + +END_NAMESPACE_DGL diff --git a/examples/ImguiSimpleGain/Makefile b/examples/ImguiSimpleGain/Makefile new file mode 100644 index 00000000..0e07c251 --- /dev/null +++ b/examples/ImguiSimpleGain/Makefile @@ -0,0 +1,51 @@ +#!/usr/bin/make -f +# Makefile for DISTRHO Plugins # +# ---------------------------- # +# Created by falkTX, Christopher Arndt, and Patrick Desaulniers +# + +# -------------------------------------------------------------- +# Project name, used for binaries + +NAME = d_ImguiSimpleGain + +# -------------------------------------------------------------- +# Files to build + +FILES_DSP = \ + PluginSimpleGain.cpp + +FILES_UI = \ + UISimpleGain.cpp \ + ImGuiUI.cpp \ + ImGuiSrc.cpp + +# -------------------------------------------------------------- +# Do some magic + +include ../../Makefile.plugins.mk + +BUILD_CXX_FLAGS += -I../../../imgui -I../../../imgui/backends +BUILD_CXX_FLAGS += $(shell $(PKG_CONFIG) glew --cflags) +LINK_FLAGS += $(shell $(PKG_CONFIG) glew --libs) + +# -------------------------------------------------------------- +# Enable all selected plugin types + +ifeq ($(HAVE_JACK),true) +ifeq ($(HAVE_OPENGL),true) +TARGETS += jack +endif +endif + +ifeq ($(HAVE_OPENGL),true) +TARGETS += lv2_sep +else +TARGETS += lv2_dsp +endif + +TARGETS += vst + +all: $(TARGETS) + +# -------------------------------------------------------------- diff --git a/examples/ImguiSimpleGain/PluginSimpleGain.cpp b/examples/ImguiSimpleGain/PluginSimpleGain.cpp new file mode 100644 index 00000000..6c38238b --- /dev/null +++ b/examples/ImguiSimpleGain/PluginSimpleGain.cpp @@ -0,0 +1,161 @@ +/* + * Simple Gain audio effect based on DISTRHO Plugin Framework (DPF) + * + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2021 Jean Pierre Cimalando + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "PluginSimpleGain.hpp" + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------- + +PluginSimpleGain::PluginSimpleGain() + : Plugin(paramCount, presetCount, 0) // paramCount param(s), presetCount program(s), 0 states +{ + smooth_gain = new CParamSmooth(20.0f, getSampleRate()); + + for (unsigned p = 0; p < paramCount; ++p) { + Parameter param; + initParameter(p, param); + setParameterValue(p, param.ranges.def); + } +} + +PluginSimpleGain::~PluginSimpleGain() { + delete smooth_gain; +} + +// ----------------------------------------------------------------------- +// Init + +void PluginSimpleGain::initParameter(uint32_t index, Parameter& parameter) { + if (index >= paramCount) + return; + + parameter.ranges.min = -90.0f; + parameter.ranges.max = 30.0f; + parameter.ranges.def = -0.0f; + parameter.unit = "db"; + parameter.hints = kParameterIsAutomable; + + switch (index) { + case paramGain: + parameter.name = "Gain (dB)"; + parameter.shortName = "Gain"; + parameter.symbol = "gain"; + break; + } +} + +/** + Set the name of the program @a index. + This function will be called once, shortly after the plugin is created. +*/ +void PluginSimpleGain::initProgramName(uint32_t index, String& programName) { + if (index < presetCount) { + programName = factoryPresets[index].name; + } +} + +// ----------------------------------------------------------------------- +// Internal data + +/** + Optional callback to inform the plugin about a sample rate change. +*/ +void PluginSimpleGain::sampleRateChanged(double newSampleRate) { + fSampleRate = newSampleRate; + smooth_gain->setSampleRate(newSampleRate); +} + +/** + Get the current value of a parameter. +*/ +float PluginSimpleGain::getParameterValue(uint32_t index) const { + return fParams[index]; +} + +/** + Change a parameter value. +*/ +void PluginSimpleGain::setParameterValue(uint32_t index, float value) { + fParams[index] = value; + + switch (index) { + case paramGain: + gain = DB_CO(CLAMP(fParams[paramGain], -90.0, 30.0)); + break; + } +} + +/** + Load a program. + The host may call this function from any context, + including realtime processing. +*/ +void PluginSimpleGain::loadProgram(uint32_t index) { + if (index < presetCount) { + for (int i=0; i < paramCount; i++) { + setParameterValue(i, factoryPresets[index].params[i]); + } + } +} + +// ----------------------------------------------------------------------- +// Process + +void PluginSimpleGain::activate() { + // plugin is activated +} + + + +void PluginSimpleGain::run(const float** inputs, float** outputs, + uint32_t frames) { + + // get the left and right audio inputs + const float* const inpL = inputs[0]; + const float* const inpR = inputs[1]; + + // get the left and right audio outputs + float* const outL = outputs[0]; + float* const outR = outputs[1]; + + // apply gain against all samples + for (uint32_t i=0; i < frames; ++i) { + float gainval = smooth_gain->process(gain); + outL[i] = inpL[i] * gainval; + outR[i] = inpR[i] * gainval; + } +} + +// ----------------------------------------------------------------------- + +Plugin* createPlugin() { + return new PluginSimpleGain(); +} + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/examples/ImguiSimpleGain/PluginSimpleGain.hpp b/examples/ImguiSimpleGain/PluginSimpleGain.hpp new file mode 100644 index 00000000..69da27d0 --- /dev/null +++ b/examples/ImguiSimpleGain/PluginSimpleGain.hpp @@ -0,0 +1,161 @@ +/* + * Simple Gain audio effect based on DISTRHO Plugin Framework (DPF) + * + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2021 Jean Pierre Cimalando + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef PLUGIN_SIMPLEGAIN_H +#define PLUGIN_SIMPLEGAIN_H + +#include "DistrhoPlugin.hpp" +#include "CParamSmooth.hpp" + +START_NAMESPACE_DISTRHO + +#ifndef MIN +#define MIN(a,b) ( (a) < (b) ? (a) : (b) ) +#endif + +#ifndef MAX +#define MAX(a,b) ( (a) > (b) ? (a) : (b) ) +#endif + +#ifndef CLAMP +#define CLAMP(v, min, max) (MIN((max), MAX((min), (v)))) +#endif + +#ifndef DB_CO +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) +#endif + +// ----------------------------------------------------------------------- + +class PluginSimpleGain : public Plugin { +public: + enum Parameters { + paramGain = 0, + paramCount + }; + + PluginSimpleGain(); + + ~PluginSimpleGain(); + +protected: + // ------------------------------------------------------------------- + // Information + + const char* getLabel() const noexcept override { + return "SimpleGain"; + } + + const char* getDescription() const override { + return "A simple audio volume gain plugin"; + } + + const char* getMaker() const noexcept override { + return "example.com"; + } + + const char* getHomePage() const override { + return "https://example.com/plugins/simplegain"; + } + + const char* getLicense() const noexcept override { + return "https://spdx.org/licenses/MIT"; + } + + uint32_t getVersion() const noexcept override { + return d_version(0, 1, 0); + } + + // Go to: + // + // http://service.steinberg.de/databases/plugin.nsf/plugIn + // + // Get a proper plugin UID and fill it in here! + int64_t getUniqueId() const noexcept override { + return d_cconst('a', 'b', 'c', 'd'); + } + + // ------------------------------------------------------------------- + // 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; + + // ------------------------------------------------------------------- + // Optional + + // Optional callback to inform the plugin about a sample rate change. + void sampleRateChanged(double newSampleRate) override; + + // ------------------------------------------------------------------- + // Process + + void activate() override; + + void run(const float**, float** outputs, uint32_t frames) override; + + + // ------------------------------------------------------------------- + +private: + float fParams[paramCount]; + double fSampleRate; + float gain; + CParamSmooth *smooth_gain; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginSimpleGain) +}; + +struct Preset { + const char* name; + float params[PluginSimpleGain::paramCount]; +}; + +const Preset factoryPresets[] = { + { + "Unity Gain", + {0.0f} + } + //,{ + // "Another preset", // preset name + // {-14.0f, ...} // array of presetCount float param values + //} +}; + +const uint presetCount = sizeof(factoryPresets) / sizeof(Preset); + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // #ifndef PLUGIN_SIMPLEGAIN_H diff --git a/examples/ImguiSimpleGain/UISimpleGain.cpp b/examples/ImguiSimpleGain/UISimpleGain.cpp new file mode 100644 index 00000000..70af1d5c --- /dev/null +++ b/examples/ImguiSimpleGain/UISimpleGain.cpp @@ -0,0 +1,130 @@ +/* + * Simple Gain audio effect based on DISTRHO Plugin Framework (DPF) + * + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2021 Jean Pierre Cimalando + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "UISimpleGain.hpp" +#include +// #include "Window.hpp" + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------- +// Init / Deinit + +UISimpleGain::UISimpleGain() +: UI(600, 400) +{ + setGeometryConstraints(600, 400, true); +} + +UISimpleGain::~UISimpleGain() { + +} + +// ----------------------------------------------------------------------- +// DSP/Plugin callbacks + +/** + A parameter has changed on the plugin side. + This is called by the host to inform the UI about parameter changes. +*/ +void UISimpleGain::parameterChanged(uint32_t index, float value) { + params[index] = value; + + switch (index) { + case PluginSimpleGain::paramGain: + // do something when Gain param is set, such as update a widget + break; + } + + (void)value; +} + +/** + A program has been loaded on the plugin side. + This is called by the host to inform the UI about program changes. +*/ +void UISimpleGain::programLoaded(uint32_t index) { + if (index < presetCount) { + for (int i=0; i < PluginSimpleGain::paramCount; i++) { + // set values for each parameter and update their widgets + parameterChanged(i, factoryPresets[index].params[i]); + } + } +} + +/** + Optional callback to inform the UI about a sample rate change on the plugin side. +*/ +void UISimpleGain::sampleRateChanged(double newSampleRate) { + (void)newSampleRate; +} + +// ----------------------------------------------------------------------- +// Widget callbacks + + +/** + A function called to draw the view contents. +*/ +void UISimpleGain::onImGuiDisplay() { + float width = getWidth(); + float height = getHeight(); + float margin = 20.0f; + + ImGui::SetNextWindowPos(ImVec2(margin, margin)); + ImGui::SetNextWindowSize(ImVec2(width - 2 * margin, height - 2 * margin)); + + if (ImGui::Begin("Simple gain")) { + static char aboutText[256] = + "This is a demo plugin made with ImGui.\n"; + ImGui::InputTextMultiline("About", aboutText, sizeof(aboutText)); + + float& gain = params[PluginSimpleGain::paramGain]; + if (ImGui::SliderFloat("Gain (dB)", &gain, -90.0f, 30.0f)) + { + if (ImGui::IsItemActivated()) + { + editParameter(PluginSimpleGain::paramGain, true); + } + setParameterValue(PluginSimpleGain::paramGain, gain); + } + if (ImGui::IsItemDeactivated()) + { + editParameter(PluginSimpleGain::paramGain, false); + } + } + ImGui::End(); +} + +// ----------------------------------------------------------------------- + +UI* createUI() { + return new UISimpleGain(); +} + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/examples/ImguiSimpleGain/UISimpleGain.hpp b/examples/ImguiSimpleGain/UISimpleGain.hpp new file mode 100644 index 00000000..cf28dd8e --- /dev/null +++ b/examples/ImguiSimpleGain/UISimpleGain.hpp @@ -0,0 +1,55 @@ +/* + * Simple Gain audio effect based on DISTRHO Plugin Framework (DPF) + * + * SPDX-License-Identifier: MIT + * + * Copyright (C) 2021 Jean Pierre Cimalando + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UI_SIMPLEGAIN_H +#define UI_SIMPLEGAIN_H + +#include "DistrhoUI.hpp" +#include "PluginSimpleGain.hpp" + +START_NAMESPACE_DISTRHO + +class UISimpleGain : public UI { +public: + UISimpleGain(); + ~UISimpleGain(); + +protected: + void parameterChanged(uint32_t, float value) override; + void programLoaded(uint32_t index) override; + void sampleRateChanged(double newSampleRate) override; + + void onImGuiDisplay() override; + +private: + float params[PluginSimpleGain::paramCount] {}; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UISimpleGain) +}; + +END_NAMESPACE_DISTRHO + +#endif