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