@@ -50,6 +50,7 @@ const unsigned short MAX_MIDI_EVENTS = 512; | |||||
const unsigned int PLUGIN_HINT_HAS_MIDI_IN = 0x1; | const unsigned int PLUGIN_HINT_HAS_MIDI_IN = 0x1; | ||||
const unsigned int PLUGIN_HINT_HAS_MIDI_OUT = 0x2; | const unsigned int PLUGIN_HINT_HAS_MIDI_OUT = 0x2; | ||||
const unsigned int PLUGIN_HINT_CAN_RUN_RACK = 0x4; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -548,6 +549,11 @@ struct CarlaPluginProtectedData { | |||||
return plugin->kData->audioOut.ports[index].port; | return plugin->kData->audioOut.ports[index].port; | ||||
} | } | ||||
static bool canRunInRack(CarlaPlugin* const plugin) | |||||
{ | |||||
return (plugin->kData->extraHints & PLUGIN_HINT_CAN_RUN_RACK); | |||||
} | |||||
CARLA_LEAK_DETECTOR(CarlaPluginProtectedData) | CARLA_LEAK_DETECTOR(CarlaPluginProtectedData) | ||||
}; | }; | ||||
@@ -120,7 +120,7 @@ public: | |||||
int32_t chunkData(void** const dataPtr) | int32_t chunkData(void** const dataPtr) | ||||
{ | { | ||||
CARLA_ASSERT(fHints & PLUGIN_USES_CHUNKS); | |||||
CARLA_ASSERT(fOptions & PLUGIN_OPTION_USE_CHUNKS); | |||||
CARLA_ASSERT(fDssiDescriptor != nullptr); | CARLA_ASSERT(fDssiDescriptor != nullptr); | ||||
CARLA_ASSERT(fDssiDescriptor->get_custom_data != nullptr); | CARLA_ASSERT(fDssiDescriptor->get_custom_data != nullptr); | ||||
CARLA_ASSERT(fHandle != nullptr); | CARLA_ASSERT(fHandle != nullptr); | ||||
@@ -255,7 +255,7 @@ public: | |||||
void setChunkData(const char* const stringData) | void setChunkData(const char* const stringData) | ||||
{ | { | ||||
CARLA_ASSERT(fHints & PLUGIN_USES_CHUNKS); | |||||
CARLA_ASSERT(fOptions & PLUGIN_OPTION_USE_CHUNKS); | |||||
CARLA_ASSERT(fDssiDescriptor != nullptr); | CARLA_ASSERT(fDssiDescriptor != nullptr); | ||||
CARLA_ASSERT(fDssiDescriptor->set_custom_data != nullptr); | CARLA_ASSERT(fDssiDescriptor->set_custom_data != nullptr); | ||||
CARLA_ASSERT(fHandle != nullptr); | CARLA_ASSERT(fHandle != nullptr); | ||||
@@ -668,8 +668,14 @@ public: | |||||
kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | ||||
} | } | ||||
// plugin checks | |||||
fHints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); | |||||
// plugin hints | |||||
const bool haveGUI = (fHints & PLUGIN_HAS_GUI); | |||||
const bool isDssiVst = QString(fFilename).endsWith("dssi-vst.so", Qt::CaseInsensitive); | |||||
fHints = 0x0; | |||||
if (haveGUI) | |||||
fHints |= PLUGIN_HAS_GUI; | |||||
if (mIns == 1 && aIns == 0 && aOuts > 0) | if (mIns == 1 && aIns == 0 && aOuts > 0) | ||||
fHints |= PLUGIN_IS_SYNTH; | fHints |= PLUGIN_IS_SYNTH; | ||||
@@ -683,38 +689,37 @@ public: | |||||
if (aOuts >= 2 && aOuts % 2 == 0) | if (aOuts >= 2 && aOuts % 2 == 0) | ||||
fHints |= PLUGIN_CAN_BALANCE; | fHints |= PLUGIN_CAN_BALANCE; | ||||
// extra plugin hints | |||||
kData->extraHints = 0x0; | |||||
if (mIns > 0) | |||||
kData->extraHints |= PLUGIN_HINT_HAS_MIDI_IN; | |||||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) | if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) | ||||
fHints |= PLUGIN_CAN_FORCE_STEREO; | |||||
kData->extraHints |= PLUGIN_HINT_CAN_RUN_RACK; | |||||
// plugin options | // plugin options | ||||
kData->availOptions &= ~(PLUGIN_OPTION_FIXED_BUFFER | PLUGIN_OPTION_SELF_AUTOMATION | PLUGIN_OPTION_SEND_ALL_SOUND_OFF | PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH | PLUGIN_OPTION_SEND_PITCHBEND); | |||||
fOptions = 0x0; | |||||
// always available if needed | |||||
kData->availOptions |= PLUGIN_OPTION_SELF_AUTOMATION; | |||||
fOptions |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; | |||||
// dssi-vst can do chunks, but needs fixed buffers | |||||
if (QString(fFilename).endsWith("dssi-vst.so", Qt::CaseInsensitive)) | |||||
if (forcedStereoIn || forcedStereoOut) | |||||
fOptions |= PLUGIN_OPTION_FORCE_STEREO; | |||||
if (isDssiVst) | |||||
{ | { | ||||
carla_stdout("dssi-vst detected, disabling sample accurate events (ie, fixed buffer)"); | |||||
fOptions |= PLUGIN_OPTION_FIXED_BUFFER; | fOptions |= PLUGIN_OPTION_FIXED_BUFFER; | ||||
if (fOptions & PLUGIN_OPTION_USE_CHUNKS) | |||||
{ | |||||
if (fDssiDescriptor->get_custom_data != nullptr && fDssiDescriptor->set_custom_data != nullptr) | |||||
fHints |= PLUGIN_USES_CHUNKS; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
kData->availOptions |= PLUGIN_OPTION_FIXED_BUFFER; | |||||
if (kData->engine->getOptions().useDssiVstChunks && fDssiDescriptor->get_custom_data != nullptr && fDssiDescriptor->set_custom_data != nullptr) | |||||
fOptions |= PLUGIN_OPTION_USE_CHUNKS; | |||||
} | } | ||||
// only for plugins with midi input | |||||
if (mIns > 0) | if (mIns > 0) | ||||
{ | { | ||||
kData->availOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | |||||
fOptions |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; | |||||
fOptions |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; | |||||
fOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | |||||
fOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
} | } | ||||
// check latency | // check latency | ||||
@@ -1246,7 +1251,7 @@ public: | |||||
postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); | postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); | ||||
} | } | ||||
else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status)) | |||||
else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) != 0) | |||||
{ | { | ||||
const uint8_t note = midiEvent.data[1]; | const uint8_t note = midiEvent.data[1]; | ||||
const uint8_t pressure = midiEvent.data[2]; | const uint8_t pressure = midiEvent.data[2]; | ||||
@@ -1256,7 +1261,7 @@ public: | |||||
fMidiEvents[midiEventCount].data.note.note = note; | fMidiEvents[midiEventCount].data.note.note = note; | ||||
fMidiEvents[midiEventCount].data.note.velocity = pressure; | fMidiEvents[midiEventCount].data.note.velocity = pressure; | ||||
} | } | ||||
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fHints & PLUGIN_OPTION_SELF_AUTOMATION) != 0) | |||||
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0) | |||||
{ | { | ||||
const uint8_t control = midiEvent.data[1]; | const uint8_t control = midiEvent.data[1]; | ||||
const uint8_t value = midiEvent.data[2]; | const uint8_t value = midiEvent.data[2]; | ||||
@@ -1266,7 +1271,7 @@ public: | |||||
fMidiEvents[midiEventCount].data.control.param = control; | fMidiEvents[midiEventCount].data.control.param = control; | ||||
fMidiEvents[midiEventCount].data.control.value = value; | fMidiEvents[midiEventCount].data.control.value = value; | ||||
} | } | ||||
else if (MIDI_IS_STATUS_AFTERTOUCH(status)) | |||||
else if (MIDI_IS_STATUS_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) != 0) | |||||
{ | { | ||||
const uint8_t pressure = midiEvent.data[1]; | const uint8_t pressure = midiEvent.data[1]; | ||||
@@ -1274,7 +1279,7 @@ public: | |||||
fMidiEvents[midiEventCount].data.control.channel = channel; | fMidiEvents[midiEventCount].data.control.channel = channel; | ||||
fMidiEvents[midiEventCount].data.control.value = pressure; | fMidiEvents[midiEventCount].data.control.value = pressure; | ||||
} | } | ||||
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status)) | |||||
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (fOptions & PLUGIN_OPTION_SEND_PITCHBEND) != 0) | |||||
{ | { | ||||
const uint8_t lsb = midiEvent.data[1]; | const uint8_t lsb = midiEvent.data[1]; | ||||
const uint8_t msb = midiEvent.data[2]; | const uint8_t msb = midiEvent.data[2]; | ||||
@@ -1795,7 +1800,7 @@ CarlaPlugin* CarlaPlugin::newDSSI(const Initializer& init, const char* const gui | |||||
plugin->reload(); | plugin->reload(); | ||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && (plugin->hints() & PLUGIN_CAN_FORCE_STEREO) == 0) | |||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && ! CarlaPluginProtectedData::canRunInRack(plugin)) | |||||
{ | { | ||||
init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo DSSI plugins, sorry!"); | init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo DSSI plugins, sorry!"); | ||||
delete plugin; | delete plugin; | ||||
@@ -726,23 +726,24 @@ public: | |||||
// --------------------------------------- | // --------------------------------------- | ||||
// plugin checks | |||||
fHints = 0; | |||||
// plugin hints | |||||
fHints = 0x0; | |||||
fHints |= PLUGIN_IS_RTSAFE; | fHints |= PLUGIN_IS_RTSAFE; | ||||
fHints |= PLUGIN_IS_SYNTH; | fHints |= PLUGIN_IS_SYNTH; | ||||
fHints |= PLUGIN_CAN_VOLUME; | fHints |= PLUGIN_CAN_VOLUME; | ||||
fHints |= PLUGIN_CAN_BALANCE; | |||||
if (! kUses16Outs) | |||||
{ | |||||
fHints |= PLUGIN_CAN_BALANCE; | |||||
} | |||||
// extra plugin hints | |||||
kData->extraHints = 0x0; | |||||
kData->extraHints |= PLUGIN_HINT_CAN_RUN_RACK; | |||||
// plugin options | // plugin options | ||||
fOptions = 0; | |||||
fOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
fOptions = 0x0; | |||||
fOptions |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; | |||||
fOptions |= PLUGIN_OPTION_SEND_CONTROL_CHANGES; | |||||
fOptions |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; | |||||
fOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | fOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | ||||
fOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
bufferSizeChanged(kData->engine->getBufferSize()); | bufferSizeChanged(kData->engine->getBufferSize()); | ||||
reloadPrograms(true); | reloadPrograms(true); | ||||
@@ -673,8 +673,8 @@ public: | |||||
kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | ||||
} | } | ||||
// plugin checks | |||||
fHints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); | |||||
// plugin hints | |||||
fHints = 0x0; | |||||
if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | ||||
fHints |= PLUGIN_CAN_DRYWET; | fHints |= PLUGIN_CAN_DRYWET; | ||||
@@ -685,14 +685,17 @@ public: | |||||
if (aOuts >= 2 && aOuts % 2 == 0) | if (aOuts >= 2 && aOuts % 2 == 0) | ||||
fHints |= PLUGIN_CAN_BALANCE; | fHints |= PLUGIN_CAN_BALANCE; | ||||
// extra plugin hints | |||||
kData->extraHints = 0x0; | |||||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) | if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) | ||||
fHints |= PLUGIN_CAN_FORCE_STEREO; | |||||
kData->extraHints |= PLUGIN_HINT_CAN_RUN_RACK; | |||||
// plugin options | // plugin options | ||||
kData->availOptions &= ~(PLUGIN_OPTION_FIXED_BUFFER | PLUGIN_OPTION_SELF_AUTOMATION | PLUGIN_OPTION_SEND_ALL_SOUND_OFF | PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH | PLUGIN_OPTION_SEND_PITCHBEND); | |||||
fOptions = 0x0; | |||||
// always available if needed | |||||
kData->availOptions |= PLUGIN_OPTION_FIXED_BUFFER; | |||||
if (forcedStereoIn || forcedStereoOut) | |||||
fOptions |= PLUGIN_OPTION_FORCE_STEREO; | |||||
// check latency | // check latency | ||||
if (fHints & PLUGIN_CAN_DRYWET) | if (fHints & PLUGIN_CAN_DRYWET) | ||||
@@ -1392,7 +1395,7 @@ CarlaPlugin* CarlaPlugin::newLADSPA(const Initializer& init, const LADSPA_RDF_De | |||||
plugin->reload(); | plugin->reload(); | ||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && (plugin->hints() & PLUGIN_CAN_FORCE_STEREO) == 0) | |||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && ! CarlaPluginProtectedData::canRunInRack(plugin)) | |||||
{ | { | ||||
init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LADSPA plugins, sorry!"); | init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LADSPA plugins, sorry!"); | ||||
delete plugin; | delete plugin; | ||||
@@ -355,22 +355,23 @@ public: | |||||
// --------------------------------------- | // --------------------------------------- | ||||
// plugin checks | |||||
fHints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); | |||||
// plugin hints | |||||
fHints = 0x0; | |||||
fHints |= PLUGIN_IS_RTSAFE; | |||||
fHints |= PLUGIN_IS_SYNTH; | fHints |= PLUGIN_IS_SYNTH; | ||||
fHints |= PLUGIN_CAN_VOLUME; | fHints |= PLUGIN_CAN_VOLUME; | ||||
fHints |= PLUGIN_CAN_BALANCE; | fHints |= PLUGIN_CAN_BALANCE; | ||||
fHints |= PLUGIN_CAN_FORCE_STEREO; | |||||
// plugin options | |||||
kData->availOptions &= ~(PLUGIN_OPTION_FIXED_BUFFER | PLUGIN_OPTION_SELF_AUTOMATION | PLUGIN_OPTION_SEND_ALL_SOUND_OFF | PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH | PLUGIN_OPTION_SEND_PITCHBEND); | |||||
// extra plugin hints | |||||
kData->extraHints = 0x0; | |||||
kData->extraHints |= PLUGIN_HINT_CAN_RUN_RACK; | |||||
// always available if needed | |||||
kData->availOptions |= PLUGIN_OPTION_SELF_AUTOMATION; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | |||||
// plugin options | |||||
fOptions = 0x0; | |||||
fOptions |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; | |||||
fOptions |= PLUGIN_OPTION_SEND_CONTROL_CHANGES; | |||||
fOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | |||||
fOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
bufferSizeChanged(kData->engine->getBufferSize()); | bufferSizeChanged(kData->engine->getBufferSize()); | ||||
reloadPrograms(true); | reloadPrograms(true); | ||||
@@ -726,27 +727,27 @@ public: | |||||
postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); | postponeRtEvent(kPluginPostRtEventNoteOn, channel, note, velo); | ||||
} | } | ||||
else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status)) | |||||
else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) != 0) | |||||
{ | { | ||||
//const uint8_t note = midiEvent.data[1]; | //const uint8_t note = midiEvent.data[1]; | ||||
//const uint8_t pressure = midiEvent.data[2]; | //const uint8_t pressure = midiEvent.data[2]; | ||||
// unsupported | // unsupported | ||||
} | } | ||||
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fHints & PLUGIN_OPTION_SELF_AUTOMATION) != 0) | |||||
else if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0) | |||||
{ | { | ||||
const uint8_t control = midiEvent.data[1]; | const uint8_t control = midiEvent.data[1]; | ||||
const uint8_t value = midiEvent.data[2]; | const uint8_t value = midiEvent.data[2]; | ||||
fMidiInputPort->DispatchControlChange(control, value, channel, fragmentPos); | fMidiInputPort->DispatchControlChange(control, value, channel, fragmentPos); | ||||
} | } | ||||
else if (MIDI_IS_STATUS_AFTERTOUCH(status)) | |||||
else if (MIDI_IS_STATUS_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) != 0) | |||||
{ | { | ||||
//const uint8_t pressure = midiEvent.data[1]; | //const uint8_t pressure = midiEvent.data[1]; | ||||
// unsupported | // unsupported | ||||
} | } | ||||
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status)) | |||||
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (fOptions & PLUGIN_OPTION_SEND_PITCHBEND) != 0) | |||||
{ | { | ||||
const uint8_t lsb = midiEvent.data[1]; | const uint8_t lsb = midiEvent.data[1]; | ||||
const uint8_t msb = midiEvent.data[2]; | const uint8_t msb = midiEvent.data[2]; | ||||
@@ -4671,14 +4671,11 @@ CarlaPlugin* CarlaPlugin::newLV2(const Initializer& init) | |||||
plugin->reload(); | plugin->reload(); | ||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK) | |||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && ! CarlaPluginProtectedData::canRunInRack(plugin)) | |||||
{ | { | ||||
if (! (plugin->hints() & PLUGIN_CAN_FORCE_STEREO)) | |||||
{ | |||||
init.engine->setLastError("Carla's rack mode can only work with Mono (simple) or Stereo LV2 plugins, sorry!"); | |||||
delete plugin; | |||||
return nullptr; | |||||
} | |||||
init.engine->setLastError("Carla's rack mode can only work with Mono (simple) or Stereo LV2 plugins, sorry!"); | |||||
delete plugin; | |||||
return nullptr; | |||||
} | } | ||||
//plugin->updateUi(); | //plugin->updateUi(); | ||||
@@ -160,7 +160,7 @@ public: | |||||
return PLUGIN_INTERNAL; | return PLUGIN_INTERNAL; | ||||
} | } | ||||
PluginCategory category() | |||||
PluginCategory category() const | |||||
{ | { | ||||
CARLA_ASSERT(fDescriptor != nullptr); | CARLA_ASSERT(fDescriptor != nullptr); | ||||
@@ -491,7 +491,7 @@ public: | |||||
deleteBuffers(); | deleteBuffers(); | ||||
const double sampleRate = kData->engine->getSampleRate(); | |||||
const float sampleRate = (float)kData->engine->getSampleRate(); | |||||
uint32_t aIns, aOuts, mIns, mOuts, params, j; | uint32_t aIns, aOuts, mIns, mOuts, params, j; | ||||
@@ -561,7 +561,7 @@ public: | |||||
kData->param.createNew(params); | kData->param.createNew(params); | ||||
} | } | ||||
const int portNameSize = kData->engine->maxPortNameSize(); | |||||
const uint portNameSize = kData->engine->maxPortNameSize(); | |||||
CarlaString portName; | CarlaString portName; | ||||
// Audio Ins | // Audio Ins | ||||
@@ -808,8 +808,8 @@ public: | |||||
kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); | ||||
} | } | ||||
// plugin checks | |||||
fHints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); | |||||
// plugin hints | |||||
fHints = 0x0; | |||||
if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | ||||
fHints |= PLUGIN_CAN_DRYWET; | fHints |= PLUGIN_CAN_DRYWET; | ||||
@@ -817,12 +817,9 @@ public: | |||||
if (aOuts > 0) | if (aOuts > 0) | ||||
fHints |= PLUGIN_CAN_VOLUME; | fHints |= PLUGIN_CAN_VOLUME; | ||||
if (aOuts >= 2 && aOuts%2 == 0) | |||||
if (aOuts >= 2 && aOuts % 2 == 0) | |||||
fHints |= PLUGIN_CAN_BALANCE; | fHints |= PLUGIN_CAN_BALANCE; | ||||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0) && mIns <= 1 && mOuts <= 1) | |||||
fHints |= PLUGIN_CAN_FORCE_STEREO; | |||||
// native plugin hints | // native plugin hints | ||||
if (fDescriptor->hints & ::PLUGIN_IS_RTSAFE) | if (fDescriptor->hints & ::PLUGIN_IS_RTSAFE) | ||||
fHints |= PLUGIN_IS_RTSAFE; | fHints |= PLUGIN_IS_RTSAFE; | ||||
@@ -831,21 +828,28 @@ public: | |||||
if (fDescriptor->hints & ::PLUGIN_HAS_GUI) | if (fDescriptor->hints & ::PLUGIN_HAS_GUI) | ||||
fHints |= PLUGIN_HAS_GUI; | fHints |= PLUGIN_HAS_GUI; | ||||
if (fDescriptor->hints & ::PLUGIN_USES_SINGLE_THREAD) | if (fDescriptor->hints & ::PLUGIN_USES_SINGLE_THREAD) | ||||
fHints |= PLUGIN_USES_SINGLE_THREAD; | |||||
fHints |= PLUGIN_HAS_SINGLE_THREAD; | |||||
// extra plugin hints | |||||
kData->extraHints = 0x0; | |||||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0) && mIns <= 1 && mOuts <= 1) | |||||
kData->extraHints |= PLUGIN_HINT_CAN_RUN_RACK; | |||||
// plugin options | // plugin options | ||||
kData->availOptions &= ~(PLUGIN_OPTION_FIXED_BUFFER | PLUGIN_OPTION_SELF_AUTOMATION | PLUGIN_OPTION_SEND_ALL_SOUND_OFF | PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH | PLUGIN_OPTION_SEND_PITCHBEND); | |||||
fOptions = 0x0; | |||||
// always available if needed | |||||
kData->availOptions |= PLUGIN_OPTION_FIXED_BUFFER; | |||||
kData->availOptions |= PLUGIN_OPTION_SELF_AUTOMATION; | |||||
fOptions |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; | |||||
if (forcedStereoIn || forcedStereoOut) | |||||
fOptions |= PLUGIN_OPTION_FORCE_STEREO; | |||||
// only for plugins with midi input | |||||
if (mIns > 0) | if (mIns > 0) | ||||
{ | { | ||||
kData->availOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; | |||||
kData->availOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | |||||
fOptions |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; | |||||
fOptions |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; | |||||
fOptions |= PLUGIN_OPTION_SEND_PITCHBEND; | |||||
fOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; | |||||
} | } | ||||
bufferSizeChanged(kData->engine->getBufferSize()); | bufferSizeChanged(kData->engine->getBufferSize()); | ||||
@@ -1295,10 +1299,16 @@ public: | |||||
uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); | uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); | ||||
uint8_t channel = event.channel; | uint8_t channel = event.channel; | ||||
if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fHints & PLUGIN_OPTION_SELF_AUTOMATION) == 0) | |||||
if (MIDI_IS_STATUS_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0) | |||||
continue; | |||||
if (MIDI_IS_STATUS_CONTROL_CHANGE(status) && (fOptions & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0) | |||||
continue; | |||||
if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) && (fOptions & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0) | |||||
continue; | |||||
if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status) && (fOptions & PLUGIN_OPTION_SEND_PITCHBEND) == 0) | |||||
continue; | continue; | ||||
// Fix bad note-off (per DSSI spec) | |||||
// Fix bad note-off | |||||
if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) | if (MIDI_IS_STATUS_NOTE_ON(status) && midiEvent.data[2] == 0) | ||||
status -= 0x10; | status -= 0x10; | ||||
@@ -1855,7 +1865,7 @@ CarlaPlugin* CarlaPlugin::newNative(const Initializer& init) | |||||
plugin->reload(); | plugin->reload(); | ||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && (plugin->hints() & PLUGIN_CAN_FORCE_STEREO) == 0) | |||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && ! CarlaPluginProtectedData::canRunInRack(plugin)) | |||||
{ | { | ||||
init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo Internal plugins, sorry!"); | init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo Internal plugins, sorry!"); | ||||
delete plugin; | delete plugin; | ||||
@@ -2398,14 +2398,11 @@ CarlaPlugin* CarlaPlugin::newVST(const Initializer& init) | |||||
plugin->reload(); | plugin->reload(); | ||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK) | |||||
if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && ! CarlaPluginProtectedData::canRunInRack(plugin)) | |||||
{ | { | ||||
if (! (plugin->hints() & PLUGIN_CAN_FORCE_STEREO)) | |||||
{ | |||||
init.engine->setLastError("Carla's rack mode can only work with Stereo VST plugins, sorry!"); | |||||
delete plugin; | |||||
return nullptr; | |||||
} | |||||
init.engine->setLastError("Carla's rack mode can only work with Stereo VST plugins, sorry!"); | |||||
delete plugin; | |||||
return nullptr; | |||||
} | } | ||||
return plugin; | return plugin; | ||||
@@ -166,7 +166,7 @@ const CarlaNativePluginInfo* carla_get_internal_plugin_info(unsigned int interna | |||||
if (nativePlugin->hints & PLUGIN_HAS_GUI) | if (nativePlugin->hints & PLUGIN_HAS_GUI) | ||||
info.hints |= CarlaBackend::PLUGIN_HAS_GUI; | info.hints |= CarlaBackend::PLUGIN_HAS_GUI; | ||||
if (nativePlugin->hints & PLUGIN_USES_SINGLE_THREAD) | if (nativePlugin->hints & PLUGIN_USES_SINGLE_THREAD) | ||||
info.hints |= CarlaBackend::PLUGIN_USES_SINGLE_THREAD; | |||||
info.hints |= CarlaBackend::PLUGIN_HAS_SINGLE_THREAD; | |||||
info.audioIns = nativePlugin->audioIns; | info.audioIns = nativePlugin->audioIns; | ||||
info.audioOuts = nativePlugin->audioOuts; | info.audioOuts = nativePlugin->audioOuts; | ||||
@@ -912,7 +912,7 @@ const char* carla_get_chunk_data(unsigned int pluginId) | |||||
if (CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId)) | if (CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId)) | ||||
{ | { | ||||
if (plugin->hints() & CarlaBackend::PLUGIN_USES_CHUNKS) | |||||
if (plugin->options() & CarlaBackend::PLUGIN_OPTION_USE_CHUNKS) | |||||
{ | { | ||||
void* data = nullptr; | void* data = nullptr; | ||||
const int32_t dataSize = plugin->chunkData(&data); | const int32_t dataSize = plugin->chunkData(&data); | ||||
@@ -1484,7 +1484,7 @@ void carla_set_chunk_data(unsigned int pluginId, const char* chunkData) | |||||
if (CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId)) | if (CarlaPlugin* const plugin = standalone.engine->getPlugin(pluginId)) | ||||
{ | { | ||||
if (plugin->hints() & CarlaBackend::PLUGIN_USES_CHUNKS) | |||||
if (plugin->options() & CarlaBackend::PLUGIN_OPTION_USE_CHUNKS) | |||||
return plugin->setChunkData(chunkData); | return plugin->setChunkData(chunkData); | ||||
carla_stderr2("carla_set_chunk_data(%i, \"%s\") - plugin does not support chunks", pluginId, chunkData); | carla_stderr2("carla_set_chunk_data(%i, \"%s\") - plugin does not support chunks", pluginId, chunkData); | ||||
@@ -231,7 +231,7 @@ public: | |||||
fEngine->osc_send_bridge_set_custom_data(cdata.type, cdata.key, cdata.value); | fEngine->osc_send_bridge_set_custom_data(cdata.type, cdata.key, cdata.value); | ||||
} | } | ||||
if (fPlugin->hints() & CarlaBackend::PLUGIN_USES_CHUNKS) | |||||
if (fPlugin->options() & CarlaBackend::PLUGIN_OPTION_USE_CHUNKS) | |||||
{ | { | ||||
void* data = nullptr; | void* data = nullptr; | ||||
int32_t dataSize = fPlugin->chunkData(&data); | int32_t dataSize = fPlugin->chunkData(&data); | ||||