| @@ -274,6 +274,8 @@ struct CARLA_API EngineOptions { | |||
| * Engine BBT Time information. | |||
| */ | |||
| struct CARLA_API EngineTimeInfoBBT { | |||
| bool valid; | |||
| int32_t bar; //!< current bar | |||
| int32_t beat; //!< current beat-within-bar | |||
| int32_t tick; //!< current tick-within-beat | |||
| @@ -294,12 +296,9 @@ struct CARLA_API EngineTimeInfoBBT { | |||
| * Engine Time information. | |||
| */ | |||
| struct CARLA_API EngineTimeInfo { | |||
| static const uint kValidBBT = 0x1; | |||
| bool playing; | |||
| uint64_t frame; | |||
| uint64_t usecs; | |||
| uint valid; | |||
| EngineTimeInfoBBT bbt; | |||
| /*! | |||
| @@ -788,14 +788,7 @@ uint64_t carla_get_current_transport_frame() | |||
| const CarlaTransportInfo* carla_get_transport_info() | |||
| { | |||
| static CarlaTransportInfo retInfo; | |||
| // reset | |||
| retInfo.playing = false; | |||
| retInfo.frame = 0; | |||
| retInfo.bar = 0; | |||
| retInfo.beat = 0; | |||
| retInfo.tick = 0; | |||
| retInfo.bpm = 0.0; | |||
| carla_zeroStruct(retInfo); | |||
| CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr && gStandalone.engine->isRunning(), &retInfo); | |||
| @@ -804,7 +797,7 @@ const CarlaTransportInfo* carla_get_transport_info() | |||
| retInfo.playing = timeInfo.playing; | |||
| retInfo.frame = timeInfo.frame; | |||
| if (timeInfo.valid & CB::EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| retInfo.bar = timeInfo.bbt.bar; | |||
| retInfo.beat = timeInfo.bbt.beat; | |||
| @@ -1180,12 +1180,12 @@ protected: | |||
| EngineTimeInfo& timeInfo(pData->timeInfo); | |||
| timeInfo.playing = bridgeTimeInfo.playing; | |||
| timeInfo.frame = bridgeTimeInfo.frame; | |||
| timeInfo.usecs = bridgeTimeInfo.usecs; | |||
| timeInfo.valid = bridgeTimeInfo.valid; | |||
| timeInfo.playing = bridgeTimeInfo.playing; | |||
| timeInfo.frame = bridgeTimeInfo.frame; | |||
| timeInfo.usecs = bridgeTimeInfo.usecs; | |||
| timeInfo.bbt.valid = (bridgeTimeInfo.validFlags & kPluginBridgeTimeInfoValidBBT) != 0; | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| timeInfo.bbt.bar = bridgeTimeInfo.bar; | |||
| timeInfo.bbt.beat = bridgeTimeInfo.beat; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -308,7 +308,8 @@ EngineOptions::Wine::~Wine() noexcept | |||
| // EngineTimeInfoBBT | |||
| EngineTimeInfoBBT::EngineTimeInfoBBT() noexcept | |||
| : bar(0), | |||
| : valid(false), | |||
| bar(0), | |||
| beat(0), | |||
| tick(0), | |||
| barStartTick(0.0), | |||
| @@ -324,7 +325,6 @@ EngineTimeInfo::EngineTimeInfo() noexcept | |||
| : playing(false), | |||
| frame(0), | |||
| usecs(0), | |||
| valid(0x0), | |||
| bbt() {} | |||
| void EngineTimeInfo::clear() noexcept | |||
| @@ -332,14 +332,14 @@ void EngineTimeInfo::clear() noexcept | |||
| playing = false; | |||
| frame = 0; | |||
| usecs = 0; | |||
| valid = 0x0; | |||
| carla_zeroStruct(bbt); | |||
| } | |||
| bool EngineTimeInfo::operator==(const EngineTimeInfo& timeInfo) const noexcept | |||
| { | |||
| if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.valid != valid) | |||
| if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.bbt.valid != bbt.valid) | |||
| return false; | |||
| if ((valid & kValidBBT) == 0) | |||
| if (! bbt.valid) | |||
| return true; | |||
| if (carla_isNotEqual(timeInfo.bbt.beatsPerMinute, bbt.beatsPerMinute)) | |||
| return false; | |||
| @@ -175,7 +175,7 @@ void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept | |||
| if (needsReset) | |||
| { | |||
| timeInfo.valid = EngineTimeInfo::kValidBBT; | |||
| timeInfo.bbt.valid = true; | |||
| timeInfo.bbt.beatType = 4.0f; | |||
| timeInfo.bbt.ticksPerBeat = kTicksPerBeat; | |||
| @@ -563,6 +563,11 @@ void CarlaEngine::ProtectedData::initTime(const char* const features) | |||
| #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE) | |||
| const bool linkEnabled = features != nullptr && std::strstr(features, ":link:") != nullptr; | |||
| time.enableLink(linkEnabled); | |||
| #else | |||
| return; | |||
| // unused | |||
| (void)features; | |||
| #endif | |||
| } | |||
| @@ -1393,7 +1393,7 @@ public: | |||
| if (fClient != nullptr) | |||
| { | |||
| if ((pData->timeInfo.valid & EngineTimeInfo::kValidBBT) == 0x0) | |||
| if (! pData->timeInfo.bbt.valid) | |||
| { | |||
| // old timebase master no longer active, make ourselves master again | |||
| pData->time.setNeedsReset(); | |||
| @@ -1573,7 +1573,7 @@ protected: | |||
| if (jpos.valid & JackPositionBBT) | |||
| { | |||
| pData->timeInfo.valid = EngineTimeInfo::kValidBBT; | |||
| pData->timeInfo.bbt.valid = true; | |||
| pData->timeInfo.bbt.bar = jpos.bar; | |||
| pData->timeInfo.bbt.beat = jpos.beat; | |||
| pData->timeInfo.bbt.tick = jpos.tick; | |||
| @@ -1585,13 +1585,14 @@ protected: | |||
| } | |||
| else | |||
| { | |||
| pData->timeInfo.valid = 0x0; | |||
| pData->timeInfo.bbt.valid = false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| pData->timeInfo.frame = 0; | |||
| pData->timeInfo.valid = 0x0; | |||
| pData->timeInfo.usecs = 0; | |||
| pData->timeInfo.bbt.valid = false; | |||
| } | |||
| } | |||
| @@ -1471,15 +1471,13 @@ protected: | |||
| const NativeTimeInfo* const timeInfo(pHost->get_time_info(pHost->handle)); | |||
| pData->timeInfo.playing = timeInfo->playing; | |||
| pData->timeInfo.frame = timeInfo->frame; | |||
| pData->timeInfo.usecs = timeInfo->usecs; | |||
| pData->timeInfo.valid = 0x0; | |||
| pData->timeInfo.playing = timeInfo->playing; | |||
| pData->timeInfo.frame = timeInfo->frame; | |||
| pData->timeInfo.usecs = timeInfo->usecs; | |||
| pData->timeInfo.bbt.valid = timeInfo->bbt.valid; | |||
| if (timeInfo->bbt.valid) | |||
| { | |||
| pData->timeInfo.valid |= EngineTimeInfo::kValidBBT; | |||
| pData->timeInfo.bbt.bar = timeInfo->bbt.bar; | |||
| pData->timeInfo.bbt.beat = timeInfo->bbt.beat; | |||
| pData->timeInfo.bbt.tick = timeInfo->bbt.tick; | |||
| @@ -1748,7 +1746,7 @@ protected: | |||
| if (! fUiServer.writeMessage(timeInfo.playing ? "true\n" : "false\n")) | |||
| return; | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| std::sprintf(tmpBuf, P_UINT64 ":%i:%i:%i\n", timeInfo.frame, timeInfo.bbt.bar, timeInfo.bbt.beat, timeInfo.bbt.tick); | |||
| if (! fUiServer.writeMessage(tmpBuf)) | |||
| @@ -1388,12 +1388,12 @@ public: | |||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||
| BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | |||
| bridgeTimeInfo.playing = timeInfo.playing; | |||
| bridgeTimeInfo.frame = timeInfo.frame; | |||
| bridgeTimeInfo.usecs = timeInfo.usecs; | |||
| bridgeTimeInfo.valid = timeInfo.valid; | |||
| bridgeTimeInfo.playing = timeInfo.playing; | |||
| bridgeTimeInfo.frame = timeInfo.frame; | |||
| bridgeTimeInfo.usecs = timeInfo.usecs; | |||
| bridgeTimeInfo.validFlags = timeInfo.bbt.valid ? kPluginBridgeTimeInfoValidBBT : 0x0; | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| bridgeTimeInfo.bar = timeInfo.bbt.bar; | |||
| bridgeTimeInfo.beat = timeInfo.bbt.beat; | |||
| @@ -921,12 +921,12 @@ public: | |||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||
| BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | |||
| bridgeTimeInfo.playing = timeInfo.playing; | |||
| bridgeTimeInfo.frame = timeInfo.frame; | |||
| bridgeTimeInfo.usecs = timeInfo.usecs; | |||
| bridgeTimeInfo.valid = timeInfo.valid; | |||
| bridgeTimeInfo.playing = timeInfo.playing; | |||
| bridgeTimeInfo.frame = timeInfo.frame; | |||
| bridgeTimeInfo.usecs = timeInfo.usecs; | |||
| bridgeTimeInfo.validFlags = timeInfo.bbt.valid ? kPluginBridgeTimeInfoValidBBT : 0x0; | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| bridgeTimeInfo.bar = timeInfo.bbt.bar; | |||
| bridgeTimeInfo.beat = timeInfo.bbt.beat; | |||
| @@ -2824,6 +2824,7 @@ public: | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_FRAME: | |||
| if (fLastTimeInfo.frame != timeInfo.frame) | |||
| { | |||
| @@ -2831,55 +2832,62 @@ public: | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_FRAMES_PER_SECOND: | |||
| break; | |||
| // BBT | |||
| case LV2_PORT_DESIGNATION_TIME_BAR: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && fLastTimeInfo.bbt.bar != timeInfo.bbt.bar) | |||
| if (timeInfo.bbt.valid && fLastTimeInfo.bbt.bar != timeInfo.bbt.bar) | |||
| { | |||
| fParamBuffers[k] = static_cast<float>(timeInfo.bbt.bar - 1); | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_BAR_BEAT: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && (fLastTimeInfo.bbt.tick != timeInfo.bbt.tick || | |||
| fLastTimeInfo.bbt.beat != timeInfo.bbt.beat)) | |||
| if (timeInfo.bbt.valid && (fLastTimeInfo.bbt.tick != timeInfo.bbt.tick || | |||
| fLastTimeInfo.bbt.beat != timeInfo.bbt.beat)) | |||
| { | |||
| fParamBuffers[k] = static_cast<float>(static_cast<double>(timeInfo.bbt.beat) - 1.0 + (static_cast<double>(timeInfo.bbt.tick) / timeInfo.bbt.ticksPerBeat)); | |||
| fParamBuffers[k] = static_cast<float>(static_cast<double>(timeInfo.bbt.beat) - 1.0 | |||
| + (static_cast<double>(timeInfo.bbt.tick) / timeInfo.bbt.ticksPerBeat)); | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_BEAT: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && fLastTimeInfo.bbt.beat != timeInfo.bbt.beat) | |||
| if (timeInfo.bbt.valid && fLastTimeInfo.bbt.beat != timeInfo.bbt.beat) | |||
| { | |||
| fParamBuffers[k] = static_cast<float>(timeInfo.bbt.beat - 1); | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_BEAT_UNIT: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && carla_isNotEqual(fLastTimeInfo.bbt.beatType, timeInfo.bbt.beatType)) | |||
| if (timeInfo.bbt.valid && carla_isNotEqual(fLastTimeInfo.bbt.beatType, timeInfo.bbt.beatType)) | |||
| { | |||
| fParamBuffers[k] = timeInfo.bbt.beatType; | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_BEATS_PER_BAR: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && carla_isNotEqual(fLastTimeInfo.bbt.beatsPerBar, timeInfo.bbt.beatsPerBar)) | |||
| if (timeInfo.bbt.valid && carla_isNotEqual(fLastTimeInfo.bbt.beatsPerBar, timeInfo.bbt.beatsPerBar)) | |||
| { | |||
| fParamBuffers[k] = timeInfo.bbt.beatsPerBar; | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_BEATS_PER_MINUTE: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && carla_isNotEqual(fLastTimeInfo.bbt.beatsPerMinute, timeInfo.bbt.beatsPerMinute)) | |||
| if (timeInfo.bbt.valid && carla_isNotEqual(fLastTimeInfo.bbt.beatsPerMinute, timeInfo.bbt.beatsPerMinute)) | |||
| { | |||
| fParamBuffers[k] = static_cast<float>(timeInfo.bbt.beatsPerMinute); | |||
| doPostRt = true; | |||
| } | |||
| break; | |||
| case LV2_PORT_DESIGNATION_TIME_TICKS_PER_BEAT: | |||
| if ((timeInfo.valid & EngineTimeInfo::kValidBBT) != 0 && carla_isNotEqual(fLastTimeInfo.bbt.ticksPerBeat, timeInfo.bbt.ticksPerBeat)) | |||
| if (timeInfo.bbt.valid && carla_isNotEqual(fLastTimeInfo.bbt.ticksPerBeat, timeInfo.bbt.ticksPerBeat)) | |||
| { | |||
| fParamBuffers[k] = static_cast<float>(timeInfo.bbt.ticksPerBeat); | |||
| doPostRt = true; | |||
| @@ -2908,7 +2916,7 @@ public: | |||
| lv2_atom_forge_key(&fAtomForge, kUridTimeFrame); | |||
| lv2_atom_forge_long(&fAtomForge, static_cast<int64_t>(timeInfo.frame)); | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| lv2_atom_forge_key(&fAtomForge, kUridTimeBar); | |||
| lv2_atom_forge_long(&fAtomForge, timeInfo.bbt.bar - 1); | |||
| @@ -1383,7 +1383,7 @@ public: | |||
| fTimeInfo.frame = timeInfo.frame; | |||
| fTimeInfo.usecs = timeInfo.usecs; | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| fTimeInfo.bbt.valid = true; | |||
| @@ -1399,7 +1399,9 @@ public: | |||
| fTimeInfo.bbt.beatsPerMinute = timeInfo.bbt.beatsPerMinute; | |||
| } | |||
| else | |||
| { | |||
| fTimeInfo.bbt.valid = false; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Event Input and Processing | |||
| @@ -1092,7 +1092,7 @@ public: | |||
| fTimeInfo.flags |= kVstNanosValid; | |||
| } | |||
| if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
| if (timeInfo.bbt.valid) | |||
| { | |||
| CARLA_SAFE_ASSERT_INT(timeInfo.bbt.bar > 0, timeInfo.bbt.bar); | |||
| CARLA_SAFE_ASSERT_INT(timeInfo.bbt.beat > 0, timeInfo.bbt.beat); | |||
| @@ -29,12 +29,12 @@ | |||
| #include "water/files/File.h" | |||
| // --------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| class CarlaEngineLV2Single : public CarlaEngine, | |||
| public Lv2PluginBaseClass | |||
| public Lv2PluginBaseClass<EngineTimeInfo> | |||
| { | |||
| public: | |||
| CarlaEngineLV2Single(const double sampleRate, | |||
| @@ -42,10 +42,8 @@ public: | |||
| const LV2_Feature* const* const features) | |||
| : Lv2PluginBaseClass(sampleRate, features), | |||
| fPlugin(nullptr), | |||
| fIsActive(false), | |||
| fIsOffline(false), | |||
| fPorts(), | |||
| fUI() | |||
| fUiName(), | |||
| fPorts() | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount == 0,) | |||
| CARLA_SAFE_ASSERT_RETURN(pData->plugins[0].plugin == nullptr,); | |||
| @@ -112,7 +110,7 @@ public: | |||
| return fPlugin != nullptr; | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // LV2 functions | |||
| void lv2_connect_port(const uint32_t port, void* const dataLocation) noexcept | |||
| @@ -124,6 +122,8 @@ public: | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(! fIsActive,); | |||
| resetTimeInfo(); | |||
| fPlugin->setActive(true, false, false); | |||
| fIsActive = true; | |||
| } | |||
| @@ -138,6 +138,9 @@ public: | |||
| void lv2_run(const uint32_t frames) | |||
| { | |||
| if (! lv2_pre_run(frames)) | |||
| return; | |||
| fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f); | |||
| // Check for updated parameters | |||
| @@ -174,10 +177,11 @@ public: | |||
| carla_zeroFloats(fPorts.audioOuts[i], frames); | |||
| } | |||
| lv2_post_run(frames); | |||
| fPorts.updateOutputs(); | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||
| LV2UI_Widget* widget, const LV2_Feature* const* features) | |||
| @@ -185,9 +189,11 @@ public: | |||
| fUI.writeFunction = writeFunction; | |||
| fUI.controller = controller; | |||
| fUiName.clear(); | |||
| const LV2_URID_Map* uridMap = nullptr; | |||
| // ------------------------------------------------------------------------------------------------------------- | |||
| // ------------------------------------------------------------------------------------------------------------ | |||
| // see if the host supports external-ui, get uridMap | |||
| for (int i=0; features[i] != nullptr; ++i) | |||
| @@ -205,12 +211,12 @@ public: | |||
| if (fUI.host != nullptr) | |||
| { | |||
| fUI.name = fUI.host->plugin_human_id; | |||
| *widget = (LV2_External_UI_Widget*)this; | |||
| fUiName = fUI.host->plugin_human_id; | |||
| *widget = (LV2_External_UI_Widget*)this; | |||
| return; | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------- | |||
| // ------------------------------------------------------------------------------------------------------------ | |||
| // no external-ui support, use showInterface | |||
| for (int i=0; features[i] != nullptr; ++i) | |||
| @@ -223,7 +229,7 @@ public: | |||
| { | |||
| if (options[j].key == uridMap->map(uridMap->handle, LV2_UI__windowTitle)) | |||
| { | |||
| fUI.name = (const char*)options[j].value; | |||
| fUiName = (const char*)options[j].value; | |||
| break; | |||
| } | |||
| } | |||
| @@ -231,8 +237,8 @@ public: | |||
| } | |||
| } | |||
| if (fUI.name.isEmpty()) | |||
| fUI.name = fPlugin->getName(); | |||
| if (fUiName.isEmpty()) | |||
| fUiName = fPlugin->getName(); | |||
| *widget = nullptr; | |||
| } | |||
| @@ -241,48 +247,15 @@ public: | |||
| { | |||
| if (format != 0 || bufferSize != sizeof(float) || buffer == nullptr) | |||
| return; | |||
| if (portIndex >= fPorts.indexOffset || ! fUI.visible) | |||
| if (portIndex >= fPorts.indexOffset || ! fUI.isVisible) | |||
| return; | |||
| const float value(*(const float*)buffer); | |||
| fPlugin->uiParameterChange(portIndex-fPorts.indexOffset, value); | |||
| } | |||
| void lv2ui_cleanup() | |||
| { | |||
| if (fUI.visible) | |||
| handleUiHide(); | |||
| fUI.writeFunction = nullptr; | |||
| fUI.controller = nullptr; | |||
| fUI.host = nullptr; | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| int lv2ui_idle() const | |||
| { | |||
| if (! fUI.visible) | |||
| return 1; | |||
| handleUiRun(); | |||
| return 0; | |||
| } | |||
| int lv2ui_show() | |||
| { | |||
| handleUiShow(); | |||
| return 0; | |||
| } | |||
| int lv2ui_hide() | |||
| { | |||
| handleUiHide(); | |||
| return 0; | |||
| } | |||
| protected: | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // CarlaEngine virtual calls | |||
| bool init(const char* const clientName) override | |||
| @@ -330,7 +303,7 @@ protected: | |||
| { | |||
| case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED: | |||
| CARLA_SAFE_ASSERT_RETURN(value1 >= 0,); | |||
| if (fUI.writeFunction != nullptr && fUI.controller != nullptr && fUI.visible) | |||
| if (fUI.writeFunction != nullptr && fUI.controller != nullptr && fUI.isVisible) | |||
| { | |||
| fUI.writeFunction(fUI.controller, | |||
| static_cast<uint32_t>(value1)+fPorts.indexOffset, | |||
| @@ -339,7 +312,7 @@ protected: | |||
| break; | |||
| case ENGINE_CALLBACK_UI_STATE_CHANGED: | |||
| fUI.visible = value1 == 1; | |||
| fUI.isVisible = (value1 == 1); | |||
| if (fUI.host != nullptr) | |||
| fUI.host->ui_closed(fUI.controller); | |||
| break; | |||
| @@ -354,7 +327,7 @@ protected: | |||
| } | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| void handleUiRun() const override | |||
| { | |||
| @@ -366,23 +339,32 @@ protected: | |||
| void handleUiShow() override | |||
| { | |||
| fPlugin->showCustomUI(true); | |||
| fUI.visible = true; | |||
| fUI.isVisible = true; | |||
| } | |||
| void handleUiHide() override | |||
| { | |||
| fUI.visible = false; | |||
| fUI.isVisible = false; | |||
| fPlugin->showCustomUI(false); | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| void handleBufferSizeChanged(const uint32_t bufferSize) override | |||
| { | |||
| CarlaEngine::bufferSizeChanged(bufferSize); | |||
| } | |||
| void handleSampleRateChanged(const double sampleRate) override | |||
| { | |||
| CarlaEngine::sampleRateChanged(sampleRate); | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| private: | |||
| CarlaPlugin* fPlugin; | |||
| // Lv2 host data | |||
| bool fIsActive; | |||
| bool fIsOffline; | |||
| CarlaString fUiName; | |||
| struct Ports { | |||
| uint32_t numAudioIns; | |||
| @@ -535,22 +517,6 @@ private: | |||
| CARLA_DECLARE_NON_COPY_STRUCT(Ports); | |||
| } fPorts; | |||
| struct UI { | |||
| LV2UI_Write_Function writeFunction; | |||
| LV2UI_Controller controller; | |||
| const LV2_External_UI_Host* host; | |||
| CarlaString name; | |||
| bool visible; | |||
| UI() | |||
| : writeFunction(nullptr), | |||
| controller(nullptr), | |||
| host(nullptr), | |||
| name(), | |||
| visible(false) {} | |||
| CARLA_DECLARE_NON_COPY_STRUCT(UI) | |||
| } fUI; | |||
| // ------------------------------------------------------------------- | |||
| #define handlePtr ((CarlaEngineLV2Single*)handle) | |||
| @@ -569,7 +535,7 @@ CARLA_BACKEND_END_NAMESPACE | |||
| using CarlaBackend::CarlaEngineLV2Single; | |||
| // --------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // LV2 DSP functions | |||
| static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sampleRate, const char* bundlePath, const LV2_Feature* const* features) | |||
| @@ -624,7 +590,7 @@ static const void* lv2_extension_data(const char* uri) | |||
| #undef instancePtr | |||
| // --------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // LV2 UI functions | |||
| static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*, | |||
| @@ -703,7 +669,7 @@ static const void* lv2ui_extension_data(const char* uri) | |||
| #undef uiPtr | |||
| // --------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Startup code | |||
| CARLA_EXPORT | |||
| @@ -762,4 +728,4 @@ const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | |||
| return (index == 0) ? &lv2UiExtDesc : nullptr; | |||
| } | |||
| // --------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -596,7 +596,7 @@ bool CarlaJackAppClient::handleRtData() | |||
| fServer.position.frame = bridgeTimeInfo.frame; | |||
| fServer.position.usecs = bridgeTimeInfo.usecs; | |||
| if (bridgeTimeInfo.valid & 0x1 /* kValidBBT */) | |||
| if (bridgeTimeInfo.validFlags & kPluginBridgeTimeInfoValidBBT) | |||
| { | |||
| fServer.position.valid = JackPositionBBT; | |||
| @@ -613,7 +613,7 @@ bool CarlaJackAppClient::handleRtData() | |||
| } | |||
| else | |||
| { | |||
| fServer.position.valid = static_cast<jack_position_bits_t>(0); | |||
| fServer.position.valid = static_cast<jack_position_bits_t>(0x0); | |||
| } | |||
| int numClientOutputsProcessed = 0; | |||
| @@ -25,7 +25,7 @@ | |||
| // ----------------------------------------------------------------------- | |||
| // LV2 descriptor functions | |||
| class NativePlugin : public Lv2PluginBaseClass | |||
| class NativePlugin : public Lv2PluginBaseClass<NativeTimeInfo> | |||
| { | |||
| public: | |||
| static const uint32_t kMaxMidiEvents = 512; | |||
| @@ -42,9 +42,6 @@ public: | |||
| fProgramDesc({0, 0, nullptr}), | |||
| #endif | |||
| fMidiEventCount(0), | |||
| fTimeInfo(), | |||
| fLastPositionData(), | |||
| fUI(), | |||
| fPorts() | |||
| { | |||
| carla_zeroStruct(fHost); | |||
| @@ -82,6 +79,12 @@ public: | |||
| delete[] fHost.resourceDir; | |||
| fHost.resourceDir = nullptr; | |||
| } | |||
| if (fHost.uiName != nullptr) | |||
| { | |||
| delete[] fHost.uiName; | |||
| fHost.uiName = nullptr; | |||
| } | |||
| } | |||
| bool init() | |||
| @@ -96,7 +99,6 @@ public: | |||
| } | |||
| carla_zeroStructs(fMidiEvents, kMaxMidiEvents); | |||
| carla_zeroStruct(fTimeInfo); | |||
| fHandle = fDescriptor->instantiate(&fHost); | |||
| CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); | |||
| @@ -128,17 +130,7 @@ public: | |||
| if (fDescriptor->activate != nullptr) | |||
| fDescriptor->activate(fHandle); | |||
| carla_zeroStruct(fTimeInfo); | |||
| // hosts may not send all values, resulting on some invalid data | |||
| fTimeInfo.bbt.bar = 1; | |||
| fTimeInfo.bbt.beat = 1; | |||
| fTimeInfo.bbt.tick = 0; | |||
| fTimeInfo.bbt.barStartTick = 0; | |||
| fTimeInfo.bbt.beatsPerBar = 4; | |||
| fTimeInfo.bbt.beatType = 4; | |||
| fTimeInfo.bbt.ticksPerBeat = 960.0; | |||
| fTimeInfo.bbt.beatsPerMinute = 120.0; | |||
| resetTimeInfo(); | |||
| } | |||
| void lv2_deactivate() | |||
| @@ -157,6 +149,9 @@ public: | |||
| void lv2_run(const uint32_t frames) | |||
| { | |||
| if (! lv2_pre_run(frames)) | |||
| return; | |||
| fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f); | |||
| // cache midi events and time information first | |||
| @@ -484,130 +479,12 @@ public: | |||
| const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, | |||
| fMidiEvents, fMidiEventCount); | |||
| // update timePos for next callback | |||
| if (carla_isNotZero(fLastPositionData.speed)) | |||
| { | |||
| if (fLastPositionData.speed > 0.0) | |||
| { | |||
| // playing forwards | |||
| fLastPositionData.frame += frames; | |||
| } | |||
| else | |||
| { | |||
| // playing backwards | |||
| if (frames >= fLastPositionData.frame) | |||
| fLastPositionData.frame = 0; | |||
| else | |||
| fLastPositionData.frame -= frames; | |||
| } | |||
| fTimeInfo.frame = fLastPositionData.frame; | |||
| if (fTimeInfo.bbt.valid) | |||
| { | |||
| const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; | |||
| const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; | |||
| const double addedBarBeats = double(frames) / framesPerBeat; | |||
| if (fLastPositionData.barBeat >= 0.0f) | |||
| { | |||
| fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+static_cast<float>(addedBarBeats), | |||
| fLastPositionData.beatsPerBar); | |||
| const double rest = std::fmod(fLastPositionData.barBeat, 1.0f); | |||
| fTimeInfo.bbt.beat = static_cast<int32_t>(fLastPositionData.barBeat-rest+1.0); | |||
| fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5); | |||
| if (fLastPositionData.bar_f >= 0.0f) | |||
| { | |||
| fLastPositionData.bar_f += std::floor((fLastPositionData.barBeat+static_cast<float>(addedBarBeats))/ | |||
| fLastPositionData.beatsPerBar); | |||
| if (fLastPositionData.bar_f <= 0.0f) | |||
| { | |||
| fLastPositionData.bar = 0; | |||
| fLastPositionData.bar_f = 0.0f; | |||
| } | |||
| else | |||
| { | |||
| fLastPositionData.bar = static_cast<int32_t>(fLastPositionData.bar_f+0.5f); | |||
| } | |||
| fTimeInfo.bbt.bar = fLastPositionData.bar + 1; | |||
| fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat* | |||
| fTimeInfo.bbt.beatsPerBar* | |||
| (fTimeInfo.bbt.bar-1); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| lv2_post_run(frames); | |||
| updateParameterOutputs(); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) const | |||
| { | |||
| // currently unused | |||
| return LV2_OPTIONS_SUCCESS; | |||
| } | |||
| uint32_t lv2_set_options(const LV2_Options_Option* const options) | |||
| { | |||
| for (int i=0; options[i].key != 0; ++i) | |||
| { | |||
| if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__nominalBlockLength)) | |||
| { | |||
| if (options[i].type == fURIs.atomInt) | |||
| { | |||
| const int value(*(const int*)options[i].value); | |||
| CARLA_SAFE_ASSERT_CONTINUE(value > 0); | |||
| fBufferSize = static_cast<uint32_t>(value); | |||
| if (fDescriptor->dispatcher != nullptr) | |||
| fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, value, nullptr, 0.0f); | |||
| } | |||
| else | |||
| carla_stderr("Host changed nominalBlockLength but with wrong value type"); | |||
| } | |||
| else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength) && ! fUsingNominal) | |||
| { | |||
| if (options[i].type == fURIs.atomInt) | |||
| { | |||
| const int value(*(const int*)options[i].value); | |||
| CARLA_SAFE_ASSERT_CONTINUE(value > 0); | |||
| fBufferSize = static_cast<uint32_t>(value); | |||
| if (fDescriptor->dispatcher != nullptr) | |||
| fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, value, nullptr, 0.0f); | |||
| } | |||
| else | |||
| carla_stderr("Host changed maxBlockLength but with wrong value type"); | |||
| } | |||
| else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_CORE__sampleRate)) | |||
| { | |||
| if (options[i].type == fURIs.atomDouble) | |||
| { | |||
| const double value(*(const double*)options[i].value); | |||
| CARLA_SAFE_ASSERT_CONTINUE(value > 0.0); | |||
| fSampleRate = value; | |||
| if (fDescriptor->dispatcher != nullptr) | |||
| fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, (float)fSampleRate); | |||
| } | |||
| else | |||
| carla_stderr("Host changed sampleRate but with wrong value type"); | |||
| } | |||
| } | |||
| return LV2_OPTIONS_SUCCESS; | |||
| } | |||
| const LV2_Program_Descriptor* lv2_get_program(const uint32_t index) | |||
| { | |||
| if (fDescriptor->category == NATIVE_PLUGIN_CATEGORY_SYNTH) | |||
| @@ -696,6 +573,12 @@ public: | |||
| fUI.controller = controller; | |||
| fUI.isEmbed = isEmbed; | |||
| if (fHost.uiName != nullptr) | |||
| { | |||
| delete[] fHost.uiName; | |||
| fHost.uiName = nullptr; | |||
| } | |||
| #ifdef CARLA_OS_LINUX | |||
| // --------------------------------------------------------------- | |||
| // show embed UI if needed | |||
| @@ -810,22 +693,6 @@ public: | |||
| fDescriptor->ui_set_parameter_value(fHandle, portIndex-fUI.portOffset, value); | |||
| } | |||
| void lv2ui_cleanup() | |||
| { | |||
| if (fUI.isVisible) | |||
| handleUiHide(); | |||
| fUI.host = nullptr; | |||
| fUI.writeFunction = nullptr; | |||
| fUI.controller = nullptr; | |||
| if (fHost.uiName != nullptr) | |||
| { | |||
| delete[] fHost.uiName; | |||
| fHost.uiName = nullptr; | |||
| } | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| void lv2ui_select_program(uint32_t bank, uint32_t program) const | |||
| @@ -838,30 +705,7 @@ public: | |||
| fDescriptor->ui_set_midi_program(fHandle, 0, bank, program); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| int lv2ui_idle() const | |||
| { | |||
| if (! fUI.isVisible) | |||
| return 1; | |||
| handleUiRun(); | |||
| return 0; | |||
| } | |||
| int lv2ui_show() | |||
| { | |||
| handleUiShow(); | |||
| return 0; | |||
| } | |||
| int lv2ui_hide() | |||
| { | |||
| handleUiHide(); | |||
| return 0; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| protected: | |||
| void handleUiRun() const override | |||
| @@ -886,7 +730,25 @@ protected: | |||
| fUI.isVisible = false; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| void handleBufferSizeChanged(const uint32_t bufferSize) override | |||
| { | |||
| if (fDescriptor->dispatcher == nullptr) | |||
| return; | |||
| fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, bufferSize, nullptr, 0.0f); | |||
| } | |||
| void handleSampleRateChanged(const double sampleRate) override | |||
| { | |||
| if (fDescriptor->dispatcher == nullptr) | |||
| return; | |||
| fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, (float)sampleRate); | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| bool handleWriteMidiEvent(const NativeMidiEvent* const event) | |||
| { | |||
| @@ -1010,48 +872,6 @@ private: | |||
| uint32_t fMidiEventCount; | |||
| NativeMidiEvent fMidiEvents[kMaxMidiEvents]; | |||
| NativeTimeInfo fTimeInfo; | |||
| struct Lv2PositionData { | |||
| int32_t bar; | |||
| float bar_f; | |||
| float barBeat; | |||
| uint32_t beatUnit; | |||
| float beatsPerBar; | |||
| double beatsPerMinute; | |||
| uint64_t frame; | |||
| double speed; | |||
| double ticksPerBeat; | |||
| Lv2PositionData() | |||
| : bar(-1), | |||
| bar_f(-1.0f), | |||
| barBeat(-1.0f), | |||
| beatUnit(0), | |||
| beatsPerBar(0.0f), | |||
| beatsPerMinute(-1.0), | |||
| frame(0), | |||
| speed(0.0), | |||
| ticksPerBeat(-1.0) {} | |||
| } fLastPositionData; | |||
| struct UI { | |||
| const LV2_External_UI_Host* host; | |||
| LV2UI_Write_Function writeFunction; | |||
| LV2UI_Controller controller; | |||
| uint32_t portOffset; | |||
| bool isEmbed; | |||
| bool isVisible; | |||
| UI() | |||
| : host(nullptr), | |||
| writeFunction(nullptr), | |||
| controller(nullptr), | |||
| portOffset(0), | |||
| isEmbed(false), | |||
| isVisible(false) {} | |||
| } fUI; | |||
| struct Ports { | |||
| // need to save current state | |||
| @@ -114,6 +114,10 @@ enum PluginBridgePortType { | |||
| kPluginBridgePortTypeCount | |||
| }; | |||
| enum PluginBridgeTimeInfoFlags { | |||
| kPluginBridgeTimeInfoValidBBT = 0x1 | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| struct BridgeSemaphore { | |||
| @@ -132,7 +136,7 @@ struct BridgeTimeInfo { | |||
| uint64_t playing; | |||
| uint64_t frame; | |||
| uint64_t usecs; | |||
| uint32_t valid; | |||
| uint32_t validFlags; | |||
| // bbt | |||
| int32_t bar, beat, tick; | |||
| float beatsPerBar, beatType; | |||
| @@ -525,6 +525,7 @@ public: | |||
| # pragma GCC diagnostic push | |||
| # pragma GCC diagnostic ignored "-Weffc++" | |||
| #endif | |||
| template<class TimeInfoStruct> | |||
| class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat | |||
| { | |||
| #if defined(__clang__) | |||
| @@ -534,11 +535,16 @@ class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat | |||
| #endif | |||
| public: | |||
| Lv2PluginBaseClass(const double sampleRate, const LV2_Feature* const* const features) | |||
| : fIsOffline(false), | |||
| : fIsActive(false), | |||
| fIsOffline(false), | |||
| fUsingNominal(false), | |||
| fBufferSize(0), | |||
| fSampleRate(sampleRate), | |||
| fUsingNominal(false), | |||
| fUridMap(nullptr) | |||
| fUridMap(nullptr), | |||
| fTimeInfo(), | |||
| fLastPositionData(), | |||
| fURIs(), | |||
| fUI() | |||
| { | |||
| run = extui_run; | |||
| show = extui_show; | |||
| @@ -620,6 +626,9 @@ public: | |||
| fUridMap = uridMap; | |||
| fURIs.map(uridMap); | |||
| carla_zeroStruct(fTimeInfo); | |||
| carla_zeroStruct(fLastPositionData); | |||
| } | |||
| virtual ~Lv2PluginBaseClass() | |||
| @@ -631,20 +640,245 @@ public: | |||
| return fUridMap != nullptr && fBufferSize != 0; | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| bool lv2_pre_run(const uint32_t /*frames*/) | |||
| { | |||
| return true; | |||
| } | |||
| void lv2_post_run(const uint32_t frames) | |||
| { | |||
| // update timePos for next callback | |||
| if (carla_isZero(fLastPositionData.speed)) | |||
| return; | |||
| if (fLastPositionData.speed > 0.0) | |||
| { | |||
| // playing forwards | |||
| fLastPositionData.frame += frames; | |||
| } | |||
| else | |||
| { | |||
| // playing backwards | |||
| if (frames >= fLastPositionData.frame) | |||
| fLastPositionData.frame = 0; | |||
| else | |||
| fLastPositionData.frame -= frames; | |||
| } | |||
| fTimeInfo.frame = fLastPositionData.frame; | |||
| if (fTimeInfo.bbt.valid) | |||
| { | |||
| const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; | |||
| const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; | |||
| const double addedBarBeats = double(frames) / framesPerBeat; | |||
| if (fLastPositionData.barBeat >= 0.0f) | |||
| { | |||
| fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+static_cast<float>(addedBarBeats), | |||
| fLastPositionData.beatsPerBar); | |||
| const double rest = std::fmod(fLastPositionData.barBeat, 1.0f); | |||
| fTimeInfo.bbt.beat = static_cast<int32_t>(fLastPositionData.barBeat-rest+1.0); | |||
| fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5); | |||
| if (fLastPositionData.bar_f >= 0.0f) | |||
| { | |||
| fLastPositionData.bar_f += std::floor((fLastPositionData.barBeat+static_cast<float>(addedBarBeats))/ | |||
| fLastPositionData.beatsPerBar); | |||
| if (fLastPositionData.bar_f <= 0.0f) | |||
| { | |||
| fLastPositionData.bar = 0; | |||
| fLastPositionData.bar_f = 0.0f; | |||
| } | |||
| else | |||
| { | |||
| fLastPositionData.bar = static_cast<int32_t>(fLastPositionData.bar_f+0.5f); | |||
| } | |||
| fTimeInfo.bbt.bar = fLastPositionData.bar + 1; | |||
| fTimeInfo.bbt.barStartTick = fTimeInfo.bbt.ticksPerBeat * | |||
| fTimeInfo.bbt.beatsPerBar * | |||
| (fTimeInfo.bbt.bar-1); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) const | |||
| { | |||
| // currently unused | |||
| return LV2_OPTIONS_SUCCESS; | |||
| } | |||
| uint32_t lv2_set_options(const LV2_Options_Option* const options) | |||
| { | |||
| for (int i=0; options[i].key != 0; ++i) | |||
| { | |||
| if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__nominalBlockLength)) | |||
| { | |||
| if (options[i].type == fURIs.atomInt) | |||
| { | |||
| const int value(*(const int*)options[i].value); | |||
| CARLA_SAFE_ASSERT_CONTINUE(value > 0); | |||
| const uint32_t newBufferSize = static_cast<uint32_t>(value); | |||
| if (fBufferSize != newBufferSize) | |||
| { | |||
| fBufferSize = newBufferSize; | |||
| handleBufferSizeChanged(newBufferSize); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| carla_stderr("Host changed nominalBlockLength but with wrong value type"); | |||
| } | |||
| } | |||
| else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength) && ! fUsingNominal) | |||
| { | |||
| if (options[i].type == fURIs.atomInt) | |||
| { | |||
| const int value(*(const int*)options[i].value); | |||
| CARLA_SAFE_ASSERT_CONTINUE(value > 0); | |||
| const uint32_t newBufferSize = static_cast<uint32_t>(value); | |||
| if (fBufferSize != newBufferSize) | |||
| { | |||
| fBufferSize = newBufferSize; | |||
| handleBufferSizeChanged(newBufferSize); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| carla_stderr("Host changed maxBlockLength but with wrong value type"); | |||
| } | |||
| } | |||
| else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_PARAMETERS__sampleRate)) | |||
| { | |||
| if (options[i].type == fURIs.atomFloat) | |||
| { | |||
| const double value(*(const float*)options[i].value); | |||
| CARLA_SAFE_ASSERT_CONTINUE(value > 0.0); | |||
| if (carla_isNotEqual(fSampleRate, value)) | |||
| { | |||
| fSampleRate = value; | |||
| handleSampleRateChanged(value); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| carla_stderr("Host changed sampleRate but with wrong value type"); | |||
| } | |||
| } | |||
| } | |||
| return LV2_OPTIONS_SUCCESS; | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| int lv2ui_idle() const | |||
| { | |||
| if (! fUI.isVisible) | |||
| return 1; | |||
| handleUiRun(); | |||
| return 0; | |||
| } | |||
| int lv2ui_show() | |||
| { | |||
| handleUiShow(); | |||
| return 0; | |||
| } | |||
| int lv2ui_hide() | |||
| { | |||
| handleUiHide(); | |||
| return 0; | |||
| } | |||
| void lv2ui_cleanup() | |||
| { | |||
| if (fUI.isVisible) | |||
| handleUiHide(); | |||
| fUI.host = nullptr; | |||
| fUI.writeFunction = nullptr; | |||
| fUI.controller = nullptr; | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| protected: | |||
| virtual void handleUiRun() const = 0; | |||
| virtual void handleUiShow() = 0; | |||
| virtual void handleUiHide() = 0; | |||
| virtual void handleBufferSizeChanged(const uint32_t bufferSize) = 0; | |||
| virtual void handleSampleRateChanged(const double sampleRate) = 0; | |||
| // LV2 host data | |||
| bool fIsOffline; | |||
| bool fIsActive : 1; | |||
| bool fIsOffline : 1; | |||
| bool fUsingNominal : 1; | |||
| uint32_t fBufferSize; | |||
| double fSampleRate; | |||
| bool fUsingNominal; | |||
| // LV2 host features | |||
| const LV2_URID_Map* fUridMap; | |||
| // Time info stuff | |||
| TimeInfoStruct fTimeInfo; | |||
| struct Lv2PositionData { | |||
| int32_t bar; | |||
| float bar_f; | |||
| float barBeat; | |||
| uint32_t beatUnit; | |||
| float beatsPerBar; | |||
| double beatsPerMinute; | |||
| uint64_t frame; | |||
| double speed; | |||
| double ticksPerBeat; | |||
| Lv2PositionData() | |||
| : bar(-1), | |||
| bar_f(-1.0f), | |||
| barBeat(-1.0f), | |||
| beatUnit(0), | |||
| beatsPerBar(0.0f), | |||
| beatsPerMinute(-1.0), | |||
| frame(0), | |||
| speed(0.0), | |||
| ticksPerBeat(-1.0) {} | |||
| } fLastPositionData; | |||
| void resetTimeInfo() | |||
| { | |||
| carla_zeroStruct(fLastPositionData); | |||
| carla_zeroStruct(fTimeInfo); | |||
| // hosts may not send all values, resulting on some invalid data | |||
| fTimeInfo.bbt.bar = 1; | |||
| fTimeInfo.bbt.beat = 1; | |||
| fTimeInfo.bbt.beatsPerBar = 4; | |||
| fTimeInfo.bbt.beatType = 4; | |||
| fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat = 960.0; | |||
| fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute = 120.0; | |||
| } | |||
| // Rest of host<->plugin support | |||
| struct URIDs { | |||
| LV2_URID atomBlank; | |||
| LV2_URID atomObject; | |||
| @@ -708,6 +942,23 @@ protected: | |||
| } | |||
| } fURIs; | |||
| struct UI { | |||
| const LV2_External_UI_Host* host; | |||
| LV2UI_Write_Function writeFunction; | |||
| LV2UI_Controller controller; | |||
| uint32_t portOffset; | |||
| bool isEmbed; | |||
| bool isVisible; | |||
| UI() | |||
| : host(nullptr), | |||
| writeFunction(nullptr), | |||
| controller(nullptr), | |||
| portOffset(0), | |||
| isEmbed(false), | |||
| isVisible(false) {} | |||
| } fUI; | |||
| private: | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||