Browse Source

Continue work to separate idle and uiIdle

tags/1.9.6
falkTX 10 years ago
parent
commit
d62b7c31dd
13 changed files with 288 additions and 202 deletions
  1. +2
    -2
      source/backend/CarlaBackend.h
  2. +7
    -11
      source/backend/CarlaPlugin.hpp
  3. +2
    -4
      source/backend/CarlaUtils.cpp
  4. +3
    -10
      source/backend/engine/CarlaEngine.cpp
  5. +15
    -16
      source/backend/engine/CarlaEngineThread.cpp
  6. +211
    -151
      source/backend/plugin/CarlaPlugin.cpp
  7. +27
    -0
      source/backend/plugin/CarlaPluginInternal.cpp
  8. +13
    -0
      source/backend/plugin/CarlaPluginInternal.hpp
  9. +1
    -1
      source/backend/plugin/CarlaPluginJuce.cpp
  10. +2
    -2
      source/backend/plugin/CarlaPluginLV2.cpp
  11. +2
    -2
      source/backend/plugin/CarlaPluginNative.cpp
  12. +1
    -1
      source/backend/plugin/CarlaPluginVST2.cpp
  13. +2
    -2
      source/carla_backend.py

+ 2
- 2
source/backend/CarlaBackend.h View File

@@ -164,9 +164,9 @@ static const uint PLUGIN_CAN_PANNING = 0x080;
static const uint PLUGIN_NEEDS_FIXED_BUFFERS = 0x100; static const uint PLUGIN_NEEDS_FIXED_BUFFERS = 0x100;


/*! /*!
* Plugin needs all UI events in a single/main thread.
* Plugin needs to receive all UI events in the main thread.
*/ */
static const uint PLUGIN_NEEDS_SINGLE_THREAD = 0x200;
static const uint PLUGIN_NEEDS_UI_MAIN_THREAD = 0x200;


/** @} */ /** @} */




+ 7
- 11
source/backend/CarlaPlugin.hpp View File

@@ -665,7 +665,7 @@ public:


/*! /*!
* Idle function (non-UI), called at regular intervals. * Idle function (non-UI), called at regular intervals.
* This function is called from the main thread only if PLUGIN_USES_SINGLE_THREAD is set.
* @note: This function is NOT called from the main thread.
*/ */
virtual void idle(); virtual void idle();


@@ -729,15 +729,6 @@ public:
void sendMidiAllNotesOffToCallback(); void sendMidiAllNotesOffToCallback();
#endif #endif


// -------------------------------------------------------------------
// Post-poned events

/*!
* Process all the post-poned events.
* This function is called from the main thread if PLUGIN_USES_SINGLE_THREAD is set.
*/
void postRtEventsRun();

// ------------------------------------------------------------------- // -------------------------------------------------------------------
// UI Stuff // UI Stuff


@@ -749,33 +740,38 @@ public:


/*! /*!
* UI idle function, called at regular intervals. * UI idle function, called at regular intervals.
* This function is called from the main thread only if PLUGIN_USES_SINGLE_THREAD is set.
* This function is only called from the main thread if PLUGIN_NEEDS_UI_MAIN_THREAD is set.
* @note This function may sometimes be called even if the UI is not visible yet. * @note This function may sometimes be called even if the UI is not visible yet.
*/ */
virtual void uiIdle(); virtual void uiIdle();


/*! /*!
* Tell the UI a parameter has changed. * Tell the UI a parameter has changed.
* @see uiIdle
*/ */
virtual void uiParameterChange(const uint32_t index, const float value) noexcept; virtual void uiParameterChange(const uint32_t index, const float value) noexcept;


/*! /*!
* Tell the UI the current program has changed. * Tell the UI the current program has changed.
* @see uiIdle
*/ */
virtual void uiProgramChange(const uint32_t index) noexcept; virtual void uiProgramChange(const uint32_t index) noexcept;


/*! /*!
* Tell the UI the current midi program has changed. * Tell the UI the current midi program has changed.
* @see uiIdle
*/ */
virtual void uiMidiProgramChange(const uint32_t index) noexcept; virtual void uiMidiProgramChange(const uint32_t index) noexcept;


/*! /*!
* Tell the UI a note has been pressed. * Tell the UI a note has been pressed.
* @see uiIdle
*/ */
virtual void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept; virtual void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept;


/*! /*!
* Tell the UI a note has been released. * Tell the UI a note has been released.
* @see uiIdle
*/ */
virtual void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept; virtual void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept;




+ 2
- 4
source/backend/CarlaUtils.cpp View File

@@ -431,7 +431,7 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype,
if (desc->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) if (desc->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS; info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS;
if (desc->hints & NATIVE_PLUGIN_NEEDS_SINGLE_THREAD) if (desc->hints & NATIVE_PLUGIN_NEEDS_SINGLE_THREAD)
info.hints |= CB::PLUGIN_NEEDS_SINGLE_THREAD;
info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD;


info.audioIns = desc->audioIns; info.audioIns = desc->audioIns;
info.audioOuts = desc->audioOuts; info.audioOuts = desc->audioOuts;
@@ -460,10 +460,8 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype,
// features // features
info.hints = 0x0; info.hints = 0x0;


#if 0
if (lilvPlugin.get_uis().size() > 0 || lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr)
if (lilvPlugin.get_uis().size() > 0 /*|| lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr*/)
info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
#endif


{ {
Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features()); Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features());


+ 3
- 10
source/backend/engine/CarlaEngine.cpp View File

@@ -294,18 +294,11 @@ void CarlaEngine::idle() noexcept
{ {
const uint hints(plugin->getHints()); const uint hints(plugin->getHints());


if (hints & PLUGIN_NEEDS_SINGLE_THREAD)
if ((hints & PLUGIN_HAS_CUSTOM_UI) != 0 && (hints & PLUGIN_NEEDS_UI_MAIN_THREAD) != 0)
{ {
try { try {
plugin->idle();
} CARLA_SAFE_EXCEPTION_CONTINUE("Plugin idle");

if (hints & PLUGIN_HAS_CUSTOM_UI)
{
try {
plugin->uiIdle();
} CARLA_SAFE_EXCEPTION_CONTINUE("Plugin uiIdle");
}
plugin->uiIdle();
} CARLA_SAFE_EXCEPTION_CONTINUE("Plugin uiIdle");
} }
} }
} }


+ 15
- 16
source/backend/engine/CarlaEngineThread.cpp View File

@@ -47,17 +47,16 @@ void CarlaEngineThread::run() noexcept
#endif #endif
carla_debug("CarlaEngineThread::run()"); carla_debug("CarlaEngineThread::run()");


bool needsSingleThread, needsUiUpdates, oscRegisted;
float value; float value;
#ifdef BUILD_BRIDGE
oscRegisted = false;


#ifdef BUILD_BRIDGE
for (; /*kEngine->isRunning() &&*/ ! shouldThreadExit();) for (; /*kEngine->isRunning() &&*/ ! shouldThreadExit();)
{ {
const bool oscRegisted = false;
#else #else
for (; kEngine->isRunning() && ! shouldThreadExit();) for (; kEngine->isRunning() && ! shouldThreadExit();)
{ {
oscRegisted = kEngine->isOscControlRegistered();
const bool oscRegisted = kEngine->isOscControlRegistered();
#endif #endif


for (uint i=0, count = kEngine->getCurrentPluginCount(); i < count; ++i) for (uint i=0, count = kEngine->getCurrentPluginCount(); i < count; ++i)
@@ -67,20 +66,20 @@ void CarlaEngineThread::run() noexcept
CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr && plugin->isEnabled()); CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr && plugin->isEnabled());
CARLA_SAFE_ASSERT_UINT2(i == plugin->getId(), i, plugin->getId()); CARLA_SAFE_ASSERT_UINT2(i == plugin->getId(), i, plugin->getId());


needsSingleThread = (plugin->getHints() & PLUGIN_NEEDS_SINGLE_THREAD);
needsUiUpdates = (plugin->getHints() & PLUGIN_HAS_CUSTOM_UI) && ! needsSingleThread;
const uint hints(plugin->getHints());
const bool updateUI((hints & PLUGIN_HAS_CUSTOM_UI) != 0 && (hints & PLUGIN_NEEDS_UI_MAIN_THREAD) == 0);


// ----------------------------------------------------------- // -----------------------------------------------------------
// Process postponed events
// DSP Idle


if (! needsSingleThread)
{
try {
plugin->idle();
} CARLA_SAFE_EXCEPTION("idle()")
}
try {
plugin->idle();
} CARLA_SAFE_EXCEPTION("idle()")
// -----------------------------------------------------------
// Post-poned events


if (oscRegisted || needsUiUpdates)
if (oscRegisted || updateUI)
{ {
// ------------------------------------------------------- // -------------------------------------------------------
// Update parameter outputs // Update parameter outputs
@@ -98,11 +97,11 @@ void CarlaEngineThread::run() noexcept
kEngine->oscSend_control_set_parameter_value(i, static_cast<int32_t>(j), value); kEngine->oscSend_control_set_parameter_value(i, static_cast<int32_t>(j), value);
#endif #endif
// Update UI // Update UI
if (needsUiUpdates)
if (updateUI)
plugin->uiParameterChange(j, value); plugin->uiParameterChange(j, value);
} }


if (needsUiUpdates)
if (updateUI)
{ {
try { try {
plugin->uiIdle(); plugin->uiIdle();


+ 211
- 151
source/backend/plugin/CarlaPlugin.cpp View File

@@ -1363,7 +1363,181 @@ void CarlaPlugin::idle()
if (! pData->enabled) if (! pData->enabled)
return; return;


postRtEventsRun();
const bool hasUI(pData->hints & PLUGIN_HAS_CUSTOM_UI);
const bool needsUiMainThread(pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD);
#ifndef BUILD_BRIDGE
const bool sendOsc(pData->engine->isOscControlRegistered());
#endif

const CarlaMutexLocker sl(pData->postRtEvents.mutex);

for (RtLinkedList<PluginPostRtEvent>::Itenerator it = pData->postRtEvents.data.begin(); it.valid(); it.next())
{
const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);

switch (event.type)
{
case kPluginPostRtEventNull: {
} break;

case kPluginPostRtEventDebug: {
pData->engine->callback(ENGINE_CALLBACK_DEBUG, pData->id, event.value1, event.value2, event.value3, nullptr);
} break;

case kPluginPostRtEventParameterChange: {
// Update UI
if (event.value1 >= 0 && hasUI)
{
if (needsUiMainThread)
pData->postUiEvents.append(event);
else
uiParameterChange(static_cast<uint32_t>(event.value1), event.value3);
}

if (event.value2 != 1)
{
#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_set_parameter_value(pData->id, event.value1, event.value3);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, event.value1, 0, event.value3, nullptr);
}
} break;

case kPluginPostRtEventProgramChange: {
// Update UI
if (event.value1 >= 0 && hasUI)
{
if (needsUiMainThread)
pData->postUiEvents.append(event);
else
uiProgramChange(static_cast<uint32_t>(event.value1));
}

// Update param values
for (uint32_t j=0; j < pData->param.count; ++j)
{
const float paramDefault(pData->param.ranges[j].def);
const float paramValue(getParameterValue(j));

#ifndef BUILD_BRIDGE
if (sendOsc)
{
pData->engine->oscSend_control_set_parameter_value(pData->id, static_cast<int32_t>(j), paramValue);
pData->engine->oscSend_control_set_default_value(pData->id, j, paramDefault);
}
#endif
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, static_cast<int>(j), 0, paramValue, nullptr);
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED, pData->id, static_cast<int>(j), 0, paramDefault, nullptr);
}

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_set_current_program(pData->id, event.value1);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_PROGRAM_CHANGED, pData->id, event.value1, 0, 0.0f, nullptr);

} break;

case kPluginPostRtEventMidiProgramChange: {
// Update UI
if (event.value1 >= 0 && hasUI)
{
if (needsUiMainThread)
pData->postUiEvents.append(event);
else
uiMidiProgramChange(static_cast<uint32_t>(event.value1));
}

// Update param values
for (uint32_t j=0; j < pData->param.count; ++j)
{
const float paramDefault(pData->param.ranges[j].def);
const float paramValue(getParameterValue(j));

#ifndef BUILD_BRIDGE
if (sendOsc)
{
pData->engine->oscSend_control_set_parameter_value(pData->id, static_cast<int32_t>(j), paramValue);
pData->engine->oscSend_control_set_default_value(pData->id, j, paramDefault);
}
#endif
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, static_cast<int>(j), 0, paramValue, nullptr);
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED, pData->id, static_cast<int>(j), 0, paramDefault, nullptr);
}

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_set_current_midi_program(pData->id, event.value1);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED, pData->id, event.value1, 0, 0.0f, nullptr);

} break;

case kPluginPostRtEventNoteOn: {
CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
CARLA_SAFE_ASSERT_BREAK(event.value3 >= 0 && event.value3 < MAX_MIDI_VALUE);

const uint8_t channel = static_cast<uint8_t>(event.value1);
const uint8_t note = static_cast<uint8_t>(event.value2);
const uint8_t velocity = uint8_t(event.value3);

// Update UI
if (hasUI)
{
if (needsUiMainThread)
pData->postUiEvents.append(event);
else
uiNoteOn(channel, note, velocity);
}

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_note_on(pData->id, channel, note, velocity);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_NOTE_ON, pData->id, event.value1, event.value2, event.value3, nullptr);

} break;

case kPluginPostRtEventNoteOff: {
CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);

const uint8_t channel = static_cast<uint8_t>(event.value1);
const uint8_t note = static_cast<uint8_t>(event.value2);

// Update UI
if (hasUI)
{
if (needsUiMainThread)
pData->postUiEvents.append(event);
else
uiNoteOff(channel, note);
}

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_note_off(pData->id, channel, note);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_NOTE_OFF, pData->id, event.value1, event.value2, 0.0f, nullptr);

} break;
}
}

pData->postRtEvents.data.clear();
} }


bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept
@@ -1575,174 +1749,60 @@ void CarlaPlugin::sendMidiAllNotesOffToCallback()
#endif #endif


// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Post-poned events
// UI Stuff


void CarlaPlugin::postRtEventsRun()
void CarlaPlugin::showCustomUI(const bool)
{ {
const CarlaMutexLocker sl(pData->postRtEvents.mutex);
#ifndef BUILD_BRIDGE
const bool sendOsc(pData->engine->isOscControlRegistered());
#endif
CARLA_SAFE_ASSERT(false);
}


for (RtLinkedList<PluginPostRtEvent>::Itenerator it = pData->postRtEvents.data.begin(); it.valid(); it.next())
void CarlaPlugin::uiIdle()
{
if (pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD)
{ {
const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);

switch (event.type)
// Update parameter outputs
for (uint32_t i=0; i < pData->param.count; ++i)
{ {
case kPluginPostRtEventNull: {
} break;

case kPluginPostRtEventDebug: {
pData->engine->callback(ENGINE_CALLBACK_DEBUG, pData->id, event.value1, event.value2, event.value3, nullptr);
} break;

case kPluginPostRtEventParameterChange: {
// Update UI
if (event.value1 >= 0 && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
uiParameterChange(static_cast<uint32_t>(event.value1), event.value3);
if (pData->param.data[i].type == PARAMETER_OUTPUT)
uiParameterChange(i, getParameterValue(i));
}


if (event.value2 != 1)
{
#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_set_parameter_value(pData->id, event.value1, event.value3);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, event.value1, 0, event.value3, nullptr);
}
} break;
const CarlaMutexLocker sl(pData->postUiEvents.mutex);


case kPluginPostRtEventProgramChange: {
// Update UI
if (event.value1 >= 0 && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
uiProgramChange(static_cast<uint32_t>(event.value1));
for (LinkedList<PluginPostRtEvent>::Itenerator it = pData->postUiEvents.data.begin(); it.valid(); it.next())
{
const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);


// Update param values
for (uint32_t j=0; j < pData->param.count; ++j)
switch (event.type)
{ {
const float paramDefault(pData->param.ranges[j].def);
const float paramValue(getParameterValue(j));

#ifndef BUILD_BRIDGE
if (sendOsc)
{
pData->engine->oscSend_control_set_parameter_value(pData->id, static_cast<int32_t>(j), paramValue);
pData->engine->oscSend_control_set_default_value(pData->id, j, paramDefault);
}
#endif
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, static_cast<int>(j), 0, paramValue, nullptr);
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED, pData->id, static_cast<int>(j), 0, paramDefault, nullptr);
}
case kPluginPostRtEventNull:
case kPluginPostRtEventDebug:
break;


#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_set_current_program(pData->id, event.value1);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_PROGRAM_CHANGED, pData->id, event.value1, 0, 0.0f, nullptr);
case kPluginPostRtEventParameterChange:
uiParameterChange(static_cast<uint32_t>(event.value1), event.value3);
break;


} break;
case kPluginPostRtEventProgramChange:
uiProgramChange(static_cast<uint32_t>(event.value1));
break;


case kPluginPostRtEventMidiProgramChange: {
// Update UI
if (event.value1 >= 0 && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
case kPluginPostRtEventMidiProgramChange:
uiMidiProgramChange(static_cast<uint32_t>(event.value1)); uiMidiProgramChange(static_cast<uint32_t>(event.value1));
break;


// Update param values
for (uint32_t j=0; j < pData->param.count; ++j)
{
const float paramDefault(pData->param.ranges[j].def);
const float paramValue(getParameterValue(j));
case kPluginPostRtEventNoteOn:
uiNoteOn(static_cast<uint8_t>(event.value1), static_cast<uint8_t>(event.value2), uint8_t(event.value3));
break;


#ifndef BUILD_BRIDGE
if (sendOsc)
{
pData->engine->oscSend_control_set_parameter_value(pData->id, static_cast<int32_t>(j), paramValue);
pData->engine->oscSend_control_set_default_value(pData->id, j, paramDefault);
}
#endif
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, static_cast<int>(j), 0, paramValue, nullptr);
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED, pData->id, static_cast<int>(j), 0, paramDefault, nullptr);
case kPluginPostRtEventNoteOff:
uiNoteOff(static_cast<uint8_t>(event.value1), static_cast<uint8_t>(event.value2));
break;
} }

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_set_current_midi_program(pData->id, event.value1);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED, pData->id, event.value1, 0, 0.0f, nullptr);

} break;

case kPluginPostRtEventNoteOn: {
CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
CARLA_SAFE_ASSERT_BREAK(event.value3 >= 0 && event.value3 < MAX_MIDI_VALUE);

const uint8_t channel = static_cast<uint8_t>(event.value1);
const uint8_t note = static_cast<uint8_t>(event.value2);
const uint8_t velocity = uint8_t(event.value3);

// Update UI
if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
uiNoteOn(channel, note, velocity);

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_note_on(pData->id, channel, note, velocity);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_NOTE_ON, pData->id, event.value1, event.value2, event.value3, nullptr);

} break;

case kPluginPostRtEventNoteOff: {
CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);

const uint8_t channel = static_cast<uint8_t>(event.value1);
const uint8_t note = static_cast<uint8_t>(event.value2);

// Update UI
if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
uiNoteOff(channel, note);

#ifndef BUILD_BRIDGE
// Update OSC control client
if (sendOsc)
pData->engine->oscSend_control_note_off(pData->id, channel, note);
#endif
// Update Host
pData->engine->callback(ENGINE_CALLBACK_NOTE_OFF, pData->id, event.value1, event.value2, 0.0f, nullptr);

} break;
} }
}

pData->postRtEvents.data.clear();
}

// -------------------------------------------------------------------
// UI Stuff


void CarlaPlugin::showCustomUI(const bool)
{
CARLA_SAFE_ASSERT(false);
}

void CarlaPlugin::uiIdle()
{
// Update parameter outputs if needed
for (uint32_t i=0; i < pData->param.count; ++i)
{
if (pData->param.data[i].type == PARAMETER_OUTPUT)
uiParameterChange(i, getParameterValue(i));
pData->postUiEvents.data.clear();
} }


if (pData->transientTryCounter == 0) if (pData->transientTryCounter == 0)


+ 27
- 0
source/backend/plugin/CarlaPluginInternal.cpp View File

@@ -421,6 +421,32 @@ void CarlaPlugin::ProtectedData::PostRtEvents::clear() noexcept
mutex.unlock(); mutex.unlock();
} }


// -----------------------------------------------------------------------
// ProtectedData::PostUiEvents

CarlaPlugin::ProtectedData::PostUiEvents::PostUiEvents() noexcept
: mutex(),
data() {}

CarlaPlugin::ProtectedData::PostUiEvents::~PostUiEvents() noexcept
{
clear();
}

void CarlaPlugin::ProtectedData::PostUiEvents::append(const PluginPostRtEvent& e) noexcept
{
mutex.lock();
data.append(e);
mutex.unlock();
}

void CarlaPlugin::ProtectedData::PostUiEvents::clear() noexcept
{
mutex.lock();
data.clear();
mutex.unlock();
}

#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// ProtectedData::PostProc // ProtectedData::PostProc
@@ -471,6 +497,7 @@ CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx
stateSave(), stateSave(),
extNotes(), extNotes(),
postRtEvents(), postRtEvents(),
postUiEvents(),
#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
postProc(), postProc(),
#endif #endif


+ 13
- 0
source/backend/plugin/CarlaPluginInternal.hpp View File

@@ -283,6 +283,19 @@ struct CarlaPlugin::ProtectedData {


} postRtEvents; } postRtEvents;


struct PostUiEvents {
CarlaMutex mutex;
LinkedList<PluginPostRtEvent> data;

PostUiEvents() noexcept;
~PostUiEvents() noexcept;
void append(const PluginPostRtEvent& event) noexcept;
void clear() noexcept;

CARLA_DECLARE_NON_COPY_STRUCT(PostUiEvents)

} postUiEvents;

#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
struct PostProc { struct PostProc {
float dryWet; float dryWet;


+ 1
- 1
source/backend/plugin/CarlaPluginJuce.cpp View File

@@ -532,7 +532,7 @@ public:
if (fInstance->hasEditor()) if (fInstance->hasEditor())
{ {
pData->hints |= PLUGIN_HAS_CUSTOM_UI; pData->hints |= PLUGIN_HAS_CUSTOM_UI;
pData->hints |= PLUGIN_NEEDS_SINGLE_THREAD;
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
} }


if (aOuts > 0 && (aIns == aOuts || aIns == 1)) if (aOuts > 0 && (aIns == aOuts || aIns == 1))


+ 2
- 2
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -2305,8 +2305,8 @@ public:
{ {
pData->hints |= PLUGIN_HAS_CUSTOM_UI; pData->hints |= PLUGIN_HAS_CUSTOM_UI;


if (fUI.type == UI::TYPE_EMBED)
pData->hints |= PLUGIN_NEEDS_SINGLE_THREAD;
if (fUI.type == UI::TYPE_EMBED || fUI.type == UI::TYPE_EXTERNAL)
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
} }


if (LV2_IS_GENERATOR(fRdfDescriptor->Type[0], fRdfDescriptor->Type[1])) if (LV2_IS_GENERATOR(fRdfDescriptor->Type[0], fRdfDescriptor->Type[1]))


+ 2
- 2
source/backend/plugin/CarlaPluginNative.cpp View File

@@ -1155,10 +1155,10 @@ public:
pData->hints |= PLUGIN_IS_SYNTH; pData->hints |= PLUGIN_IS_SYNTH;
if (fDescriptor->hints & NATIVE_PLUGIN_HAS_UI) if (fDescriptor->hints & NATIVE_PLUGIN_HAS_UI)
pData->hints |= PLUGIN_HAS_CUSTOM_UI; pData->hints |= PLUGIN_HAS_CUSTOM_UI;
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_SINGLE_THREAD)
pData->hints |= PLUGIN_NEEDS_SINGLE_THREAD;
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
pData->hints |= PLUGIN_NEEDS_FIXED_BUFFERS; pData->hints |= PLUGIN_NEEDS_FIXED_BUFFERS;
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_SINGLE_THREAD)
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;


// extra plugin hints // extra plugin hints
pData->extraHints = 0x0; pData->extraHints = 0x0;


+ 1
- 1
source/backend/plugin/CarlaPluginVST2.cpp View File

@@ -809,7 +809,7 @@ public:
if (fEffect->flags & effFlagsHasEditor) if (fEffect->flags & effFlagsHasEditor)
{ {
pData->hints |= PLUGIN_HAS_CUSTOM_UI; pData->hints |= PLUGIN_HAS_CUSTOM_UI;
pData->hints |= PLUGIN_NEEDS_SINGLE_THREAD;
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
} }


if (dispatcher(effGetVstVersion, 0, 0, nullptr, 0.0f) < kVstVersion) if (dispatcher(effGetVstVersion, 0, 0, nullptr, 0.0f) < kVstVersion)


+ 2
- 2
source/carla_backend.py View File

@@ -209,8 +209,8 @@ PLUGIN_CAN_PANNING = 0x080
# Plugin needs a constant, fixed-size audio buffer. # Plugin needs a constant, fixed-size audio buffer.
PLUGIN_NEEDS_FIXED_BUFFERS = 0x100 PLUGIN_NEEDS_FIXED_BUFFERS = 0x100


# Plugin needs all UI events in a single/main thread.
PLUGIN_NEEDS_SINGLE_THREAD = 0x200
# Plugin needs to receive all UI events in the main thread.
PLUGIN_NEEDS_UI_MAIN_THREAD = 0x200


# ------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------
# Plugin Options # Plugin Options


Loading…
Cancel
Save