Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send any MIDI message from UI #215

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 6 additions & 2 deletions Makefile.plugins.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 $@

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

Expand Down
6 changes: 6 additions & 0 deletions distrho/DistrhoUI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ class UI : public UIWidget
@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
Expand Down
10 changes: 5 additions & 5 deletions distrho/src/DistrhoPluginCarla.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ 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
{
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);

Expand Down Expand Up @@ -116,7 +116,7 @@ class UICarla
#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
}
Expand Down Expand Up @@ -159,9 +159,9 @@ class UICarla
#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

Expand Down
100 changes: 100 additions & 0 deletions distrho/src/DistrhoPluginInternal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

// -----------------------------------------------------------------------
Expand Down Expand Up @@ -672,6 +676,102 @@ class PluginExporter
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
Expand Down
67 changes: 47 additions & 20 deletions distrho/src/DistrhoPluginJack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class PluginJack
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)
{
Expand Down Expand Up @@ -356,12 +356,13 @@ class PluginJack
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)
Expand Down Expand Up @@ -410,27 +411,26 @@ class PluginJack
#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
Expand Down Expand Up @@ -466,6 +466,19 @@ class PluginJack
#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);
Expand Down Expand Up @@ -535,6 +548,9 @@ class PluginJack
# if DISTRHO_PLUGIN_WANT_PROGRAMS
int fProgramChanged;
# endif
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
SimpleMidiQueue fMidiQueue;
# endif
#endif

// -------------------------------------------------------------------
Expand Down Expand Up @@ -578,6 +594,17 @@ class PluginJack
#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);
Expand Down
Loading