Interim commit for COnvolutionReverb
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Robin E. R. Davies
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "AutoLilvNode.hpp"
|
||||
#include "PiPedalHost.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
float AutoLilvNode::AsFloat(float defaultValue)
|
||||
{
|
||||
if (node == nullptr)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
if (lilv_node_is_float(node))
|
||||
{
|
||||
return lilv_node_as_float(node);
|
||||
}
|
||||
if (lilv_node_is_int(node))
|
||||
{
|
||||
return lilv_node_as_int(node);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
int AutoLilvNode::AsInt(int defaultValue)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return defaultValue;
|
||||
if (lilv_node_is_int(node))
|
||||
return lilv_node_as_int(node);
|
||||
return defaultValue;
|
||||
}
|
||||
bool AutoLilvNode::AsBool(bool defaultValue)
|
||||
{
|
||||
if (node == nullptr)
|
||||
return defaultValue;
|
||||
if (lilv_node_is_int(node))
|
||||
return lilv_node_as_bool(node);
|
||||
return defaultValue;
|
||||
}
|
||||
std::string AutoLilvNode::AsUri()
|
||||
{
|
||||
if (node == nullptr)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (lilv_node_is_uri(node))
|
||||
{
|
||||
return lilv_node_as_uri(node);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
std::string AutoLilvNode::AsString()
|
||||
{
|
||||
if (node == nullptr)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (lilv_node_is_string(node))
|
||||
{
|
||||
return lilv_node_as_string(node);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Robin E. R. Davies
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace pipedal
|
||||
{
|
||||
class AutoLilvNode
|
||||
{
|
||||
|
||||
// const LilvNode* returns must not be freed, by convention.
|
||||
private:
|
||||
LilvNode *node = nullptr;
|
||||
AutoLilvNode(const LilvNode *node) = delete;
|
||||
|
||||
public:
|
||||
AutoLilvNode()
|
||||
{
|
||||
}
|
||||
AutoLilvNode(LilvNode *node)
|
||||
: node(node)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~AutoLilvNode() { Free(); }
|
||||
|
||||
|
||||
operator const LilvNode *()
|
||||
{
|
||||
return this->node;
|
||||
}
|
||||
operator bool()
|
||||
{
|
||||
return this->node != nullptr;
|
||||
}
|
||||
LilvNode*&Get() { return node; }
|
||||
|
||||
AutoLilvNode&operator=(LilvNode*node) {
|
||||
Free();
|
||||
this->node = node;
|
||||
return *this;
|
||||
}
|
||||
AutoLilvNode&operator=(AutoLilvNode&&other) {
|
||||
std::swap(this->node,other.node);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
float AsFloat(float defaultValue = 0);
|
||||
int AsInt(int defaultValue = 0);
|
||||
bool AsBool(bool defaultValue = false);
|
||||
std::string AsUri();
|
||||
std::string AsString();
|
||||
|
||||
void Free()
|
||||
{
|
||||
if (node != nullptr)
|
||||
lilv_node_free(node);
|
||||
node = nullptr;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
@@ -153,7 +153,7 @@ void AvahiService::create_group(AvahiClient *c)
|
||||
* because it was reset previously, add our entries. */
|
||||
if (avahi_entry_group_is_empty(group))
|
||||
{
|
||||
Lv2Log::debug(SS("Adding service '" << name));
|
||||
Lv2Log::debug(SS("Adding service '" << name << "'"));
|
||||
|
||||
std::string instanceTxtRecord = SS("id=" << this->instanceId);
|
||||
|
||||
|
||||
@@ -42,6 +42,6 @@ TEST_CASE("Avahi Service Test", "[avahi_service][dev]")
|
||||
|
||||
service.Unannounce();
|
||||
service.Announce(81, "Test Announcement 2", "0a6045b0-1753-4104-b3e4-b9713b9cc358","pipedal");
|
||||
sleep(10000);
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -5,6 +5,8 @@ set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||
|
||||
set (USE_PCH 1)
|
||||
|
||||
set(CXX_STANDARD 20)
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
#################################################################
|
||||
@@ -135,6 +137,10 @@ else()
|
||||
endif()
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
AutoLilvNode.hpp
|
||||
AutoLilvNode.cpp
|
||||
PiPedalUI.hpp
|
||||
PiPedalUI.cpp
|
||||
RtInversionGuard.hpp
|
||||
CpuUse.hpp CpuUse.cpp
|
||||
P2pConfigFiles.hpp
|
||||
@@ -154,7 +160,9 @@ set (PIPEDAL_SOURCES
|
||||
WifiDirectConfigSettings.hpp WifiDirectConfigSettings.cpp
|
||||
ConfigUtil.hpp ConfigUtil.cpp
|
||||
|
||||
RequestHandler.hpp json.cpp json.hpp Scratch.cpp PiPedalHost.hpp PiPedalHost.cpp
|
||||
RequestHandler.hpp json.cpp json.hpp
|
||||
json_variant.hpp json_variant.cpp
|
||||
Scratch.cpp PiPedalHost.hpp PiPedalHost.cpp
|
||||
PluginType.hpp PluginType.cpp
|
||||
Lv2Log.hpp Lv2Log.cpp
|
||||
PiPedalSocket.hpp PiPedalSocket.cpp
|
||||
|
||||
@@ -91,3 +91,39 @@ void LogFeature::Prepare(MapFeature*map)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LogFeature::LogError(const char*fmt,...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
vprintf(uris.ridError,fmt,va);
|
||||
|
||||
}
|
||||
void LogFeature::LogWarning(const char*fmt,...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
vprintf(uris.ridWarning,fmt,va);
|
||||
|
||||
}
|
||||
void LogFeature::LogNote(const char*fmt,...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
vprintf(uris.ridNote,fmt,va);
|
||||
|
||||
}
|
||||
void LogFeature::LogTrace(const char*fmt,...)
|
||||
{
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
vprintf(uris.ridNote,fmt,va);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@ namespace pipedal {
|
||||
LogFeature();
|
||||
void Prepare(MapFeature* map);
|
||||
|
||||
void LogError(const char*fmt,...);
|
||||
void LogWarning(const char*fmt,...);
|
||||
void LogNote(const char*fmt,...);
|
||||
void LogTrace(const char*fmt,...);
|
||||
|
||||
|
||||
public:
|
||||
const LV2_Feature* GetFeature()
|
||||
{
|
||||
|
||||
@@ -40,9 +40,9 @@ TEST_CASE( "PiPedalHost memory leak", "[lv2host_leak][Build][Dev]" ) {
|
||||
}
|
||||
MemStats finalMemory = GetMemStats();
|
||||
|
||||
// Something lilv leaks a Dublin Core url.
|
||||
// Something in lilv leaks a Dublin Core url.
|
||||
// Acceptable.
|
||||
const int ACCEPTABLE_ALLOCATION_LEAKS = 4;
|
||||
const int ACCEPTABLE_ALLOCATION_LEAKS = 6;
|
||||
const int ACCEPTABLE_MEMORY_LEAK = 400;
|
||||
|
||||
if (finalMemory.allocations > initialMemory.allocations + ACCEPTABLE_ALLOCATION_LEAKS
|
||||
|
||||
+22
-4
@@ -53,6 +53,18 @@ PedalBoardItem*PedalBoard::GetItem(long pedalItemId)
|
||||
return const_cast<PedalBoardItem*>(GetItem_(this->items(),pedalItemId));
|
||||
}
|
||||
|
||||
|
||||
PropertyValue*PedalBoardItem::GetPropertyValue(const std::string&propertyUri)
|
||||
{
|
||||
for (auto&propertyValue: this->propertyValues_)
|
||||
{
|
||||
if (propertyValue.propertyUri() == propertyUri)
|
||||
{
|
||||
return &propertyValue;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
ControlValue* PedalBoardItem::GetControlValue(const std::string&symbol)
|
||||
{
|
||||
for (size_t i = 0; i < this->controlValues().size(); ++i)
|
||||
@@ -164,6 +176,10 @@ PedalBoard PedalBoard::MakeDefault()
|
||||
}
|
||||
|
||||
|
||||
bool IsPedalBoardSplitItem(const PedalBoardItem*self, const std::vector<PedalBoardItem>&value)
|
||||
{
|
||||
return self->uri() == SPLIT_PEDALBOARD_ITEM_URI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -176,17 +192,19 @@ JSON_MAP_BEGIN(ControlValue)
|
||||
JSON_MAP_REFERENCE(ControlValue,value)
|
||||
JSON_MAP_END()
|
||||
|
||||
JSON_MAP_BEGIN(PropertyValue)
|
||||
JSON_MAP_REFERENCE(PropertyValue,propertyUri)
|
||||
JSON_MAP_REFERENCE(PropertyValue,value)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
bool IsPedalBoardSplitItem(const PedalBoardItem*self, const std::vector<PedalBoardItem>&value)
|
||||
{
|
||||
return self->uri() == SPLIT_PEDALBOARD_ITEM_URI;
|
||||
}
|
||||
|
||||
JSON_MAP_BEGIN(PedalBoardItem)
|
||||
JSON_MAP_REFERENCE(PedalBoardItem,instanceId)
|
||||
JSON_MAP_REFERENCE(PedalBoardItem,uri)
|
||||
JSON_MAP_REFERENCE(PedalBoardItem,isEnabled)
|
||||
JSON_MAP_REFERENCE(PedalBoardItem,controlValues)
|
||||
JSON_MAP_REFERENCE(PedalBoardItem,propertyValues)
|
||||
JSON_MAP_REFERENCE(PedalBoardItem,pluginName)
|
||||
JSON_MAP_REFERENCE_CONDITIONAL(PedalBoardItem,topChain,IsPedalBoardSplitItem)
|
||||
JSON_MAP_REFERENCE_CONDITIONAL(PedalBoardItem,bottomChain,&IsPedalBoardSplitItem)
|
||||
|
||||
+29
-1
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "json.hpp"
|
||||
#include "json_variant.hpp"
|
||||
#include "MidiBinding.hpp"
|
||||
|
||||
namespace pipedal {
|
||||
@@ -72,25 +73,52 @@ public:
|
||||
|
||||
|
||||
};
|
||||
class PropertyValue {
|
||||
private:
|
||||
std::string propertyUri_;
|
||||
json_variant value_;
|
||||
public:
|
||||
PropertyValue()
|
||||
{
|
||||
|
||||
class PedalBoardItem: public JsonWritable {
|
||||
}
|
||||
template <typename T>
|
||||
PropertyValue(const std::string&propertyUri, T value)
|
||||
:propertyUri_(propertyUri)
|
||||
, value_(value)
|
||||
{
|
||||
|
||||
}
|
||||
GETTER_SETTER_REF(propertyUri)
|
||||
GETTER_SETTER_REF(value)
|
||||
|
||||
DECLARE_JSON_MAP(PropertyValue);
|
||||
|
||||
|
||||
};
|
||||
|
||||
class PedalBoardItem: public JsonMemberWritable {
|
||||
int64_t instanceId_ = 0;
|
||||
std::string uri_;
|
||||
std::string pluginName_;
|
||||
bool isEnabled_ = true;
|
||||
std::vector<ControlValue> controlValues_;
|
||||
std::vector<PropertyValue> propertyValues_;
|
||||
std::vector<PedalBoardItem> topChain_;
|
||||
std::vector<PedalBoardItem> bottomChain_;
|
||||
std::vector<MidiBinding> midiBindings_;
|
||||
std::string vstState_;
|
||||
public:
|
||||
ControlValue*GetControlValue(const std::string&symbol);
|
||||
PropertyValue*GetPropertyValue(const std::string&propertyUri);
|
||||
|
||||
GETTER_SETTER(instanceId)
|
||||
GETTER_SETTER_REF(uri)
|
||||
GETTER_SETTER_REF(vstState);
|
||||
GETTER_SETTER_REF(pluginName)
|
||||
GETTER_SETTER(isEnabled)
|
||||
GETTER_SETTER_VEC(controlValues)
|
||||
GETTER_SETTER_VEC(propertyValues)
|
||||
GETTER_SETTER_VEC(topChain)
|
||||
GETTER_SETTER_VEC(bottomChain)
|
||||
GETTER_SETTER_VEC(midiBindings)
|
||||
|
||||
+103
-106
@@ -34,6 +34,7 @@
|
||||
#include "lv2.h"
|
||||
#include "lv2/atom.lv2/atom.h"
|
||||
#include "lv2/time/time.h"
|
||||
#include "lv2/state/state.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/port-props/port-props.h"
|
||||
@@ -103,7 +104,6 @@ void PiPedalHost::SetConfiguration(const PiPedalConfiguration &configuration)
|
||||
this->vst3Enabled = configuration.IsVst3Enabled();
|
||||
}
|
||||
|
||||
|
||||
void PiPedalHost::LilvUris::Initialize(LilvWorld *pWorld)
|
||||
{
|
||||
rdfsComment = lilv_new_uri(pWorld, PiPedalHost::RDFS_COMMENT_URI);
|
||||
@@ -124,6 +124,18 @@ void PiPedalHost::LilvUris::Initialize(LilvWorld *pWorld)
|
||||
symbolUri = lilv_new_uri(pWorld, LV2_CORE__symbol);
|
||||
nameUri = lilv_new_uri(pWorld, LV2_CORE__name);
|
||||
|
||||
lv2Core__name = lilv_new_uri(pWorld, LV2_CORE__name);
|
||||
pipedalUI__ui = lilv_new_uri(pWorld, PIPEDAL_UI__ui);
|
||||
pipedalUI__fileProperties = lilv_new_uri(pWorld,PIPEDAL_UI__fileProperties);
|
||||
pipedalUI__patchProperty = lilv_new_uri(pWorld, PIPEDAL_UI__patchProperty);
|
||||
pipedalUI__directory = lilv_new_uri(pWorld,PIPEDAL_UI__directory);
|
||||
pipedalUI__fileTypes = lilv_new_uri(pWorld,PIPEDAL_UI__fileTypes);
|
||||
pipedalUI__fileProperty = lilv_new_uri(pWorld,PIPEDAL_UI__fileProperty);
|
||||
pipedalUI__fileExtension = lilv_new_uri(pWorld, PIPEDAL_UI__fileExtension);
|
||||
pipedalUI__outputPorts = lilv_new_uri(pWorld, PIPEDAL_UI__outputPorts);
|
||||
pipedalUI__text = lilv_new_uri(pWorld, PIPEDAL_UI__text);
|
||||
pipedalUI__defaultFile = lilv_new_uri(pWorld, PIPEDAL_UI__defaultFile);
|
||||
|
||||
time_Position = lilv_new_uri(pWorld, LV2_TIME__Position);
|
||||
time_barBeat = lilv_new_uri(pWorld, LV2_TIME__barBeat);
|
||||
time_beatsPerMinute = lilv_new_uri(pWorld, LV2_TIME__beatsPerMinute);
|
||||
@@ -202,54 +214,6 @@ static float nodeAsFloat(const LilvNode *node, float default_ = 0)
|
||||
return default_;
|
||||
}
|
||||
|
||||
class NodeAutoFree : public LilvNodePtr
|
||||
{
|
||||
|
||||
// const LilvNode* returns must not be freed, by convention.
|
||||
private:
|
||||
NodeAutoFree(const LilvNode *node)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NodeAutoFree()
|
||||
{
|
||||
}
|
||||
NodeAutoFree(LilvNode *node)
|
||||
: LilvNodePtr(node)
|
||||
{
|
||||
}
|
||||
|
||||
float as_float(float defaultValue = 0)
|
||||
{
|
||||
return nodeAsFloat(this->node, defaultValue);
|
||||
}
|
||||
int as_int()
|
||||
{
|
||||
if (node == nullptr)
|
||||
return 0;
|
||||
if (lilv_node_is_int(node))
|
||||
return lilv_node_as_int(node);
|
||||
return 0;
|
||||
}
|
||||
bool as_bool()
|
||||
{
|
||||
if (node == nullptr)
|
||||
return false;
|
||||
if (lilv_node_is_int(node))
|
||||
return lilv_node_as_bool(node);
|
||||
return false;
|
||||
}
|
||||
std::string as_string()
|
||||
{
|
||||
return nodeAsString(this->node);
|
||||
}
|
||||
|
||||
~NodeAutoFree()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
PiPedalHost::PiPedalHost()
|
||||
{
|
||||
pWorld = nullptr;
|
||||
@@ -418,7 +382,7 @@ void PiPedalHost::Load(const char *lv2Path)
|
||||
{
|
||||
const LilvPlugin *lilvPlugin = lilv_plugins_get(plugins, iPlugin);
|
||||
|
||||
std::shared_ptr<Lv2PluginInfo> pluginInfo = std::make_shared<Lv2PluginInfo>(this, lilvPlugin);
|
||||
std::shared_ptr<Lv2PluginInfo> pluginInfo = std::make_shared<Lv2PluginInfo>(this, pWorld, lilvPlugin);
|
||||
|
||||
Lv2Log::debug("Plugin: " + pluginInfo->name());
|
||||
|
||||
@@ -573,7 +537,7 @@ const char *PiPedalHost::RDFS_COMMENT_URI = "http://www.w3.org/2000/01/rdf-schem
|
||||
|
||||
LilvNode *PiPedalHost::get_comment(const std::string &uri)
|
||||
{
|
||||
NodeAutoFree uriNode = lilv_new_uri(pWorld, uri.c_str());
|
||||
AutoLilvNode uriNode = lilv_new_uri(pWorld, uri.c_str());
|
||||
LilvNode *result = lilv_world_get(pWorld, uriNode, lilvUris.rdfsComment, nullptr);
|
||||
return result;
|
||||
}
|
||||
@@ -595,21 +559,19 @@ bool Lv2PluginInfo::HasFactoryPresets(PiPedalHost *lv2Host, const LilvPlugin *pl
|
||||
return result;
|
||||
}
|
||||
|
||||
Lv2PluginInfo::Lv2PluginInfo(PiPedalHost *lv2Host, const LilvPlugin *pPlugin)
|
||||
Lv2PluginInfo::Lv2PluginInfo(PiPedalHost *lv2Host, LilvWorld *pWorld, const LilvPlugin *pPlugin)
|
||||
{
|
||||
const LilvNode *pluginUri = lilv_plugin_get_uri(pPlugin);
|
||||
|
||||
this->has_factory_presets_ = HasFactoryPresets(lv2Host, pPlugin);
|
||||
|
||||
this->uri_ = nodeAsString(lilv_plugin_get_uri(pPlugin));
|
||||
|
||||
NodeAutoFree name = (lilv_plugin_get_name(pPlugin));
|
||||
AutoLilvNode name = (lilv_plugin_get_name(pPlugin));
|
||||
this->name_ = nodeAsString(name);
|
||||
|
||||
NodeAutoFree author_name = (lilv_plugin_get_author_name(pPlugin));
|
||||
AutoLilvNode author_name = (lilv_plugin_get_author_name(pPlugin));
|
||||
this->author_name_ = nodeAsString(author_name);
|
||||
|
||||
NodeAutoFree author_homepage = (lilv_plugin_get_author_homepage(pPlugin));
|
||||
AutoLilvNode author_homepage = (lilv_plugin_get_author_homepage(pPlugin));
|
||||
this->author_homepage_ = nodeAsString(author_homepage);
|
||||
|
||||
const LilvPluginClass *pClass = lilv_plugin_get_class(pPlugin);
|
||||
@@ -627,7 +589,7 @@ Lv2PluginInfo::Lv2PluginInfo(PiPedalHost *lv2Host, const LilvPlugin *pPlugin)
|
||||
NodesAutoFree extensions = lilv_plugin_get_extension_data(pPlugin);
|
||||
this->extensions_ = nodeAsStringArray(extensions);
|
||||
|
||||
NodeAutoFree comment = lv2Host->get_comment(this->uri_);
|
||||
AutoLilvNode comment = lv2Host->get_comment(this->uri_);
|
||||
this->comment_ = nodeAsString(comment);
|
||||
|
||||
uint32_t ports = lilv_plugin_get_num_ports(pPlugin);
|
||||
@@ -671,6 +633,26 @@ Lv2PluginInfo::Lv2PluginInfo(PiPedalHost *lv2Host, const LilvPlugin *pPlugin)
|
||||
|
||||
std::sort(ports_.begin(), ports_.end(), ports_sort_compare);
|
||||
|
||||
// Fetch pipedal plugin UI
|
||||
|
||||
AutoLilvNode pipedalUINode = lilv_world_get(
|
||||
pWorld,
|
||||
lilv_plugin_get_uri(pPlugin),
|
||||
lv2Host->lilvUris.pipedalUI__ui,
|
||||
nullptr);
|
||||
if (pipedalUINode)
|
||||
{
|
||||
this->piPedalUI_ = std::make_shared<PiPedalUI>(lv2Host, pipedalUINode);
|
||||
}
|
||||
// xxx lilv_world_get(pWorld,pluginUri,);
|
||||
// for (auto&portInfo: ports_)
|
||||
// {
|
||||
// if (portInfo->is_control_port() && portInfo->is_output())
|
||||
// {
|
||||
// std::cout << "Dbg: " << "Has an output control port. " << this->uri_ << std::endl;
|
||||
// }
|
||||
// }
|
||||
|
||||
this->is_valid_ = isValid;
|
||||
}
|
||||
|
||||
@@ -684,6 +666,7 @@ std::vector<std::string> supportedFeatures = {
|
||||
LV2_BUF_SIZE__fixedBlockLength,
|
||||
LV2_BUF_SIZE__powerOf2BlockLength,
|
||||
LV2_CORE__isLive,
|
||||
LV2_STATE__loadDefaultState
|
||||
|
||||
};
|
||||
|
||||
@@ -728,16 +711,16 @@ Lv2PortInfo::Lv2PortInfo(PiPedalHost *host, const LilvPlugin *plugin, const Lilv
|
||||
index_ = lilv_port_get_index(plugin, pPort);
|
||||
symbol_ = nodeAsString(lilv_port_get_symbol(plugin, pPort));
|
||||
|
||||
NodeAutoFree name = lilv_port_get_name(plugin, pPort);
|
||||
AutoLilvNode name = lilv_port_get_name(plugin, pPort);
|
||||
name_ = nodeAsString(name);
|
||||
|
||||
classes_ = host->GetPluginPortClass(plugin, pPort);
|
||||
|
||||
NodeAutoFree minNode, maxNode, defaultNode;
|
||||
AutoLilvNode minNode, maxNode, defaultNode;
|
||||
min_value_ = 0;
|
||||
max_value_ = 1;
|
||||
default_value_ = 0;
|
||||
lilv_port_get_range(plugin, pPort, &defaultNode, &minNode, &maxNode);
|
||||
lilv_port_get_range(plugin, pPort, &defaultNode.Get(), &minNode.Get(), &maxNode.Get());
|
||||
if (defaultNode)
|
||||
{
|
||||
default_value_ = getFloat(defaultNode);
|
||||
@@ -812,19 +795,19 @@ Lv2PortInfo::Lv2PortInfo(PiPedalHost *host, const LilvPlugin *plugin, const Lilv
|
||||
supports_midi_ = lilv_port_supports_event(plugin, pPort, host->lilvUris.midiEventNode);
|
||||
supports_time_position_ = lilv_port_supports_event(plugin, pPort, host->lilvUris.time_Position);
|
||||
|
||||
NodeAutoFree designationValue = lilv_port_get(plugin, pPort, host->lilvUris.designationNode);
|
||||
AutoLilvNode designationValue = lilv_port_get(plugin, pPort, host->lilvUris.designationNode);
|
||||
designation_ = nodeAsString(designationValue);
|
||||
|
||||
NodeAutoFree portGroup_value = lilv_port_get(plugin, pPort, host->lilvUris.portGroupUri);
|
||||
AutoLilvNode portGroup_value = lilv_port_get(plugin, pPort, host->lilvUris.portGroupUri);
|
||||
port_group_ = nodeAsString(portGroup_value);
|
||||
|
||||
NodeAutoFree unitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris.unitsUri);
|
||||
AutoLilvNode unitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris.unitsUri);
|
||||
this->units_ = UriToUnits(nodeAsString(unitsValueUri));
|
||||
|
||||
NodeAutoFree commentNode = lilv_port_get(plugin, pPort, host->lilvUris.rdfsComment);
|
||||
AutoLilvNode commentNode = lilv_port_get(plugin, pPort, host->lilvUris.rdfsComment);
|
||||
this->comment_ = nodeAsString(commentNode);
|
||||
|
||||
NodeAutoFree bufferType = lilv_port_get(plugin, pPort, host->lilvUris.bufferType_uri);
|
||||
AutoLilvNode bufferType = lilv_port_get(plugin, pPort, host->lilvUris.bufferType_uri);
|
||||
|
||||
this->buffer_type_ = "";
|
||||
if (bufferType)
|
||||
@@ -953,6 +936,12 @@ Lv2PluginUiInfo::Lv2PluginUiInfo(PiPedalHost *pHost, const Lv2PluginInfo *plugin
|
||||
{
|
||||
this->port_groups_.push_back(Lv2PluginUiPortGroup(portGroup.get()));
|
||||
}
|
||||
auto &piPedalUI = plugin->piPedalUI();
|
||||
|
||||
if (piPedalUI)
|
||||
{
|
||||
this->fileProperties_ = piPedalUI->fileProperties();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Lv2PluginClass> PiPedalHost::GetLv2PluginClass() const
|
||||
@@ -1018,7 +1007,7 @@ std::vector<ControlValue> PiPedalHost::LoadFactoryPluginPreset(
|
||||
|
||||
const LilvPlugins *plugins = lilv_world_get_all_plugins(this->pWorld);
|
||||
|
||||
NodeAutoFree uriNode = lilv_new_uri(pWorld, pedalBoardItem->uri().c_str());
|
||||
AutoLilvNode uriNode = lilv_new_uri(pWorld, pedalBoardItem->uri().c_str());
|
||||
|
||||
lilv_world_load_resource(pWorld, uriNode);
|
||||
|
||||
@@ -1040,7 +1029,7 @@ std::vector<ControlValue> PiPedalHost::LoadFactoryPluginPreset(
|
||||
|
||||
/*********************************/
|
||||
|
||||
// NodeAutoFree uriNode = lilv_new_uri(pWorld, presetUri.c_str());
|
||||
// AutoLilvNode uriNode = lilv_new_uri(pWorld, presetUri.c_str());
|
||||
|
||||
auto lilvState = lilv_state_new_from_world(pWorld, GetLv2UridMap(), preset);
|
||||
|
||||
@@ -1091,7 +1080,7 @@ PluginPresets PiPedalHost::GetFactoryPluginPresets(const std::string &pluginUri)
|
||||
{
|
||||
const LilvPlugins *plugins = lilv_world_get_all_plugins(this->pWorld);
|
||||
|
||||
NodeAutoFree uriNode = lilv_new_uri(pWorld, pluginUri.c_str());
|
||||
AutoLilvNode uriNode = lilv_new_uri(pWorld, pluginUri.c_str());
|
||||
|
||||
lilv_world_load_resource(pWorld, uriNode);
|
||||
|
||||
@@ -1133,7 +1122,7 @@ IEffect *PiPedalHost::CreateEffect(PedalBoardItem &pedalBoardItem)
|
||||
{
|
||||
if (pedalBoardItem.uri().starts_with("vst3:"))
|
||||
{
|
||||
#if ENABLE_VST3
|
||||
#if ENABLE_VST3
|
||||
try
|
||||
{
|
||||
Vst3Effect::Ptr vst3Plugin = this->vst3Host->CreatePlugin(pedalBoardItem, this);
|
||||
@@ -1144,11 +1133,11 @@ IEffect *PiPedalHost::CreateEffect(PedalBoardItem &pedalBoardItem)
|
||||
Lv2Log::error(std::string("Failed to create VST3 plugin: ") + e.what());
|
||||
throw;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
Lv2Log::error(std::string("VST3 support not enabled at compile time."));
|
||||
throw PiPedalException("VST3 support not enabled at compile time, SEE ENABLE_VST3 in CMakeList.txt.");
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1165,13 +1154,19 @@ Lv2PortGroup::Lv2PortGroup(PiPedalHost *lv2Host, const std::string &groupUri)
|
||||
LilvWorld *pWorld = lv2Host->pWorld;
|
||||
|
||||
this->uri_ = groupUri;
|
||||
NodeAutoFree uri = lilv_new_uri(pWorld, groupUri.c_str());
|
||||
AutoLilvNode uri = lilv_new_uri(pWorld, groupUri.c_str());
|
||||
LilvNode *symbolNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris.symbolUri, nullptr);
|
||||
symbol_ = nodeAsString(symbolNode);
|
||||
LilvNode *nameNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris.nameUri, nullptr);
|
||||
name_ = nodeAsString(nameNode);
|
||||
}
|
||||
|
||||
void PiPedalHostLogError(const std::string&errror)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
#define MAP_REF(class, name) \
|
||||
json_map::reference(#name, &class ::name##_)
|
||||
|
||||
@@ -1188,45 +1183,47 @@ json_map::storage_type<Lv2ScalePoint> Lv2ScalePoint::jmap{{
|
||||
json_map::reference("label", &Lv2ScalePoint::label_),
|
||||
}};
|
||||
|
||||
json_map::storage_type<Lv2PortInfo> Lv2PortInfo::jmap{{json_map::reference("index", &Lv2PortInfo::index_),
|
||||
json_map::reference("symbol", &Lv2PortInfo::symbol_),
|
||||
json_map::reference("index", &Lv2PortInfo::index_),
|
||||
json_map::reference("name", &Lv2PortInfo::name_),
|
||||
json_map::storage_type<Lv2PortInfo> Lv2PortInfo::jmap{
|
||||
{json_map::reference("index", &Lv2PortInfo::index_),
|
||||
|
||||
json_map::reference("min_value", &Lv2PortInfo::min_value_),
|
||||
json_map::reference("max_value", &Lv2PortInfo::max_value_),
|
||||
json_map::reference("default_value", &Lv2PortInfo::default_value_),
|
||||
json_map::reference("classes", &Lv2PortInfo::classes_),
|
||||
json_map::reference("symbol", &Lv2PortInfo::symbol_),
|
||||
json_map::reference("index", &Lv2PortInfo::index_),
|
||||
json_map::reference("name", &Lv2PortInfo::name_),
|
||||
|
||||
json_map::reference("scale_points", &Lv2PortInfo::scale_points_),
|
||||
json_map::reference("min_value", &Lv2PortInfo::min_value_),
|
||||
json_map::reference("max_value", &Lv2PortInfo::max_value_),
|
||||
json_map::reference("default_value", &Lv2PortInfo::default_value_),
|
||||
json_map::reference("classes", &Lv2PortInfo::classes_),
|
||||
|
||||
json_map::reference("is_input", &Lv2PortInfo::is_input_),
|
||||
json_map::reference("is_output", &Lv2PortInfo::is_output_),
|
||||
json_map::reference("scale_points", &Lv2PortInfo::scale_points_),
|
||||
|
||||
json_map::reference("is_control_port", &Lv2PortInfo::is_control_port_),
|
||||
json_map::reference("is_audio_port", &Lv2PortInfo::is_audio_port_),
|
||||
json_map::reference("is_atom_port", &Lv2PortInfo::is_audio_port_),
|
||||
json_map::reference("is_cv_port", &Lv2PortInfo::is_cv_port_),
|
||||
json_map::reference("is_input", &Lv2PortInfo::is_input_),
|
||||
json_map::reference("is_output", &Lv2PortInfo::is_output_),
|
||||
|
||||
json_map::reference("is_valid", &Lv2PortInfo::is_valid_),
|
||||
json_map::reference("is_control_port", &Lv2PortInfo::is_control_port_),
|
||||
json_map::reference("is_audio_port", &Lv2PortInfo::is_audio_port_),
|
||||
json_map::reference("is_atom_port", &Lv2PortInfo::is_audio_port_),
|
||||
json_map::reference("is_cv_port", &Lv2PortInfo::is_cv_port_),
|
||||
|
||||
json_map::reference("supports_midi", &Lv2PortInfo::supports_midi_),
|
||||
json_map::reference("supports_time_position", &Lv2PortInfo::supports_time_position_),
|
||||
json_map::reference("port_group", &Lv2PortInfo::port_group_),
|
||||
json_map::reference("is_logarithmic", &Lv2PortInfo::is_logarithmic_),
|
||||
json_map::reference("is_valid", &Lv2PortInfo::is_valid_),
|
||||
|
||||
MAP_REF(Lv2PortInfo, is_logarithmic),
|
||||
MAP_REF(Lv2PortInfo, display_priority),
|
||||
MAP_REF(Lv2PortInfo, range_steps),
|
||||
MAP_REF(Lv2PortInfo, trigger),
|
||||
MAP_REF(Lv2PortInfo, integer_property),
|
||||
MAP_REF(Lv2PortInfo, enumeration_property),
|
||||
MAP_REF(Lv2PortInfo, toggled_property),
|
||||
MAP_REF(Lv2PortInfo, not_on_gui),
|
||||
MAP_REF(Lv2PortInfo, buffer_type),
|
||||
MAP_REF(Lv2PortInfo, port_group),
|
||||
json_map::enum_reference("units", &Lv2PortInfo::units_, get_units_enum_converter()),
|
||||
MAP_REF(Lv2PortInfo, comment)}};
|
||||
json_map::reference("supports_midi", &Lv2PortInfo::supports_midi_),
|
||||
json_map::reference("supports_time_position", &Lv2PortInfo::supports_time_position_),
|
||||
json_map::reference("port_group", &Lv2PortInfo::port_group_),
|
||||
json_map::reference("is_logarithmic", &Lv2PortInfo::is_logarithmic_),
|
||||
|
||||
MAP_REF(Lv2PortInfo, is_logarithmic),
|
||||
MAP_REF(Lv2PortInfo, display_priority),
|
||||
MAP_REF(Lv2PortInfo, range_steps),
|
||||
MAP_REF(Lv2PortInfo, trigger),
|
||||
MAP_REF(Lv2PortInfo, integer_property),
|
||||
MAP_REF(Lv2PortInfo, enumeration_property),
|
||||
MAP_REF(Lv2PortInfo, toggled_property),
|
||||
MAP_REF(Lv2PortInfo, not_on_gui),
|
||||
MAP_REF(Lv2PortInfo, buffer_type),
|
||||
MAP_REF(Lv2PortInfo, port_group),
|
||||
json_map::enum_reference("units", &Lv2PortInfo::units_, get_units_enum_converter()),
|
||||
MAP_REF(Lv2PortInfo, comment)}};
|
||||
|
||||
json_map::storage_type<Lv2PortGroup> Lv2PortGroup::jmap{{
|
||||
MAP_REF(Lv2PortGroup, uri),
|
||||
@@ -1308,5 +1305,5 @@ json_map::storage_type<Lv2PluginUiInfo> Lv2PluginUiInfo::jmap{{
|
||||
json_map::reference("controls", &Lv2PluginUiInfo::controls_),
|
||||
json_map::reference("port_groups", &Lv2PluginUiInfo::port_groups_),
|
||||
json_map::reference("is_vst3", &Lv2PluginUiInfo::is_vst3_),
|
||||
|
||||
json_map::reference("fileProperties",&Lv2PluginUiInfo::fileProperties_)
|
||||
}};
|
||||
|
||||
+584
-554
File diff suppressed because it is too large
Load Diff
+21
-1
@@ -1467,6 +1467,21 @@ void PiPedalModel::UpdateDefaults(PedalBoardItem *pedalBoardItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pPlugin->piPedalUI())
|
||||
{
|
||||
auto&piPedalUi = pPlugin->piPedalUI();
|
||||
for (auto &fileProperty : piPedalUi->fileProperties())
|
||||
{
|
||||
PropertyValue *pValue = pedalBoardItem->GetPropertyValue(fileProperty->patchProperty());
|
||||
if (pValue == nullptr)
|
||||
{
|
||||
// missing? set it to default value
|
||||
pedalBoardItem->propertyValues().push_back(
|
||||
PropertyValue(fileProperty->patchProperty(),fileProperty->defaultFile())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < pedalBoardItem->topChain().size(); ++i)
|
||||
{
|
||||
@@ -1716,4 +1731,9 @@ void PiPedalModel::SetSystemMidiBindings(std::vector<MidiBinding> &bindings)
|
||||
delete[] t;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> PiPedalModel::GetFileList(const PiPedalFileProperty&fileProperty)
|
||||
{
|
||||
return this->storage.GetFileList(PiPedalFilesProperty&fileProperty);
|
||||
}
|
||||
|
||||
@@ -281,6 +281,8 @@ namespace pipedal
|
||||
|
||||
std::map<std::string, bool> GetFavorites() const;
|
||||
void SetFavorites(const std::map<std::string, bool> &favorites);
|
||||
|
||||
std::vector<std::string> GetFileList(const PiPedalFileProperty&fileProperty);
|
||||
};
|
||||
|
||||
} // namespace pipedal.
|
||||
@@ -1246,6 +1246,12 @@ public:
|
||||
std::vector<MidiBinding> bindings = this->model.GetSystemMidiBidings();
|
||||
this->Reply(replyTo,"getSystemMidiBindings",bindings);
|
||||
}
|
||||
else if (message == "requestFileList")
|
||||
{
|
||||
PiPedalFileProperty fileProperty;
|
||||
std::vector<std::string> list = this->model.GetFileList(fileProperty);
|
||||
this->Reply(replyTo,"requestFileList",list);
|
||||
}
|
||||
else
|
||||
{
|
||||
Lv2Log::error("Unknown message received: %s", message.c_str());
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Robin E. R. Davies
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "PiPedalUI.hpp"
|
||||
#include "PiPedalHost.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
PiPedalUI::PiPedalUI(PiPedalHost *pHost, const LilvNode *uiNode)
|
||||
{
|
||||
auto pWorld = pHost->getWorld();
|
||||
|
||||
LilvNodes *fileNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.pipedalUI__fileProperties, nullptr);
|
||||
LILV_FOREACH(nodes, i, fileNodes)
|
||||
{
|
||||
const LilvNode *fileNode = lilv_nodes_get(fileNodes, i);
|
||||
try
|
||||
{
|
||||
PiPedalFileProperty::ptr fileUI = std::make_shared<PiPedalFileProperty>(pHost, fileNode);
|
||||
this->fileProperites_.push_back(std::move(fileUI));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
pHost->LogError(e.what());
|
||||
}
|
||||
}
|
||||
lilv_nodes_free(fileNodes);
|
||||
}
|
||||
|
||||
PiPedalFileType::PiPedalFileType(PiPedalHost*pHost, const LilvNode*node) {
|
||||
auto pWorld = pHost->getWorld();
|
||||
|
||||
AutoLilvNode name = lilv_world_get(
|
||||
pWorld,
|
||||
node,
|
||||
pHost->lilvUris.lv2Core__name,
|
||||
nullptr);
|
||||
if (name)
|
||||
{
|
||||
this->name_ = name.AsString();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("pipedal_ui:fileType is missing name property.");
|
||||
}
|
||||
AutoLilvNode fileExtension = lilv_world_get(
|
||||
pWorld,
|
||||
node,
|
||||
pHost->lilvUris.pipedalUI__fileExtension,
|
||||
nullptr);
|
||||
if (fileExtension)
|
||||
{
|
||||
this->fileExtension_ = fileExtension.AsString();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("pipedal_ui:fileType is missing fileExtension property.");
|
||||
}
|
||||
|
||||
}
|
||||
PiPedalFileProperty::PiPedalFileProperty(PiPedalHost *pHost, const LilvNode *node)
|
||||
{
|
||||
auto pWorld = pHost->getWorld();
|
||||
|
||||
AutoLilvNode name = lilv_world_get(
|
||||
pWorld,
|
||||
node,
|
||||
pHost->lilvUris.lv2Core__name,
|
||||
nullptr);
|
||||
if (name)
|
||||
{
|
||||
this->name_ = name.AsString();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->name_ = "File";
|
||||
}
|
||||
|
||||
AutoLilvNode directory = lilv_world_get(
|
||||
pWorld,
|
||||
node,
|
||||
pHost->lilvUris.pipedalUI__directory,
|
||||
nullptr);
|
||||
if (directory)
|
||||
{
|
||||
this->directory_ = name.AsString();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("PiPedal FileProperty is missing a pipedalui:directory value.");
|
||||
}
|
||||
|
||||
AutoLilvNode patchProperty = lilv_world_get(
|
||||
pWorld,
|
||||
node,
|
||||
pHost->lilvUris.pipedalUI__patchProperty,
|
||||
nullptr);
|
||||
if (patchProperty)
|
||||
{
|
||||
this->patchProperty_ = patchProperty.AsUri();
|
||||
} else {
|
||||
throw std::logic_error("PiPedal FileProperty is missing pipedalui:patchProperty value.");
|
||||
}
|
||||
AutoLilvNode defaultFile = lilv_world_get(
|
||||
pWorld,
|
||||
node,
|
||||
pHost->lilvUris.pipedalUI__defaultFile,
|
||||
nullptr);
|
||||
this->defaultFile_ = defaultFile.AsString();
|
||||
|
||||
|
||||
this->fileTypes_ = PiPedalFileType::GetArray(pHost,node,pHost->lilvUris.pipedalUI__fileTypes);
|
||||
}
|
||||
|
||||
std::vector<PiPedalFileType> PiPedalFileType::GetArray(PiPedalHost*pHost, const LilvNode*node,const LilvNode*uri)
|
||||
{
|
||||
std::vector<PiPedalFileType> result;
|
||||
LilvWorld* pWorld = pHost->getWorld();
|
||||
|
||||
LilvNodes *fileTypeNodes = lilv_world_find_nodes(pWorld, node, pHost->lilvUris.pipedalUI__fileTypes, nullptr);
|
||||
LILV_FOREACH(nodes, i, fileTypeNodes)
|
||||
{
|
||||
const LilvNode *fileTypeNode = lilv_nodes_get(fileTypeNodes, i);
|
||||
try
|
||||
{
|
||||
PiPedalFileType fileType = PiPedalFileType(pHost, fileTypeNode);
|
||||
result.push_back(std::move(fileType));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
pHost->LogError(e.what());
|
||||
}
|
||||
}
|
||||
lilv_nodes_free(fileTypeNodes);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(PiPedalFileType)
|
||||
JSON_MAP_REFERENCE(PiPedalFileType,name)
|
||||
JSON_MAP_REFERENCE(PiPedalFileType,fileExtension)
|
||||
JSON_MAP_END()
|
||||
|
||||
JSON_MAP_BEGIN(PiPedalFileProperty)
|
||||
JSON_MAP_REFERENCE(PiPedalFileProperty,patchProperty)
|
||||
JSON_MAP_REFERENCE(PiPedalFileProperty,name)
|
||||
JSON_MAP_REFERENCE(PiPedalFileProperty,defaultFile)
|
||||
JSON_MAP_REFERENCE(PiPedalFileProperty,fileTypes)
|
||||
JSON_MAP_END()
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Robin E. R. Davies
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <lilv/lilv.h>
|
||||
#include "json.hpp"
|
||||
|
||||
|
||||
#define PIPEDAL_UI "http://github.com/rerdavies/pipedal/ui"
|
||||
#define PIPEDAL_UI_PREFIX PIPEDAL_UI "#"
|
||||
|
||||
#define PIPEDAL_UI__ui PIPEDAL_UI_PREFIX "ui"
|
||||
|
||||
#define PIPEDAL_UI__fileProperties PIPEDAL_UI_PREFIX "fileProperties"
|
||||
|
||||
#define PIPEDAL_UI__fileProperty PIPEDAL_UI_PREFIX "fileProperty"
|
||||
#define PIPEDAL_UI__defaultFile PIPEDAL_UI_PREFIX "defaultFile"
|
||||
#define PIPEDAL_UI__patchProperty PIPEDAL_UI_PREFIX "patchProperty"
|
||||
#define PIPEDAL_UI__directory PIPEDAL_UI_PREFIX "directory"
|
||||
#define PIPEDAL_UI__fileTypes PIPEDAL_UI_PREFIX "fileTypes"
|
||||
|
||||
#define PIPEDAL_UI__fileType PIPEDAL_UI_PREFIX "fileType"
|
||||
#define PIPEDAL_UI__fileExtension PIPEDAL_UI_PREFIX "fileExtension"
|
||||
|
||||
#define PIPEDAL_UI__outputPorts PIPEDAL_UI_PREFIX "outputPorts"
|
||||
#define PIPEDAL_UI__text PIPEDAL_UI_PREFIX "text"
|
||||
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class PiPedalHost;
|
||||
|
||||
class PiPedalFileType {
|
||||
private:
|
||||
std::string name_;
|
||||
std::string fileExtension_;
|
||||
public:
|
||||
PiPedalFileType() { }
|
||||
PiPedalFileType(PiPedalHost*pHost, const LilvNode*node);
|
||||
|
||||
static std::vector<PiPedalFileType> GetArray(PiPedalHost*pHost, const LilvNode*node,const LilvNode*uri);
|
||||
|
||||
const std::string& name() const { return name_;}
|
||||
const std::string &fileExtension() const { return fileExtension_; }
|
||||
|
||||
public:
|
||||
DECLARE_JSON_MAP(PiPedalFileType);
|
||||
|
||||
};
|
||||
|
||||
class PiPedalFileProperty {
|
||||
private:
|
||||
std::string name_;
|
||||
std::string directory_;
|
||||
std::vector<PiPedalFileType> fileTypes_;
|
||||
std::string patchProperty_;
|
||||
std::string defaultFile_;
|
||||
public:
|
||||
using ptr = std::shared_ptr<PiPedalFileProperty>;
|
||||
PiPedalFileProperty() { }
|
||||
PiPedalFileProperty(PiPedalHost*pHost, const LilvNode*node);
|
||||
|
||||
|
||||
const std::string &name() const { return name_; }
|
||||
const std::string &directory() const { return directory_; }
|
||||
const std::string &defaultFile() const { return defaultFile_; }
|
||||
|
||||
const std::vector<PiPedalFileType> &fileTypes() const { return fileTypes_; }
|
||||
|
||||
const std::string &patchProperty() const { return patchProperty_; }
|
||||
public:
|
||||
DECLARE_JSON_MAP(PiPedalFileProperty);
|
||||
};
|
||||
|
||||
class PiPedalUI {
|
||||
public:
|
||||
using ptr = std::shared_ptr<PiPedalUI>;
|
||||
PiPedalUI(PiPedalHost*pHost, const LilvNode*uiNode);
|
||||
const std::vector<PiPedalFileProperty::ptr>& fileProperties() const
|
||||
{
|
||||
return fileProperites_;
|
||||
}
|
||||
private:
|
||||
std::vector<PiPedalFileProperty::ptr> fileProperites_;
|
||||
};
|
||||
};
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "Lv2Log.hpp"
|
||||
#include <map>
|
||||
#include <sys/stat.h>
|
||||
#include "PiPedalUI.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -254,6 +255,11 @@ std::filesystem::path Storage::GetPluginPresetsDirectory() const
|
||||
{
|
||||
return this->dataRoot / "plugin_presets";
|
||||
}
|
||||
std::filesystem::path Storage::GetAudioFilesDirectory() const
|
||||
{
|
||||
return this->dataRoot / "audio_uploads";
|
||||
}
|
||||
|
||||
std::filesystem::path Storage::GetCurrentPresetPath() const
|
||||
{
|
||||
return this->dataRoot / "currentPreset.json";
|
||||
@@ -1383,6 +1389,54 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool containsDotDot(const std::string&value)
|
||||
{
|
||||
std::size_t offset = value.find("..");
|
||||
return offset != std::string::npos;
|
||||
}
|
||||
static bool containsDirectorySeparator(const std::string&value)
|
||||
{
|
||||
if (value.find("/") != std::string::npos) return true; //linux
|
||||
if (value.find("\\") != std::string::npos) return true; // windows
|
||||
if (value.find("::") != std::string::npos) return true; // mac
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool containsNonAlphaNumericCharacter(const std::string&value)
|
||||
{
|
||||
for (char c:value)
|
||||
{
|
||||
if (
|
||||
(c >= '0' && c <= '9')
|
||||
|| (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z)
|
||||
|| (c == '_')
|
||||
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sanityCheckDirectory(const std::string&directory)
|
||||
{
|
||||
// we can afford to be highly restrictive here. Alpha-numeric only.
|
||||
if (containsNonAlphaNumericCharacter(directory))
|
||||
{
|
||||
throw std::logic_error("Invalid directory name.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Storage::GetFileList(const PiPedalFileProperty&fileProperty)
|
||||
{
|
||||
sanityCheckDirectory(fileProperty.directory());
|
||||
std::filesystem::path path = this->GetAudioFilesDirectory() / fileProperty.directory();
|
||||
|
||||
}
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(UserSettings)
|
||||
JSON_MAP_REFERENCE(UserSettings, governor)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class PiPedalFileProperty;
|
||||
|
||||
class CurrentPreset {
|
||||
public:
|
||||
@@ -67,6 +68,7 @@ private:
|
||||
static std::string SafeDecodeName(const std::string& name);
|
||||
std::filesystem::path GetPresetsDirectory() const;
|
||||
std::filesystem::path GetPluginPresetsDirectory() const;
|
||||
std::filesystem::path GetAudioFilesDirectory() const
|
||||
std::filesystem::path GetIndexFileName() const;
|
||||
std::filesystem::path GetBankFileName(const std::string & name) const;
|
||||
std::filesystem::path GetChannelSelectionFileName();
|
||||
@@ -134,6 +136,8 @@ public:
|
||||
void MoveBank(int from, int to);
|
||||
int64_t DeleteBank(int64_t bankId);
|
||||
|
||||
std::vector<std::string> GetFileList(const PiPedalFileProperty&fileProperty);
|
||||
|
||||
|
||||
void SetJackChannelSelection(const JackChannelSelection&channelSelection);
|
||||
const JackChannelSelection&GetJackChannelSelection(const JackConfiguration &jackConfiguration);
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <mutex>
|
||||
#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
|
||||
#include "Lv2Log.hpp"
|
||||
#include <iostream>
|
||||
#include <unistd.h> // for nice()
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -103,6 +105,14 @@ void Worker::EmitResponses()
|
||||
}
|
||||
void Worker::ThreadProc()
|
||||
{
|
||||
// run nice +1 (priority -1 on Windows)
|
||||
errno = 0;
|
||||
nice(1);
|
||||
if (errno != 0)
|
||||
{
|
||||
std::cout << "Warning: Unable to run Lv2 schedule thread at nice +1" << std::endl;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
"http://two-play.com/plugins/toob-power-stage-2": true,
|
||||
"http://two-play.com/plugins/toob-spectrum": true,
|
||||
"http://two-play.com/plugins/toob-tone-stack": true,
|
||||
"http://two-play.com/plugins/toob-tuner": true
|
||||
"http://two-play.com/plugins/toob-tuner": true,
|
||||
"http://two-play.com/plugins/toob-convolution-reverb": true
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <string_view>
|
||||
#include <cctype>
|
||||
#include "PiPedalException.hpp"
|
||||
#include "json_variant.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -631,3 +632,8 @@ void json_reader::throw_format_error(const char*error)
|
||||
throw PiPedalException(message);
|
||||
|
||||
}
|
||||
|
||||
// void json_writer::write(const json_variant &value)
|
||||
// {
|
||||
// ((JsonSerializable *)&value)->write_json(*this);
|
||||
// }
|
||||
|
||||
+888
-839
File diff suppressed because it is too large
Load Diff
+126
-1
@@ -25,6 +25,9 @@
|
||||
|
||||
|
||||
#include "json.hpp"
|
||||
#include "json_variant.hpp"
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -94,6 +97,7 @@ json_map::storage_type<JsonTestTarget> JsonTestTarget::jmap {{
|
||||
|
||||
|
||||
TEST_CASE( "json write", "[json_write_test]" ) {
|
||||
std::cout << "== json write ==" << std::endl;
|
||||
std::stringstream os;
|
||||
json_writer writer { os };
|
||||
|
||||
@@ -101,7 +105,7 @@ TEST_CASE( "json write", "[json_write_test]" ) {
|
||||
|
||||
writer.write(testTarget);
|
||||
|
||||
std::cout << os.str();
|
||||
std::cout << os.str() << std::endl;
|
||||
}
|
||||
|
||||
static std::string get_json()
|
||||
@@ -166,4 +170,125 @@ TEST_CASE( "json smart ptrs", "[json_smart_ptrs][Build][Dev]" ) {
|
||||
reader.read(&sharedPtr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TestVariantRoundTrip(const T &value)
|
||||
{
|
||||
json_variant variant(value);
|
||||
T out = variant.get<T>();
|
||||
REQUIRE(out == value);
|
||||
|
||||
std::string output;
|
||||
{
|
||||
std::stringstream s;
|
||||
json_writer writer(s);
|
||||
writer.write(variant);
|
||||
output = s.str();
|
||||
}
|
||||
std::cout << output << std::endl;
|
||||
|
||||
{
|
||||
std::stringstream s(output);
|
||||
json_reader reader(s);
|
||||
|
||||
json_variant outputVariant;
|
||||
reader.read(&outputVariant);
|
||||
REQUIRE(outputVariant == variant);
|
||||
|
||||
}
|
||||
}
|
||||
void TestVariantRoundTrip(json_variant &value)
|
||||
{
|
||||
json_variant variant(value);
|
||||
REQUIRE(variant == value);
|
||||
|
||||
std::string output;
|
||||
{
|
||||
std::stringstream s;
|
||||
json_writer writer(s);
|
||||
writer.write(variant);
|
||||
output = s.str();
|
||||
}
|
||||
std::cout << output << std::endl;
|
||||
|
||||
json_variant outputVariant;
|
||||
{
|
||||
std::stringstream s(output);
|
||||
json_reader reader(s);
|
||||
|
||||
json_variant outputVariant;
|
||||
reader.read(&outputVariant);
|
||||
REQUIRE(outputVariant == variant);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class X{
|
||||
public:
|
||||
|
||||
template<typename T>
|
||||
requires std::derived_from<T,JsonSerializable>
|
||||
bool write(T &v)
|
||||
{
|
||||
(void)v;
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
bool write(T &v)
|
||||
{
|
||||
(void)v;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void TestVariantSFINAE()
|
||||
{
|
||||
X x;
|
||||
|
||||
|
||||
json_variant v;
|
||||
dynamic_cast<JsonSerializable&>(v);
|
||||
|
||||
REQUIRE(x.write(v) == true);
|
||||
|
||||
int i;
|
||||
REQUIRE(x.write(i) == false);
|
||||
}
|
||||
TEST_CASE( "json variants", "[json_variants][Build][Dev]" ) {
|
||||
TestVariantSFINAE();
|
||||
json_variant v(0);
|
||||
|
||||
TestVariantRoundTrip(json_null());
|
||||
|
||||
TestVariantRoundTrip(0.0);
|
||||
TestVariantRoundTrip(std::string("abc"));
|
||||
|
||||
json_array array;
|
||||
array.push_back(json_null());
|
||||
array.push_back(3.25E19);
|
||||
array.push_back(std::string("abc"));
|
||||
|
||||
json_variant variantArray { std::move(array) };
|
||||
TestVariantRoundTrip(variantArray);
|
||||
|
||||
{
|
||||
json_object obj;
|
||||
obj["a"] = json_null();
|
||||
obj["b"] = 0.25;
|
||||
obj["c"] = std::move(variantArray);
|
||||
json_variant variantObj { std::move(obj)};
|
||||
TestVariantRoundTrip(variantObj);
|
||||
|
||||
variantObj["a"] = std::string("abc");
|
||||
TestVariantRoundTrip(variantObj);
|
||||
}
|
||||
{
|
||||
json_variant x = json_variant::MakeArray();
|
||||
x.resize(3);
|
||||
x[0] = "def";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Robin E. R. Davies
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "json_variant.hpp"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
void concrete_json_variant_base::write_double_value(json_writer &writer,double value) const
|
||||
{
|
||||
if (value < std::numeric_limits<int32_t>::max() && value > std::numeric_limits<int32_t>::min())
|
||||
{
|
||||
double frac = value-(int32_t)value;
|
||||
if (value == 0)
|
||||
{
|
||||
writer.write((int32_t)value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
writer.write(value);
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Robin E. R. Davies
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "json.hpp"
|
||||
|
||||
namespace pipedal
|
||||
{
|
||||
class json_null
|
||||
{
|
||||
public:
|
||||
bool operator==(const json_null&other) const { return true;}
|
||||
private:
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
|
||||
template <class T> // avoid ordering problem in declarations.
|
||||
class json_object_base: public JsonSerializable
|
||||
{
|
||||
public:
|
||||
using json_variant = T;
|
||||
json_object_base() {}
|
||||
|
||||
T &operator[](const std::string &index) { return values[index]; }
|
||||
const T &operator[](const std::string &index) const { return values[index]; }
|
||||
|
||||
public:
|
||||
bool operator==(const json_object_base<T> &other) const
|
||||
{
|
||||
for (const auto &pair: this->values)
|
||||
{
|
||||
auto index = other.values.find(pair.first);
|
||||
if (index == other.values.end()) return false;
|
||||
if (!(index->second == pair.second)) return false;
|
||||
}
|
||||
for (const auto &pair: other.values)
|
||||
{
|
||||
auto index = this->values.find(pair.first);
|
||||
if (index == this->values.end()) return false;
|
||||
if (!(index->second == pair.second)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
virtual void read_json(json_reader&reader) {
|
||||
reader.read(&(this->values));
|
||||
}
|
||||
virtual void write_json(json_writer&writer) const {
|
||||
writer.start_object();
|
||||
bool first = true;
|
||||
for (auto&value: values)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
writer.write_raw(",");
|
||||
}
|
||||
first = false;
|
||||
writer.write(value.first);
|
||||
writer.write_raw(": ");
|
||||
writer.writeRawWritable(value.second);
|
||||
}
|
||||
writer.end_object();
|
||||
}
|
||||
std::map<std::string, T> values;
|
||||
};
|
||||
template <class T> // avoid ordering problem in declarations.
|
||||
class json_array_base: public JsonSerializable
|
||||
{
|
||||
public:
|
||||
json_array_base() {}
|
||||
|
||||
T &operator[](size_t index) {
|
||||
check_index(index);
|
||||
return values[index]; }
|
||||
const T &operator[](size_t &index) const {
|
||||
check_index(index);
|
||||
return values[index];
|
||||
}
|
||||
void resize(size_t size)
|
||||
{
|
||||
values.resize(size);
|
||||
}
|
||||
size_t size() const { return values.size(); }
|
||||
template <typename U>
|
||||
void push_back(const U&value) { values.push_back(value); }
|
||||
template <typename U>
|
||||
void push_back(U&&value) { values.push_back(value); }
|
||||
bool operator==(const json_array_base<T>&other) const
|
||||
{
|
||||
if (!(this->size() == other.size())) return false;
|
||||
for (size_t i = 0; i < this->size(); ++i)
|
||||
{
|
||||
if (!((*this)[i] == other[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
virtual void read_json(json_reader&reader) {
|
||||
reader.read(&(this->values));
|
||||
}
|
||||
virtual void write_json(json_writer&writer) const {
|
||||
writer.start_array();
|
||||
bool first = true;
|
||||
for (auto&value: values)
|
||||
{
|
||||
if (!first) writer.write_raw(",");
|
||||
first = false;
|
||||
writer.writeRawWritable(value);
|
||||
}
|
||||
writer.end_array();
|
||||
}
|
||||
|
||||
void check_index(size_t size) const
|
||||
{
|
||||
if (size >= values.size())
|
||||
{
|
||||
throw std::out_of_range("index out of range.");
|
||||
}
|
||||
}
|
||||
std::vector<T> values;
|
||||
};
|
||||
|
||||
|
||||
class concrete_json_variant_base {
|
||||
protected:
|
||||
void write_double_value(json_writer &writer,double value) const;
|
||||
};
|
||||
|
||||
template <typename DUMMY = void>
|
||||
class json_variant_base
|
||||
: public std::variant<json_null, bool, double, std::string, json_object_base<json_variant_base<DUMMY>>, json_array_base<json_variant_base<DUMMY>>>,
|
||||
public JsonSerializable,
|
||||
private concrete_json_variant_base
|
||||
{
|
||||
public:
|
||||
using base = std::variant<json_null, bool, double, std::string, json_object_base<json_variant_base<DUMMY>>, json_array_base<json_variant_base<DUMMY>>>;
|
||||
using json_object = json_object_base<json_variant_base<DUMMY>>;
|
||||
using json_array = json_array_base<json_variant_base<DUMMY>>;
|
||||
using json_variant = json_variant_base<void>;
|
||||
|
||||
|
||||
json_variant_base(json_null value)
|
||||
:base(value)
|
||||
{
|
||||
|
||||
}
|
||||
json_variant_base(double value)
|
||||
: base(value)
|
||||
{
|
||||
}
|
||||
json_variant_base(int value)
|
||||
: base((double)value)
|
||||
{
|
||||
}
|
||||
json_variant_base(const std::string &value)
|
||||
: base(value)
|
||||
{
|
||||
}
|
||||
json_variant_base(const char*value)
|
||||
:base(std::string(value))
|
||||
{
|
||||
|
||||
}
|
||||
json_variant_base()
|
||||
: base(json_null())
|
||||
{
|
||||
}
|
||||
json_variant_base(json_object &&value)
|
||||
: base(std::forward<json_object>(value))
|
||||
{
|
||||
}
|
||||
json_variant_base(json_array &&value)
|
||||
: base(std::forward<json_array>(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
bool holds_alternative() const { return std::holds_alternative<U>(*this);}
|
||||
|
||||
bool IsNull() const { return holds_alternative<json_null>(); }
|
||||
bool IsBool() const { return holds_alternative<bool>(); }
|
||||
bool IsNumber() const { return holds_alternative<double>(); }
|
||||
bool IsString() const { return holds_alternative<std::string>(); }
|
||||
bool IsObject() const { return holds_alternative<json_object>(); }
|
||||
bool IsArray() const { return holds_alternative<json_array>(); }
|
||||
|
||||
template <typename U>
|
||||
const U &get() const
|
||||
{
|
||||
return std::get<U>(*this);
|
||||
}
|
||||
template <typename U>
|
||||
U &get()
|
||||
{
|
||||
return std::get<U>(*this);
|
||||
}
|
||||
|
||||
bool &AsBool() { return get<bool>(); }
|
||||
bool AsBool() const { return get<bool>(); }
|
||||
|
||||
double &AsNumber() { return get<double>(); }
|
||||
double AsNumber() const { return get<double>(); }
|
||||
std::string &AsString() { return get<std::string>(); }
|
||||
const std::string &AsString() const { return get<std::string>(); }
|
||||
|
||||
json_object &AsObject() { return get<json_object>(); }
|
||||
const json_object &AsObject() const { return get<json_object>(); }
|
||||
|
||||
std::vector<float> AsFloatArray() { return get<json_object>().AsFloatArray(); }
|
||||
std::vector<double> AsDoubleArray() { return get<json_object>().AsDoubleArray(); }
|
||||
|
||||
json_array &AsArray() { return get<json_array>(); }
|
||||
const json_array &AsArray() const { return get<json_array>(); }
|
||||
|
||||
// convenience methods for object and array manipulation.
|
||||
static json_variant MakeObject() { return json_variant{ json_object()};};
|
||||
static json_variant MakeArray() { return json_variant{ json_array()};};
|
||||
|
||||
void resize(size_t size) { AsArray().resize(size); }
|
||||
size_t size() const { return AsArray().size(); }
|
||||
|
||||
json_variant&operator[](size_t index) { return AsArray()[index];}
|
||||
const json_variant&operator[](size_t index) const { return AsArray()[index];}
|
||||
|
||||
const json_variant&operator[](const std::string& index) const { return AsObject()[index];}
|
||||
json_variant&operator[](const std::string& index) { return AsObject()[index];}
|
||||
|
||||
|
||||
private:
|
||||
virtual void read_json(json_reader &reader)
|
||||
{
|
||||
int v = reader.peek();
|
||||
if (v == '[')
|
||||
{
|
||||
json_array array;
|
||||
reader.read(&array);
|
||||
(*this) = std::move(array);
|
||||
} else if (v == '{')
|
||||
{
|
||||
json_object object;
|
||||
reader.read(&object);
|
||||
(*this) = std::move(object);
|
||||
}
|
||||
else if (v == '\"') {
|
||||
std::string s;
|
||||
reader.read(&s);
|
||||
(*this) = std::move(s);
|
||||
} else if (v == 'n')
|
||||
{
|
||||
reader.read_null();
|
||||
(*this) = json_null();
|
||||
|
||||
} else if (v == 't' || v == 'f')
|
||||
{
|
||||
bool b;
|
||||
reader.read(&b);
|
||||
(*this) = b;
|
||||
|
||||
} else {
|
||||
// it's a number.
|
||||
double v;
|
||||
reader.read(&v);
|
||||
(*this) = v;
|
||||
}
|
||||
}
|
||||
virtual void write_json(json_writer&writer) const
|
||||
{
|
||||
switch (this->index())
|
||||
{
|
||||
case 0:
|
||||
writer.write_raw("null");
|
||||
break;
|
||||
case 1:
|
||||
writer.write(this->get<bool>());
|
||||
break;
|
||||
case 2:
|
||||
write_double_value(writer,this->get<double>());
|
||||
break;
|
||||
case 3:
|
||||
writer.write(get<std::string>());
|
||||
break;
|
||||
case 4:
|
||||
writer.writeRawWritable(get<json_object>());
|
||||
break;
|
||||
case 5:
|
||||
writer.writeRawWritable(get<json_array>());
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Invalid variant index");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using json_variant = json_variant_base<void>;
|
||||
using json_object = json_variant::json_object;
|
||||
using json_array = json_variant::json_array;
|
||||
|
||||
} // namespace pipedal
|
||||
Reference in New Issue
Block a user