Browse Source

More VST work; cleanup

tags/1.9.4
falkTX 11 years ago
parent
commit
1a6b10e0c4
10 changed files with 502 additions and 330 deletions
  1. +1
    -1
      source/backend/CarlaBackend.hpp
  2. +1
    -1
      source/backend/plugin/BridgePlugin.cpp
  3. +25
    -27
      source/backend/plugin/DssiPlugin.cpp
  4. +2
    -2
      source/backend/plugin/FluidSynthPlugin.cpp
  5. +2
    -2
      source/backend/plugin/LinuxSamplerPlugin.cpp
  6. +29
    -22
      source/backend/plugin/Lv2Plugin.cpp
  7. +28
    -25
      source/backend/plugin/NativePlugin.cpp
  8. +93
    -0
      source/backend/plugin/Vst3Plugin.cpp
  9. +320
    -249
      source/backend/plugin/VstPlugin.cpp
  10. +1
    -1
      source/utils/CarlaVstUtils.hpp

+ 1
- 1
source/backend/CarlaBackend.hpp View File

@@ -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



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

@@ -119,7 +119,7 @@ public:
return fInfo.category;
}

long uniqueId()
long uniqueId() const
{
return fInfo.uniqueId;
}


+ 25
- 27
source/backend/plugin/DssiPlugin.cpp View File

@@ -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<uint32_t>(pdesc->Bank);
kData->midiprog.data[i].program = static_cast<uint32_t>(pdesc->Program);
kData->midiprog.data[i].name = carla_strdup(pdesc->Name);
kData->midiprog.data[i].bank = static_cast<uint32_t>(pdesc->Bank);
kData->midiprog.data[i].program = static_cast<uint32_t>(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<int32_t>(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<int32_t>(count))
{
// current midi program > count
kData->midiprog.current = 0;
programChanged = true;
}
else
{
// no change


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

@@ -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


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

@@ -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


+ 29
- 22
source/backend/plugin/Lv2Plugin.cpp View File

@@ -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<int32_t>(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);


+ 28
- 25
source/backend/plugin/NativePlugin.cpp View File

@@ -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<int32_t>(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<int32_t>(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
}


+ 93
- 0
source/backend/plugin/Vst3Plugin.cpp View File

@@ -0,0 +1,93 @@
/*
* Carla VST Plugin
* Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
*
* 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

+ 320
- 249
source/backend/plugin/VstPlugin.cpp View File

@@ -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<int32_t>(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<uintptr_t>(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<uint32_t>(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<int32_t>(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<uintptr_t>(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<uintptr_t>(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;


+ 1
- 1
source/utils/CarlaVstUtils.hpp View File

@@ -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);
}


Loading…
Cancel
Save