Fixes to handling of path properties in presets.
This commit is contained in:
@@ -87,6 +87,8 @@ namespace pipedal
|
|||||||
|
|
||||||
json_variant(const void *) = delete; // do NOT allow implicit conversion of pointers to bool
|
json_variant(const void *) = delete; // do NOT allow implicit conversion of pointers to bool
|
||||||
|
|
||||||
|
static json_variant parse(const std::string&text);
|
||||||
|
|
||||||
json_variant &operator=(json_variant &&value);
|
json_variant &operator=(json_variant &&value);
|
||||||
json_variant &operator=(const json_variant &value);
|
json_variant &operator=(const json_variant &value);
|
||||||
json_variant &operator=(bool value);
|
json_variant &operator=(bool value);
|
||||||
|
|||||||
@@ -570,6 +570,15 @@ json_variant::json_variant(json_reader&reader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
json_variant json_variant::parse(const std::string&jsonText)
|
||||||
|
{
|
||||||
|
std::istringstream s(jsonText);
|
||||||
|
json_reader reader(s);
|
||||||
|
json_variant result;
|
||||||
|
reader.read(&result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ json_null json_null::instance;
|
/*static*/ json_null json_null::instance;
|
||||||
/*static*/ int64_t json_array::allocation_count_ = 0; // strictly for testing purposes. not thread safe.
|
/*static*/ int64_t json_array::allocation_count_ = 0; // strictly for testing purposes. not thread safe.
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ set(SDBUSCPP_BUILD_TESTS off)
|
|||||||
add_subdirectory("sdbus-cpp")
|
add_subdirectory("sdbus-cpp")
|
||||||
|
|
||||||
|
|
||||||
|
option(ENABLE_COMMONCRYPTO "Enable use of CommonCrypto" OFF)
|
||||||
|
option(ENABLE_GNUTLS "Enable use of GnuTLS" OFF)
|
||||||
|
option(ENABLE_MBEDTLS "Enable use of mbed TLS" OFF)
|
||||||
|
option(ENABLE_OPENSSL "Enable use of OpenSSL" OFF)
|
||||||
|
option(ENABLE_WINDOWS_CRYPTO "Enable use of Windows cryptography libraries" OFF)
|
||||||
|
|
||||||
|
|
||||||
option(BUILD_TOOLS "Build tools in the src directory (zipcmp, zipmerge, ziptool)" OFF)
|
option(BUILD_TOOLS "Build tools in the src directory (zipcmp, zipmerge, ziptool)" OFF)
|
||||||
option(BUILD_REGRESS "Build regression tests" OFF)
|
option(BUILD_REGRESS "Build regression tests" OFF)
|
||||||
option(BUILD_OSSFUZZ "Build fuzzers for ossfuzz" OFF)
|
option(BUILD_OSSFUZZ "Build fuzzers for ossfuzz" OFF)
|
||||||
|
|||||||
+19
-14
@@ -26,6 +26,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <filesystem>
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include "ss.hpp"
|
#include "ss.hpp"
|
||||||
#include "lv2/atom/util.h"
|
#include "lv2/atom/util.h"
|
||||||
@@ -90,20 +91,21 @@ std::string AtomConverter::ToString(const LV2_Atom*atom)
|
|||||||
}
|
}
|
||||||
json_variant AtomConverter::MapPath(const json_variant&json, const std::string &pluginStoragePath)
|
json_variant AtomConverter::MapPath(const json_variant&json, const std::string &pluginStoragePath)
|
||||||
{
|
{
|
||||||
std::string oType = json[OTYPE_TAG].as_string();
|
if (json.is_null())
|
||||||
if (oType == SHORT_ATOM__Path)
|
|
||||||
{
|
{
|
||||||
std::string path = json["value"].as_string().c_str();
|
return EmptyPath();
|
||||||
if (path.length() == 0 || path[0] == '/')
|
}
|
||||||
{
|
if (json.is_object() && json[OTYPE_TAG].as_string() == SHORT_ATOM__Path)
|
||||||
return json;
|
{
|
||||||
|
std::filesystem::path path = json["value"].as_string();
|
||||||
|
if (path.empty()) {
|
||||||
|
return EmptyPath();
|
||||||
}
|
}
|
||||||
std::string newPath = SS(pluginStoragePath << "/" << path);
|
if (path.is_relative())
|
||||||
json_variant result = json_variant::make_object();
|
{
|
||||||
result[OTYPE_TAG] = json_variant(SHORT_ATOM__Path);
|
path = pluginStoragePath / path;
|
||||||
result["value"] = newPath;
|
}
|
||||||
|
return TypedProperty(SHORT_ATOM__Path,path.string());
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return json;
|
return json;
|
||||||
@@ -111,8 +113,7 @@ json_variant AtomConverter::MapPath(const json_variant&json, const std::string &
|
|||||||
}
|
}
|
||||||
json_variant AtomConverter::AbstractPath(const json_variant&json, const std::string &pluginStoragePath)
|
json_variant AtomConverter::AbstractPath(const json_variant&json, const std::string &pluginStoragePath)
|
||||||
{
|
{
|
||||||
std::string oType = json[OTYPE_TAG].as_string();
|
if (json.is_object() && json[OTYPE_TAG].as_string() == SHORT_ATOM__Path)
|
||||||
if (oType == SHORT_ATOM__Path)
|
|
||||||
{
|
{
|
||||||
std::string path = json["value"].as_string().c_str();
|
std::string path = json["value"].as_string().c_str();
|
||||||
if (path.length() == 0)
|
if (path.length() == 0)
|
||||||
@@ -592,6 +593,10 @@ static bool gEmptyPathInitialized = false;
|
|||||||
static std::mutex gInitMutex;
|
static std::mutex gInitMutex;
|
||||||
std::string gEmptyPathstring;
|
std::string gEmptyPathstring;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
json_variant AtomConverter::gEmptyPath = TypedProperty(SHORT_ATOM__Path,std::string(""));
|
||||||
|
|
||||||
std::string AtomConverter::EmptyPathstring()
|
std::string AtomConverter::EmptyPathstring()
|
||||||
{
|
{
|
||||||
std::lock_guard lock{gInitMutex};
|
std::lock_guard lock{gInitMutex};
|
||||||
|
|||||||
@@ -153,17 +153,21 @@ namespace pipedal
|
|||||||
|
|
||||||
std::string ToString(const LV2_Atom*atom);
|
std::string ToString(const LV2_Atom*atom);
|
||||||
|
|
||||||
json_variant MapPath(const json_variant&json, const std::string &pluginStoragePath);
|
static json_variant MapPath(const json_variant&json, const std::string &pluginStoragePath);
|
||||||
json_variant AbstractPath(const json_variant&json, const std::string &pluginStoragePath);
|
static json_variant AbstractPath(const json_variant&json, const std::string &pluginStoragePath);
|
||||||
|
|
||||||
|
|
||||||
static std::string EmptyPathstring();
|
static std::string EmptyPathstring();
|
||||||
|
static const json_variant& EmptyPath() { return gEmptyPath; }
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const std::string OTYPE_TAG;
|
static const std::string OTYPE_TAG;
|
||||||
static const std::string VTYPE_TAG;
|
static const std::string VTYPE_TAG;
|
||||||
static const std::string ID_TAG;
|
static const std::string ID_TAG;
|
||||||
|
|
||||||
|
static json_variant gEmptyPath;
|
||||||
|
|
||||||
std::map<std::string, LV2_URID> stringToTypeUrid;
|
std::map<std::string, LV2_URID> stringToTypeUrid;
|
||||||
std::map<LV2_URID,std::string> typeUridToString;
|
std::map<LV2_URID,std::string> typeUridToString;
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace pipedal
|
|||||||
int64_t clientId;
|
int64_t clientId;
|
||||||
int64_t instanceId;
|
int64_t instanceId;
|
||||||
LV2_URID uridUri;
|
LV2_URID uridUri;
|
||||||
|
std::string uri;
|
||||||
|
|
||||||
enum class RequestType
|
enum class RequestType
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ using namespace pipedal;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
|
|
||||||
Storage storage;
|
std::unique_ptr<Storage> storage;
|
||||||
|
|
||||||
static std::string GetPluginid(const std::string &pluginUrl)
|
static std::string GetPluginid(const std::string &pluginUrl)
|
||||||
{
|
{
|
||||||
@@ -136,7 +136,7 @@ void WritePrefixes(ofstream &f)
|
|||||||
static void WriteSeeAlso(ofstream &f, const std::string &uri)
|
static void WriteSeeAlso(ofstream &f, const std::string &uri)
|
||||||
{
|
{
|
||||||
std::string id = GetPluginid(uri);
|
std::string id = GetPluginid(uri);
|
||||||
PluginPresets presets = storage.GetPluginPresets(uri);
|
PluginPresets presets = storage->GetPluginPresets(uri);
|
||||||
|
|
||||||
f << "###" << endl;
|
f << "###" << endl;
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ void WritePresetFile(const path &outputDirectory, const std::string &uri)
|
|||||||
|
|
||||||
WritePrefixes(f);
|
WritePrefixes(f);
|
||||||
|
|
||||||
PluginPresets presets = storage.GetPluginPresets(uri);
|
PluginPresets presets = storage->GetPluginPresets(uri);
|
||||||
|
|
||||||
for (size_t i = 0; i < presets.presets_.size(); ++i)
|
for (size_t i = 0; i < presets.presets_.size(); ++i)
|
||||||
{
|
{
|
||||||
@@ -273,6 +273,9 @@ void WritePresetFile(const path &outputDirectory, const std::string &uri)
|
|||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
storage = std::make_unique<Storage>();
|
||||||
|
|
||||||
// A utility for the ToobAmp project which converts Pipedal presets to LV2 presets so
|
// A utility for the ToobAmp project which converts Pipedal presets to LV2 presets so
|
||||||
// that they can be imported as pre-declared presets respective TTL files.
|
// that they can be imported as pre-declared presets respective TTL files.
|
||||||
|
|
||||||
@@ -284,11 +287,11 @@ int main(int argc, const char *argv[])
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
storage.SetConfigRoot("/etc/pipedal/config");
|
storage->SetConfigRoot("/etc/pipedal/config");
|
||||||
storage.SetDataRoot("/var/pipedal");
|
storage->SetDataRoot("/var/pipedal");
|
||||||
storage.Initialize();
|
storage->Initialize();
|
||||||
|
|
||||||
const PluginPresetIndex &index = storage.GetPluginPresetIndex();
|
const PluginPresetIndex &index = storage->GetPluginPresetIndex();
|
||||||
|
|
||||||
std::filesystem::create_directories(outputPath);
|
std::filesystem::create_directories(outputPath);
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ static std::vector<ModFileTypes::ModDirectory> *CreateModDirectories()
|
|||||||
{"sfz", "shared/sfz", "Sfz Files", {".sfz"}}, // SFZ Instruments, must have sfz file extension
|
{"sfz", "shared/sfz", "Sfz Files", {".sfz"}}, // SFZ Instruments, must have sfz file extension
|
||||||
// extensions observed in the field.
|
// extensions observed in the field.
|
||||||
{"audio", "shared/audio", "Audio", {"audio/*"}}, // all audio files (Ratatouille)
|
{"audio", "shared/audio", "Audio", {"audio/*"}}, // all audio files (Ratatouille)
|
||||||
{"nammodel", "NeuralAmpModels", "Neural Amp Models", {".nam"}}, // Ratatouille, Mike's NAM.
|
{"nammodel", "NeuralAmpModels", "Neural Amp Models", {".nam" ,".aidax"}}, // Ratatouille, Mike's NAM.
|
||||||
{"aidadspmodel", "shared/aidaaix", "AIDA IAX Models", {".json", ".aidaiax"}}, // Ratatouille
|
{"aidadspmodel", "shared/aidaaix", "AIDA IAX Models", {".json", ".aidaiax"}}, // Ratatouille
|
||||||
{"mlmodel", "ToobMlModels", "ML Models", {".json"}}, //
|
{"mlmodel", "ToobMlModels", "ML Models", {".json"}}, //
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ public:
|
|||||||
GETTER_SETTER_VEC(bottomChain)
|
GETTER_SETTER_VEC(bottomChain)
|
||||||
GETTER_SETTER_VEC(midiBindings)
|
GETTER_SETTER_VEC(midiBindings)
|
||||||
GETTER_SETTER_REF(midiChannelBinding)
|
GETTER_SETTER_REF(midiChannelBinding)
|
||||||
|
GETTER_SETTER_REF(pathProperties)
|
||||||
GETTER_SETTER(stateUpdateCount)
|
GETTER_SETTER(stateUpdateCount)
|
||||||
GETTER_SETTER_REF(lv2State)
|
GETTER_SETTER_REF(lv2State)
|
||||||
GETTER_SETTER_REF(title)
|
GETTER_SETTER_REF(title)
|
||||||
@@ -134,6 +135,8 @@ public:
|
|||||||
GETTER_SETTER_REF(lilvPresetUri)
|
GETTER_SETTER_REF(lilvPresetUri)
|
||||||
|
|
||||||
PropertyMap&PatchProperties() { return patchProperties; }
|
PropertyMap&PatchProperties() { return patchProperties; }
|
||||||
|
const PropertyMap&PatchProperties() const { return patchProperties; }
|
||||||
|
|
||||||
|
|
||||||
bool isSplit() const
|
bool isSplit() const
|
||||||
{
|
{
|
||||||
|
|||||||
+54
-19
@@ -1721,23 +1721,20 @@ void PiPedalModel::SendSetPatchProperty(
|
|||||||
|
|
||||||
// save the property to the preset (currently used to reconstruct snapshots only)
|
// save the property to the preset (currently used to reconstruct snapshots only)
|
||||||
PedalboardItem *pedalboardItem = this->pedalboard.GetItem(instanceId);
|
PedalboardItem *pedalboardItem = this->pedalboard.GetItem(instanceId);
|
||||||
if (pedalboardItem && value.is_string())
|
if (pedalboardItem)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Lv2PluginInfo> pluginInfo = GetPluginInfo(pedalboardItem->uri_);
|
std::shared_ptr<Lv2PluginInfo> pluginInfo = GetPluginInfo(pedalboardItem->uri_);
|
||||||
auto pipedalUi = pluginInfo->piPedalUI();
|
auto pipedalUi = pluginInfo->piPedalUI();
|
||||||
auto fileProperty = pipedalUi->GetFileProperty(propertyUri);
|
auto fileProperty = pipedalUi->GetFileProperty(propertyUri);
|
||||||
if (fileProperty && value.is_string())
|
if (fileProperty)
|
||||||
{
|
{
|
||||||
|
|
||||||
json_variant abstractPath = pluginHost.AbstractPath(value);
|
json_variant abstractPath = pluginHost.AbstractPath(value);
|
||||||
std::ostringstream ss;
|
std::string atomString = abstractPath.to_string();
|
||||||
json_writer writer(ss);
|
|
||||||
writer.write(abstractPath);
|
|
||||||
std::string atomString = ss.str();
|
|
||||||
pedalboardItem->pathProperties_[propertyUri] = atomString;
|
pedalboardItem->pathProperties_[propertyUri] = atomString;
|
||||||
}
|
}
|
||||||
this->SetPresetChanged(clientId, true);
|
this->SetPresetChanged(clientId, true);
|
||||||
}
|
}
|
||||||
LV2_Atom *atomValue = atomConverter.ToAtom(value);
|
LV2_Atom *atomValue = atomConverter.ToAtom(value);
|
||||||
|
|
||||||
std::function<void(RealtimePatchPropertyRequest *)> onRequestComplete{
|
std::function<void(RealtimePatchPropertyRequest *)> onRequestComplete{
|
||||||
@@ -1827,7 +1824,24 @@ void PiPedalModel::SendGetPatchProperty(
|
|||||||
{
|
{
|
||||||
if (pParameter->onError)
|
if (pParameter->onError)
|
||||||
{
|
{
|
||||||
pParameter->onError("No response.");
|
// For plugins that don't respond (e.g. a buncha MOD plugins), use the value we last set on the plugin!
|
||||||
|
bool foundValue = false;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
|
auto pedalboardItem = this->pedalboard.GetItem(pParameter->instanceId);
|
||||||
|
if (pedalboardItem) {
|
||||||
|
if (pedalboardItem->pathProperties_.contains(pParameter->uri))
|
||||||
|
{
|
||||||
|
pParameter->jsonResponse = pedalboardItem->pathProperties_[pParameter->uri];
|
||||||
|
if (pParameter->onSuccess) {
|
||||||
|
foundValue = true;
|
||||||
|
pParameter->onSuccess(pParameter->jsonResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundValue)
|
||||||
|
{
|
||||||
|
pParameter->onError("No response.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1854,6 +1868,7 @@ void PiPedalModel::SendGetPatchProperty(
|
|||||||
RealtimePatchPropertyRequest *request = new RealtimePatchPropertyRequest(
|
RealtimePatchPropertyRequest *request = new RealtimePatchPropertyRequest(
|
||||||
onRequestComplete,
|
onRequestComplete,
|
||||||
clientId, instanceId, urid, onSuccess, onError, sampleTimeout);
|
clientId, instanceId, urid, onSuccess, onError, sampleTimeout);
|
||||||
|
request->uri = uri;
|
||||||
|
|
||||||
outstandingParameterRequests.push_back(request);
|
outstandingParameterRequests.push_back(request);
|
||||||
this->audioHost->sendRealtimeParameterRequest(request);
|
this->audioHost->sendRealtimeParameterRequest(request);
|
||||||
@@ -2058,14 +2073,24 @@ void PiPedalModel::UpdateDefaults(PedalboardItem *pedalboardItem, std::unordered
|
|||||||
if (pPlugin->piPedalUI())
|
if (pPlugin->piPedalUI())
|
||||||
{
|
{
|
||||||
PiPedalUI::ptr piPedalUI = pPlugin->piPedalUI();
|
PiPedalUI::ptr piPedalUI = pPlugin->piPedalUI();
|
||||||
|
std::set<std::string> validFileProperties;
|
||||||
for (auto &fileProperty : piPedalUI->fileProperties())
|
for (auto &fileProperty : piPedalUI->fileProperties())
|
||||||
{
|
{
|
||||||
|
validFileProperties.insert(fileProperty->patchProperty());
|
||||||
if (!pedalboardItem->pathProperties_.contains(fileProperty->patchProperty()))
|
if (!pedalboardItem->pathProperties_.contains(fileProperty->patchProperty()))
|
||||||
{
|
{
|
||||||
// make sure each pedalboard item has a complete list of path properties, even if it doesn't yet have values.
|
// make sure each pedalboard item has a complete list of path properties, even if it doesn't yet have values.
|
||||||
pedalboardItem->pathProperties_[fileProperty->patchProperty()] = "null";
|
pedalboardItem->pathProperties_[fileProperty->patchProperty()] = "null";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto i = pedalboardItem->pathProperties_.begin(); i != pedalboardItem->pathProperties_.end(); /**/)
|
||||||
|
{
|
||||||
|
if (!validFileProperties.contains(i->first)) {
|
||||||
|
i = pedalboardItem->pathProperties_.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2162,8 +2187,9 @@ void PiPedalModel::LoadPluginPreset(int64_t pluginInstanceId, uint64_t presetIns
|
|||||||
this->pedalboard.SetControlValue(pluginInstanceId, control.key(), control.value());
|
this->pedalboard.SetControlValue(pluginInstanceId, control.key(), control.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!presetValues.state.isValid_) && presetValues.lilvPresetUri.empty())
|
if ((!presetValues.state.isValid_) && presetValues.lilvPresetUri.empty() && presetValues.pathProperties.empty())
|
||||||
{
|
{
|
||||||
|
// fast path for control changes only.
|
||||||
audioHost->SetPluginPreset(pluginInstanceId, presetValues.controls);
|
audioHost->SetPluginPreset(pluginInstanceId, presetValues.controls);
|
||||||
|
|
||||||
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
||||||
@@ -2177,6 +2203,7 @@ void PiPedalModel::LoadPluginPreset(int64_t pluginInstanceId, uint64_t presetIns
|
|||||||
pedalboardItem->lv2State(presetValues.state);
|
pedalboardItem->lv2State(presetValues.state);
|
||||||
pedalboardItem->lilvPresetUri(presetValues.lilvPresetUri);
|
pedalboardItem->lilvPresetUri(presetValues.lilvPresetUri);
|
||||||
pedalboardItem->stateUpdateCount(oldStateUpdateCount + 1);
|
pedalboardItem->stateUpdateCount(oldStateUpdateCount + 1);
|
||||||
|
pedalboardItem->pathProperties(presetValues.pathProperties);
|
||||||
FirePedalboardChanged(-1); // does a complete reload of both client and audio server.
|
FirePedalboardChanged(-1); // does a complete reload of both client and audio server.
|
||||||
}
|
}
|
||||||
this->SetPresetChanged(-1, true);
|
this->SetPresetChanged(-1, true);
|
||||||
@@ -2297,7 +2324,8 @@ void PiPedalModel::OnNotifyPathPatchPropertyReceived(
|
|||||||
auto i = pedalboardItem->pathProperties_.find(pathPatchPropertyUri);
|
auto i = pedalboardItem->pathProperties_.find(pathPatchPropertyUri);
|
||||||
if (i != pedalboardItem->pathProperties_.end())
|
if (i != pedalboardItem->pathProperties_.end())
|
||||||
{
|
{
|
||||||
pedalboardItem->pathProperties_[pathPatchPropertyUri] = atomString;
|
std::string abstractAtomString = storage.ToAbstractPathJson(atomString);
|
||||||
|
pedalboardItem->pathProperties_[pathPatchPropertyUri] = abstractAtomString;
|
||||||
|
|
||||||
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
||||||
for (auto &subscriber : t)
|
for (auto &subscriber : t)
|
||||||
@@ -2305,7 +2333,7 @@ void PiPedalModel::OnNotifyPathPatchPropertyReceived(
|
|||||||
subscriber->OnNotifyPathPatchPropertyChanged(
|
subscriber->OnNotifyPathPatchPropertyChanged(
|
||||||
instanceId,
|
instanceId,
|
||||||
pathPatchPropertyUri,
|
pathPatchPropertyUri,
|
||||||
atomString);
|
abstractAtomString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2382,16 +2410,23 @@ void PiPedalModel::MonitorPatchProperty(int64_t clientId, int64_t clientHandle,
|
|||||||
PedalboardItem *item = this->pedalboard.GetItem(instanceId);
|
PedalboardItem *item = this->pedalboard.GetItem(instanceId);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
auto &map = item->PatchProperties();
|
auto &map = item->pathProperties();
|
||||||
if (map.contains(propertyUri))
|
if (map.contains(propertyUri))
|
||||||
{
|
{
|
||||||
const auto &value = map[propertyUri];
|
const auto &value = map.at(propertyUri);
|
||||||
std::string json = this->audioHost->AtomToJson(value.get());
|
if (value != "null") {
|
||||||
for (auto &subscriber : this->subscribers)
|
try {
|
||||||
{
|
std::string json = storage.FromAbstractPathJson(value);
|
||||||
if (subscriber->GetClientId() == clientId)
|
|
||||||
{
|
for (auto &subscriber : this->subscribers)
|
||||||
subscriber->OnNotifyPatchProperty(clientHandle, instanceId, propertyUri, json);
|
{
|
||||||
|
if (subscriber->GetClientId() == clientId)
|
||||||
|
{
|
||||||
|
subscriber->OnNotifyPatchProperty(clientHandle, instanceId, propertyUri, json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception& ignored) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,7 +279,8 @@ namespace pipedal
|
|||||||
Decrease
|
Decrease
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GetHasWifi();
|
Storage&GetStorage() { return storage; }
|
||||||
|
bool GetHasWifi();
|
||||||
|
|
||||||
void NextBank(Direction direction = Direction::Increase);
|
void NextBank(Direction direction = Direction::Increase);
|
||||||
void PreviousBank() { NextBank(Direction::Decrease); }
|
void PreviousBank() { NextBank(Direction::Decrease); }
|
||||||
|
|||||||
+26
-17
@@ -49,7 +49,7 @@
|
|||||||
#include "StdErrorCapture.hpp"
|
#include "StdErrorCapture.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "ModFileTypes.hpp"
|
#include "ModFileTypes.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Locale.hpp"
|
#include "Locale.hpp"
|
||||||
|
|
||||||
@@ -304,7 +304,6 @@ PluginHost::PluginHost()
|
|||||||
lv2Features.push_back(nullptr);
|
lv2Features.push_back(nullptr);
|
||||||
|
|
||||||
this->urids = new Urids(mapFeature);
|
this->urids = new Urids(mapFeature);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginHost::OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings)
|
void PluginHost::OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings)
|
||||||
@@ -660,13 +659,14 @@ static std::vector<UiFileType> ToPiPedalFileTypes(
|
|||||||
std::string type = fileType;
|
std::string type = fileType;
|
||||||
if (type.find("/") != std::string::npos) // mime type?
|
if (type.find("/") != std::string::npos) // mime type?
|
||||||
{
|
{
|
||||||
UiFileType t = UiFileType(type,type,"");
|
UiFileType t = UiFileType(type, type, "");
|
||||||
result.push_back(t);
|
result.push_back(t);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add a leading dot.
|
// add a leading dot.
|
||||||
if (!type.starts_with(".")) {
|
if (!type.starts_with("."))
|
||||||
|
{
|
||||||
type = "." + type;
|
type = "." + type;
|
||||||
}
|
}
|
||||||
auto t = UiFileType(SS(type << " file"), type);
|
auto t = UiFileType(SS(type << " file"), type);
|
||||||
@@ -776,7 +776,8 @@ Lv2PluginInfo::FindWritablePathProperties(PluginHost *lv2Host, const LilvPlugin
|
|||||||
auto modDirectory = modFileTypes.GetModDirectory(modName);
|
auto modDirectory = modFileTypes.GetModDirectory(modName);
|
||||||
fileProperty->directory(modDirectory->pipedalPath);
|
fileProperty->directory(modDirectory->pipedalPath);
|
||||||
std::set<std::string> fileExtensions = modDirectory->fileExtensions;
|
std::set<std::string> fileExtensions = modDirectory->fileExtensions;
|
||||||
if (!modFileExtensions.empty()) {
|
if (!modFileExtensions.empty())
|
||||||
|
{
|
||||||
auto extensions = split(modFileExtensions, ',');
|
auto extensions = split(modFileExtensions, ',');
|
||||||
fileExtensions = std::set<std::string>(extensions.begin(), extensions.end());
|
fileExtensions = std::set<std::string>(extensions.begin(), extensions.end());
|
||||||
}
|
}
|
||||||
@@ -879,7 +880,6 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP
|
|||||||
this->plugin_class_ = "http://lv2plug.in/ns/lv2core#Plugin";
|
this->plugin_class_ = "http://lv2plug.in/ns/lv2core#Plugin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoLilvNodes required_features = lilv_plugin_get_required_features(pPlugin);
|
AutoLilvNodes required_features = lilv_plugin_get_required_features(pPlugin);
|
||||||
this->required_features_ = nodeAsStringArray(required_features);
|
this->required_features_ = nodeAsStringArray(required_features);
|
||||||
|
|
||||||
@@ -1236,18 +1236,19 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP
|
|||||||
if (unitsValueUri)
|
if (unitsValueUri)
|
||||||
{
|
{
|
||||||
this->units_ = UriToUnits(nodeAsString(unitsValueUri));
|
this->units_ = UriToUnits(nodeAsString(unitsValueUri));
|
||||||
if (this->units_ == Units::unknown) {
|
if (this->units_ == Units::unknown)
|
||||||
|
{
|
||||||
// try for a custom format string.
|
// try for a custom format string.
|
||||||
AutoLilvNode render = lilv_world_get(
|
AutoLilvNode render = lilv_world_get(
|
||||||
pWorld,
|
pWorld,
|
||||||
unitsValueUri,
|
unitsValueUri,
|
||||||
host->lilvUris->units__render,
|
host->lilvUris->units__render,
|
||||||
nullptr);
|
nullptr);
|
||||||
if (render) {
|
if (render)
|
||||||
const char*strRender = lilv_node_as_string(render);
|
{
|
||||||
|
const char *strRender = lilv_node_as_string(render);
|
||||||
custom_units_ = strRender;
|
custom_units_ = strRender;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1630,7 +1631,13 @@ PluginPresets PluginHost::GetFactoryPluginPresets(const std::string &pluginUri)
|
|||||||
{
|
{
|
||||||
if (!cbData.failed)
|
if (!cbData.failed)
|
||||||
{
|
{
|
||||||
result.presets_.push_back(PluginPreset(result.nextInstanceId_++, strLabel, controlValues, Lv2PluginState()));
|
result.presets_.push_back(
|
||||||
|
PluginPreset(
|
||||||
|
result.nextInstanceId_++,
|
||||||
|
strLabel,
|
||||||
|
controlValues,
|
||||||
|
std::map<std::string, std::string>(),
|
||||||
|
Lv2PluginState()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1904,11 +1911,13 @@ Lv2PatchPropertyInfo::Lv2PatchPropertyInfo(PluginHost *pluginHost, const LilvNod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ffs.
|
// ffs.
|
||||||
static inline bool contains(const std::vector<std::string> &vec, const std::string &value) {
|
static inline bool contains(const std::vector<std::string> &vec, const std::string &value)
|
||||||
return std::find(vec.begin(),vec.end(),value) != vec.end();
|
{
|
||||||
|
return std::find(vec.begin(), vec.end(), value) != vec.end();
|
||||||
}
|
}
|
||||||
bool Lv2PluginInfo::WantsWorkerThread() const {
|
bool Lv2PluginInfo::WantsWorkerThread() const
|
||||||
return contains(this->required_features_,LV2_WORKER__schedule) || contains(this->supported_features_,LV2_WORKER__schedule);
|
{
|
||||||
|
return contains(this->required_features_, LV2_WORKER__schedule) || contains(this->supported_features_, LV2_WORKER__schedule);
|
||||||
}
|
}
|
||||||
// void PiPedalHostLogError(const std::string &error)
|
// void PiPedalHostLogError(const std::string &error)
|
||||||
// {
|
// {
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ JSON_MAP_BEGIN(PluginPreset)
|
|||||||
JSON_MAP_REFERENCE(PluginPreset,instanceId)
|
JSON_MAP_REFERENCE(PluginPreset,instanceId)
|
||||||
JSON_MAP_REFERENCE(PluginPreset,label)
|
JSON_MAP_REFERENCE(PluginPreset,label)
|
||||||
JSON_MAP_REFERENCE(PluginPreset,controlValues)
|
JSON_MAP_REFERENCE(PluginPreset,controlValues)
|
||||||
|
JSON_MAP_REFERENCE(PluginPreset,pathProperties)
|
||||||
JSON_MAP_REFERENCE(PluginPreset,state)
|
JSON_MAP_REFERENCE(PluginPreset,state)
|
||||||
JSON_MAP_REFERENCE(PluginPreset,lilvPresetUri)
|
JSON_MAP_REFERENCE(PluginPreset,lilvPresetUri)
|
||||||
JSON_MAP_END()
|
JSON_MAP_END()
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public:
|
|||||||
PluginPreset(uint64_t instanceId, const std::string&label,const PedalboardItem&pedalboardItem)
|
PluginPreset(uint64_t instanceId, const std::string&label,const PedalboardItem&pedalboardItem)
|
||||||
: instanceId_(instanceId)
|
: instanceId_(instanceId)
|
||||||
, label_(label)
|
, label_(label)
|
||||||
|
, pathProperties_(pedalboardItem.pathProperties())
|
||||||
, state_(pedalboardItem.lv2State())
|
, state_(pedalboardItem.lv2State())
|
||||||
{
|
{
|
||||||
for (auto & controlValue : pedalboardItem.controlValues())
|
for (auto & controlValue : pedalboardItem.controlValues())
|
||||||
@@ -89,10 +90,12 @@ public:
|
|||||||
const std::string&label,
|
const std::string&label,
|
||||||
const std::map<std::string,
|
const std::map<std::string,
|
||||||
float> & controlValues,
|
float> & controlValues,
|
||||||
|
const std::map<std::string,std::string>&pathProperties,
|
||||||
const Lv2PluginState &state)
|
const Lv2PluginState &state)
|
||||||
: instanceId_(instanceId),
|
: instanceId_(instanceId),
|
||||||
label_(label),
|
label_(label),
|
||||||
controlValues_((controlValues)),
|
controlValues_((controlValues)),
|
||||||
|
pathProperties_(pathProperties),
|
||||||
state_(state)
|
state_(state)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -117,7 +120,9 @@ public:
|
|||||||
std::string label_;
|
std::string label_;
|
||||||
std::string lilvPresetUri_;
|
std::string lilvPresetUri_;
|
||||||
std::map<std::string,float> controlValues_;
|
std::map<std::string,float> controlValues_;
|
||||||
|
std::map<std::string,std::string> pathProperties_;
|
||||||
Lv2PluginState state_;
|
Lv2PluginState state_;
|
||||||
|
|
||||||
DECLARE_JSON_MAP(PluginPreset);
|
DECLARE_JSON_MAP(PluginPreset);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+64
-10
@@ -40,6 +40,7 @@
|
|||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "AudioFiles.hpp"
|
#include "AudioFiles.hpp"
|
||||||
#include "Utf8Utils.hpp"
|
#include "Utf8Utils.hpp"
|
||||||
|
#include "AtomConverter.hpp"
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@@ -189,6 +190,7 @@ void Storage::SetConfigRoot(const std::filesystem::path &path)
|
|||||||
void Storage::SetDataRoot(const std::filesystem::path &path)
|
void Storage::SetDataRoot(const std::filesystem::path &path)
|
||||||
{
|
{
|
||||||
this->dataRoot = ResolveHomePath(path);
|
this->dataRoot = ResolveHomePath(path);
|
||||||
|
this->dataRoot__audio_uploads = dataRoot / "audio_uploads";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::filesystem::path &Storage::GetConfigRoot()
|
const std::filesystem::path &Storage::GetConfigRoot()
|
||||||
@@ -302,9 +304,9 @@ std::filesystem::path Storage::GetPluginPresetsDirectory() const
|
|||||||
{
|
{
|
||||||
return this->dataRoot / "plugin_presets";
|
return this->dataRoot / "plugin_presets";
|
||||||
}
|
}
|
||||||
std::filesystem::path Storage::GetPluginUploadDirectory() const
|
const std::filesystem::path &Storage::GetPluginUploadDirectory() const
|
||||||
{
|
{
|
||||||
return this->dataRoot / "audio_uploads";
|
return dataRoot__audio_uploads;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path Storage::GetCurrentPresetPath() const
|
std::filesystem::path Storage::GetCurrentPresetPath() const
|
||||||
@@ -1409,6 +1411,10 @@ PluginPresetValues Storage::GetPluginPresetValues(const std::string &pluginUri,
|
|||||||
{
|
{
|
||||||
result.controls.push_back(ControlValue(valuePair.first.c_str(), valuePair.second));
|
result.controls.push_back(ControlValue(valuePair.first.c_str(), valuePair.second));
|
||||||
}
|
}
|
||||||
|
for (const auto&pair: preset.pathProperties_)
|
||||||
|
{
|
||||||
|
result.pathProperties[pair.first] = pair.second;
|
||||||
|
}
|
||||||
result.state = preset.state_;
|
result.state = preset.state_;
|
||||||
result.lilvPresetUri = preset.lilvPresetUri_;
|
result.lilvPresetUri = preset.lilvPresetUri_;
|
||||||
return result;
|
return result;
|
||||||
@@ -1417,6 +1423,31 @@ PluginPresetValues Storage::GetPluginPresetValues(const std::string &pluginUri,
|
|||||||
throw PiPedalException("Plugin preset not found.");
|
throw PiPedalException("Plugin preset not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Storage::ToAbstractPaths(PluginPreset &pluginPreset)
|
||||||
|
{
|
||||||
|
if (pluginPreset.pathProperties_.size() != 0)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> newPathProperties;
|
||||||
|
for (const auto &pair : pluginPreset.pathProperties_)
|
||||||
|
{
|
||||||
|
newPathProperties[pair.first] = this->ToAbstractPathJson(pair.second);
|
||||||
|
}
|
||||||
|
pluginPreset.pathProperties_ = newPathProperties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Storage::FromAbstractPaths(PluginPreset &pluginPreset)
|
||||||
|
{
|
||||||
|
if (pluginPreset.pathProperties_.size() != 0)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> newPathProperties;
|
||||||
|
for (const auto &pair : pluginPreset.pathProperties_)
|
||||||
|
{
|
||||||
|
newPathProperties[pair.first] = this->FromAbstractPathJson(pair.second);
|
||||||
|
}
|
||||||
|
pluginPreset.pathProperties_ = newPathProperties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t Storage::SavePluginPreset(
|
uint64_t Storage::SavePluginPreset(
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
const PedalboardItem &pedalboardItem)
|
const PedalboardItem &pedalboardItem)
|
||||||
@@ -1425,6 +1456,7 @@ uint64_t Storage::SavePluginPreset(
|
|||||||
auto presets = GetPluginPresets(pluginUri);
|
auto presets = GetPluginPresets(pluginUri);
|
||||||
uint64_t result = -1;
|
uint64_t result = -1;
|
||||||
bool existing = false;
|
bool existing = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < presets.presets_.size(); ++i)
|
for (size_t i = 0; i < presets.presets_.size(); ++i)
|
||||||
{
|
{
|
||||||
auto &preset = presets.presets_[i];
|
auto &preset = presets.presets_[i];
|
||||||
@@ -1432,6 +1464,8 @@ uint64_t Storage::SavePluginPreset(
|
|||||||
{
|
{
|
||||||
existing = true;
|
existing = true;
|
||||||
result = preset.instanceId_;
|
result = preset.instanceId_;
|
||||||
|
PluginPreset pluginPreset{preset.instanceId_, preset.label_, pedalboardItem};
|
||||||
|
|
||||||
presets.presets_[i] = PluginPreset(preset.instanceId_, preset.label_, pedalboardItem);
|
presets.presets_[i] = PluginPreset(preset.instanceId_, preset.label_, pedalboardItem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1439,10 +1473,12 @@ uint64_t Storage::SavePluginPreset(
|
|||||||
if (!existing)
|
if (!existing)
|
||||||
{
|
{
|
||||||
result = presets.nextInstanceId_++;
|
result = presets.nextInstanceId_++;
|
||||||
presets.presets_.push_back(
|
auto preset = PluginPreset(
|
||||||
PluginPreset(result,
|
result,
|
||||||
name,
|
name,
|
||||||
pedalboardItem));
|
pedalboardItem);
|
||||||
|
ToAbstractPaths(preset);
|
||||||
|
presets.presets_.push_back(preset);
|
||||||
}
|
}
|
||||||
this->SavePluginPresets(pluginUri, presets);
|
this->SavePluginPresets(pluginUri, presets);
|
||||||
return result;
|
return result;
|
||||||
@@ -1451,9 +1487,8 @@ uint64_t Storage::SavePluginPreset(
|
|||||||
uint64_t Storage::SavePluginPreset(
|
uint64_t Storage::SavePluginPreset(
|
||||||
const std::string &pluginUri,
|
const std::string &pluginUri,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
float inputVolume,
|
|
||||||
float outputVolume,
|
|
||||||
const std::map<std::string, float> &values,
|
const std::map<std::string, float> &values,
|
||||||
|
const std::map<std::string,std::string> &pathProperties,
|
||||||
const Lv2PluginState &lv2State)
|
const Lv2PluginState &lv2State)
|
||||||
{
|
{
|
||||||
auto presets = GetPluginPresets(pluginUri);
|
auto presets = GetPluginPresets(pluginUri);
|
||||||
@@ -1466,6 +1501,7 @@ uint64_t Storage::SavePluginPreset(
|
|||||||
{
|
{
|
||||||
existing = true;
|
existing = true;
|
||||||
preset.controlValues_ = values;
|
preset.controlValues_ = values;
|
||||||
|
preset.pathProperties_ = pathProperties;
|
||||||
preset.state_ = lv2State;
|
preset.state_ = lv2State;
|
||||||
|
|
||||||
result = preset.instanceId_;
|
result = preset.instanceId_;
|
||||||
@@ -1480,6 +1516,7 @@ uint64_t Storage::SavePluginPreset(
|
|||||||
result,
|
result,
|
||||||
name,
|
name,
|
||||||
values,
|
values,
|
||||||
|
pathProperties,
|
||||||
lv2State));
|
lv2State));
|
||||||
}
|
}
|
||||||
this->SavePluginPresets(pluginUri, presets);
|
this->SavePluginPresets(pluginUri, presets);
|
||||||
@@ -1533,7 +1570,7 @@ uint64_t Storage::CopyPluginPreset(const std::string &pluginUri, uint64_t preset
|
|||||||
size_t pos = presets.Find(presetId);
|
size_t pos = presets.Find(presetId);
|
||||||
if (pos == -1)
|
if (pos == -1)
|
||||||
{
|
{
|
||||||
throw PiPedalException("Perset not found.");
|
throw PiPedalException("Preset not found.");
|
||||||
}
|
}
|
||||||
PluginPreset t = presets.presets_[pos];
|
PluginPreset t = presets.presets_[pos];
|
||||||
t.instanceId_ = presets.nextInstanceId_++;
|
t.instanceId_ = presets.nextInstanceId_++;
|
||||||
@@ -1922,7 +1959,7 @@ static void AddTracksToResult(
|
|||||||
FileRequestResult Storage::GetModFileList2(const std::string &relativePath, const UiFileProperty &fileProperty)
|
FileRequestResult Storage::GetModFileList2(const std::string &relativePath, const UiFileProperty &fileProperty)
|
||||||
{
|
{
|
||||||
FileRequestResult result;
|
FileRequestResult result;
|
||||||
fs::path uploadsDirectory = GetPluginUploadDirectory();
|
const fs::path &uploadsDirectory = GetPluginUploadDirectory();
|
||||||
|
|
||||||
if (relativePath.empty())
|
if (relativePath.empty())
|
||||||
{
|
{
|
||||||
@@ -2651,6 +2688,23 @@ std::string Storage::GetTone3000Auth() const
|
|||||||
return tone3000Auth;
|
return tone3000Auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Storage::ToAbstractPathJson(const std::string &pathJson)
|
||||||
|
{
|
||||||
|
json_variant v = json_variant::parse(pathJson);
|
||||||
|
|
||||||
|
v = AtomConverter::AbstractPath(v,GetPluginUploadDirectory().string());
|
||||||
|
|
||||||
|
return v.to_string();
|
||||||
|
}
|
||||||
|
std::string Storage::FromAbstractPathJson(const std::string &pathJson)
|
||||||
|
{
|
||||||
|
json_variant v = json_variant::parse(pathJson);
|
||||||
|
|
||||||
|
v = AtomConverter::MapPath(v,GetPluginUploadDirectory().string());
|
||||||
|
|
||||||
|
return v.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
JSON_MAP_BEGIN(UserSettings)
|
JSON_MAP_BEGIN(UserSettings)
|
||||||
JSON_MAP_REFERENCE(UserSettings, governor)
|
JSON_MAP_REFERENCE(UserSettings, governor)
|
||||||
JSON_MAP_REFERENCE(UserSettings, showStatusMonitor)
|
JSON_MAP_REFERENCE(UserSettings, showStatusMonitor)
|
||||||
|
|||||||
+13
-4
@@ -60,15 +60,19 @@ public:
|
|||||||
struct PluginPresetValues {
|
struct PluginPresetValues {
|
||||||
|
|
||||||
std::vector<ControlValue> controls;
|
std::vector<ControlValue> controls;
|
||||||
|
std::map<std::string,std::string> pathProperties;
|
||||||
Lv2PluginState state;
|
Lv2PluginState state;
|
||||||
std::string lilvPresetUri;
|
std::string lilvPresetUri;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// controls user-defined storage. Implmentation hidden to allow to later migration to a database (perhaps)
|
// controls user-defined storage. Implmentation hidden to allow to later migration to a database (perhaps)
|
||||||
|
|
||||||
class Storage {
|
class Storage {
|
||||||
private:
|
private:
|
||||||
std::filesystem::path dataRoot;
|
std::filesystem::path dataRoot;
|
||||||
|
std::filesystem::path dataRoot__audio_uploads;
|
||||||
|
|
||||||
std::filesystem::path configRoot;
|
std::filesystem::path configRoot;
|
||||||
BankIndex bankIndex;
|
BankIndex bankIndex;
|
||||||
BankFile currentBank;
|
BankFile currentBank;
|
||||||
@@ -125,7 +129,11 @@ public:
|
|||||||
const std::filesystem::path&GetConfigRoot();
|
const std::filesystem::path&GetConfigRoot();
|
||||||
const std::filesystem::path&GetDataRoot();
|
const std::filesystem::path&GetDataRoot();
|
||||||
|
|
||||||
std::filesystem::path GetPluginUploadDirectory() const;
|
const std::filesystem::path &GetPluginUploadDirectory() const;
|
||||||
|
|
||||||
|
std::string ToAbstractPathJson(const std::string &jsonAtomPath);
|
||||||
|
std::string FromAbstractPathJson(const std::string &jsonAtomPath);
|
||||||
|
|
||||||
|
|
||||||
//std::vector<std::string> GetPedalboards();
|
//std::vector<std::string> GetPedalboards();
|
||||||
|
|
||||||
@@ -208,6 +216,8 @@ private:
|
|||||||
std::filesystem::path GetPluginPresetPath(const std::string &pluginUri) const;
|
std::filesystem::path GetPluginPresetPath(const std::string &pluginUri) const;
|
||||||
bool IsValidSampleFileName(const std::filesystem::path&fileName);
|
bool IsValidSampleFileName(const std::filesystem::path&fileName);
|
||||||
std::filesystem::path MakeUserFilePath(const std::string &directory, const std::string&filename);
|
std::filesystem::path MakeUserFilePath(const std::string &directory, const std::string&filename);
|
||||||
|
void ToAbstractPaths(PluginPreset&pluginPreset);
|
||||||
|
void FromAbstractPaths(PluginPreset&pluginPreset);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool HasPluginPresets(const std::string&pluginUri) const;
|
bool HasPluginPresets(const std::string&pluginUri) const;
|
||||||
@@ -227,9 +237,8 @@ public:
|
|||||||
uint64_t SavePluginPreset(
|
uint64_t SavePluginPreset(
|
||||||
const std::string &pluginUri,
|
const std::string &pluginUri,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
float inputVolume,
|
|
||||||
float outputVolume,
|
|
||||||
const std::map<std::string, float> &values,
|
const std::map<std::string, float> &values,
|
||||||
|
const std::map<std::string,std::string>&pathProperties,
|
||||||
const Lv2PluginState& lv2State);
|
const Lv2PluginState& lv2State);
|
||||||
|
|
||||||
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ public:
|
|||||||
|
|
||||||
res.set(HttpField::content_type, "application/json");
|
res.set(HttpField::content_type, "application/json");
|
||||||
res.set(HttpField::cache_control, "no-cache");
|
res.set(HttpField::cache_control, "no-cache");
|
||||||
fs::path path = request_uri.query("path");
|
fs::path path = model->GetStorage().FromAbstractPathJson(request_uri.query("path"));
|
||||||
|
|
||||||
if (!fs::exists(path) || !this->model->IsInUploadsDirectory(path) || HasDotDot(path))
|
if (!fs::exists(path) || !this->model->IsInUploadsDirectory(path) || HasDotDot(path))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,26 +1,12 @@
|
|||||||
|
|
||||||
ffmpeg -ss <start_time> -i input.mp4 -filter_complex "loop=loop=<num_loops>:size=<frame_count>:start=<start_frame>" output.mp4
|
|
||||||
-ss <start_time>: Seeks to the desired start point (e.g., 00:00:10 or 10).
|
|
||||||
loop=<num_loops>: Number of times to loop the segment (e.g., 3 for 4 total plays).
|
|
||||||
size=<frame_count>: The number of frames in the segment to loop.
|
|
||||||
start=<start_frame>: The starting frame of the segment to loop within the input.
|
|
||||||
Note: This method requires re-encoding, as filters are applied.
|
|
||||||
3. Looping a single image:
|
|
||||||
To loop a single image for a specific duration, use the -loop option with the image demuxer:
|
|
||||||
Code
|
|
||||||
|
|
||||||
|
|
||||||
Use ffmpeg
|
|
||||||
Check ToOB Cab SIM F/R range.
|
|
||||||
|
|
||||||
Convert CRVB presets!
|
|
||||||
|
|
||||||
double select on double-click/ok in file dialog.
|
double select on double-click/ok in file dialog.
|
||||||
sudo apt install libbz2-dev
|
sudo apt install libbz2-dev
|
||||||
Move status to pedalboard view.
|
|
||||||
Default to dark theme.
|
README, license files in file browser.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ls
|
||||||
Carla Project icons.
|
Carla Project icons.
|
||||||
check reload after change of LV2 plugins.
|
check reload after change of LV2 plugins.
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const modDirectories: ModDirectory[] = [
|
|||||||
{modType: "sfz", pipedalPath: "shared/sfz",displayName: "Sfz Files", defaultFileExtensions: [".sfz"]}, // SFZ Instruments, must have sfz file extension
|
{modType: "sfz", pipedalPath: "shared/sfz",displayName: "Sfz Files", defaultFileExtensions: [".sfz"]}, // SFZ Instruments, must have sfz file extension
|
||||||
// extensions observed in the field.
|
// extensions observed in the field.
|
||||||
{modType: "audio", pipedalPath: "shared/audio", displayName: "Audio", defaultFileExtensions: ["audio/*"]}, // all audio files (Ratatoille)
|
{modType: "audio", pipedalPath: "shared/audio", displayName: "Audio", defaultFileExtensions: ["audio/*"]}, // all audio files (Ratatoille)
|
||||||
{modType: "nammodel", pipedalPath: "NeuralAmpModels", displayName: "Neural Amp Models", defaultFileExtensions: [".nam"]}, // Ratatoille, Mike's NAM.
|
{modType: "nammodel", pipedalPath: "NeuralAmpModels", displayName: "Neural Amp Models", defaultFileExtensions: [".nam","aidax"]}, // Ratatoille, Mike's NAM.
|
||||||
{modType: "aidadspmodel", pipedalPath: "shared/aidaaix", displayName: "AIDA IAX Models", defaultFileExtensions: [".json", ".aidaiax"]}, // Ratatoille
|
{modType: "aidadspmodel", pipedalPath: "shared/aidaaix", displayName: "AIDA IAX Models", defaultFileExtensions: [".json", ".aidaiax"]}, // Ratatoille
|
||||||
{modType: "mlmodel", pipedalPath: "ToobMlModels", displayName: "ML Models", defaultFileExtensions: [".json"]}, //
|
{modType: "mlmodel", pipedalPath: "ToobMlModels", displayName: "ML Models", defaultFileExtensions: [".json"]}, //
|
||||||
|
|
||||||
|
|||||||
@@ -2623,7 +2623,8 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
let pedalboard = this.pedalboard.get();
|
let pedalboard = this.pedalboard.get();
|
||||||
try {
|
try {
|
||||||
let pedalboardItem = pedalboard.tryGetItem(instanceId);
|
let pedalboardItem = pedalboard.tryGetItem(instanceId);
|
||||||
if (pedalboardItem) {
|
|
||||||
|
if (pedalboardItem && pedalboardItem.pathProperties[propertyUri] !== undefined) {
|
||||||
pedalboardItem.pathProperties[propertyUri] = JSON.stringify(jsonObject);
|
pedalboardItem.pathProperties[propertyUri] = JSON.stringify(jsonObject);
|
||||||
}
|
}
|
||||||
} catch (ignored) {
|
} catch (ignored) {
|
||||||
|
|||||||
Reference in New Issue
Block a user