diff --git a/source/backend/CarlaBackend.hpp b/source/backend/CarlaBackend.hpp index 58036058b..492eeb987 100644 --- a/source/backend/CarlaBackend.hpp +++ b/source/backend/CarlaBackend.hpp @@ -26,7 +26,7 @@ #define CARLA_BACKEND_END_NAMESPACE } #define CARLA_BACKEND_USE_NAMESPACE using namespace CarlaBackend; -#define STR_MAX 0xFF +#define STR_MAX 0xFF+1 CARLA_BACKEND_START_NAMESPACE diff --git a/source/backend/plugin/BridgePlugin.cpp b/source/backend/plugin/BridgePlugin.cpp index 30e30015c..2205db15a 100644 --- a/source/backend/plugin/BridgePlugin.cpp +++ b/source/backend/plugin/BridgePlugin.cpp @@ -119,7 +119,7 @@ public: return fInfo.category; } - long uniqueId() + long uniqueId() const { return fInfo.uniqueId; } diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index 2a68ecea7..ba0d9f6eb 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -42,10 +42,6 @@ public: carla_zeroMem(fMidiEvents, sizeof(snd_seq_event_t)*MAX_MIDI_EVENTS); kData->osc.thread.setMode(CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI); - - // FIXME - if (engine->getOptions().useDssiVstChunks) - fOptions |= PLUGIN_OPTION_USE_CHUNKS; } ~DssiPlugin() @@ -708,13 +704,13 @@ public: } // plugin hints - const bool haveGUI = (fHints & PLUGIN_HAS_GUI); + const bool hasGUI = (fHints & PLUGIN_HAS_GUI); const bool isDssiVst = fFilename.contains("dssi-vst", true); const bool isZASX = fFilename.contains("zynaddsubfx", true); fHints = 0x0; - if (haveGUI) + if (hasGUI) fHints |= PLUGIN_HAS_GUI; if (mIns == 1 && aIns == 0 && aOuts > 0) @@ -840,34 +836,36 @@ public: } if (count > 0) + { kData->midiprog.createNew(count); - // Update data - for (i=0; i < kData->midiprog.count; i++) - { - const DSSI_Program_Descriptor* const pdesc = fDssiDescriptor->get_program(fHandle, i); - CARLA_ASSERT(pdesc != nullptr); - CARLA_ASSERT(pdesc->Name != nullptr); + // Update data + for (i=0; i < count; i++) + { + const DSSI_Program_Descriptor* const pdesc = fDssiDescriptor->get_program(fHandle, i); + CARLA_ASSERT(pdesc != nullptr); + CARLA_ASSERT(pdesc->Name != nullptr); - kData->midiprog.data[i].bank = static_cast(pdesc->Bank); - kData->midiprog.data[i].program = static_cast(pdesc->Program); - kData->midiprog.data[i].name = carla_strdup(pdesc->Name); + kData->midiprog.data[i].bank = static_cast(pdesc->Bank); + kData->midiprog.data[i].program = static_cast(pdesc->Program); + kData->midiprog.data[i].name = carla_strdup(pdesc->Name); + } } #ifndef BUILD_BRIDGE // Update OSC Names if (kData->engine->isOscControlRegistered()) { - kData->engine->osc_send_control_set_midi_program_count(fId, kData->midiprog.count); + kData->engine->osc_send_control_set_midi_program_count(fId, count); - for (i=0; i < kData->midiprog.count; i++) + for (i=0; i < count; i++) kData->engine->osc_send_control_set_midi_program_data(fId, i, kData->midiprog.data[i].bank, kData->midiprog.data[i].program, kData->midiprog.data[i].name); } #endif if (init) { - if (kData->midiprog.count > 0) + if (count > 0) setMidiProgram(0, false, false, false); } else @@ -875,30 +873,30 @@ public: // Check if current program is invalid bool programChanged = false; - if (kData->midiprog.count == oldCount+1) + if (count == oldCount+1) { // one midi program added, probably created by user kData->midiprog.current = oldCount; programChanged = true; } - else if (current >= static_cast(kData->midiprog.count)) - { - // current midi program > count - kData->midiprog.current = 0; - programChanged = true; - } - else if (current < 0 && kData->midiprog.count > 0) + else if (current < 0 && count > 0) { // programs exist now, but not before kData->midiprog.current = 0; programChanged = true; } - else if (current >= 0 && kData->midiprog.count == 0) + else if (current >= 0 && count == 0) { // programs existed before, but not anymore kData->midiprog.current = -1; programChanged = true; } + else if (current >= static_cast(count)) + { + // current midi program > count + kData->midiprog.current = 0; + programChanged = true; + } else { // no change diff --git a/source/backend/plugin/FluidSynthPlugin.cpp b/source/backend/plugin/FluidSynthPlugin.cpp index 0371f9271..388375ad6 100644 --- a/source/backend/plugin/FluidSynthPlugin.cpp +++ b/source/backend/plugin/FluidSynthPlugin.cpp @@ -818,9 +818,9 @@ public: // Update OSC Names if (kData->engine->isOscControlRegistered()) { - kData->engine->osc_send_control_set_midi_program_count(fId, kData->midiprog.count); + kData->engine->osc_send_control_set_midi_program_count(fId, count); - for (i=0; i < kData->midiprog.count; i++) + for (i=0; i < count; i++) kData->engine->osc_send_control_set_midi_program_data(fId, i, kData->midiprog.data[i].bank, kData->midiprog.data[i].program, kData->midiprog.data[i].name); } #endif diff --git a/source/backend/plugin/LinuxSamplerPlugin.cpp b/source/backend/plugin/LinuxSamplerPlugin.cpp index 3f7e0ddf4..d372f398e 100644 --- a/source/backend/plugin/LinuxSamplerPlugin.cpp +++ b/source/backend/plugin/LinuxSamplerPlugin.cpp @@ -427,9 +427,9 @@ public: // Update OSC Names if (kData->engine->isOscControlRegistered()) { - kData->engine->osc_send_control_set_midi_program_count(fId, kData->midiprog.count); + kData->engine->osc_send_control_set_midi_program_count(fId, count); - for (i=0; i < kData->midiprog.count; i++) + for (i=0; i < count; i++) kData->engine->osc_send_control_set_midi_program_data(fId, i, kData->midiprog.data[i].bank, kData->midiprog.data[i].program, kData->midiprog.data[i].name); } #endif diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index c304ee8a4..3e7d57578 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -550,7 +550,7 @@ public: return getPluginCategoryFromName(m_name); } - long uniqueId() + long uniqueId() const { CARLA_ASSERT(rdf_descriptor); @@ -1853,34 +1853,36 @@ public: } if (midiprog.count > 0) + { midiprog.data = new MidiProgramData[midiprog.count]; - // Update data - for (i=0; i < midiprog.count; i++) - { - const LV2_Program_Descriptor* const pdesc = ext.programs->get_program(handle, i); - CARLA_ASSERT(pdesc); - CARLA_ASSERT(pdesc->name); + // Update data + for (i=0; i < midiprog.count; i++) + { + const LV2_Program_Descriptor* const pdesc = ext.programs->get_program(handle, i); + CARLA_ASSERT(pdesc); + CARLA_ASSERT(pdesc->name); - midiprog.data[i].bank = pdesc->bank; - midiprog.data[i].program = pdesc->program; - midiprog.data[i].name = strdup(pdesc->name ? pdesc->name : ""); + midiprog.data[i].bank = pdesc->bank; + midiprog.data[i].program = pdesc->program; + midiprog.data[i].name = strdup(pdesc->name ? pdesc->name : ""); + } } #ifndef BUILD_BRIDGE // Update OSC Names if (x_engine->isOscControlRegistered()) { - x_engine->osc_send_control_set_midi_program_count(m_id, midiprog.count); + x_engine->osc_send_control_set_midi_program_count(m_id, count); - for (i=0; i < midiprog.count; i++) + for (i=0; i < count; i++) x_engine->osc_send_control_set_midi_program_data(m_id, i, midiprog.data[i].bank, midiprog.data[i].program, midiprog.data[i].name); } #endif if (init) { - if (midiprog.count > 0) + if (count > 0) setMidiProgram(0, false, false, false, true); } else @@ -1890,30 +1892,35 @@ public: // Check if current program is invalid bool programChanged = false; - if (midiprog.count == oldCount+1) + if (count == oldCount+1) { // one midi program added, probably created by user midiprog.current = oldCount; programChanged = true; } - else if (midiprog.current >= (int32_t)midiprog.count) - { - // current midi program > count - midiprog.current = 0; - programChanged = true; - } - else if (midiprog.current < 0 && midiprog.count > 0) + else if (current < 0 && count > 0) { // programs exist now, but not before midiprog.current = 0; programChanged = true; } - else if (midiprog.current >= 0 && midiprog.count == 0) + else if (current >= 0 && count == 0) { // programs existed before, but not anymore midiprog.current = -1; programChanged = true; } + else if (current >= static_cast(count)) + { + // current midi program > count + midiprog.current = 0; + programChanged = true; + } + else + { + // no change + kData->midiprog.current = current; + } if (programChanged) setMidiProgram(midiprog.current, true, true, true, true); diff --git a/source/backend/plugin/NativePlugin.cpp b/source/backend/plugin/NativePlugin.cpp index c1e25eca1..b02ca026c 100644 --- a/source/backend/plugin/NativePlugin.cpp +++ b/source/backend/plugin/NativePlugin.cpp @@ -952,34 +952,36 @@ public: count = fDescriptor->get_midi_program_count(fHandle); if (count > 0) + { kData->midiprog.createNew(count); - // Update data - for (i=0; i < kData->midiprog.count; i++) - { - const ::MidiProgram* const mpDesc = fDescriptor->get_midi_program_info(fHandle, i); - CARLA_ASSERT(mpDesc != nullptr); - CARLA_ASSERT(mpDesc->name != nullptr); + // Update data + for (i=0; i < count; i++) + { + const ::MidiProgram* const mpDesc = fDescriptor->get_midi_program_info(fHandle, i); + CARLA_ASSERT(mpDesc != nullptr); + CARLA_ASSERT(mpDesc->name != nullptr); - kData->midiprog.data[i].bank = mpDesc->bank; - kData->midiprog.data[i].program = mpDesc->program; - kData->midiprog.data[i].name = carla_strdup(mpDesc->name); + kData->midiprog.data[i].bank = mpDesc->bank; + kData->midiprog.data[i].program = mpDesc->program; + kData->midiprog.data[i].name = carla_strdup(mpDesc->name); + } } #ifndef BUILD_BRIDGE // Update OSC Names if (kData->engine->isOscControlRegistered()) { - kData->engine->osc_send_control_set_midi_program_count(fId, kData->midiprog.count); + kData->engine->osc_send_control_set_midi_program_count(fId, count); - for (i=0; i < kData->midiprog.count; i++) + for (i=0; i < count; i++) kData->engine->osc_send_control_set_midi_program_data(fId, i, kData->midiprog.data[i].bank, kData->midiprog.data[i].program, kData->midiprog.data[i].name); } #endif if (init) { - if (kData->midiprog.count > 0) + if (count > 0) setMidiProgram(0, false, false, false); } else @@ -987,30 +989,30 @@ public: // Check if current program is invalid bool programChanged = false; - if (kData->midiprog.count == oldCount+1) + if (count == oldCount+1) { // one midi program added, probably created by user kData->midiprog.current = oldCount; programChanged = true; } - else if (current >= static_cast(kData->midiprog.count)) - { - // current midi program > count - kData->midiprog.current = 0; - programChanged = true; - } - else if (current < 0 && kData->midiprog.count > 0) + else if (current < 0 && count > 0) { // programs exist now, but not before kData->midiprog.current = 0; programChanged = true; } - else if (current >= 0 && kData->midiprog.count == 0) + else if (current >= 0 && count == 0) { // programs existed before, but not anymore kData->midiprog.current = -1; programChanged = true; } + else if (current >= static_cast(count)) + { + // current midi program > count + kData->midiprog.current = 0; + programChanged = true; + } else { // no change @@ -1872,10 +1874,11 @@ public: // --------------------------------------------------------------- // get descriptor that matches label - // FIXME - use itenerator when available - for (size_t i=0; i < sPluginDescriptors.count(); i++) + for (auto it = sPluginDescriptors.begin(); it.valid(); it.next()) { - fDescriptor = sPluginDescriptors.getAt(i); + fDescriptor = *it; + + CARLA_ASSERT(fDescriptor != nullptr); if (fDescriptor == nullptr) break; @@ -2110,7 +2113,7 @@ CarlaPlugin* CarlaPlugin::newNative(const Initializer& init) return plugin; #else - init.engine->setLastError("Internal plugins not available"); + init.engine->setLastError("Internal plugins support not available"); return nullptr; #endif } diff --git a/source/backend/plugin/Vst3Plugin.cpp b/source/backend/plugin/Vst3Plugin.cpp new file mode 100644 index 000000000..e0601b241 --- /dev/null +++ b/source/backend/plugin/Vst3Plugin.cpp @@ -0,0 +1,93 @@ +/* + * Carla VST Plugin + * Copyright (C) 2011-2013 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the GPL.txt file + */ + +#include "CarlaPluginInternal.hpp" + +#ifdef WANT_VST3 + +//#include "CarlaVstUtils.hpp" + +CARLA_BACKEND_START_NAMESPACE + +class Vst3Plugin : public CarlaPlugin +{ +public: + Vst3Plugin(CarlaEngine* const engine, const unsigned short id) + : CarlaPlugin(engine, id) + { + carla_debug("Vst3Plugin::Vst3Plugin(%p, %i)", engine, id); + } + + ~Vst3Plugin() + { + carla_debug("Vst3Plugin::~Vst3Plugin()"); + + kData->singleMutex.lock(); + kData->masterMutex.lock(); + } + + // ------------------------------------------------------------------- + // Information (base) + + PluginType type() const + { + return PLUGIN_VST3; + } + +private: + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Vst3Plugin) +}; + +CARLA_BACKEND_END_NAMESPACE + +#else // WANT_VST3 +// no point on warning when the plugin doesn't even work yet +// # warning Building without VST3 support +#endif + +CARLA_BACKEND_START_NAMESPACE + +CarlaPlugin* CarlaPlugin::newVST3(const Initializer& init) +{ + carla_debug("CarlaPlugin::newVST3(%p, \"%s\", \"%s\", \"%s\")", init.engine, init.filename, init.name, init.label); + +#ifdef WANT_VST3 + Vst3Plugin* const plugin = new Vst3Plugin(init.engine, init.id); + + //if (! plugin->init(init.filename, init.name, init.label)) + { + delete plugin; + return nullptr; + } + + plugin->reload(); + + if (init.engine->getProccessMode() == PROCESS_MODE_CONTINUOUS_RACK && ! CarlaPluginProtectedData::canRunInRack(plugin)) + { + init.engine->setLastError("Carla's rack mode can only work with Stereo VST3 plugins, sorry!"); + delete plugin; + return nullptr; + } + + return plugin; +#else + init.engine->setLastError("VST3 support not available"); + return nullptr; +#endif +} + +CARLA_BACKEND_END_NAMESPACE diff --git a/source/backend/plugin/VstPlugin.cpp b/source/backend/plugin/VstPlugin.cpp index e12e84d94..48dea3057 100644 --- a/source/backend/plugin/VstPlugin.cpp +++ b/source/backend/plugin/VstPlugin.cpp @@ -140,11 +140,11 @@ public: return getPluginCategoryFromName(fName); } - long uniqueId() + long uniqueId() const { CARLA_ASSERT(fEffect != nullptr); - return fEffect ? fEffect->uniqueID : 0; + return (fEffect != nullptr) ? fEffect->uniqueID : 0; } // ------------------------------------------------------------------- @@ -313,7 +313,7 @@ public: else if (index > static_cast(kData->prog.count)) return; - if (index >= 0) + if (fEffect != nullptr && index >= 0) { const ScopedProcessLocker spl(this, (sendGui || sendOsc || sendCallback)); @@ -450,63 +450,65 @@ public: CarlaPlugin::idleGui(); } -#if 0 // ------------------------------------------------------------------- // Plugin state void reload() { carla_debug("VstPlugin::reload() - start"); - CARLA_ASSERT(effect); + CARLA_ASSERT(kData->engine != nullptr); + CARLA_ASSERT(fEffect != nullptr); - const ProcessMode processMode(x_engine->getOptions().processMode); + const ProcessMode processMode(kData->engine->getProccessMode()); // Safely disable plugin for reload - const ScopedDisabler m(this); + const ScopedDisabler sd(this); - // Remove client ports - removeClientPorts(); - - // Delete old data deleteBuffers(); uint32_t aIns, aOuts, mIns, mOuts, params, j; - aIns = effect->numInputs; - aOuts = effect->numOutputs; - params = effect->numParams; + bool needsCtrlIn, needsCtrlOut; + needsCtrlIn = needsCtrlOut = false; + + aIns = fEffect->numInputs; + aOuts = fEffect->numOutputs; + params = fEffect->numParams; - if (vstPluginCanDo(effect, "receiveVstEvents") || vstPluginCanDo(effect, "receiveVstMidiEvent") || (effect->flags & effFlagsIsSynth) > 0 || (m_hints & PLUGIN_WANTS_MIDI_INPUT)) + if (vstPluginCanDo(fEffect, "receiveVstEvents") || vstPluginCanDo(fEffect, "receiveVstMidiEvent") || (fEffect->flags & effFlagsIsSynth) > 0 || (fHints & PLUGIN_WANTS_MIDI_INPUT)) + { mIns = 1; + needsCtrlIn = true; + } else mIns = 0; - if (vstPluginCanDo(effect, "sendVstEvents") || vstPluginCanDo(effect, "sendVstMidiEvent")) + if (vstPluginCanDo(fEffect, "sendVstEvents") || vstPluginCanDo(fEffect, "sendVstMidiEvent")) + { mOuts = 1; + needsCtrlOut = true; + } else mOuts = 0; if (aIns > 0) { - aIn.ports = new CarlaEngineAudioPort*[aIns]; - aIn.rindexes = new uint32_t[aIns]; + kData->audioIn.createNew(aIns); } if (aOuts > 0) { - aOut.ports = new CarlaEngineAudioPort*[aOuts]; - aOut.rindexes = new uint32_t[aOuts]; + kData->audioOut.createNew(aOuts); + needsCtrlIn = true; } if (params > 0) { - param.data = new ParameterData[params]; - param.ranges = new ParameterRanges[params]; + kData->param.createNew(params); + needsCtrlIn = true; } - bool needsCtrlIn = (aOuts > 0 || params > 0); - - const int portNameSize = x_engine->maxPortNameSize(); + const uint portNameSize = kData->engine->maxPortNameSize(); CarlaString portName; // Audio Ins @@ -516,16 +518,21 @@ public: if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } - char tmp[12] = { 0 }; - sprintf(tmp, "input_%02i", j+1); - portName += tmp; + if (aIns > 1) + { + portName += "input_"; + portName += CarlaString(j+1); + } + else + portName += "input"; + portName.truncate(portNameSize); - aIn.ports[j] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, true); - aIn.rindexes[j] = j; + kData->audioIn.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, true); + kData->audioIn.ports[j].rindex = j; } // Audio Outs @@ -535,82 +542,114 @@ public: if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } - char tmp[12] = { 0 }; - sprintf(tmp, "output_%02i", j+1); - portName += tmp; + if (aOuts > 1) + { + portName += "output_"; + portName += CarlaString(j+1); + } + else + portName += "output"; + portName.truncate(portNameSize); - aOut.ports[j] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false); - aOut.rindexes[j] = j; + kData->audioOut.ports[j].port = (CarlaEngineAudioPort*)kData->client->addPort(kEnginePortTypeAudio, portName, false); + kData->audioOut.ports[j].rindex = j; } for (j=0; j < params; j++) { - param.data[j].type = PARAMETER_INPUT; - param.data[j].index = j; - param.data[j].rindex = j; - param.data[j].hints = 0; - param.data[j].midiChannel = 0; - param.data[j].midiCC = -1; + kData->param.data[j].type = PARAMETER_INPUT; + kData->param.data[j].index = j; + kData->param.data[j].rindex = j; + kData->param.data[j].hints = 0x0; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; - double min, max, def, step, stepSmall, stepLarge; + float min, max, def, step, stepSmall, stepLarge; VstParameterProperties prop; - prop.flags = 0; + carla_zeroMem(&prop, sizeof(VstParameterProperties)); - if (effect->dispatcher(effect, effGetParameterProperties, j, 0, &prop, 0)) + if (fHints & PLUGIN_HAS_COCKOS_EXTENSIONS) { double range[2] = { 0.0, 1.0 }; - if ((m_hints & PLUGIN_HAS_COCKOS_EXTENSIONS) > 0 && effect->dispatcher(effect, effVendorSpecific, 0xdeadbef0, j, range, 0.0) >= 0xbeef) + if (dispatcher(effVendorSpecific, 0xdeadbef0, j, range, 0.0f) >= 0xbeef) { min = range[0]; max = range[1]; + + if (min > max) + max = min; + else if (max < min) + min = max; + + if (max - min == 0.0f) + { + carla_stderr2("WARNING - Broken plugin parameter: max - min == 0.0f (with cockos extensions)"); + max = min + 0.1f; + } + } + else + { + min = 0.0f; + max = 1.0f; } - else if (prop.flags & kVstParameterUsesIntegerMinMax) + + if (dispatcher(effVendorSpecific, kVstParameterUsesIntStep, j, nullptr, 0.0f) >= 0xbeef) { - min = prop.minInteger; - max = prop.maxInteger; + step = 1.0f; + stepSmall = 1.0f; + stepLarge = 10.0f; } else { - min = 0.0; - max = 1.0; + float range = max - min; + step = range/100.0f; + stepSmall = range/1000.0f; + stepLarge = range/10.0f; } + } + else if (dispatcher(effGetParameterProperties, j, 0, &prop, 0) == 1) + { + if (prop.flags & kVstParameterUsesIntegerMinMax) + { + min = float(prop.minInteger); + max = float(prop.maxInteger); - if (min > max) - max = min; - else if (max < min) - min = max; + if (min > max) + max = min; + else if (max < min) + min = max; - if (max - min == 0.0) - { - carla_stderr("Broken plugin parameter: max - min == 0"); - max = min + 0.1; + if (max - min == 0.0f) + { + carla_stderr2("WARNING - Broken plugin parameter: max - min == 0.0f"); + max = min + 0.1f; + } } - - if ((m_hints & PLUGIN_HAS_COCKOS_EXTENSIONS) > 0 && effect->dispatcher(effect, effVendorSpecific, kVstParameterUsesIntStep, j, nullptr, 0.0f) >= 0xbeef) + else { - step = 1.0; - stepSmall = 1.0; - stepLarge = 10.0; + min = 0.0f; + max = 1.0f; } - else if (prop.flags & kVstParameterIsSwitch) + + if (prop.flags & kVstParameterIsSwitch) { step = max - min; stepSmall = step; stepLarge = step; - param.data[j].hints |= PARAMETER_IS_BOOLEAN; + kData->param.data[j].hints |= PARAMETER_IS_BOOLEAN; } else if (prop.flags & kVstParameterUsesIntStep) { - step = prop.stepInteger; - stepSmall = prop.stepInteger; - stepLarge = prop.largeStepInteger; - param.data[j].hints |= PARAMETER_IS_INTEGER; + step = float(prop.stepInteger); + stepSmall = float(prop.stepInteger)/10; + stepLarge = float(prop.largeStepInteger); + kData->param.data[j].hints |= PARAMETER_IS_INTEGER; } else if (prop.flags & kVstParameterUsesFloatStep) { @@ -620,46 +659,46 @@ public: } else { - double range = max - min; - step = range/100.0; - stepSmall = range/1000.0; - stepLarge = range/10.0; + float range = max - min; + step = range/100.0f; + stepSmall = range/1000.0f; + stepLarge = range/10.0f; } if (prop.flags & kVstParameterCanRamp) - param.data[j].hints |= PARAMETER_IS_LOGARITHMIC; + kData->param.data[j].hints |= PARAMETER_IS_LOGARITHMIC; } else { - min = 0.0; - max = 1.0; - step = 0.001; - stepSmall = 0.0001; - stepLarge = 0.1; + min = 0.0f; + max = 1.0f; + step = 0.001f; + stepSmall = 0.0001f; + stepLarge = 0.1f; } + kData->param.data[j].hints |= PARAMETER_IS_ENABLED; +#ifndef BUILD_BRIDGE + kData->param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT; +#endif + + if ((fHints & PLUGIN_USES_OLD_VSTSDK) != 0 || dispatcher(effCanBeAutomated, j, 0, nullptr, 0.0f) == 1) + kData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE; + // no such thing as VST default parameters - def = effect->getParameter(effect, j); + def = fEffect->getParameter(fEffect, j); if (def < min) def = min; else if (def > max) def = max; - param.ranges[j].min = min; - param.ranges[j].max = max; - param.ranges[j].def = def; - param.ranges[j].step = step; - param.ranges[j].stepSmall = stepSmall; - param.ranges[j].stepLarge = stepLarge; - - param.data[j].hints |= PARAMETER_IS_ENABLED; -#ifndef BUILD_BRIDGE - param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT; -#endif - - if ((m_hints & PLUGIN_USES_OLD_VSTSDK) > 0 || effect->dispatcher(effect, effCanBeAutomated, j, 0, nullptr, 0.0f) == 1) - param.data[j].hints |= PARAMETER_IS_AUTOMABLE; + kData->param.ranges[j].min = min; + kData->param.ranges[j].max = max; + kData->param.ranges[j].def = def; + kData->param.ranges[j].step = step; + kData->param.ranges[j].stepSmall = stepSmall; + kData->param.ranges[j].stepLarge = stepLarge; } if (needsCtrlIn) @@ -668,96 +707,130 @@ public: if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } - portName += "control-in"; + portName += "event-in"; portName.truncate(portNameSize); - param.portCin = (CarlaEngineControlPort*)x_client->addPort(CarlaEnginePortTypeControl, portName, true); + kData->event.portIn = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, true); } - if (mIns == 1) + if (needsCtrlOut) { portName.clear(); if (processMode == PROCESS_MODE_SINGLE_CLIENT) { - portName = m_name; + portName = fName; portName += ":"; } - portName += "midi-in"; + portName += "event-out"; portName.truncate(portNameSize); - midi.portMin = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, true); + kData->event.portOut = (CarlaEngineEventPort*)kData->client->addPort(kEnginePortTypeEvent, portName, false); } - if (mOuts == 1) - { - portName.clear(); + // plugin hints + const intptr_t vstCategory = dispatcher(effGetPlugCategory, 0, 0, nullptr, 0.0f); - if (processMode == PROCESS_MODE_SINGLE_CLIENT) - { - portName = m_name; - portName += ":"; - } + fHints = 0x0; - portName += "midi-out"; - portName.truncate(portNameSize); + if (vstCategory == kPlugCategSynth || vstCategory == kPlugCategGenerator) + fHints |= PLUGIN_IS_SYNTH; - midi.portMout = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, false); - } + if (fEffect->flags & effFlagsHasEditor) + { + fHints |= PLUGIN_HAS_GUI; - aIn.count = aIns; - aOut.count = aOuts; - param.count = params; + if (! fGui.isOsc) + fHints |= PLUGIN_HAS_SINGLE_THREAD; + } - // plugin checks - m_hints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO); + if (dispatcher(effGetVstVersion, 0, 0, nullptr, 0.0f) < kVstVersion) + fHints |= PLUGIN_USES_OLD_VSTSDK; - intptr_t vstCategory = effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f); + if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) + fHints |= PLUGIN_CAN_PROCESS_REPLACING; - if (vstCategory == kPlugCategSynth || vstCategory == kPlugCategGenerator) - m_hints |= PLUGIN_IS_SYNTH; + if (fEffect->flags & effFlagsHasEditor) + fHints |= PLUGIN_HAS_GUI; - if (effect->flags & effFlagsProgramChunks) - m_hints |= PLUGIN_USES_CHUNKS; + if (static_cast(dispatcher(effCanDo, 0, 0, (void*)"hasCockosExtensions", 0.0f)) == 0xbeef0000) + fHints |= PLUGIN_HAS_COCKOS_EXTENSIONS; if (aOuts > 0 && (aIns == aOuts || aIns == 1)) - m_hints |= PLUGIN_CAN_DRYWET; + fHints |= PLUGIN_CAN_DRYWET; if (aOuts > 0) - m_hints |= PLUGIN_CAN_VOLUME; + fHints |= PLUGIN_CAN_VOLUME; + + if (aOuts >= 2 && aOuts % 2 == 0) + fHints |= PLUGIN_CAN_BALANCE; + + // extra plugin hints + kData->extraHints = 0x0; - if (aOuts >= 2 && aOuts%2 == 0) - m_hints |= PLUGIN_CAN_BALANCE; + if (mIns > 0) + kData->extraHints |= PLUGIN_HINT_HAS_MIDI_IN; - if ((aIns == 0 || aIns == 2) && (aOuts == 0 || aOuts == 2)) - m_hints |= PLUGIN_CAN_FORCE_STEREO; + if (mOuts > 0) + kData->extraHints |= PLUGIN_HINT_HAS_MIDI_OUT; + + if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) + kData->extraHints |= PLUGIN_HINT_CAN_RUN_RACK; + + // plugin options + fOptions = 0x0; + + fOptions |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; + + if (fEffect->flags & effFlagsProgramChunks) + fOptions |= PLUGIN_OPTION_USE_CHUNKS; + +#ifdef CARLA_OS_WIN + // Most Windows plugins have issues with this + fOptions |= PLUGIN_OPTION_FIXED_BUFFER; +#endif + + if (mIns > 0) + { + fOptions |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; + fOptions |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; + fOptions |= PLUGIN_OPTION_SEND_PITCHBEND; + fOptions |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; + } + + // dummy pre-start to catch latency and possible wantEvents() call on old plugins + { + dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); + dispatcher(effStartProcess, 0, 0, nullptr, 0.0f); + dispatcher(effStopProcess, 0, 0, nullptr, 0.0f); + dispatcher(effMainsChanged, 0, 0, nullptr, 0.0f); + } // check latency - if (m_hints & PLUGIN_CAN_DRYWET) + if (fHints & PLUGIN_CAN_DRYWET) { #ifdef VESTIGE_HEADER - char* const empty3Ptr = &effect->empty3[0]; + char* const empty3Ptr = &fEffect->empty3[0]; int32_t* initialDelayPtr = (int32_t*)empty3Ptr; - m_latency = *initialDelayPtr; + kData->latency = *initialDelayPtr; #else - m_latency = effect->initialDelay; + kData->latency = fEffect->initialDelay; #endif - x_client->setLatency(m_latency); + kData->client->setLatency(kData->latency); recreateLatencyBuffers(); } // special plugin fixes -#ifdef __WINE__ // 1. IL Harmless - disable threaded processing - if (effect->uniqueID == 1229484653) + if (fEffect->uniqueID == 1229484653) { - char strBuf[255] = { 0 }; + char strBuf[STR_MAX] = { 0 }; getLabel(strBuf); if (std::strcmp(strBuf, "IL Harmless") == 0) @@ -765,8 +838,8 @@ public: // TODO - disable threaded processing } } -#endif + bufferSizeChanged(kData->engine->getBufferSize()); reloadPrograms(true); carla_debug("VstPlugin::reload() - end"); @@ -775,100 +848,96 @@ public: void reloadPrograms(const bool init) { carla_debug("VstPlugin::reloadPrograms(%s)", bool2str(init)); - uint32_t i, oldCount = prog.count; + uint32_t i, oldCount = kData->prog.count; + const int32_t current = kData->prog.current; // Delete old programs - if (prog.count > 0) - { - for (i=0; i < prog.count; i++) - { - if (prog.names[i]) - free((void*)prog.names[i]); - } - - delete[] prog.names; - } - - prog.count = 0; - prog.names = nullptr; + kData->prog.clear(); // Query new programs - prog.count = effect->numPrograms; - - if (prog.count > 0) - prog.names = new const char* [prog.count]; + uint32_t count = static_cast(fEffect->numPrograms); - // Update names - for (i=0; i < prog.count; i++) + if (count > 0) { - char strBuf[STR_MAX] = { 0 }; - if (effect->dispatcher(effect, effGetProgramNameIndexed, i, 0, strBuf, 0.0f) != 1) + kData->prog.createNew(count); + + // Update names + for (i=0; i < count; i++) { - // program will be [re-]changed later - effect->dispatcher(effect, effSetProgram, 0, i, nullptr, 0.0f); - effect->dispatcher(effect, effGetProgramName, 0, 0, strBuf, 0.0f); + char strBuf[STR_MAX] = { 0 }; + if (dispatcher(effGetProgramNameIndexed, i, 0, strBuf, 0.0f) != 1) + { + // program will be [re-]changed later + dispatcher(effSetProgram, 0, i, nullptr, 0.0f); + dispatcher(effGetProgramName, 0, 0, strBuf, 0.0f); + } + kData->prog.names[i] = strdup(strBuf); } - prog.names[i] = strdup(strBuf); } #ifndef BUILD_BRIDGE // Update OSC Names - if (x_engine->isOscControlRegistered()) + if (kData->engine->isOscControlRegistered()) { - x_engine->osc_send_control_set_program_count(m_id, prog.count); + kData->engine->osc_send_control_set_program_count(fId, count); - for (i=0; i < prog.count; i++) - x_engine->osc_send_control_set_program_name(m_id, i, prog.names[i]); + for (i=0; i < count; i++) + kData->engine->osc_send_control_set_program_name(fId, i, kData->prog.names[i]); } #endif if (init) { - if (prog.count > 0) - setProgram(0, false, false, false, true); + if (count > 0) + setProgram(0, false, false, false); } else { - x_engine->callback(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0, nullptr); - // Check if current program is invalid bool programChanged = false; - if (prog.count == oldCount+1) + if (count == oldCount+1) { // one program added, probably created by user - prog.current = oldCount; + kData->prog.current = oldCount; programChanged = true; } - else if (prog.current >= (int32_t)prog.count) + else if (current < 0 && count > 0) { - // current program > count - prog.current = 0; + // programs exist now, but not before + kData->prog.current = 0; programChanged = true; } - else if (prog.current < 0 && prog.count > 0) + else if (current >= 0 && count == 0) { - // programs exist now, but not before - prog.current = 0; + // programs existed before, but not anymore + kData->prog.current = -1; programChanged = true; } - else if (prog.current >= 0 && prog.count == 0) + else if (current >= static_cast(count)) { - // programs existed before, but not anymore - prog.current = -1; + // current program > count + kData->prog.current = 0; programChanged = true; } + else + { + // no change + kData->prog.current = current; + } if (programChanged) { - setProgram(prog.current, true, true, true, true); + setProgram(kData->prog.current, true, true, true); } else { // Program was changed during update, re-set it - if (prog.current >= 0) - effect->dispatcher(effect, effSetProgram, 0, prog.current, nullptr, 0.0f); + if (kData->prog.current >= 0) + dispatcher(effSetProgram, 0, kData->prog.current, nullptr, 0.0f); } + + kData->engine->callback(CALLBACK_RELOAD_PROGRAMS, fId, 0, 0, 0.0f, nullptr); } } @@ -880,6 +949,7 @@ public: uint32_t i, k; uint32_t midiEventCount = 0; +#if 0 vstTimeOffset = 0; double aInsPeak[2] = { 0.0 }; @@ -1406,25 +1476,26 @@ public: x_engine->setOutputPeak(m_id, 1, aOutsPeak[1]); m_activeBefore = m_active; +#endif } void bufferSizeChanged(uint32_t newBufferSize) { - if (m_active) + if (kData->active) { - effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f); - effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f); + dispatcher(effStopProcess, 0, 0, nullptr, 0.0f); + dispatcher(effMainsChanged, 0, 0, nullptr, 0.0f); } #if ! VST_FORCE_DEPRECATED - effect->dispatcher(effect, effSetBlockSizeAndSampleRate, 0, newBufferSize, nullptr, x_engine->getSampleRate()); + dispatcher(effSetBlockSizeAndSampleRate, 0, newBufferSize, nullptr, kData->engine->getSampleRate()); #endif - effect->dispatcher(effect, effSetBlockSize, 0, newBufferSize, nullptr, 0.0f); + dispatcher(effSetBlockSize, 0, newBufferSize, nullptr, 0.0f); - if (m_active) + if (kData->active) { - effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f); - effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f); + dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); + dispatcher(effStartProcess, 0, 0, nullptr, 0.0f); } } @@ -1433,58 +1504,81 @@ public: void uiParameterChange(const uint32_t index, const double value) { - CARLA_ASSERT(index < param.count); + CARLA_ASSERT(index < kData->param.count); - if (index >= param.count) + if (index >= kData->param.count) + return; + if (! fGui.isOsc) + return; + if (kData->osc.data.target == nullptr) return; - if (gui.type == GUI_EXTERNAL_OSC && osc.data.target) - osc_send_control(&osc.data, param.data[index].rindex, value); + osc_send_control(&kData->osc.data, kData->param.data[index].rindex, value); } void uiProgramChange(const uint32_t index) { - CARLA_ASSERT(index < prog.count); + CARLA_ASSERT(index < kData->prog.count); - if (index >= prog.count) + if (index >= kData->prog.count) + return; + if (! fGui.isOsc) + return; + if (kData->osc.data.target == nullptr) return; - if (gui.type == GUI_EXTERNAL_OSC && osc.data.target) - osc_send_program(&osc.data, index); + osc_send_program(&kData->osc.data, index); } void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) { - CARLA_ASSERT(channel < 16); - CARLA_ASSERT(note < 128); - CARLA_ASSERT(velo > 0 && velo < 128); + CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); + CARLA_ASSERT(note < MAX_MIDI_NOTE); + CARLA_ASSERT(velo > 0 && velo < MAX_MIDI_VALUE); - if (gui.type == GUI_EXTERNAL_OSC && osc.data.target) - { - uint8_t midiData[4] = { 0 }; - midiData[1] = MIDI_STATUS_NOTE_ON + channel; - midiData[2] = note; - midiData[3] = velo; - osc_send_midi(&osc.data, midiData); - } + if (channel >= MAX_MIDI_CHANNELS) + return; + if (note >= MAX_MIDI_NOTE) + return; + if (velo >= MAX_MIDI_VALUE) + return; + if (! fGui.isOsc) + return; + if (kData->osc.data.target == nullptr) + return; + + uint8_t midiData[4] = { 0 }; + midiData[1] = MIDI_STATUS_NOTE_ON + channel; + midiData[2] = note; + midiData[3] = velo; + + osc_send_midi(&kData->osc.data, midiData); } void uiNoteOff(const uint8_t channel, const uint8_t note) { - CARLA_ASSERT(channel < 16); - CARLA_ASSERT(note < 128); + CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); + CARLA_ASSERT(note < MAX_MIDI_NOTE); - if (gui.type == GUI_EXTERNAL_OSC && osc.data.target) - { - uint8_t midiData[4] = { 0 }; - midiData[1] = MIDI_STATUS_NOTE_OFF + channel; - midiData[2] = note; - osc_send_midi(&osc.data, midiData); - } + if (channel >= MAX_MIDI_CHANNELS) + return; + if (note >= MAX_MIDI_NOTE) + return; + if (! fGui.isOsc) + return; + if (kData->osc.data.target == nullptr) + return; + + uint8_t midiData[4] = { 0 }; + midiData[1] = MIDI_STATUS_NOTE_OFF + channel; + midiData[2] = note; + + osc_send_midi(&kData->osc.data, midiData); } // ------------------------------------------------------------------- +#if 0 intptr_t handleAudioMasterTempoAt() { const CarlaEngineTimeInfo* const timeInfo = x_engine->getTimeInfo(); @@ -1974,8 +2068,6 @@ public: #endif dispatcher(effOpen, 0, 0, nullptr, 0.0f); - //dispatcher(effStopProcess, 0, 0, nullptr, 0.0f); - //dispatcher(effMainsChanged, 0, 0, nullptr, 0.0f); // --------------------------------------------------------------- // get info @@ -2021,34 +2113,17 @@ public: dispatcher(effStopProcess, 0, 0, nullptr, 0.0f); dispatcher(effMainsChanged, 0, 0, nullptr, 0.0f); -#if ! VST_FORCE_DEPRECATED - // dummy pre-start to catch possible wantEvents() call on old plugins - //dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); - //dispatcher(effStartProcess, 0, 0, nullptr, 0.0f); - //dispatcher(effStopProcess, 0, 0, nullptr, 0.0f); - //dispatcher(effMainsChanged, 0, 0, nullptr, 0.0f); -#endif - - // special checks - if (static_cast(dispatcher(effCanDo, 0, 0, (void*)"hasCockosExtensions", 0.0f)) == 0xbeef0000) - { - carla_debug("Plugin has Cockos extensions!"); - fHints |= PLUGIN_HAS_COCKOS_EXTENSIONS; - } - if (dispatcher(effGetVstVersion, 0, 0, nullptr, 0.0f) < kVstVersion) fHints |= PLUGIN_USES_OLD_VSTSDK; - if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) - fHints |= PLUGIN_CAN_PROCESS_REPLACING; + if (static_cast(dispatcher(effCanDo, 0, 0, (void*)"hasCockosExtensions", 0.0f)) == 0xbeef0000) + fHints |= PLUGIN_HAS_COCKOS_EXTENSIONS; // --------------------------------------------------------------- // gui stuff if (fEffect->flags & effFlagsHasEditor) { - fHints |= PLUGIN_HAS_GUI; - const EngineOptions& engineOptions(kData->engine->getOptions()); if (engineOptions.preferUiBridges && engineOptions.bridge_vstx11.isNotEmpty() && (fEffect->flags & effFlagsProgramChunks) == 0) @@ -2056,10 +2131,6 @@ public: kData->osc.thread.setOscData(engineOptions.bridge_vstx11, label); fGui.isOsc = true; } - else - { - fHints |= PLUGIN_HAS_SINGLE_THREAD; - } } return true; diff --git a/source/utils/CarlaVstUtils.hpp b/source/utils/CarlaVstUtils.hpp index 93a198764..29f0c1e11 100644 --- a/source/utils/CarlaVstUtils.hpp +++ b/source/utils/CarlaVstUtils.hpp @@ -128,7 +128,7 @@ typedef AEffect* (*VST_Function)(audioMasterCallback); // Check if feature is supported by the plugin static inline -bool vstPluginCanDo(AEffect* const effect, char* const feature) +bool vstPluginCanDo(AEffect* const effect, const char* const feature) { return (effect->dispatcher(effect, effCanDo, 0, 0, (void*)feature, 0.0f) == 1); }