DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit ae52c3647c2be6b41812b1b86cf37ad574a935fa
parent 9315bc71e7b578079b92dd1b1a1c4d3fc9dd7636
Author: falkTX <falktx@falktx.com>
Date:   Mon, 24 May 2021 12:09:34 +0100

Import SendNote example from #212, slightly adjusted

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
MMakefile | 2++
Aexamples/SendNote/DistrhoPluginInfo.h | 32++++++++++++++++++++++++++++++++
Aexamples/SendNote/Makefile | 46++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/SendNote/README.md | 6++++++
Aexamples/SendNote/SendNoteExamplePlugin.cpp | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/SendNote/SendNoteExampleUI.cpp | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 450 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -25,6 +25,7 @@ examples: dgl $(MAKE) all -C examples/Meters $(MAKE) all -C examples/MidiThrough $(MAKE) all -C examples/Parameters + $(MAKE) all -C examples/SendNote $(MAKE) all -C examples/States ifeq ($(HAVE_CAIRO),true) $(MAKE) all -C examples/CairoUI @@ -65,6 +66,7 @@ clean: $(MAKE) clean -C examples/Meters $(MAKE) clean -C examples/MidiThrough $(MAKE) clean -C examples/Parameters + $(MAKE) clean -C examples/SendNote $(MAKE) clean -C examples/States $(MAKE) clean -C utils/lv2-ttl-generator ifneq ($(MACOS_OR_WINDOWS),true) diff --git a/examples/SendNote/DistrhoPluginInfo.h b/examples/SendNote/DistrhoPluginInfo.h @@ -0,0 +1,32 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 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 "SendNote" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/examples/SendNote" + +#define DISTRHO_PLUGIN_HAS_UI 1 +#define DISTRHO_PLUGIN_HAS_EMBED_UI 1 +#define DISTRHO_PLUGIN_IS_RT_SAFE 1 +#define DISTRHO_PLUGIN_NUM_INPUTS 0 +#define DISTRHO_PLUGIN_NUM_OUTPUTS 1 +#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 +#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 + +#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/examples/SendNote/Makefile b/examples/SendNote/Makefile @@ -0,0 +1,46 @@ +#!/usr/bin/make -f +# Makefile for DISTRHO Plugins # +# ---------------------------- # +# Created by falkTX +# + +# -------------------------------------------------------------- +# Project name, used for binaries + +NAME = d_sendNote + +# -------------------------------------------------------------- +# Files to build + +FILES_DSP = \ + SendNoteExamplePlugin.cpp + + +FILES_UI = \ + SendNoteExampleUI.cpp + +# -------------------------------------------------------------- +# Do some magic + +include ../../Makefile.plugins.mk + +# -------------------------------------------------------------- +# Enable all possible 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/SendNote/README.md b/examples/SendNote/README.md @@ -0,0 +1,6 @@ +# SendNote example + +This example will show how to send MIDI notes in DPF based UIs.<br/> + +The UI presents a row of MIDI keys which transmit note events to a synthesizer. + diff --git a/examples/SendNote/SendNoteExamplePlugin.cpp b/examples/SendNote/SendNoteExamplePlugin.cpp @@ -0,0 +1,192 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 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 "DistrhoPlugin.hpp" + +#include <cmath> +#include <cstring> + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +/** + Plugin that demonstrates sending notes from the editor in DPF. + */ +class SendNoteExamplePlugin : public Plugin +{ +public: + SendNoteExamplePlugin() + : Plugin(0, 0, 0) + { + std::memset(fNotesPlayed, 0, sizeof(fNotesPlayed)); + std::memset(fOscillatorPhases, 0, sizeof(fOscillatorPhases)); + } + +protected: + /* -------------------------------------------------------------------------------------------------------- + * Information */ + + /** + Get the plugin label. + This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. + */ + const char* getLabel() const override + { + return "SendNote"; + } + + /** + Get an extensive comment/description about the plugin. + */ + const char* getDescription() const override + { + return "Plugin that demonstrates sending notes from the editor in DPF."; + } + + /** + Get the plugin author/maker. + */ + const char* getMaker() const override + { + return "DISTRHO"; + } + + /** + Get the plugin homepage. + */ + const char* getHomePage() const override + { + return "https://github.com/DISTRHO/DPF"; + } + + /** + Get the plugin license name (a single line of text). + For commercial plugins this should return some short copyright information. + */ + const char* getLicense() const override + { + return "ISC"; + } + + /** + Get the plugin version, in hexadecimal. + */ + uint32_t getVersion() const override + { + return d_version(1, 0, 0); + } + + /** + Get the plugin unique Id. + This value is used by LADSPA, DSSI and VST plugin formats. + */ + int64_t getUniqueId() const override + { + return d_cconst('d', 'S', 'N', 'o'); + } + + /* -------------------------------------------------------------------------------------------------------- + * Init and Internal data, unused in this plugin */ + + void initParameter(uint32_t, Parameter&) override {} + float getParameterValue(uint32_t) const override { return 0.0f;} + void setParameterValue(uint32_t, float) override {} + + /* -------------------------------------------------------------------------------------------------------- + * Audio/MIDI Processing */ + + /** + Run/process function for plugins with MIDI input. + This synthesizes the MIDI voices with a sum of sine waves. + */ + void run(const float**, float** outputs, uint32_t frames, + const MidiEvent* midiEvents, uint32_t midiEventCount) override + { + for (uint32_t i = 0; i < midiEventCount; ++i) + { + if (midiEvents[i].size <= 3) + { + uint8_t status = midiEvents[i].data[0]; + uint8_t note = midiEvents[i].data[1] & 127; + uint8_t velocity = midiEvents[i].data[2] & 127; + + switch (status & 0xf0) + { + case 0x90: + if (velocity != 0) + { + fNotesPlayed[note] = velocity; + break; + } + /* fall through */ + case 0x80: + fNotesPlayed[note] = 0; + fOscillatorPhases[note] = 0; + break; + } + } + } + + float* const output = outputs[0]; + std::memset(output, 0, frames * sizeof(float)); + + for (uint32_t noteNumber = 0; noteNumber < 128; ++noteNumber) + { + if (fNotesPlayed[noteNumber] == 0) + continue; + + float notePitch = 8.17579891564 * std::exp(0.0577622650 * noteNumber); + + float phase = fOscillatorPhases[noteNumber]; + float timeStep = notePitch / getSampleRate(); + float k2pi = 2.0 * M_PI; + float gain = 0.1; + + for (uint32_t i = 0; i < frames; ++i) + { + output[i] += gain * std::sin(k2pi * phase); + phase += timeStep; + phase -= (int)phase; + } + + fOscillatorPhases[noteNumber] = phase; + } + } + + // ------------------------------------------------------------------------------------------------------- + +private: + uint8_t fNotesPlayed[128]; + float fOscillatorPhases[128]; + + /** + Set our plugin class as non-copyable and add a leak detector just in case. + */ + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SendNoteExamplePlugin) +}; + +/* ------------------------------------------------------------------------------------------------------------ + * Plugin entry point, called by DPF to create a new plugin instance. */ + +Plugin* createPlugin() +{ + return new SendNoteExamplePlugin(); +} + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/examples/SendNote/SendNoteExampleUI.cpp b/examples/SendNote/SendNoteExampleUI.cpp @@ -0,0 +1,172 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 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 "DistrhoUI.hpp" + +#include "Color.hpp" + +#include <cstring> + +START_NAMESPACE_DISTRHO + +/** + We need the rectangle class from DGL. + */ +using DGL_NAMESPACE::Rectangle; + +// ----------------------------------------------------------------------------------------------------------- + +class SendNoteExampleUI : public UI +{ +public: + SendNoteExampleUI() + : UI(64*12+8, 64+8), + fLastKey(-1) + { + std::memset(fKeyState, 0, sizeof(fKeyState)); + } + +protected: + /* -------------------------------------------------------------------------------------------------------- + * 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 parameterChanged(uint32_t index, float value) override + { + (void)index; + (void)value; + } + + /* -------------------------------------------------------------------------------------------------------- + * Widget Callbacks */ + + /** + The OpenGL drawing function. + This UI will draw a row of 12 keys, with on/off states according to pressed status. + */ + void onDisplay() override + { + const GraphicsContext& context(getGraphicsContext()); + + for (int key = 0; key < 12; ++key) + { + bool pressed = fKeyState[key]; + Rectangle<int> bounds = getKeyBounds(key); + + if (pressed) + Color(0.8f, 0.5f, 0.3f).setFor(context); + else + Color(0.3f, 0.5f, 0.8f).setFor(context); + + bounds.draw(context); + } + } + + /** + Mouse press event. + This UI will de/activate keys when you click them and reports it as MIDI note events to the plugin. + */ + bool onMouse(const MouseEvent& ev) override + { + // Test for last key release first + if (fLastKey != -1 && ! ev.press) + { + // Send a note event. Velocity=0 means off + sendNote(0, kNoteOctaveStart+fLastKey, 0); + // Unset key state + fKeyState[fLastKey] = false; + fLastKey = -1; + repaint(); + return true; + } + + // Test for left-clicked first. + if (ev.button != 1) + return false; + + // Find the key which is pressed, if any + int whichKey = -1; + for (int key = 0; key < 12 && whichKey == -1; ++key) + { + Rectangle<int> bounds = getKeyBounds(key); + + if (bounds.contains(ev.pos)) + whichKey = key; + } + + if (whichKey == -1) + return false; + if (fKeyState[whichKey] == ev.press) + return false; + + // Send a note event. Velocity=0 means off + sendNote(0, kNoteOctaveStart+whichKey, ev.press ? kNoteVelocity : 0); + + // Set pressed state of this key, and update display + fLastKey = whichKey; + fKeyState[whichKey] = ev.press; + repaint(); + + return true; + } + + /** + Set our UI class as non-copyable and add a leak detector just in case. + */ + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SendNoteExampleUI) + +private: + /** + Get the bounds of a particular key of the virtual MIDI keyboard. + */ + Rectangle<int> getKeyBounds(unsigned index) const + { + Rectangle<int> bounds; + int padding = 8; + bounds.setX(64 * index + padding); + bounds.setY(padding); + bounds.setWidth(64 - padding); + bounds.setHeight(64 - padding); + return bounds; + } + + /** + The pressed state of one octave of a virtual MIDI keyboard. + */ + bool fKeyState[12]; + int8_t fLastKey; + + enum + { + kNoteVelocity = 100, // velocity of sent Note-On events + kNoteOctaveStart = 60, // starting note of the virtual MIDI keyboard + }; +}; + +/* ------------------------------------------------------------------------------------------------------------ + * UI entry point, called by DPF to create a new UI instance. */ + +UI* createUI() +{ + return new SendNoteExampleUI(); +} + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO