diff --git a/c++/carla-backend/carla_backend.h b/c++/carla-backend/carla_backend.h index 4024318..92545d5 100644 --- a/c++/carla-backend/carla_backend.h +++ b/c++/carla-backend/carla_backend.h @@ -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. /**@}*/ /*! diff --git a/c++/carla-backend/carla_engine.h b/c++/carla-backend/carla_engine.h index 6e9b5b8..bd43ea3 100644 --- a/c++/carla-backend/carla_engine.h +++ b/c++/carla-backend/carla_engine.h @@ -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) diff --git a/c++/carla-backend/carla_engine_jack.cpp b/c++/carla-backend/carla_engine_jack.cpp index b999245..de36298 100644 --- a/c++/carla-backend/carla_engine_jack.cpp +++ b/c++/carla-backend/carla_engine_jack.cpp @@ -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()) { diff --git a/c++/carla-backend/carla_engine_rtaudio.cpp b/c++/carla-backend/carla_engine_rtaudio.cpp index 9befcc0..4107c6f 100644 --- a/c++/carla-backend/carla_engine_rtaudio.cpp +++ b/c++/carla-backend/carla_engine_rtaudio.cpp @@ -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()) { diff --git a/c++/carla-backend/carla_osc.cpp b/c++/carla-backend/carla_osc.cpp index 5b0ddd6..d152786 100644 --- a/c++/carla-backend/carla_osc.cpp +++ b/c++/carla-backend/carla_osc.cpp @@ -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(); diff --git a/c++/carla-backend/carla_plugin.h b/c++/carla-backend/carla_plugin.h index d6c2282..558da7c 100644 --- a/c++/carla-backend/carla_plugin.h +++ b/c++/carla-backend/carla_plugin.h @@ -503,6 +503,18 @@ public: return ¶m.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 diff --git a/c++/carla-backend/carla_threads.cpp b/c++/carla-backend/carla_threads.cpp index 6920b11..caa6aee 100644 --- a/c++/carla-backend/carla_threads.cpp +++ b/c++/carla-backend/carla_threads.cpp @@ -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; diff --git a/c++/carla-backend/carla_threads.h b/c++/carla-backend/carla_threads.h index 89a8f71..6e907b9 100644 --- a/c++/carla-backend/carla_threads.h +++ b/c++/carla-backend/carla_threads.h @@ -20,6 +20,7 @@ #include "carla_backend.h" +#include #include 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; }; diff --git a/c++/carla-backend/dssi.cpp b/c++/carla-backend/dssi.cpp index 84fcb57..cb0ab6c 100644 --- a/c++/carla-backend/dssi.cpp +++ b/c++/carla-backend/dssi.cpp @@ -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 diff --git a/c++/carla-backend/lv2.cpp b/c++/carla-backend/lv2.cpp index aea6884..eee3aa1 100644 --- a/c++/carla-backend/lv2.cpp +++ b/c++/carla-backend/lv2.cpp @@ -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) { diff --git a/c++/carla-backend/vst.cpp b/c++/carla-backend/vst.cpp index 5304a36..cdf2d9b 100644 --- a/c++/carla-backend/vst.cpp +++ b/c++/carla-backend/vst.cpp @@ -312,6 +312,8 @@ public: // FIXME if (gui.visible) effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f); + + CarlaPlugin::idleGui(); } // ------------------------------------------------------------------- diff --git a/c++/xycontroller/xycontroller.cpp b/c++/xycontroller/xycontroller.cpp index 6d95aaa..2b866cc 100644 --- a/c++/xycontroller/xycontroller.cpp +++ b/c++/xycontroller/xycontroller.cpp @@ -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; diff --git a/src/shared_carla.py b/src/shared_carla.py index 14ccae3..64b12f2 100644 --- a/src/shared_carla.py +++ b/src/shared_carla.py @@ -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