Browse Source

Carla: Support plugins that want single-thread (LV2 only); misc fixing

tags/v0.9.0
falkTX 13 years ago
parent
commit
34ad95ba81
13 changed files with 263 additions and 160 deletions
  1. +8
    -7
      c++/carla-backend/carla_backend.h
  2. +1
    -5
      c++/carla-backend/carla_engine.h
  3. +2
    -2
      c++/carla-backend/carla_engine_jack.cpp
  4. +1
    -1
      c++/carla-backend/carla_engine_rtaudio.cpp
  5. +1
    -1
      c++/carla-backend/carla_osc.cpp
  6. +84
    -103
      c++/carla-backend/carla_plugin.h
  7. +44
    -13
      c++/carla-backend/carla_threads.cpp
  8. +12
    -0
      c++/carla-backend/carla_threads.h
  9. +48
    -0
      c++/carla-backend/dssi.cpp
  10. +51
    -20
      c++/carla-backend/lv2.cpp
  11. +2
    -0
      c++/carla-backend/vst.cpp
  12. +1
    -1
      c++/xycontroller/xycontroller.cpp
  13. +8
    -7
      src/shared_carla.py

+ 8
- 7
c++/carla-backend/carla_backend.h View File

@@ -49,13 +49,14 @@ const unsigned int MAX_PARAMETERS = 200; //!< Default value for the maximum numb
* \see CarlaPlugin::hints()
* @{
*/
const unsigned int PLUGIN_IS_BRIDGE = 0x01; //!< Plugin is a bridge (ie, BridgePlugin). This hint is required because "bridge" itself is not a plugin type.
const unsigned int PLUGIN_IS_SYNTH = 0x02; //!< Plugin is a synthesizer (produces sound).
const unsigned int PLUGIN_HAS_GUI = 0x04; //!< Plugin has its own custom GUI.
const unsigned int PLUGIN_USES_CHUNKS = 0x08; //!< Plugin uses chunks to save internal data.\see CarlaPlugin::chunkData()
const unsigned int PLUGIN_CAN_DRYWET = 0x10; //!< Plugin can make use of Dry/Wet controls.
const unsigned int PLUGIN_CAN_VOLUME = 0x20; //!< Plugin can make use of Volume controls.
const unsigned int PLUGIN_CAN_BALANCE = 0x40; //!< Plugin can make use of Left & Right Balance controls.
const unsigned int PLUGIN_IS_BRIDGE = 0x01; //!< Plugin is a bridge (ie, BridgePlugin). This hint is required because "bridge" itself is not a plugin type.
const unsigned int PLUGIN_IS_SYNTH = 0x02; //!< Plugin is a synthesizer (produces sound).
const unsigned int PLUGIN_HAS_GUI = 0x04; //!< Plugin has its own custom GUI.
const unsigned int PLUGIN_USES_CHUNKS = 0x08; //!< Plugin uses chunks to save internal data.\see CarlaPlugin::chunkData()
const unsigned int PLUGIN_USES_SINGLE_THREAD = 0x10; //!< Plugin has its own custom GUI.
const unsigned int PLUGIN_CAN_DRYWET = 0x20; //!< Plugin can make use of Dry/Wet controls.
const unsigned int PLUGIN_CAN_VOLUME = 0x40; //!< Plugin can make use of Volume controls.
const unsigned int PLUGIN_CAN_BALANCE = 0x80; //!< Plugin can make use of Left & Right Balance controls.
/**@}*/

/*!


+ 1
- 5
c++/carla-backend/carla_engine.h View File

@@ -187,6 +187,7 @@ public:

short getNewPluginId() const;
CarlaPlugin* getPlugin(const unsigned short id) const;
CarlaPlugin* getPluginUnchecked(const unsigned short id) const { return m_carlaPlugins[id]; }
const char* getUniqueName(const char* const name);

short addPlugin(const BinaryType btype, const PluginType ptype, const char* const filename, const char* const name, const char* const label, void* const extra = nullptr);
@@ -202,11 +203,6 @@ public:
m_carlaPlugins[id] = plugin;
}

CarlaPlugin* __getPlugin(const unsigned short id) const
{
return m_carlaPlugins[id];
}

// -------------------------------------------------------------------
// Information (base)



+ 2
- 2
c++/carla-backend/carla_engine_jack.cpp View File

@@ -317,7 +317,7 @@ void CarlaEngineJack::handleProcessCallback(uint32_t nframes)
{
for (unsigned short i=0; i < MAX_PLUGINS; i++)
{
CarlaPlugin* const plugin = __getPlugin(i);
CarlaPlugin* const plugin = getPluginUnchecked(i);

if (plugin && plugin->enabled())
{
@@ -451,7 +451,7 @@ void CarlaEngineJack::handleProcessCallback(uint32_t nframes)
// process plugins
for (unsigned short i=0; i < MAX_PLUGINS; i++)
{
CarlaPlugin* const plugin = __getPlugin(i);
CarlaPlugin* const plugin = getPluginUnchecked(i);

if (plugin && plugin->enabled())
{


+ 1
- 1
c++/carla-backend/carla_engine_rtaudio.cpp View File

@@ -207,7 +207,7 @@ void CarlaEngineRtAudio::handleProcessCallback(void* outputBuffer, void* inputBu
// process plugins
for (unsigned short i=0; i < MAX_PLUGINS; i++)
{
CarlaPlugin* const plugin = __getPlugin(i);
CarlaPlugin* const plugin = getPluginUnchecked(i);

if (plugin && plugin->enabled())
{


+ 1
- 1
c++/carla-backend/carla_osc.cpp View File

@@ -265,7 +265,7 @@ int CarlaOsc::handle_register(const int argc, const lo_arg* const* const argv, c

for (unsigned short i=0; i < CarlaBackend::MAX_PLUGINS; i++)
{
CarlaBackend::CarlaPlugin* const plugin = engine->__getPlugin(i);
CarlaBackend::CarlaPlugin* const plugin = engine->getPluginUnchecked(i);

if (plugin && plugin->enabled())
plugin->registerToOsc();


+ 84
- 103
c++/carla-backend/carla_plugin.h View File

@@ -503,6 +503,18 @@ public:
return &param.ranges[parameterId];
}

/*!
* Check if a parameter is out output type.
*
* \see PARAMETER_OUTPUT
*/
bool parameterIsOutput(uint32_t parameterId) const
{
Q_ASSERT(parameterId < param.count);

return (param.data[parameterId].type == PARAMETER_OUTPUT);
}

/*!
* Get the MIDI program at \a index.
*
@@ -695,21 +707,17 @@ public:
*/
void getParameterCountInfo(uint32_t* ins, uint32_t* outs, uint32_t* total)
{
uint32_t _ins = 0;
uint32_t _outs = 0;
uint32_t _total = param.count;
*ins = 0;
*outs = 0;
*total = param.count;

for (uint32_t i=0; i < param.count; i++)
{
if (param.data[i].type == PARAMETER_INPUT)
_ins += 1;
*ins += 1;
else if (param.data[i].type == PARAMETER_OUTPUT)
_outs += 1;
*outs += 1;
}

*ins = _ins;
*outs = _outs;
*total = _total;
}

/*!
@@ -1252,36 +1260,19 @@ public:
*/
virtual void idleGui()
{
m_needsParamUpdate = false;
m_needsProgUpdate = false;

if (! m_enabled)
return;

// -------------------------------------------------------
// Process postponed events

postEventsRun();

// -------------------------------------------------------
// Update parameters (OSC)

updateOscParameterOutputs();

// -------------------------------------------------------
// Send peak values (OSC)

if (x_engine->isOscControllerRegisted())
if (m_hints & PLUGIN_USES_SINGLE_THREAD)
{
if (audioInCount() > 0)
{
x_engine->osc_send_set_input_peak_value(m_id, 1, x_engine->getInputPeak(m_id, 0));
x_engine->osc_send_set_input_peak_value(m_id, 2, x_engine->getInputPeak(m_id, 1));
}
if (audioOutCount() > 0)
// Process postponed events
postEventsRun();

// Update parameter outputs
for (uint32_t i=0; i < param.count; i++)
{
x_engine->osc_send_set_output_peak_value(m_id, 1, x_engine->getOutputPeak(m_id, 0));
x_engine->osc_send_set_output_peak_value(m_id, 2, x_engine->getOutputPeak(m_id, 1));
if (param.data[i].type == PARAMETER_OUTPUT)
uiParameterChange(i, getParameterValue(i));
}
}
}
@@ -1550,34 +1541,6 @@ public:
}
}

/*!
* TODO
*/
void updateOscParameterOutputs()
{
// Check if it needs update
bool updatePortsGui = (osc.data.target && (m_hints & PLUGIN_IS_BRIDGE) == 0);

if (! (x_engine->isOscControllerRegisted() || updatePortsGui))
return;

// Update
double value;

for (uint32_t i=0; i < param.count; i++)
{
if (param.data[i].type == PARAMETER_OUTPUT /*&& (paramData->hints & PARAMETER_IS_AUTOMABLE) > 0*/)
{
value = getParameterValue(i);

if (updatePortsGui)
osc_send_control(&osc.data, param.data[i].rindex, value);

x_engine->osc_send_set_parameter_value(m_id, i, value);
}
}
}

/*!
* Clear the plugin's internal OSC data.
*/
@@ -1744,16 +1707,15 @@ public:
switch (event->type)
{
case PluginPostEventNull:
return;
break;

case PluginPostEventDebug:
x_engine->callback(CALLBACK_DEBUG, m_id, event->value1, event->value2, event->value3);
break;

case PluginPostEventParameterChange:
// Update OSC based UIs
m_needsParamUpdate = true;
osc_send_control(&osc.data, event->value1, event->value3);
// Update UI
uiParameterChange(event->value1, event->value3);

// Update OSC control client
x_engine->osc_send_set_parameter_value(m_id, event->value1, event->value3);
@@ -1763,9 +1725,8 @@ public:
break;

case PluginPostEventProgramChange:
// Update OSC based UIs
m_needsProgUpdate = true;
osc_send_program(&osc.data, event->value1);
// Update UI
uiProgramChange(event->value1);

// Update OSC control client
x_engine->osc_send_set_program(m_id, event->value1);
@@ -1778,16 +1739,8 @@ public:
break;

case PluginPostEventMidiProgramChange:
// Update OSC based UIs
m_needsProgUpdate = true;

if (m_type == PLUGIN_DSSI)
{
if (event->value1 >= 0 && event->value1 < (int32_t)midiprog.count)
osc_send_program(&osc.data, midiprog.data[event->value1].bank, midiprog.data[event->value1].program);
}
else
osc_send_midi_program(&osc.data, event->value1);
// Update UI
uiMidiProgramChange(event->value1);

// Update OSC control client
x_engine->osc_send_set_midi_program(m_id, event->value1);
@@ -1797,19 +1750,11 @@ public:

// Update Host
x_engine->callback(CALLBACK_MIDI_PROGRAM_CHANGED, m_id, event->value1, 0, 0.0);
//}
break;

case PluginPostEventNoteOn:
// Update OSC based UIs
if (osc.data.target)
{
uint8_t midiData[4] = { 0 };
midiData[1] = MIDI_STATUS_NOTE_ON + event->value1;
midiData[2] = event->value2;
midiData[3] = rint(event->value3);
osc_send_midi(&osc.data, midiData);
}
// Update UI
uiNoteOn(event->value1, event->value2, rint(event->value3));

// Update OSC control client
x_engine->osc_send_note_on(m_id, event->value1, event->value2, event->value3);
@@ -1819,14 +1764,8 @@ public:
break;

case PluginPostEventNoteOff:
// Update OSC based UIs
if (osc.data.target)
{
uint8_t midiData[4] = { 0 };
midiData[1] = MIDI_STATUS_NOTE_OFF + event->value1;
midiData[2] = event->value2;
osc_send_midi(&osc.data, midiData);
}
// Update UI
uiNoteOff(event->value1, event->value2);

// Update OSC control client
x_engine->osc_send_note_off(m_id, event->value1, event->value2);
@@ -1838,6 +1777,53 @@ public:
}
}

/*!
* TODO
*/
virtual void uiParameterChange(uint32_t index, double value)
{
Q_ASSERT(index < param.count);
Q_UNUSED(index);
Q_UNUSED(value);
}

/*!
* TODO
*/
virtual void uiProgramChange(uint32_t index)
{
Q_ASSERT(index < prog.count);
Q_UNUSED(index);
}

/*!
* TODO
*/
virtual void uiMidiProgramChange(uint32_t index)
{
Q_ASSERT(index < midiprog.count);
Q_UNUSED(index);
}

/*!
* TODO
*/
virtual void uiNoteOn(uint8_t channel, uint8_t note, uint8_t velo)
{
Q_UNUSED(channel);
Q_UNUSED(note);
Q_UNUSED(velo);
}

/*!
* TODO
*/
virtual void uiNoteOff(uint8_t channel, uint8_t note)
{
Q_UNUSED(channel);
Q_UNUSED(note);
}

// -------------------------------------------------------------------
// Cleanup

@@ -2048,11 +2034,10 @@ public:
// -------------------------------------------------------------------

protected:
// static
unsigned short m_id;
CarlaEngine* const x_engine;
CarlaEngineClient* x_client;

// non-static
PluginType m_type;
unsigned int m_hints;

@@ -2067,10 +2052,6 @@ protected:
int8_t cin_channel;

double x_drywet, x_vol, x_bal_left, x_bal_right;
CarlaEngineClient* x_client;

bool m_needsParamUpdate;
bool m_needsProgUpdate;

// -------------------------------------------------------------------
// Storage Data


+ 44
- 13
c++/carla-backend/carla_threads.cpp View File

@@ -40,6 +40,9 @@ void CarlaCheckThread::stopNow()
{
m_stopNow = true;

// TESTING - let processing finish first
QMutexLocker(&this->mutex); // FIXME

if (isRunning() && ! wait(200))
{
quit();
@@ -53,32 +56,60 @@ void CarlaCheckThread::run()
{
qDebug("CarlaCheckThread::run()");

bool oscControllerRegisted, usesSingleThread;
unsigned short id;
double value;

m_stopNow = false;

while (engine->isRunning() && ! m_stopNow)
{
QMutexLocker(&this->mutex); // FIXME
oscControllerRegisted = engine->isOscControllerRegisted();

for (unsigned short i=0; i < CarlaBackend::MAX_PLUGINS; i++)
{
CarlaBackend::CarlaPlugin* const plugin = engine->__getPlugin(i);
CarlaBackend::CarlaPlugin* const plugin = engine->getPluginUnchecked(i);

if (plugin && plugin->enabled())
{
id = plugin->id();
usesSingleThread = (plugin->hints() & CarlaBackend::PLUGIN_USES_SINGLE_THREAD);

// -------------------------------------------------------
// Process postponed events

plugin->postEventsRun();
if (! usesSingleThread)
plugin->postEventsRun();

// -------------------------------------------------------
// Update parameters (OSC)
// Update parameter outputs

plugin->updateOscParameterOutputs();
if (oscControllerRegisted || ! usesSingleThread)
{
for (uint32_t i=0; i < plugin->parameterCount(); i++)
{
if (plugin->parameterIsOutput(i))
{
value = plugin->getParameterValue(i);

// Update UI
if (! usesSingleThread)
plugin->uiParameterChange(i, value);

// Update OSC control client
if (oscControllerRegisted)
engine->osc_send_set_parameter_value(id, i, value);
}
}
}

// -------------------------------------------------------
// Send peak values (OSC)
// Update OSC control client

if (engine->isOscControllerRegisted())
if (oscControllerRegisted)
{
const unsigned short id = plugin->id();

// Peak values
if (plugin->audioInCount() > 0)
{
engine->osc_send_set_input_peak_value(id, 1, engine->getInputPeak(id, 0));
@@ -146,7 +177,7 @@ void CarlaPluginThread::run()
{
qDebug("CarlaPluginThread::run()");

if (m_process == nullptr)
if (! m_process)
m_process = new QProcess(nullptr);

m_process->setProcessChannelMode(QProcess::ForwardedChannels);
@@ -156,21 +187,21 @@ void CarlaPluginThread::run()
switch (mode)
{
case PLUGIN_THREAD_DSSI_GUI:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath()).arg(plugin->id());
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id());
/* filename */ arguments << plugin->filename();
/* label */ arguments << m_label;
/* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
break;

case PLUGIN_THREAD_LV2_GUI:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath()).arg(plugin->id());
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id());
/* URI */ arguments << m_label;
/* ui-URI */ arguments << m_data1;
/* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
break;

case PLUGIN_THREAD_VST_GUI:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath()).arg(plugin->id());
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id());
/* filename */ arguments << plugin->filename();
/* label */ arguments << m_label;
/* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
@@ -183,7 +214,7 @@ void CarlaPluginThread::run()
if (! name)
name = "(none)";

/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath()).arg(plugin->id());
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPath(), plugin->id());
/* stype */ arguments << m_data1;
/* filename */ arguments << plugin->filename();
/* name */ arguments << name;


+ 12
- 0
c++/carla-backend/carla_threads.h View File

@@ -20,6 +20,7 @@

#include "carla_backend.h"

#include <QtCore/QMutex>
#include <QtCore/QThread>

class QProcess;
@@ -35,11 +36,22 @@ public:

void stopNow();

void lock()
{
mutex.lock();
}

void unlock()
{
mutex.unlock();
}

protected:
void run();

private:
CarlaBackend::CarlaEngine* const engine;
QMutex mutex;
bool m_stopNow;
};



+ 48
- 0
c++/carla-backend/dssi.cpp View File

@@ -1325,6 +1325,54 @@ public:
m_activeBefore = m_active;
}

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

void uiParameterChange(uint32_t index, double value)
{
Q_ASSERT(index < param.count);
if (index >= param.count)
return;
if (! osc.data.target)
return;

osc_send_control(&osc.data, param.data[index].rindex, value);
}

void uiMidiProgramChange(uint32_t index)
{
Q_ASSERT(index < midiprog.count);
if (index >= midiprog.count)
return;
if (! osc.data.target)
return;

osc_send_program(&osc.data, midiprog.data[index].bank, midiprog.data[index].program);
}

void uiNoteOn(uint8_t channel, uint8_t note, uint8_t velo)
{
if (! osc.data.target)
return;

uint8_t midiData[4] = { 0 };
midiData[1] = MIDI_STATUS_NOTE_ON + channel;
midiData[2] = note;
midiData[3] = velo;
osc_send_midi(&osc.data, midiData);
}

void uiNoteOff(uint8_t channel, uint8_t note)
{
if (! osc.data.target)
return;

uint8_t midiData[4] = { 0 };
midiData[1] = MIDI_STATUS_NOTE_OFF + channel;
midiData[2] = note;
osc_send_midi(&osc.data, midiData);
}

// -------------------------------------------------------------------
// Cleanup



+ 51
- 20
c++/carla-backend/lv2.cpp View File

@@ -907,27 +907,11 @@ public:

void idleGui()
{
if (ui.handle && ui.descriptor && gui.type != GUI_EXTERNAL_OSC)
{
// Update output port values
if (ui.descriptor->port_event)
{
float value;
// Update external UI
if (ui.handle && ui.descriptor && ui.widget && gui.type == GUI_EXTERNAL_LV2)
LV2_EXTERNAL_UI_RUN((lv2_external_ui*)ui.widget);

for (uint32_t i=0; i < param.count; i++)
{
if (param.data[i].type == PARAMETER_OUTPUT)
{
value = getParameterValue(i);
ui.descriptor->port_event(ui.handle, param.data[i].rindex, sizeof(float), 0, &value);
}
}
}

// Update UI
if (ui.widget && gui.type == GUI_EXTERNAL_LV2)
LV2_EXTERNAL_UI_RUN((lv2_external_ui*)ui.widget);
}
CarlaPlugin::idleGui();
}

// -------------------------------------------------------------------
@@ -2300,6 +2284,51 @@ public:
m_activeBefore = m_active;
}

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

void uiParameterChange(uint32_t index, double value)
{
Q_ASSERT(index < param.count);
if (index >= param.count)
return;

if (osc.data.target)
osc_send_control(&osc.data, param.data[index].rindex, value);
else if (ui.handle && ui.descriptor && ui.descriptor->port_event)
{
float valuef = value;
ui.descriptor->port_event(ui.handle, param.data[index].rindex, sizeof(float), 0, &valuef);
}
}

void uiMidiProgramChange(uint32_t index)
{
Q_ASSERT(index < midiprog.count);
if (index >= midiprog.count)
return;

if (osc.data.target)
osc_send_program(&osc.data, midiprog.data[index].bank, midiprog.data[index].program);
else if (ext.uiprograms)
ext.uiprograms->select_program(ui.handle, midiprog.data[index].bank, midiprog.data[index].program);
}

void uiNoteOn(uint8_t channel, uint8_t note, uint8_t velo)
{
// TODO
Q_UNUSED(channel);
Q_UNUSED(note);
Q_UNUSED(velo);
}

void uiNoteOff(uint8_t channel, uint8_t note)
{
// TODO
Q_UNUSED(channel);
Q_UNUSED(note);
}

// -------------------------------------------------------------------
// Cleanup

@@ -3662,6 +3691,7 @@ public:
gui.type = GUI_INTERNAL_QT4;
gui.resizable = isUiResizable();
ui.handle = ui.descriptor->instantiate(ui.descriptor, descriptor->URI, ui.rdf_descriptor->Bundle, carla_lv2_ui_write_function, this, &ui.widget, features);
m_hints |= PLUGIN_USES_SINGLE_THREAD;
updateUi();
break;

@@ -3689,6 +3719,7 @@ public:
gui.type = GUI_EXTERNAL_SUIL;
gui.resizable = isUiResizable();
suil.handle = suil_instance_new(suil.host, this, LV2_UI__Qt4UI, rdf_descriptor->URI, ui.rdf_descriptor->URI, get_lv2_ui_uri(ui.rdf_descriptor->Type), ui.rdf_descriptor->Bundle, ui.rdf_descriptor->Binary, features);
m_hints |= PLUGIN_USES_SINGLE_THREAD;

if (suil.handle)
{


+ 2
- 0
c++/carla-backend/vst.cpp View File

@@ -312,6 +312,8 @@ public:
// FIXME
if (gui.visible)
effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f);

CarlaPlugin::idleGui();
}

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


+ 1
- 1
c++/xycontroller/xycontroller.cpp View File

@@ -171,7 +171,7 @@ private:
: d1(0), d2(0), d3(0) {}
};

static const unsigned short MAX_SIZE = 128;
static const unsigned short MAX_SIZE = 512;
datatype data[MAX_SIZE];
unsigned short index;
bool empty, full;


+ 8
- 7
src/shared_carla.py View File

@@ -53,13 +53,14 @@ MAX_PLUGINS = 99
MAX_PARAMETERS = 200

# plugin hints
PLUGIN_IS_BRIDGE = 0x01
PLUGIN_IS_SYNTH = 0x02
PLUGIN_HAS_GUI = 0x04
PLUGIN_USES_CHUNKS = 0x08
PLUGIN_CAN_DRYWET = 0x10
PLUGIN_CAN_VOLUME = 0x20
PLUGIN_CAN_BALANCE = 0x40
PLUGIN_IS_BRIDGE = 0x01
PLUGIN_IS_SYNTH = 0x02
PLUGIN_HAS_GUI = 0x04
PLUGIN_USES_CHUNKS = 0x08
PLUGIN_USES_SINGLE_THREAD = 0x10
PLUGIN_CAN_DRYWET = 0x20
PLUGIN_CAN_VOLUME = 0x40
PLUGIN_CAN_BALANCE = 0x80

# parameter hints
PARAMETER_IS_BOOLEAN = 0x01


Loading…
Cancel
Save