Browse Source

Merge df89c74914 into 05752d0fb2

pull/215/merge
JP Cimalando GitHub 6 years ago
parent
commit
ed237ac751
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 710 additions and 73 deletions
  1. +2
    -0
      Makefile
  2. +6
    -2
      Makefile.plugins.mk
  3. +6
    -0
      distrho/DistrhoUI.hpp
  4. +5
    -5
      distrho/src/DistrhoPluginCarla.cpp
  5. +100
    -0
      distrho/src/DistrhoPluginInternal.hpp
  6. +47
    -20
      distrho/src/DistrhoPluginJack.cpp
  7. +65
    -12
      distrho/src/DistrhoPluginVST.cpp
  8. +11
    -1
      distrho/src/DistrhoUI.cpp
  9. +16
    -14
      distrho/src/DistrhoUIDSSI.cpp
  10. +8
    -8
      distrho/src/DistrhoUIInternal.hpp
  11. +8
    -11
      distrho/src/DistrhoUILV2.cpp
  12. +32
    -0
      examples/SendNote/DistrhoPluginInfo.h
  13. +46
    -0
      examples/SendNote/Makefile
  14. +6
    -0
      examples/SendNote/README.md
  15. +196
    -0
      examples/SendNote/SendNoteExamplePlugin.cpp
  16. +156
    -0
      examples/SendNote/SendNoteExampleUI.cpp

+ 2
- 0
Makefile View File

@@ -19,6 +19,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)
@@ -58,6 +59,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)


+ 6
- 2
Makefile.plugins.mk View File

@@ -98,6 +98,10 @@ DGL_FLAGS += -DDGL_EXTERNAL
HAVE_DGL = true
endif

ifneq ($(UI_TYPE),none)
THREAD_LIBS += -lpthread
endif

DGL_LIBS += $(DGL_SYSTEM_LIBS)

ifneq ($(HAVE_DGL),true)
@@ -171,7 +175,7 @@ $(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@echo "Creating JACK standalone for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(shell $(PKG_CONFIG) --libs jack) -o $@
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(THREAD_LIBS) $(shell $(PKG_CONFIG) --libs jack) -o $@

# ---------------------------------------------------------------------------------------------------------------------
# LADSPA
@@ -234,7 +238,7 @@ $(vst): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@echo "Creating VST plugin for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -o $@
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(THREAD_LIBS) $(SHARED) -o $@

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



+ 6
- 0
distrho/DistrhoUI.hpp View File

@@ -118,6 +118,12 @@ public:
@note Work in progress. Implemented for DSSI and LV2 formats.
*/
void sendNote(uint8_t channel, uint8_t note, uint8_t velocity);

/**
sendMidi.
@TODO Document this.
*/
void sendMidi(const uint8_t* data, uint32_t size);
#endif

#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS


+ 5
- 5
distrho/src/DistrhoPluginCarla.cpp View File

@@ -38,7 +38,7 @@ static const writeMidiFunc writeMidiCallback = nullptr;
static const setStateFunc setStateCallback = nullptr;
#endif
#if ! DISTRHO_PLUGIN_IS_SYNTH
static const sendNoteFunc sendNoteCallback = nullptr;
static const sendMidiFunc sendMidiCallback = nullptr;
#endif

class UICarla
@@ -46,7 +46,7 @@ class UICarla
public:
UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin)
: fHost(host),
fUI(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, plugin->getInstancePointer())
fUI(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendMidiCallback, setSizeCallback, plugin->getInstancePointer())
{
fUI.setWindowTitle(host->uiName);

@@ -116,7 +116,7 @@ protected:
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
void handleSendNote(const uint8_t, const uint8_t, const uint8_t)
void handleSendMidi(const uint8_t* const, const uint32_t)
{
// TODO
}
@@ -159,9 +159,9 @@ private:
#endif

#if DISTRHO_PLUGIN_IS_SYNTH
static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
static void sendMidiCallback(void* ptr, const uint8_t* data, uint32_t size)
{
handlePtr->handleSendNote(channel, note, velocity);
handlePtr->handleSendMidi(data, size);
}
#endif



+ 100
- 0
distrho/src/DistrhoPluginInternal.hpp View File

@@ -19,6 +19,10 @@

#include "../DistrhoPlugin.hpp"

#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
# include "extra/Mutex.hpp"
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
@@ -672,6 +676,102 @@ private:
DISTRHO_PREVENT_HEAP_ALLOCATION
};

#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
// -----------------------------------------------------------------------
// Midi queue class

/**
Single-consumer, single-producer FIFO queue of short MIDI messages, intended
for UI-to-DSP messaging in case of VST or similar plugin formats.
The access is guarded by mutex, using try-lock on the receiving side.
*/
class SimpleMidiQueue
{
public:
SimpleMidiQueue()
: fMidiStorage(nullptr),
fMidiCount(0),
fWriterIndex(0)
{
fMidiStorage = new ShortMessage[kMidiStorageCapacity];
}

virtual ~SimpleMidiQueue()
{
delete[] fMidiStorage;
fMidiStorage = nullptr;
}

void clear()
{
const MutexLocker locker(fMutex);
fMidiCount = 0;
}

void send(const uint8_t midiData[3])
{
const MutexLocker locker(fMutex);

uint32_t count = fMidiCount;
if (count == kMidiStorageCapacity)
return;

uint32_t index = fWriterIndex;
ShortMessage &msg = fMidiStorage[index];
std::memcpy(msg.data, midiData, 3);

fMidiCount = count + 1;
fWriterIndex = (index + 1) % kMidiStorageCapacity;
}

uint32_t receive(MidiEvent* events, uint32_t eventCount)
{
if (fMidiCount == 0)
return eventCount;

const MutexTryLocker locker(fMutex);
if (locker.wasNotLocked())
return eventCount;

// preserve the ordering of frame times according to messages before us
uint32_t frame = 0;
if (eventCount > 0)
frame = events[eventCount - 1].frame;

uint32_t countAvailable = fMidiCount;
uint32_t readerIndex = (fWriterIndex + kMidiStorageCapacity - countAvailable) % kMidiStorageCapacity;
for (; countAvailable > 0 && eventCount < kMaxMidiEvents; --countAvailable)
{
ShortMessage msg = fMidiStorage[readerIndex];
MidiEvent &event = events[eventCount++];
event.frame = frame;
event.size = 3;
std::memcpy(event.data, msg.data, sizeof(uint8_t)*3);
readerIndex = (readerIndex + 1) % kMaxMidiEvents;
}

fMidiCount = countAvailable;
return eventCount;
}

protected:
enum
{
kMidiStorageCapacity = 256,
};

struct ShortMessage
{
uint8_t data[3];
};

ShortMessage* fMidiStorage;
volatile uint32_t fMidiCount;
uint32_t fWriterIndex;
Mutex fMutex;
};
#endif

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

END_NAMESPACE_DISTRHO


+ 47
- 20
distrho/src/DistrhoPluginJack.cpp View File

@@ -101,7 +101,7 @@ public:
PluginJack(jack_client_t* const client)
: fPlugin(this, writeMidiCallback),
#if DISTRHO_PLUGIN_HAS_UI
fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, nullptr, setSizeCallback, getDesktopScaleFactor(), fPlugin.getInstancePointer()),
fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, sendMidiCallback, setSizeCallback, getDesktopScaleFactor(), fPlugin.getInstancePointer()),
#endif
fClient(client)
{
@@ -356,12 +356,13 @@ protected:
jack_midi_clear_buffer(fPortMidiOutBuffer);
#endif

if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf))
{
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
uint32_t midiEventCount = 0;
MidiEvent midiEvents[eventCount];
uint32_t midiEventCount = 0;
MidiEvent midiEvents[kMaxMidiEvents];
#endif

if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf))
{
jack_midi_event_t jevent;

for (uint32_t i=0; i < eventCount; ++i)
@@ -410,27 +411,26 @@ protected:
#endif

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
MidiEvent& midiEvent(midiEvents[midiEventCount++]);
if (midiEventCount < kMaxMidiEvents)
{
MidiEvent& midiEvent(midiEvents[midiEventCount++]);

midiEvent.frame = jevent.time;
midiEvent.size = jevent.size;
midiEvent.frame = jevent.time;
midiEvent.size = jevent.size;

if (midiEvent.size > MidiEvent::kDataSize)
midiEvent.dataExt = jevent.buffer;
else
std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size);
if (midiEvent.size > MidiEvent::kDataSize)
midiEvent.dataExt = jevent.buffer;
else
std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size);
}
#endif
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount);
#endif
}
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
else
{
fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0);
}
# if DISTRHO_PLUGIN_HAS_UI
midiEventCount = fMidiQueue.receive(midiEvents, midiEventCount);
# endif
fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount);
#else
fPlugin.run(audioIns, audioOuts, nframes);
#endif
@@ -466,6 +466,19 @@ protected:
#endif

#if DISTRHO_PLUGIN_HAS_UI
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void sendMidi(const uint8_t* const data, const uint32_t size)
{
if (size > 3)
return;

uint8_t midiData[3] = {0, 0, 0};
memcpy(midiData, data, size);

fMidiQueue.send(midiData);
}
# endif

void setSize(const uint width, const uint height)
{
fUI.setWindowSize(width, height);
@@ -535,6 +548,9 @@ private:
# if DISTRHO_PLUGIN_WANT_PROGRAMS
int fProgramChanged;
# endif
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
SimpleMidiQueue fMidiQueue;
# endif
#endif

// -------------------------------------------------------------------
@@ -578,6 +594,17 @@ private:
#endif

#if DISTRHO_PLUGIN_HAS_UI
static void sendMidiCallback(void* ptr, const uint8_t* data, uint32_t size)
{
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
thisPtr->sendMidi(data, size);
# else
(void)ptr;
(void)data;
(void)size;
# endif
}

static void setSizeCallback(void* ptr, uint width, uint height)
{
thisPtr->setSize(width, height);


+ 65
- 12
distrho/src/DistrhoPluginVST.cpp View File

@@ -155,18 +155,59 @@ public:
#endif
};

#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
// -----------------------------------------------------------------------

class MidiSendFromEditorHelper
{
public:
virtual ~MidiSendFromEditorHelper() {}

void clearEditorMidi()
{
fQueue.clear();
}

void sendEditorMidi(const uint8_t midiData[3])
{
fQueue.send(midiData);
}

uint32_t receiveEditorMidi(MidiEvent* events, uint32_t eventCount)
{
return fQueue.receive(events, eventCount);
}

private:
SimpleMidiQueue fQueue;
};
#endif

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

class UIHelperVst : public ParameterCheckHelper
#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
, public MidiSendFromEditorHelper
#endif
{
public:
virtual ~UIHelperVst()
{
}
};

#if DISTRHO_PLUGIN_HAS_UI
// -----------------------------------------------------------------------

class UIVst
{
public:
UIVst(const audioMasterCallback audioMaster, AEffect* const effect, ParameterCheckHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId, const float scaleFactor)
UIVst(const audioMasterCallback audioMaster, AEffect* const effect, UIHelperVst* const uiHelper, PluginExporter* const plugin, const intptr_t winId, const float scaleFactor)
: fAudioMaster(audioMaster),
fEffect(effect),
fUiHelper(uiHelper),
fPlugin(plugin),
fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, scaleFactor, plugin->getInstancePointer()),
fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendMidiCallback, setSizeCallback, scaleFactor, plugin->getInstancePointer()),
fShouldCaptureVstKeys(false)
{
// FIXME only needed for windows?
@@ -316,15 +357,20 @@ protected:
# endif
}

void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
void sendMidi(const uint8_t* const data, const uint32_t size)
{
# if 0 //DISTRHO_PLUGIN_WANT_MIDI_INPUT
// TODO
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
if (size > 3)
return;

uint8_t midiData[3] = {0, 0, 0};
memcpy(midiData, data, size);

fUiHelper->sendEditorMidi(midiData);
# else
return; // unused
(void)channel;
(void)note;
(void)velocity;
(void)data;
(void)size;
# endif
}

@@ -338,7 +384,7 @@ private:
// Vst stuff
const audioMasterCallback fAudioMaster;
AEffect* const fEffect;
ParameterCheckHelper* const fUiHelper;
UIHelperVst* const fUiHelper;
PluginExporter* const fPlugin;

// Plugin UI
@@ -365,9 +411,9 @@ private:
handlePtr->setState(key, value);
}

static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
static void sendMidiCallback(void* ptr, const uint8_t* data, uint32_t size)
{
handlePtr->sendNote(channel, note, velocity);
handlePtr->sendMidi(data, size);
}

static void setSizeCallback(void* ptr, uint width, uint height)
@@ -381,7 +427,7 @@ private:

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

class PluginVst : public ParameterCheckHelper
class PluginVst : public UIHelperVst
{
public:
PluginVst(const audioMasterCallback audioMaster, AEffect* const effect)
@@ -542,6 +588,10 @@ public:
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fMidiEventCount = 0;

#if DISTRHO_PLUGIN_HAS_UI
clearEditorMidi();
#endif

// tell host we want MIDI events
hostCallback(audioMasterWantMidi);
#endif
@@ -1017,6 +1067,9 @@ public:
#endif

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
#if DISTRHO_PLUGIN_HAS_UI
fMidiEventCount = receiveEditorMidi(fMidiEvents, fMidiEventCount);
#endif
fPlugin.run(inputs, outputs, sampleFrames, fMidiEvents, fMidiEventCount);
fMidiEventCount = 0;
#else


+ 11
- 1
distrho/src/DistrhoUI.cpp View File

@@ -106,7 +106,17 @@ void UI::setState(const char* key, const char* value)
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity)
{
pData->sendNoteCallback(channel, note, velocity);
uint8_t data[3];
data[0] = 0x90 | channel;
data[1] = note;
data[2] = velocity;

sendMidi(data, sizeof(data));
}

void UI::sendMidi(const uint8_t* data, uint32_t size)
{
pData->sendMidiCallback(data, size);
}
#endif



+ 16
- 14
distrho/src/DistrhoUIDSSI.cpp View File

@@ -27,7 +27,7 @@
START_NAMESPACE_DISTRHO

#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
static const sendNoteFunc sendNoteCallback = nullptr;
static const sendMidiFunc sendMidiCallback = nullptr;
#endif

// -----------------------------------------------------------------------
@@ -97,7 +97,7 @@ class UIDssi
{
public:
UIDssi(const OscData& oscData, const char* const uiTitle)
: fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback),
: fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendMidiCallback, setSizeCallback),
fHostClosed(false),
fOscData(oscData)
{
@@ -188,20 +188,22 @@ protected:
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
void sendMidi(const uint8_t* const data, const uint32_t size)
{
if (fOscData.server == nullptr)
if (size > 3)
return;
if (channel > 0xF)
if (fOscData.server == nullptr)
return;

uint8_t mdata[4] = {
0,
static_cast<uint8_t>(channel + (velocity != 0 ? 0x90 : 0x80)),
note,
velocity
};
fOscData.send_midi(mdata);
uint8_t midiBuf[4] = {0, 0, 0, 0};
memcpy(midiBuf + 1, data, size);

if ((midiBuf[1] & 0xf0) == 0x90 && midiBuf[3] == 0)
{
midiBuf[1] = 0x80 | (midiBuf[1] & 0x0f);
}

fOscData.send_midi(midiBuf);
}
#endif

@@ -232,9 +234,9 @@ private:
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
static void sendMidiCallback(void* ptr, const uint8_t* data, uint32_t size)
{
uiPtr->sendNote(channel, note, velocity);
uiPtr->sendMidi(data, size);
}
#endif



+ 8
- 8
distrho/src/DistrhoUIInternal.hpp View File

@@ -51,7 +51,7 @@ extern Window* d_lastUiWindow;
typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started);
typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value);
typedef void (*setStateFunc) (void* ptr, const char* key, const char* value);
typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
typedef void (*sendMidiFunc) (void* ptr, const uint8_t* data, uint32_t size);
typedef void (*setSizeFunc) (void* ptr, uint width, uint height);

// -----------------------------------------------------------------------
@@ -76,7 +76,7 @@ struct UI::PrivateData {
editParamFunc editParamCallbackFunc;
setParamFunc setParamCallbackFunc;
setStateFunc setStateCallbackFunc;
sendNoteFunc sendNoteCallbackFunc;
sendMidiFunc sendMidiCallbackFunc;
setSizeFunc setSizeCallbackFunc;

PrivateData() noexcept
@@ -93,7 +93,7 @@ struct UI::PrivateData {
editParamCallbackFunc(nullptr),
setParamCallbackFunc(nullptr),
setStateCallbackFunc(nullptr),
sendNoteCallbackFunc(nullptr),
sendMidiCallbackFunc(nullptr),
setSizeCallbackFunc(nullptr)
{
DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate));
@@ -133,10 +133,10 @@ struct UI::PrivateData {
setStateCallbackFunc(callbacksPtr, key, value);
}

void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
void sendMidiCallback(const uint8_t* data, uint32_t size)
{
if (sendNoteCallbackFunc != nullptr)
sendNoteCallbackFunc(callbacksPtr, channel, note, velocity);
if (sendMidiCallbackFunc != nullptr)
sendMidiCallbackFunc(callbacksPtr, data, size);
}

void setSizeCallback(const uint width, const uint height)
@@ -256,7 +256,7 @@ public:
const editParamFunc editParamCall,
const setParamFunc setParamCall,
const setStateFunc setStateCall,
const sendNoteFunc sendNoteCall,
const sendMidiFunc sendMidiCall,
const setSizeFunc setSizeCall,
const float scaleFactor = 1.0f,
void* const dspPtr = nullptr,
@@ -278,7 +278,7 @@ public:
fData->editParamCallbackFunc = editParamCall;
fData->setParamCallbackFunc = setParamCall;
fData->setStateCallbackFunc = setStateCall;
fData->sendNoteCallbackFunc = sendNoteCall;
fData->sendMidiCallbackFunc = sendMidiCall;
fData->setSizeCallbackFunc = setSizeCall;

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI


+ 8
- 11
distrho/src/DistrhoUILV2.cpp View File

@@ -42,7 +42,7 @@ typedef struct _LV2_Atom_MidiEvent {
} LV2_Atom_MidiEvent;

#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
static const sendNoteFunc sendNoteCallback = nullptr;
static const sendMidiFunc sendMidiCallback = nullptr;
#endif

// -----------------------------------------------------------------------
@@ -54,7 +54,7 @@ public:
const LV2_Options_Option* options, const LV2_URID_Map* const uridMap, const LV2UI_Resize* const uiResz, const LV2UI_Touch* uiTouch,
const LV2UI_Controller controller, const LV2UI_Write_Function writeFunc,
const float scaleFactor, LV2UI_Widget* const widget, void* const dspPtr)
: fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, scaleFactor, dspPtr, bundlePath),
: fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendMidiCallback, setSizeCallback, scaleFactor, dspPtr, bundlePath),
fUridMap(uridMap),
fUiResize(uiResz),
fUiTouch(uiTouch),
@@ -268,22 +268,19 @@ protected:
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
void sendMidi(const uint8_t* const data, const uint32_t size)
{
DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);

if (channel > 0xF)
if (size > 3)
return;

const uint32_t eventInPortIndex(DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS);

LV2_Atom_MidiEvent atomMidiEvent;
atomMidiEvent.atom.size = 3;
atomMidiEvent.atom.size = size;
atomMidiEvent.atom.type = fMidiEventURID;

atomMidiEvent.data[0] = channel + (velocity != 0 ? 0x90 : 0x80);
atomMidiEvent.data[1] = note;
atomMidiEvent.data[2] = velocity;
memcpy(atomMidiEvent.data, data, size);

// send to DSP side
fWriteFunction(fController, eventInPortIndex, lv2_atom_total_size(&atomMidiEvent.atom), fEventTransferURID, &atomMidiEvent);
@@ -339,9 +336,9 @@ private:
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
static void sendMidiCallback(void* ptr, const uint8_t* data, uint32_t size)
{
uiPtr->sendNote(channel, note, velocity);
uiPtr->sendMidi(data, size);
}
#endif



+ 32
- 0
examples/SendNote/DistrhoPluginInfo.h View File

@@ -0,0 +1,32 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2018 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 2
#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0

#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED

+ 46
- 0
examples/SendNote/Makefile View File

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

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

+ 6
- 0
examples/SendNote/README.md View File

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


+ 196
- 0
examples/SendNote/SendNoteExamplePlugin.cpp View File

@@ -0,0 +1,196 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2018 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* outputLeft = outputs[0];
float* outputRight = outputs[1];
std::memset(outputLeft, 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)
{
outputLeft[i] += gain * std::sin(k2pi * phase);
phase += timeStep;
phase -= (int)phase;
}
fOscillatorPhases[noteNumber] = phase;
}
std::memcpy(outputRight, outputLeft, frames * sizeof(float));
}
// -------------------------------------------------------------------------------------------------------
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

+ 156
- 0
examples/SendNote/SendNoteExampleUI.cpp View File

@@ -0,0 +1,156 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2019 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 "DistrhoPluginInfo.h"

#include "DistrhoUI.hpp"

#include "Window.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)
{
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
{
for (int key = 0; key < 12; ++key)
{
bool pressed = fKeyState[key];
Rectangle<int> bounds = getKeyBounds(key);

if (pressed)
glColor3f(0.8f, 0.5f, 0.3f);
else
glColor3f(0.3f, 0.5f, 0.8f);

bounds.draw();
}
}

/**
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 left-clicked + pressed first.
if (ev.button != 1 || ! ev.press)
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;

// Send a note event. Velocity=0 means off
bool pressed = !fKeyState[whichKey];
sendNote(0, kNoteOctaveStart+whichKey, pressed ? kNoteVelocity : 0);

// Invert the pressed state of this key, and update display
fKeyState[whichKey] = pressed;
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];

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

Loading…
Cancel
Save