Browse Source

Finish splitting lv2 code; Add midi and time ports to export-lv2

tags/1.9.8
falkTX 8 years ago
parent
commit
cde56e0de4
5 changed files with 806 additions and 718 deletions
  1. +68
    -11
      source/backend/plugin/CarlaPlugin.cpp
  2. +128
    -162
      source/bridges-plugin/CarlaBridgeLV2.cpp
  3. +82
    -538
      source/plugin/carla-lv2.cpp
  4. +2
    -1
      source/plugin/carla-vst.cpp
  5. +526
    -6
      source/utils/CarlaLv2Utils.hpp

+ 68
- 11
source/backend/plugin/CarlaPlugin.cpp View File

@@ -1019,31 +1019,62 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
mainStream << "\n";
}

const uint32_t midiIns = getMidiInCount();
const uint32_t midiOuts = getMidiOutCount();

int portIndex = 0;

for (uint32_t i=0; i<pData->audioIn.count; ++i)
if (midiIns > 0)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);
mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, lv2:AtomPort ;\n";
mainStream << " lv2:index 0 ;\n";
mainStream << " lv2:symbol \"lv2_events_in\" ;\n";
mainStream << " lv2:name \"Events Input\" ;\n";
mainStream << " atom:bufferType atom:Sequence ;\n";
mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,\n";
mainStream << " <http://lv2plug.in/ns/ext/time#Position> ;\n";
mainStream << " ] ;\n";
++portIndex;

for (uint32_t i=1; i<midiIns; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);

mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, lv2:AtomPort ;\n";
mainStream << " lv2:index " << portIndexNum << " ;\n";
mainStream << " lv2:symbol \"lv2_midi_in_" << portIndexLabel << "\" ;\n";
mainStream << " lv2:name \"MIDI Input " << portIndexLabel << "\" ;\n";
mainStream << " ] ;\n";
}
}
else
{
mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, lv2:AudioPort ;\n";
mainStream << " lv2:index " << portIndexNum << " ;\n";
mainStream << " lv2:symbol \"lv2_audio_in_" << portIndexLabel << "\" ;\n";
mainStream << " lv2:name \"Audio Input " << portIndexLabel << "\" ;\n";
mainStream << " a lv2:InputPort, lv2:AtomPort ;\n";
mainStream << " lv2:index 0 ;\n";
mainStream << " lv2:symbol \"lv2_time_info\" ;\n";
mainStream << " lv2:name \"Time Info\" ;\n";
mainStream << " atom:bufferType atom:Sequence ;\n";
mainStream << " atom:supports <http://lv2plug.in/ns/ext/time#Position> ;\n";
mainStream << " ] ;\n";
++portIndex;
}

for (uint32_t i=0; i<pData->audioOut.count; ++i)
for (uint32_t i=0; i<midiOuts; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);

mainStream << " lv2:port [\n";
mainStream << " a lv2:OutputPort, lv2:AudioPort ;\n";
mainStream << " a lv2:InputPort, lv2:AtomPort ;\n";
mainStream << " lv2:index " << portIndexNum << " ;\n";
mainStream << " lv2:symbol \"lv2_audio_out_" << portIndexLabel << "\" ;\n";
mainStream << " lv2:name \"Audio Output " << portIndexLabel << "\" ;\n";
mainStream << " lv2:symbol \"lv2_midi_out_" << portIndexLabel << "\" ;\n";
mainStream << " lv2:name \"MIDI Output " << portIndexLabel << "\" ;\n";
mainStream << " atom:bufferType atom:Sequence ;\n";
mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
mainStream << " ] ;\n";
}

@@ -1060,6 +1091,32 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
mainStream << " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#notOnGUI> ;\n";
mainStream << " ] ;\n";

for (uint32_t i=0; i<pData->audioIn.count; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);

mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, lv2:AudioPort ;\n";
mainStream << " lv2:index " << portIndexNum << " ;\n";
mainStream << " lv2:symbol \"lv2_audio_in_" << portIndexLabel << "\" ;\n";
mainStream << " lv2:name \"Audio Input " << portIndexLabel << "\" ;\n";
mainStream << " ] ;\n";
}

for (uint32_t i=0; i<pData->audioOut.count; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);

mainStream << " lv2:port [\n";
mainStream << " a lv2:OutputPort, lv2:AudioPort ;\n";
mainStream << " lv2:index " << portIndexNum << " ;\n";
mainStream << " lv2:symbol \"lv2_audio_out_" << portIndexLabel << "\" ;\n";
mainStream << " lv2:name \"Audio Output " << portIndexLabel << "\" ;\n";
mainStream << " ] ;\n";
}

for (uint32_t i=0; i<pData->param.count; ++i)
{
const ParameterData& paramData(pData->param.data[i]);


+ 128
- 162
source/bridges-plugin/CarlaBridgeLV2.cpp View File

@@ -42,8 +42,7 @@ public:
const LV2_Feature* const* const features)
: Lv2PluginBaseClass(sampleRate, features),
fPlugin(nullptr),
fUiName(),
fPorts()
fUiName()
{
CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount == 0,)
CARLA_SAFE_ASSERT_RETURN(pData->plugins[0].plugin == nullptr,);
@@ -94,7 +93,20 @@ public:
CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),);

fPorts.init(fPlugin);
fPorts.usesTime = true;
fPorts.numAudioIns = fPlugin->getAudioInCount();
fPorts.numAudioOuts = fPlugin->getAudioOutCount();
fPorts.numMidiIns = fPlugin->getMidiInCount();
fPorts.numMidiOuts = fPlugin->getMidiOutCount();
fPorts.numParams = fPlugin->getParameterCount();

fPorts.init();

for (uint32_t i=0; i < fPorts.numParams; ++i)
{
fPorts.paramsLast[i] = fPlugin->getParameterValue(i);
fPorts.paramsOut [i] = fPlugin->isParameterOutput(i);
}
}

~CarlaEngineLV2Single()
@@ -113,11 +125,6 @@ public:
// ----------------------------------------------------------------------------------------------------------------
// LV2 functions

void lv2_connect_port(const uint32_t port, void* const dataLocation) noexcept
{
fPorts.connectPort(port, dataLocation);
}

void lv2_activate() noexcept
{
CARLA_SAFE_ASSERT_RETURN(! fIsActive,);
@@ -138,38 +145,98 @@ public:

void lv2_run(const uint32_t frames)
{
//const PendingRtEventsRunner prt(this, frames);

if (! lv2_pre_run(frames))
{
updateParameterOutputs();
return;
}

fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);

// Check for updated parameters
float curValue;

for (uint32_t i=0; i < fPorts.numParams; ++i)
if (fPorts.numMidiIns > 0)
{
if (fPorts.paramsOut[i])
continue;
uint32_t engineEventIndex = 0;
carla_zeroStructs(pData->events.in, kMaxEngineEventInternalCount);

CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)
for (uint32_t i=0; i < fPorts.numMidiIns; ++i)
{
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], event)
{
if (event == nullptr)
continue;
if (event->body.type != fURIs.midiEvent)
continue;
if (event->body.size > 4)
continue;
if (event->time.frames >= frames)
break;

curValue = *fPorts.paramsPtr[i];
const uint8_t* const data((const uint8_t*)(event + 1));

if (carla_isEqual(fPorts.paramsLast[i], curValue))
continue;
EngineEvent& engineEvent(pData->events.in[engineEventIndex++]);

engineEvent.time = (uint32_t)event->time.frames;
engineEvent.fillFromMidiData((uint8_t)event->body.size, data, (uint8_t)i);

fPorts.paramsLast[i] = curValue;
fPlugin->setParameterValue(i, curValue, false, false, false);
if (engineEventIndex >= kMaxEngineEventInternalCount)
break;
}
}
}

if (frames == 0)
return fPorts.updateOutputs();
if (fPorts.numMidiOuts > 0)
{
carla_zeroStructs(pData->events.out, kMaxEngineEventInternalCount);
}

if (fPlugin->tryLock(fIsOffline))
{
fPlugin->initBuffers();
fPlugin->process(fPorts.audioIns, fPorts.audioOuts, nullptr, nullptr, frames);
fPlugin->unlock();

if (fPorts.numMidiOuts > 0)
{
uint8_t port = 0;
uint8_t size = 0;
uint8_t data[3] = { 0, 0, 0 };
const uint8_t* dataPtr = data;

for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
{
const EngineEvent& engineEvent(pData->events.out[i]);

switch (engineEvent.type)
{
case kEngineEventTypeNull:
break;

case kEngineEventTypeControl: {
const EngineControlEvent& ctrlEvent(engineEvent.ctrl);
ctrlEvent.convertToMidiData(engineEvent.channel, size, data);
dataPtr = data;
break;
}

case kEngineEventTypeMidi: {
const EngineMidiEvent& midiEvent(engineEvent.midi);

port = midiEvent.port;
size = midiEvent.size;

if (size > EngineMidiEvent::kDataSize && midiEvent.dataExt != nullptr)
dataPtr = midiEvent.dataExt;
else
dataPtr = midiEvent.data;

break;
}
}

if (size > 0 && ! writeMidiEvent(port, engineEvent.time, size, dataPtr))
break;
}
}
}
else
{
@@ -178,7 +245,7 @@ public:
}

lv2_post_run(frames);
fPorts.updateOutputs();
updateParameterOutputs();
}

// ----------------------------------------------------------------------------------------------------------------
@@ -350,6 +417,11 @@ protected:

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

void handleParameterValueChanged(const uint32_t index, const float value) override
{
fPlugin->setParameterValue(index, value, false, false, false);
}

void handleBufferSizeChanged(const uint32_t bufferSize) override
{
CarlaEngine::bufferSizeChanged(bufferSize);
@@ -366,156 +438,50 @@ private:
CarlaPlugin* fPlugin;
CarlaString fUiName;

struct Ports {
uint32_t numAudioIns;
uint32_t numAudioOuts;
uint32_t numParams;
const float** audioIns;
/* */ float** audioOuts;
float* freewheel;
float* paramsLast;
float** paramsPtr;
bool* paramsOut;
uint32_t indexOffset;
const CarlaPlugin* plugin;

Ports()
: numAudioIns(0),
numAudioOuts(0),
numParams(0),
audioIns(nullptr),
audioOuts(nullptr),
freewheel(nullptr),
paramsLast(nullptr),
paramsPtr(nullptr),
paramsOut(nullptr),
indexOffset(1),
plugin(nullptr) {}

~Ports()
{
if (audioIns != nullptr)
{
delete[] audioIns;
audioIns = nullptr;
}

if (audioOuts != nullptr)
{
delete[] audioOuts;
audioOuts = nullptr;
}

if (paramsLast != nullptr)
{
delete[] paramsLast;
paramsLast = nullptr;
}

if (paramsPtr != nullptr)
{
delete[] paramsPtr;
paramsPtr = nullptr;
}

if (paramsOut != nullptr)
{
delete[] paramsOut;
paramsOut = nullptr;
}
}
void updateParameterOutputs() noexcept
{
float value;

void init(const CarlaPlugin* const pl)
for (uint32_t i=0; i < fPorts.numParams; ++i)
{
plugin = pl;

if ((numAudioIns = plugin->getAudioInCount()) > 0)
{
audioIns = new const float*[numAudioIns];

for (uint32_t i=0; i < numAudioIns; ++i)
audioIns[i] = nullptr;
}

if ((numAudioOuts = plugin->getAudioOutCount()) > 0)
{
audioOuts = new float*[numAudioOuts];

for (uint32_t i=0; i < numAudioOuts; ++i)
audioOuts[i] = nullptr;
}

if ((numParams = plugin->getParameterCount()) > 0)
{
paramsLast = new float[numParams];
paramsPtr = new float*[numParams];
paramsOut = new bool[numParams];
if (! fPorts.paramsOut[i])
continue;

for (uint32_t i=0; i < numParams; ++i)
{
paramsLast[i] = plugin->getParameterValue(i);
paramsPtr [i] = nullptr;
paramsOut [i] = plugin->isParameterOutput(i);
}
}
fPorts.paramsLast[i] = value = fPlugin->getParameterValue(i);

indexOffset = numAudioIns + numAudioOuts + 1;
if (fPorts.paramsPtr[i] != nullptr)
*fPorts.paramsPtr[i] = value;
}
}

void connectPort(const uint32_t port, void* const dataLocation) noexcept
{
uint32_t index = 0;

for (uint32_t i=0; i < numAudioIns; ++i)
{
if (port == index++)
{
audioIns[i] = (float*)dataLocation;
return;
}
}
bool writeMidiEvent(const uint8_t port, const uint32_t time, const uint8_t midiSize, const uint8_t* midiData)
{
CARLA_SAFE_ASSERT_RETURN(fPorts.numMidiOuts > 0, false);
CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false);
CARLA_SAFE_ASSERT_RETURN(midiData != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(midiSize > 0, false);

for (uint32_t i=0; i < numAudioOuts; ++i)
{
if (port == index++)
{
audioOuts[i] = (float*)dataLocation;
return;
}
}
LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]);
CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false);

if (port == index++)
{
freewheel = (float*)dataLocation;
return;
}
Ports::MidiOutData& mData(fPorts.midiOutData[port]);

for (uint32_t i=0; i < numParams; ++i)
{
if (port == index++)
{
paramsPtr[i] = (float*)dataLocation;
return;
}
}
}
if (sizeof(LV2_Atom_Event) + midiSize > mData.capacity - mData.offset)
return false;

void updateOutputs() noexcept
{
for (uint32_t i=0; i < numParams; ++i)
{
if (! paramsOut[i])
continue;
LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset);

paramsLast[i] = plugin->getParameterValue(i);
aev->time.frames = time;
aev->body.size = midiSize;
aev->body.type = fURIs.midiEvent;
std::memcpy(LV2_ATOM_BODY(&aev->body), midiData, midiSize);

if (paramsPtr[i] != nullptr)
*paramsPtr[i] = paramsLast[i];
}
}
const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + midiSize));
mData.offset += size;
seq->atom.size += size;

CARLA_DECLARE_NON_COPY_STRUCT(Ports);
} fPorts;
return true;
}

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



+ 82
- 538
source/plugin/carla-lv2.cpp View File

@@ -22,8 +22,8 @@
#include "CarlaMathUtils.hpp"
#include "CarlaString.hpp"

// -----------------------------------------------------------------------
// LV2 descriptor functions
// --------------------------------------------------------------------------------------------------------------------
// Carla Internal Plugin API exposed as LV2 plugin

class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo>
{
@@ -41,8 +41,7 @@ public:
#ifdef CARLA_PROPER_CPP11_SUPPORT
fProgramDesc({0, 0, nullptr}),
#endif
fMidiEventCount(0),
fPorts()
fMidiEventCount(0)
{
carla_zeroStruct(fHost);

@@ -87,6 +86,8 @@ public:
}
}

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

bool init()
{
if (fHost.resourceDir == nullptr)
@@ -103,305 +104,92 @@ public:
fHandle = fDescriptor->instantiate(&fHost);
CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);

if (fDescriptor->midiIns > 0)
fUI.portOffset += fDescriptor->midiIns;
else if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME)
fUI.portOffset += 1;
fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME;
fPorts.numAudioIns = fDescriptor->audioIns;
fPorts.numAudioOuts = fDescriptor->audioOuts;
fPorts.numMidiIns = fDescriptor->midiIns;
fPorts.numMidiOuts = fDescriptor->midiOuts;

fUI.portOffset += fDescriptor->midiOuts;
fUI.portOffset += 1; // freewheel
fUI.portOffset += fDescriptor->audioIns;
fUI.portOffset += fDescriptor->audioOuts;
if (fDescriptor->get_parameter_count != nullptr &&
fDescriptor->get_parameter_info != nullptr &&
fDescriptor->get_parameter_value != nullptr &&
fDescriptor->set_parameter_value != nullptr)
{
fPorts.numParams = fDescriptor->get_parameter_count(fHandle);
}

fPorts.init();

if (fPorts.numParams > 0)
{
for (uint32_t i=0; i < fPorts.numParams; ++i)
{
fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);
fPorts.paramsOut [i] = fDescriptor->get_parameter_info(fHandle, i)->hints & NATIVE_PARAMETER_IS_OUTPUT;
}
}

fPorts.init(fDescriptor, fHandle);
return true;
}

// -------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// LV2 functions

void lv2_connect_port(const uint32_t port, void* const dataLocation)
{
fPorts.connectPort(fDescriptor, port, dataLocation);
}

void lv2_activate()
{
CARLA_SAFE_ASSERT_RETURN(! fIsActive,);

resetTimeInfo();

if (fDescriptor->activate != nullptr)
fDescriptor->activate(fHandle);

resetTimeInfo();
fIsActive = true;
}

void lv2_deactivate()
{
CARLA_SAFE_ASSERT_RETURN(fIsActive,);

fIsActive = false;

if (fDescriptor->deactivate != nullptr)
fDescriptor->deactivate(fHandle);
}

void lv2_cleanup()
{
if (fIsActive)
{
carla_stderr("Warning: Host forgot to call deactivate!");
fIsActive = false;

if (fDescriptor->deactivate != nullptr)
fDescriptor->deactivate(fHandle);
}

if (fDescriptor->cleanup != nullptr)
fDescriptor->cleanup(fHandle);

fHandle = nullptr;
}

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

void lv2_run(const uint32_t frames)
{
if (! lv2_pre_run(frames))
{
updateParameterOutputs();
return;
}

fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);

// cache midi events and time information first
if (fDescriptor->midiIns > 0 || (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME) != 0)
if (fPorts.numMidiIns > 0)
{
fMidiEventCount = 0;
carla_zeroStructs(fMidiEvents, kMaxMidiEvents);

if (fDescriptor->hints & NATIVE_PLUGIN_USES_TIME)
{
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], event)
{
if (event == nullptr)
continue;
if (event->body.type != fURIs.atomBlank && event->body.type != fURIs.atomObject)
continue;

const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body);

if (obj->body.otype != fURIs.timePos)
continue;

LV2_Atom* bar = nullptr;
LV2_Atom* barBeat = nullptr;
LV2_Atom* beatUnit = nullptr;
LV2_Atom* beatsPerBar = nullptr;
LV2_Atom* beatsPerMinute = nullptr;
LV2_Atom* frame = nullptr;
LV2_Atom* speed = nullptr;
LV2_Atom* ticksPerBeat = nullptr;

lv2_atom_object_get(obj,
fURIs.timeBar, &bar,
fURIs.timeBarBeat, &barBeat,
fURIs.timeBeatUnit, &beatUnit,
fURIs.timeBeatsPerBar, &beatsPerBar,
fURIs.timeBeatsPerMinute, &beatsPerMinute,
fURIs.timeFrame, &frame,
fURIs.timeSpeed, &speed,
fURIs.timeTicksPerBeat, &ticksPerBeat,
0);

// need to handle this first as other values depend on it
if (ticksPerBeat != nullptr)
{
double ticksPerBeatValue = -1.0;

/**/ if (ticksPerBeat->type == fURIs.atomDouble)
ticksPerBeatValue = ((LV2_Atom_Double*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomFloat)
ticksPerBeatValue = ((LV2_Atom_Float*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomInt)
ticksPerBeatValue = static_cast<double>(((LV2_Atom_Int*)ticksPerBeat)->body);
else if (ticksPerBeat->type == fURIs.atomLong)
ticksPerBeatValue = static_cast<double>(((LV2_Atom_Long*)ticksPerBeat)->body);
else
carla_stderr("Unknown lv2 ticksPerBeat value type");

if (ticksPerBeatValue > 0.0)
fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat = ticksPerBeatValue;
else
carla_stderr("Invalid lv2 ticksPerBeat value");
}

// same
if (speed != nullptr)
{
/**/ if (speed->type == fURIs.atomDouble)
fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body;
else if (speed->type == fURIs.atomFloat)
fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body;
else if (speed->type == fURIs.atomInt)
fLastPositionData.speed = static_cast<double>(((LV2_Atom_Int*)speed)->body);
else if (speed->type == fURIs.atomLong)
fLastPositionData.speed = static_cast<double>(((LV2_Atom_Long*)speed)->body);
else
carla_stderr("Unknown lv2 speed value type");

fTimeInfo.playing = carla_isNotZero(fLastPositionData.speed);

if (fTimeInfo.playing && fLastPositionData.beatsPerMinute > 0.0f)
{
fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute*
std::abs(fLastPositionData.speed);
}
}

if (bar != nullptr)
{
int64_t barValue = -1;

/**/ if (bar->type == fURIs.atomDouble)
barValue = static_cast<int64_t>(((LV2_Atom_Double*)bar)->body);
else if (bar->type == fURIs.atomFloat)
barValue = static_cast<int64_t>(((LV2_Atom_Float*)bar)->body);
else if (bar->type == fURIs.atomInt)
barValue = ((LV2_Atom_Int*)bar)->body;
else if (bar->type == fURIs.atomLong)
barValue = ((LV2_Atom_Long*)bar)->body;
else
carla_stderr("Unknown lv2 bar value type");

if (barValue >= 0 && barValue < INT32_MAX)
{
fLastPositionData.bar = static_cast<int32_t>(barValue);
fLastPositionData.bar_f = static_cast<float>(barValue);
fTimeInfo.bbt.bar = fLastPositionData.bar + 1;
}
else
{
carla_stderr("Invalid lv2 bar value");
}
}

if (barBeat != nullptr)
{
double barBeatValue = -1.0;

/**/ if (barBeat->type == fURIs.atomDouble)
barBeatValue = ((LV2_Atom_Double*)barBeat)->body;
else if (barBeat->type == fURIs.atomFloat)
barBeatValue = ((LV2_Atom_Float*)barBeat)->body;
else if (barBeat->type == fURIs.atomInt)
barBeatValue = static_cast<float>(((LV2_Atom_Int*)barBeat)->body);
else if (barBeat->type == fURIs.atomLong)
barBeatValue = static_cast<float>(((LV2_Atom_Long*)barBeat)->body);
else
carla_stderr("Unknown lv2 barBeat value type");

if (barBeatValue >= 0.0)
{
fLastPositionData.barBeat = static_cast<float>(barBeatValue);

const double rest = std::fmod(barBeatValue, 1.0);
fTimeInfo.bbt.beat = static_cast<int32_t>(barBeatValue-rest+1.0);
fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5);
}
else
{
carla_stderr("Invalid lv2 barBeat value");
}
}

if (beatUnit != nullptr)
{
int64_t beatUnitValue = -1;

/**/ if (beatUnit->type == fURIs.atomDouble)
beatUnitValue = static_cast<int64_t>(((LV2_Atom_Double*)beatUnit)->body);
else if (beatUnit->type == fURIs.atomFloat)
beatUnitValue = static_cast<int64_t>(((LV2_Atom_Float*)beatUnit)->body);
else if (beatUnit->type == fURIs.atomInt)
beatUnitValue = ((LV2_Atom_Int*)beatUnit)->body;
else if (beatUnit->type == fURIs.atomLong)
beatUnitValue = ((LV2_Atom_Long*)beatUnit)->body;
else
carla_stderr("Unknown lv2 beatUnit value type");

if (beatUnitValue > 0 && beatUnitValue < UINT32_MAX)
{
fLastPositionData.beatUnit = static_cast<uint32_t>(beatUnitValue);
fTimeInfo.bbt.beatType = static_cast<float>(beatUnitValue);
}
else
{
carla_stderr("Invalid lv2 beatUnit value");
}
}

if (beatsPerBar != nullptr)
{
float beatsPerBarValue = -1.0f;

/**/ if (beatsPerBar->type == fURIs.atomDouble)
beatsPerBarValue = static_cast<float>(((LV2_Atom_Double*)beatsPerBar)->body);
else if (beatsPerBar->type == fURIs.atomFloat)
beatsPerBarValue = ((LV2_Atom_Float*)beatsPerBar)->body;
else if (beatsPerBar->type == fURIs.atomInt)
beatsPerBarValue = static_cast<float>(((LV2_Atom_Int*)beatsPerBar)->body);
else if (beatsPerBar->type == fURIs.atomLong)
beatsPerBarValue = static_cast<float>(((LV2_Atom_Long*)beatsPerBar)->body);
else
carla_stderr("Unknown lv2 beatsPerBar value type");

if (beatsPerBarValue > 0.0f)
fTimeInfo.bbt.beatsPerBar = fLastPositionData.beatsPerBar = beatsPerBarValue;
else
carla_stderr("Invalid lv2 beatsPerBar value");
}

if (beatsPerMinute != nullptr)
{
double beatsPerMinuteValue = -1.0;

/**/ if (beatsPerMinute->type == fURIs.atomDouble)
beatsPerMinuteValue = ((LV2_Atom_Double*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomFloat)
beatsPerMinuteValue = ((LV2_Atom_Float*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomInt)
beatsPerMinuteValue = static_cast<double>(((LV2_Atom_Int*)beatsPerMinute)->body);
else if (beatsPerMinute->type == fURIs.atomLong)
beatsPerMinuteValue = static_cast<double>(((LV2_Atom_Long*)beatsPerMinute)->body);
else
carla_stderr("Unknown lv2 beatsPerMinute value type");

if (beatsPerMinuteValue >= 12.0 && beatsPerMinuteValue <= 999.0)
{
fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute = beatsPerMinuteValue;

if (carla_isNotZero(fLastPositionData.speed))
fTimeInfo.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed);
}
else
{
carla_stderr("Invalid lv2 beatsPerMinute value");
}
}

if (frame != nullptr)
{
int64_t frameValue = -1;

/**/ if (frame->type == fURIs.atomDouble)
frameValue = static_cast<int64_t>(((LV2_Atom_Double*)frame)->body);
else if (frame->type == fURIs.atomFloat)
frameValue = static_cast<int64_t>(((LV2_Atom_Float*)frame)->body);
else if (frame->type == fURIs.atomInt)
frameValue = ((LV2_Atom_Int*)frame)->body;
else if (frame->type == fURIs.atomLong)
frameValue = ((LV2_Atom_Long*)frame)->body;
else
carla_stderr("Unknown lv2 frame value type");

if (frameValue >= 0)
fTimeInfo.frame = fLastPositionData.frame = static_cast<uint64_t>(frameValue);
else
carla_stderr("Invalid lv2 frame value");
}

fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*
fTimeInfo.bbt.beatsPerBar*
(fTimeInfo.bbt.bar-1);

fTimeInfo.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 &&
fLastPositionData.beatUnit > 0 &&
fLastPositionData.beatsPerBar > 0.0f);
}
}

for (uint32_t i=0; i < fDescriptor->midiIns; ++i)
for (uint32_t i=0; i < fPorts.numMidiIns; ++i)
{
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], event)
{
@@ -413,8 +201,6 @@ public:
continue;
if (event->time.frames >= frames)
break;
if (fMidiEventCount >= kMaxMidiEvents)
break;

const uint8_t* const data((const uint8_t*)(event + 1));

@@ -429,51 +215,13 @@ public:
nativeEvent.data[j] = data[j];
for (; j<4; ++j)
nativeEvent.data[j] = 0;
}
}
}

// init midi out data
if (fDescriptor->midiOuts > 0)
{
for (uint32_t i=0, size=fDescriptor->midiOuts; i<size; ++i)
{
LV2_Atom_Sequence* const seq(fPorts.midiOuts[i]);
CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr);

Ports::MidiOutData& mData(fPorts.midiOutData[i]);
mData.capacity = seq->atom.size;
mData.offset = 0;

seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
seq->atom.type = fURIs.atomSequence;
seq->body.unit = 0;
seq->body.pad = 0;
if (fMidiEventCount >= kMaxMidiEvents)
break;
}
}
}

// Check for updated parameters
float curValue;

for (uint32_t i=0; i < fPorts.paramCount; ++i)
{
if (fPorts.paramsOut[i])
continue;

CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)

curValue = *fPorts.paramsPtr[i];

if (carla_isEqual(fPorts.paramsLast[i], curValue))
continue;

fPorts.paramsLast[i] = curValue;
fDescriptor->set_parameter_value(fHandle, i, curValue);
}

if (frames == 0)
return updateParameterOutputs();

// FIXME
fDescriptor->process(fHandle,
const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames,
@@ -483,7 +231,7 @@ public:
updateParameterOutputs();
}

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

const LV2_Program_Descriptor* lv2_get_program(const uint32_t index)
{
@@ -517,7 +265,7 @@ public:

fDescriptor->set_midi_program(fHandle, 0, bank, program);

for (uint32_t i=0; i < fPorts.paramCount; ++i)
for (uint32_t i=0; i < fPorts.numParams; ++i)
{
fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);

@@ -526,7 +274,10 @@ public:
}
}

LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle, const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const
// ----------------------------------------------------------------------------------------------------------------

LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle,
const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const
{
if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr)
return LV2_STATE_ERR_NO_FEATURE;
@@ -541,7 +292,8 @@ public:
return LV2_STATE_ERR_UNKNOWN;
}

LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* const /*features*/) const
LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle,
uint32_t flags, const LV2_Feature* const* const /*features*/) const
{
if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr)
return LV2_STATE_ERR_NO_FEATURE;
@@ -564,7 +316,7 @@ public:
return LV2_STATE_SUCCESS;
}

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

void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller,
LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed)
@@ -684,16 +436,16 @@ public:
{
if (format != 0 || bufferSize != sizeof(float) || buffer == nullptr)
return;
if (portIndex >= fUI.portOffset || ! fUI.isVisible)
if (portIndex >= fPorts.indexOffset || ! fUI.isVisible)
return;
if (fDescriptor->ui_set_parameter_value == nullptr)
return;

const float value(*(const float*)buffer);
fDescriptor->ui_set_parameter_value(fHandle, portIndex-fUI.portOffset, value);
fDescriptor->ui_set_parameter_value(fHandle, portIndex-fPorts.indexOffset, value);
}

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

void lv2ui_select_program(uint32_t bank, uint32_t program) const
{
@@ -732,6 +484,11 @@ protected:

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

void handleParameterValueChanged(const uint32_t index, const float value) override
{
fDescriptor->set_parameter_value(fHandle, index, value);
}

void handleBufferSizeChanged(const uint32_t bufferSize) override
{
if (fDescriptor->dispatcher == nullptr)
@@ -752,12 +509,12 @@ protected:

bool handleWriteMidiEvent(const NativeMidiEvent* const event)
{
CARLA_SAFE_ASSERT_RETURN(fDescriptor->midiOuts > 0, false);
CARLA_SAFE_ASSERT_RETURN(fPorts.numMidiOuts > 0, false);
CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(event->size > 0, false);

const uint8_t port(event->port);
CARLA_SAFE_ASSERT_RETURN(port < fDescriptor->midiOuts, false);
CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false);

LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]);
CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false);
@@ -784,7 +541,7 @@ protected:
void handleUiParameterChanged(const uint32_t index, const float value) const
{
if (fUI.writeFunction != nullptr && fUI.controller != nullptr)
fUI.writeFunction(fUI.controller, index+fUI.portOffset, sizeof(float), 0, &value);
fUI.writeFunction(fUI.controller, index+fPorts.indexOffset, sizeof(float), 0, &value);
}

void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const
@@ -849,15 +606,17 @@ protected:

void updateParameterOutputs()
{
for (uint32_t i=0; i < fPorts.paramCount; ++i)
float value;

for (uint32_t i=0; i < fPorts.numParams; ++i)
{
if (! fPorts.paramsOut[i])
continue;

fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);
fPorts.paramsLast[i] = value = fDescriptor->get_parameter_value(fHandle, i);

if (fPorts.paramsPtr[i] != nullptr)
*fPorts.paramsPtr[i] = fPorts.paramsLast[i];
*fPorts.paramsPtr[i] = value;
}
}

@@ -873,221 +632,6 @@ private:
uint32_t fMidiEventCount;
NativeMidiEvent fMidiEvents[kMaxMidiEvents];

struct Ports {
// need to save current state
struct MidiOutData {
uint32_t capacity;
uint32_t offset;

MidiOutData()
: capacity(0),
offset(0) {}
};

const LV2_Atom_Sequence** eventsIn;
/* */ LV2_Atom_Sequence** midiOuts;
/* */ MidiOutData* midiOutData;
const float** audioIns;
/* */ float** audioOuts;
float* freewheel;
uint32_t paramCount;
float* paramsLast;
float** paramsPtr;
bool* paramsOut;

Ports()
: eventsIn(nullptr),
midiOuts(nullptr),
midiOutData(nullptr),
audioIns(nullptr),
audioOuts(nullptr),
freewheel(nullptr),
paramCount(0),
paramsLast(nullptr),
paramsPtr(nullptr),
paramsOut(nullptr) {}

~Ports()
{
if (eventsIn != nullptr)
{
delete[] eventsIn;
eventsIn = nullptr;
}

if (midiOuts != nullptr)
{
delete[] midiOuts;
midiOuts = nullptr;
}

if (midiOutData != nullptr)
{
delete[] midiOutData;
midiOutData = nullptr;
}

if (audioIns != nullptr)
{
delete[] audioIns;
audioIns = nullptr;
}

if (audioOuts != nullptr)
{
delete[] audioOuts;
audioOuts = nullptr;
}

if (paramsLast != nullptr)
{
delete[] paramsLast;
paramsLast = nullptr;
}

if (paramsPtr != nullptr)
{
delete[] paramsPtr;
paramsPtr = nullptr;
}

if (paramsOut != nullptr)
{
delete[] paramsOut;
paramsOut = nullptr;
}
}

void init(const NativePluginDescriptor* const desc, NativePluginHandle handle)
{
CARLA_SAFE_ASSERT_RETURN(desc != nullptr && handle != nullptr,)

if (desc->midiIns > 0)
{
eventsIn = new const LV2_Atom_Sequence*[desc->midiIns];

for (uint32_t i=0; i < desc->midiIns; ++i)
eventsIn[i] = nullptr;
}
else if (desc->hints & NATIVE_PLUGIN_USES_TIME)
{
eventsIn = new const LV2_Atom_Sequence*[1];
eventsIn[0] = nullptr;
}

if (desc->midiOuts > 0)
{
midiOuts = new LV2_Atom_Sequence*[desc->midiOuts];
midiOutData = new MidiOutData[desc->midiOuts];

for (uint32_t i=0; i < desc->midiOuts; ++i)
midiOuts[i] = nullptr;
}

if (desc->audioIns > 0)
{
audioIns = new const float*[desc->audioIns];

for (uint32_t i=0; i < desc->audioIns; ++i)
audioIns[i] = nullptr;
}

if (desc->audioOuts > 0)
{
audioOuts = new float*[desc->audioOuts];

for (uint32_t i=0; i < desc->audioOuts; ++i)
audioOuts[i] = nullptr;
}

if (desc->get_parameter_count != nullptr && desc->get_parameter_info != nullptr && desc->get_parameter_value != nullptr && desc->set_parameter_value != nullptr)
{
paramCount = desc->get_parameter_count(handle);

if (paramCount > 0)
{
paramsLast = new float[paramCount];
paramsPtr = new float*[paramCount];
paramsOut = new bool[paramCount];

for (uint32_t i=0; i < paramCount; ++i)
{
paramsLast[i] = desc->get_parameter_value(handle, i);
paramsPtr [i] = nullptr;
paramsOut [i] = (desc->get_parameter_info(handle, i)->hints & NATIVE_PARAMETER_IS_OUTPUT);
}
}
}
}

void connectPort(const NativePluginDescriptor* const desc, const uint32_t port, void* const dataLocation)
{
uint32_t index = 0;

if (desc->midiIns > 0 || (desc->hints & NATIVE_PLUGIN_USES_TIME) != 0)
{
if (port == index++)
{
eventsIn[0] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

for (uint32_t i=1; i < desc->midiIns; ++i)
{
if (port == index++)
{
eventsIn[i] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

for (uint32_t i=0; i < desc->midiOuts; ++i)
{
if (port == index++)
{
midiOuts[i] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

if (port == index++)
{
freewheel = (float*)dataLocation;
return;
}

for (uint32_t i=0; i < desc->audioIns; ++i)
{
if (port == index++)
{
audioIns[i] = (float*)dataLocation;
return;
}
}

for (uint32_t i=0; i < desc->audioOuts; ++i)
{
if (port == index++)
{
audioOuts[i] = (float*)dataLocation;
return;
}
}

for (uint32_t i=0; i < paramCount; ++i)
{
if (port == index++)
{
paramsPtr[i] = (float*)dataLocation;
return;
}
}
}

CARLA_DECLARE_NON_COPY_STRUCT(Ports);
} fPorts;

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

#define handlePtr ((NativePlugin*)handle)


+ 2
- 1
source/plugin/carla-vst.cpp View File

@@ -48,7 +48,8 @@ static double d_lastSampleRate = 0.0;

static const int32_t kVstMidiEventSize = static_cast<int32_t>(sizeof(VstMidiEvent));

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Carla Internal Plugin API exposed as VST plugin

class NativePlugin
{


+ 526
- 6
source/utils/CarlaLv2Utils.hpp View File

@@ -631,9 +631,7 @@ public:
carla_zeroStruct(fLastPositionData);
}

virtual ~Lv2PluginBaseClass()
{
}
virtual ~Lv2PluginBaseClass() {}

bool loadedInProperHost() const noexcept
{
@@ -642,8 +640,299 @@ public:

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

bool lv2_pre_run(const uint32_t /*frames*/)
void lv2_connect_port(const uint32_t port, void* const dataLocation) noexcept
{
fPorts.connectPort(port, dataLocation);
}

bool lv2_pre_run(const uint32_t frames)
{
CARLA_SAFE_ASSERT_RETURN(fIsActive, false);

fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);

// cache midi events and time information first
if (fPorts.usesTime)
{
LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], event)
{
if (event == nullptr)
continue;
if (event->body.type != fURIs.atomBlank && event->body.type != fURIs.atomObject)
continue;

const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body);

if (obj->body.otype != fURIs.timePos)
continue;

LV2_Atom* bar = nullptr;
LV2_Atom* barBeat = nullptr;
LV2_Atom* beatUnit = nullptr;
LV2_Atom* beatsPerBar = nullptr;
LV2_Atom* beatsPerMinute = nullptr;
LV2_Atom* frame = nullptr;
LV2_Atom* speed = nullptr;
LV2_Atom* ticksPerBeat = nullptr;

lv2_atom_object_get(obj,
fURIs.timeBar, &bar,
fURIs.timeBarBeat, &barBeat,
fURIs.timeBeatUnit, &beatUnit,
fURIs.timeBeatsPerBar, &beatsPerBar,
fURIs.timeBeatsPerMinute, &beatsPerMinute,
fURIs.timeFrame, &frame,
fURIs.timeSpeed, &speed,
fURIs.timeTicksPerBeat, &ticksPerBeat,
0);

// need to handle this first as other values depend on it
if (ticksPerBeat != nullptr)
{
double ticksPerBeatValue = -1.0;

/**/ if (ticksPerBeat->type == fURIs.atomDouble)
ticksPerBeatValue = ((LV2_Atom_Double*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomFloat)
ticksPerBeatValue = ((LV2_Atom_Float*)ticksPerBeat)->body;
else if (ticksPerBeat->type == fURIs.atomInt)
ticksPerBeatValue = static_cast<double>(((LV2_Atom_Int*)ticksPerBeat)->body);
else if (ticksPerBeat->type == fURIs.atomLong)
ticksPerBeatValue = static_cast<double>(((LV2_Atom_Long*)ticksPerBeat)->body);
else
carla_stderr("Unknown lv2 ticksPerBeat value type");

if (ticksPerBeatValue > 0.0)
fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat = ticksPerBeatValue;
else
carla_stderr("Invalid lv2 ticksPerBeat value");
}

// same
if (speed != nullptr)
{
/**/ if (speed->type == fURIs.atomDouble)
fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body;
else if (speed->type == fURIs.atomFloat)
fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body;
else if (speed->type == fURIs.atomInt)
fLastPositionData.speed = static_cast<double>(((LV2_Atom_Int*)speed)->body);
else if (speed->type == fURIs.atomLong)
fLastPositionData.speed = static_cast<double>(((LV2_Atom_Long*)speed)->body);
else
carla_stderr("Unknown lv2 speed value type");

fTimeInfo.playing = carla_isNotZero(fLastPositionData.speed);

if (fTimeInfo.playing && fLastPositionData.beatsPerMinute > 0.0f)
{
fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute*
std::abs(fLastPositionData.speed);
}
}

if (bar != nullptr)
{
int64_t barValue = -1;

/**/ if (bar->type == fURIs.atomDouble)
barValue = static_cast<int64_t>(((LV2_Atom_Double*)bar)->body);
else if (bar->type == fURIs.atomFloat)
barValue = static_cast<int64_t>(((LV2_Atom_Float*)bar)->body);
else if (bar->type == fURIs.atomInt)
barValue = ((LV2_Atom_Int*)bar)->body;
else if (bar->type == fURIs.atomLong)
barValue = ((LV2_Atom_Long*)bar)->body;
else
carla_stderr("Unknown lv2 bar value type");

if (barValue >= 0 && barValue < INT32_MAX)
{
fLastPositionData.bar = static_cast<int32_t>(barValue);
fLastPositionData.bar_f = static_cast<float>(barValue);
fTimeInfo.bbt.bar = fLastPositionData.bar + 1;
}
else
{
carla_stderr("Invalid lv2 bar value");
}
}

if (barBeat != nullptr)
{
double barBeatValue = -1.0;

/**/ if (barBeat->type == fURIs.atomDouble)
barBeatValue = ((LV2_Atom_Double*)barBeat)->body;
else if (barBeat->type == fURIs.atomFloat)
barBeatValue = ((LV2_Atom_Float*)barBeat)->body;
else if (barBeat->type == fURIs.atomInt)
barBeatValue = static_cast<float>(((LV2_Atom_Int*)barBeat)->body);
else if (barBeat->type == fURIs.atomLong)
barBeatValue = static_cast<float>(((LV2_Atom_Long*)barBeat)->body);
else
carla_stderr("Unknown lv2 barBeat value type");

if (barBeatValue >= 0.0)
{
fLastPositionData.barBeat = static_cast<float>(barBeatValue);

const double rest = std::fmod(barBeatValue, 1.0);
fTimeInfo.bbt.beat = static_cast<int32_t>(barBeatValue-rest+1.0);
fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5);
}
else
{
carla_stderr("Invalid lv2 barBeat value");
}
}

if (beatUnit != nullptr)
{
int64_t beatUnitValue = -1;

/**/ if (beatUnit->type == fURIs.atomDouble)
beatUnitValue = static_cast<int64_t>(((LV2_Atom_Double*)beatUnit)->body);
else if (beatUnit->type == fURIs.atomFloat)
beatUnitValue = static_cast<int64_t>(((LV2_Atom_Float*)beatUnit)->body);
else if (beatUnit->type == fURIs.atomInt)
beatUnitValue = ((LV2_Atom_Int*)beatUnit)->body;
else if (beatUnit->type == fURIs.atomLong)
beatUnitValue = ((LV2_Atom_Long*)beatUnit)->body;
else
carla_stderr("Unknown lv2 beatUnit value type");

if (beatUnitValue > 0 && beatUnitValue < UINT32_MAX)
{
fLastPositionData.beatUnit = static_cast<uint32_t>(beatUnitValue);
fTimeInfo.bbt.beatType = static_cast<float>(beatUnitValue);
}
else
{
carla_stderr("Invalid lv2 beatUnit value");
}
}

if (beatsPerBar != nullptr)
{
float beatsPerBarValue = -1.0f;

/**/ if (beatsPerBar->type == fURIs.atomDouble)
beatsPerBarValue = static_cast<float>(((LV2_Atom_Double*)beatsPerBar)->body);
else if (beatsPerBar->type == fURIs.atomFloat)
beatsPerBarValue = ((LV2_Atom_Float*)beatsPerBar)->body;
else if (beatsPerBar->type == fURIs.atomInt)
beatsPerBarValue = static_cast<float>(((LV2_Atom_Int*)beatsPerBar)->body);
else if (beatsPerBar->type == fURIs.atomLong)
beatsPerBarValue = static_cast<float>(((LV2_Atom_Long*)beatsPerBar)->body);
else
carla_stderr("Unknown lv2 beatsPerBar value type");

if (beatsPerBarValue > 0.0f)
fTimeInfo.bbt.beatsPerBar = fLastPositionData.beatsPerBar = beatsPerBarValue;
else
carla_stderr("Invalid lv2 beatsPerBar value");
}

if (beatsPerMinute != nullptr)
{
double beatsPerMinuteValue = -1.0;

/**/ if (beatsPerMinute->type == fURIs.atomDouble)
beatsPerMinuteValue = ((LV2_Atom_Double*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomFloat)
beatsPerMinuteValue = ((LV2_Atom_Float*)beatsPerMinute)->body;
else if (beatsPerMinute->type == fURIs.atomInt)
beatsPerMinuteValue = static_cast<double>(((LV2_Atom_Int*)beatsPerMinute)->body);
else if (beatsPerMinute->type == fURIs.atomLong)
beatsPerMinuteValue = static_cast<double>(((LV2_Atom_Long*)beatsPerMinute)->body);
else
carla_stderr("Unknown lv2 beatsPerMinute value type");

if (beatsPerMinuteValue >= 12.0 && beatsPerMinuteValue <= 999.0)
{
fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute = beatsPerMinuteValue;

if (carla_isNotZero(fLastPositionData.speed))
fTimeInfo.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed);
}
else
{
carla_stderr("Invalid lv2 beatsPerMinute value");
}
}

if (frame != nullptr)
{
int64_t frameValue = -1;

/**/ if (frame->type == fURIs.atomDouble)
frameValue = static_cast<int64_t>(((LV2_Atom_Double*)frame)->body);
else if (frame->type == fURIs.atomFloat)
frameValue = static_cast<int64_t>(((LV2_Atom_Float*)frame)->body);
else if (frame->type == fURIs.atomInt)
frameValue = ((LV2_Atom_Int*)frame)->body;
else if (frame->type == fURIs.atomLong)
frameValue = ((LV2_Atom_Long*)frame)->body;
else
carla_stderr("Unknown lv2 frame value type");

if (frameValue >= 0)
fTimeInfo.frame = fLastPositionData.frame = static_cast<uint64_t>(frameValue);
else
carla_stderr("Invalid lv2 frame value");
}

fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat*
fTimeInfo.bbt.beatsPerBar*
(fTimeInfo.bbt.bar-1);

fTimeInfo.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 &&
fLastPositionData.beatUnit > 0 &&
fLastPositionData.beatsPerBar > 0.0f);
}
}

// Check for updated parameters
float curValue;

for (uint32_t i=0; i < fPorts.numParams; ++i)
{
if (fPorts.paramsOut[i])
continue;

CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)

curValue = *fPorts.paramsPtr[i];

if (carla_isEqual(fPorts.paramsLast[i], curValue))
continue;

fPorts.paramsLast[i] = curValue;
handleParameterValueChanged(i, curValue);
}

if (frames == 0)
return false;

// init midi out data
if (fPorts.numMidiOuts > 0)
{
for (uint32_t i=0; i<fPorts.numMidiOuts; ++i)
{
LV2_Atom_Sequence* const seq(fPorts.midiOuts[i]);
CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr);

fPorts.midiOutData[i].capacity = seq->atom.size;
fPorts.midiOutData[i].offset = 0;

seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
seq->atom.type = fURIs.atomSequence;
seq->body.unit = 0;
seq->body.pad = 0;
}
}

return true;
}

@@ -825,6 +1114,7 @@ protected:
virtual void handleUiShow() = 0;
virtual void handleUiHide() = 0;

virtual void handleParameterValueChanged(const uint32_t index, const float value) = 0;
virtual void handleBufferSizeChanged(const uint32_t bufferSize) = 0;
virtual void handleSampleRateChanged(const double sampleRate) = 0;

@@ -878,6 +1168,238 @@ protected:
fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute = 120.0;
}

// Port stuff
struct Ports {
// need to save current state
struct MidiOutData {
uint32_t capacity;
uint32_t offset;

MidiOutData()
: capacity(0),
offset(0) {}
};

// store port info
uint32_t indexOffset;
uint32_t numAudioIns;
uint32_t numAudioOuts;
uint32_t numMidiIns;
uint32_t numMidiOuts;
uint32_t numParams;
bool usesTime;

// port buffers
const LV2_Atom_Sequence** eventsIn;
/* */ LV2_Atom_Sequence** midiOuts;
/* */ MidiOutData* midiOutData;
const float** audioIns;
/* */ float** audioOuts;
/* */ float* freewheel;

// cached parameter values
float* paramsLast;
float** paramsPtr;
bool* paramsOut;

Ports()
: indexOffset(0),
numAudioIns(0),
numAudioOuts(0),
numMidiIns(0),
numMidiOuts(0),
numParams(0),
usesTime(false),
eventsIn(nullptr),
midiOuts(nullptr),
midiOutData(nullptr),
audioIns(nullptr),
audioOuts(nullptr),
freewheel(nullptr),
paramsLast(nullptr),
paramsPtr(nullptr),
paramsOut(nullptr) {}

~Ports()
{
if (eventsIn != nullptr)
{
delete[] eventsIn;
eventsIn = nullptr;
}

if (midiOuts != nullptr)
{
delete[] midiOuts;
midiOuts = nullptr;
}

if (midiOutData != nullptr)
{
delete[] midiOutData;
midiOutData = nullptr;
}

if (audioIns != nullptr)
{
delete[] audioIns;
audioIns = nullptr;
}

if (audioOuts != nullptr)
{
delete[] audioOuts;
audioOuts = nullptr;
}

if (paramsLast != nullptr)
{
delete[] paramsLast;
paramsLast = nullptr;
}

if (paramsPtr != nullptr)
{
delete[] paramsPtr;
paramsPtr = nullptr;
}

if (paramsOut != nullptr)
{
delete[] paramsOut;
paramsOut = nullptr;
}
}

// NOTE: assumes num* has been filled by parent class
void init()
{
if (numMidiIns > 0)
{
eventsIn = new const LV2_Atom_Sequence*[numMidiIns];

for (uint32_t i=0; i < numMidiIns; ++i)
eventsIn[i] = nullptr;
}
else if (usesTime)
{
eventsIn = new const LV2_Atom_Sequence*[1];
eventsIn[0] = nullptr;
}

if (numMidiOuts > 0)
{
midiOuts = new LV2_Atom_Sequence*[numMidiOuts];
midiOutData = new MidiOutData[numMidiOuts];

for (uint32_t i=0; i < numMidiOuts; ++i)
midiOuts[i] = nullptr;
}

if (numAudioIns > 0)
{
audioIns = new const float*[numAudioIns];

for (uint32_t i=0; i < numAudioIns; ++i)
audioIns[i] = nullptr;
}

if (numAudioOuts > 0)
{
audioOuts = new float*[numAudioOuts];

for (uint32_t i=0; i < numAudioOuts; ++i)
audioOuts[i] = nullptr;
}

if (numParams > 0)
{
paramsLast = new float[numParams];
paramsPtr = new float*[numParams];
paramsOut = new bool[numParams];

carla_zeroFloats(paramsLast, numParams);
carla_zeroPointers(paramsPtr, numParams);
carla_zeroStructs(paramsOut, numParams);

// NOTE: need to be filled in by the parent class
}

indexOffset = numAudioIns + numAudioOuts + numMidiOuts;
// 1 event port for time if no midi input is used
indexOffset += numMidiIns > 0 ? numMidiIns : (usesTime ? 1 : 0);
// 1 extra for freewheel port
indexOffset += 1;
}

void connectPort(const uint32_t port, void* const dataLocation)
{
uint32_t index = 0;

if (numMidiIns > 0 || usesTime)
{
if (port == index++)
{
eventsIn[0] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

for (uint32_t i=1; i < numMidiIns; ++i)
{
if (port == index++)
{
eventsIn[i] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

for (uint32_t i=0; i < numMidiOuts; ++i)
{
if (port == index++)
{
midiOuts[i] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

if (port == index++)
{
freewheel = (float*)dataLocation;
return;
}

for (uint32_t i=0; i < numAudioIns; ++i)
{
if (port == index++)
{
audioIns[i] = (float*)dataLocation;
return;
}
}

for (uint32_t i=0; i < numAudioOuts; ++i)
{
if (port == index++)
{
audioOuts[i] = (float*)dataLocation;
return;
}
}

for (uint32_t i=0; i < numParams; ++i)
{
if (port == index++)
{
paramsPtr[i] = (float*)dataLocation;
return;
}
}
}

CARLA_DECLARE_NON_COPY_STRUCT(Ports);
} fPorts;

// Rest of host<->plugin support
struct URIDs {
LV2_URID atomBlank;
@@ -946,7 +1468,6 @@ protected:
const LV2_External_UI_Host* host;
LV2UI_Write_Function writeFunction;
LV2UI_Controller controller;
uint32_t portOffset;
bool isEmbed;
bool isVisible;

@@ -954,7 +1475,6 @@ protected:
: host(nullptr),
writeFunction(nullptr),
controller(nullptr),
portOffset(0),
isEmbed(false),
isVisible(false) {}
} fUI;


Loading…
Cancel
Save