Import Prests from Bank
This commit is contained in:
+299
-271
@@ -23,316 +23,344 @@
|
||||
#include "Pedalboard.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
|
||||
namespace pipedal {
|
||||
namespace pipedal
|
||||
{
|
||||
|
||||
#define GETTER_SETTER_REF(name) \
|
||||
decltype(name##_)& name() { return name##_;} \
|
||||
const decltype(name##_)& name() const { return name##_;} \
|
||||
#define GETTER_SETTER_REF(name) \
|
||||
decltype(name##_) &name() { return name##_; } \
|
||||
const decltype(name##_) &name() const { return name##_; } \
|
||||
void name(const decltype(name##_) &value) { name##_ = value; }
|
||||
|
||||
#define GETTER_SETTER_VEC(name) \
|
||||
decltype(name##_)& name() { return name##_;} \
|
||||
const decltype(name##_)& name() const { return name##_;}
|
||||
#define GETTER_SETTER_VEC(name) \
|
||||
decltype(name##_) &name() { return name##_; } \
|
||||
const decltype(name##_) &name() const { return name##_; }
|
||||
|
||||
|
||||
#define GETTER_SETTER(name) \
|
||||
decltype(name##_) name() const { return name##_;} \
|
||||
#define GETTER_SETTER(name) \
|
||||
decltype(name##_) name() const { return name##_; } \
|
||||
void name(decltype(name##_) value) { name##_ = value; }
|
||||
|
||||
class PresetIndexEntry
|
||||
{
|
||||
int64_t instanceId_ = 0;
|
||||
std::string name_;
|
||||
|
||||
class PresetIndexEntry {
|
||||
int64_t instanceId_ = 0;
|
||||
std::string name_;
|
||||
public:
|
||||
GETTER_SETTER(instanceId);
|
||||
GETTER_SETTER(name);
|
||||
DECLARE_JSON_MAP(PresetIndexEntry);
|
||||
};
|
||||
|
||||
class PresetIndex {
|
||||
int64_t selectedInstanceId_ = -1;
|
||||
bool presetChanged_ = false;
|
||||
std::vector<PresetIndexEntry> presets_;
|
||||
public:
|
||||
bool GetPresetName(int64_t instanceId, std::string*pResult) {
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
public:
|
||||
PresetIndexEntry() {}
|
||||
PresetIndexEntry(uint64_t instanceId, const std::string &name)
|
||||
: instanceId_(instanceId), name_(name)
|
||||
{
|
||||
if (presets_[i].instanceId() == instanceId)
|
||||
}
|
||||
|
||||
GETTER_SETTER(instanceId);
|
||||
GETTER_SETTER(name);
|
||||
DECLARE_JSON_MAP(PresetIndexEntry);
|
||||
};
|
||||
|
||||
class PresetIndex
|
||||
{
|
||||
int64_t selectedInstanceId_ = -1;
|
||||
bool presetChanged_ = false;
|
||||
std::vector<PresetIndexEntry> presets_;
|
||||
|
||||
public:
|
||||
bool GetPresetName(int64_t instanceId, std::string *pResult)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
*pResult = presets_[i].name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
GETTER_SETTER(selectedInstanceId);
|
||||
GETTER_SETTER_VEC(presets);
|
||||
GETTER_SETTER(presetChanged);
|
||||
|
||||
DECLARE_JSON_MAP(PresetIndex);
|
||||
};
|
||||
|
||||
|
||||
class BankFileEntry {
|
||||
int64_t instanceId_;
|
||||
Pedalboard preset_;
|
||||
public:
|
||||
GETTER_SETTER(instanceId);
|
||||
GETTER_SETTER_REF(preset);
|
||||
|
||||
DECLARE_JSON_MAP(BankFileEntry);
|
||||
};
|
||||
class BankFile {
|
||||
std::string name_;
|
||||
int64_t nextInstanceId_ = 0;
|
||||
int64_t selectedPreset_ = -1;
|
||||
std::vector<std::unique_ptr<BankFileEntry>> presets_;
|
||||
|
||||
public:
|
||||
GETTER_SETTER(name);
|
||||
GETTER_SETTER(nextInstanceId);
|
||||
GETTER_SETTER(selectedPreset);
|
||||
GETTER_SETTER_VEC(presets);
|
||||
|
||||
void clear()
|
||||
{
|
||||
nextInstanceId_ = 0;
|
||||
presets_.clear();
|
||||
selectedPreset_ = -1;
|
||||
}
|
||||
|
||||
void move(size_t from, size_t to)
|
||||
{
|
||||
if (from >= this->presets_.size()) {
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
if (to >= this->presets_.size()) {
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
std::unique_ptr<BankFileEntry> t = std::move(this->presets_[from]);
|
||||
presets_.erase(presets_.begin()+from);
|
||||
presets_.insert(presets_.begin()+to,std::move(t));
|
||||
}
|
||||
void updateNextIndex() {
|
||||
int64_t t = 0;
|
||||
for (size_t i = 0; i < this->presets_.size(); ++i)
|
||||
{
|
||||
int64_t instanceId = this->presets_[i]->instanceId();
|
||||
if (instanceId > t) t = instanceId;
|
||||
|
||||
}
|
||||
this->nextInstanceId_ = t;
|
||||
}
|
||||
int64_t addPreset(const Pedalboard&preset, int64_t afterItem = -1)
|
||||
{
|
||||
if (hasName(preset.name()))
|
||||
{
|
||||
throw PiPedalStateException("A preset by that name already exists.");
|
||||
}
|
||||
std::unique_ptr<BankFileEntry> entry = std::make_unique<BankFileEntry>();
|
||||
entry->instanceId(++nextInstanceId_);
|
||||
entry->preset(preset);
|
||||
int64_t instanceId = entry->instanceId();
|
||||
if (afterItem == -1)
|
||||
{
|
||||
this->presets_.push_back(std::move(entry));
|
||||
} else {
|
||||
for (auto it = this->presets_.begin(); it != this->presets_.end(); ++it)
|
||||
{
|
||||
if ((*it)->instanceId() == afterItem)
|
||||
if (presets_[i].instanceId() == instanceId)
|
||||
{
|
||||
++it;
|
||||
this->presets_.insert(it,std::move(entry));
|
||||
break;
|
||||
*pResult = presets_[i].name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return instanceId;
|
||||
}
|
||||
bool hasItem(int64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool hasName(const std::string &name) {
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i]->preset().name() == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool renamePreset(int64_t instanceId, const std::string&name)
|
||||
{
|
||||
if (hasName(name))
|
||||
{
|
||||
throw PiPedalStateException("A preset by that name already exists.");
|
||||
}
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i]->instanceId() ==instanceId)
|
||||
{
|
||||
presets_[i]->preset().name(name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
GETTER_SETTER(selectedInstanceId);
|
||||
GETTER_SETTER_VEC(presets);
|
||||
GETTER_SETTER(presetChanged);
|
||||
|
||||
}
|
||||
DECLARE_JSON_MAP(PresetIndex);
|
||||
};
|
||||
|
||||
BankFileEntry &getItem(int64_t instanceId)
|
||||
class BankFileEntry
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
int64_t instanceId_;
|
||||
Pedalboard preset_;
|
||||
|
||||
public:
|
||||
GETTER_SETTER(instanceId);
|
||||
GETTER_SETTER_REF(preset);
|
||||
|
||||
DECLARE_JSON_MAP(BankFileEntry);
|
||||
};
|
||||
class BankFile
|
||||
{
|
||||
std::string name_;
|
||||
int64_t nextInstanceId_ = 0;
|
||||
int64_t selectedPreset_ = -1;
|
||||
std::vector<std::unique_ptr<BankFileEntry>> presets_;
|
||||
|
||||
public:
|
||||
GETTER_SETTER(name);
|
||||
GETTER_SETTER(nextInstanceId);
|
||||
GETTER_SETTER(selectedPreset);
|
||||
GETTER_SETTER_VEC(presets);
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
{
|
||||
return *(presets_[i].get());
|
||||
}
|
||||
nextInstanceId_ = 0;
|
||||
presets_.clear();
|
||||
selectedPreset_ = -1;
|
||||
}
|
||||
throw PiPedalArgumentException("Instance not found.");
|
||||
}
|
||||
int64_t deletePreset(int64_t instanceId) {
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
|
||||
void move(size_t from, size_t to)
|
||||
{
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
if (from >= this->presets_.size())
|
||||
{
|
||||
presets_.erase(presets_.begin()+i);
|
||||
int64_t newSelection;
|
||||
if (i < presets_.size())
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
if (to >= this->presets_.size())
|
||||
{
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
std::unique_ptr<BankFileEntry> t = std::move(this->presets_[from]);
|
||||
presets_.erase(presets_.begin() + from);
|
||||
presets_.insert(presets_.begin() + to, std::move(t));
|
||||
}
|
||||
void updateNextIndex()
|
||||
{
|
||||
int64_t t = 0;
|
||||
for (size_t i = 0; i < this->presets_.size(); ++i)
|
||||
{
|
||||
int64_t instanceId = this->presets_[i]->instanceId();
|
||||
if (instanceId > t)
|
||||
t = instanceId;
|
||||
}
|
||||
this->nextInstanceId_ = t;
|
||||
}
|
||||
int64_t addPreset(const Pedalboard &preset, int64_t afterItem = -1)
|
||||
{
|
||||
if (hasName(preset.name()))
|
||||
{
|
||||
throw PiPedalStateException("A preset by that name already exists.");
|
||||
}
|
||||
std::unique_ptr<BankFileEntry> entry = std::make_unique<BankFileEntry>();
|
||||
entry->instanceId(++nextInstanceId_);
|
||||
entry->preset(preset);
|
||||
int64_t instanceId = entry->instanceId();
|
||||
if (afterItem == -1)
|
||||
{
|
||||
this->presets_.push_back(std::move(entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto it = this->presets_.begin(); it != this->presets_.end(); ++it)
|
||||
{
|
||||
newSelection = presets_[i]->instanceId();
|
||||
} else if (presets_.size() > 1) {
|
||||
newSelection = presets_[0]->instanceId();
|
||||
} else {
|
||||
// zero length? We can never have a zero-length bank.
|
||||
// Add a default preset and make it the selected preset.
|
||||
Pedalboard pedalboard = Pedalboard::MakeDefault();
|
||||
this->addPreset(pedalboard);
|
||||
newSelection = presets_[0]->instanceId();
|
||||
if ((*it)->instanceId() == afterItem)
|
||||
{
|
||||
++it;
|
||||
this->presets_.insert(it, std::move(entry));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (instanceId == this->selectedPreset_)
|
||||
}
|
||||
return instanceId;
|
||||
}
|
||||
bool hasItem(int64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
{
|
||||
this->selectedPreset_ = newSelection;
|
||||
return true;
|
||||
}
|
||||
return newSelection;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
throw PiPedalStateException("Preset not found.");
|
||||
}
|
||||
|
||||
DECLARE_JSON_MAP(BankFile);
|
||||
};
|
||||
|
||||
class BankIndexEntry {
|
||||
int64_t instanceId_ = 0;
|
||||
std::string name_;
|
||||
public:
|
||||
GETTER_SETTER(instanceId);
|
||||
GETTER_SETTER_REF(name);
|
||||
|
||||
DECLARE_JSON_MAP(BankIndexEntry);
|
||||
};
|
||||
|
||||
class BankIndex {
|
||||
int64_t selectedBank_ = 0;
|
||||
int64_t nextInstanceId_ = 0;
|
||||
std::vector<BankIndexEntry> entries_;
|
||||
public:
|
||||
GETTER_SETTER(selectedBank);
|
||||
GETTER_SETTER_VEC(entries);
|
||||
|
||||
DECLARE_JSON_MAP(BankIndex);
|
||||
|
||||
bool hasName(const std::string&name) const {
|
||||
for (size_t i = 0; i < this->entries_.size(); ++i)
|
||||
bool hasName(const std::string &name)
|
||||
{
|
||||
if (this->entries_[i].name() == name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void move(size_t from, size_t to)
|
||||
{
|
||||
if (from >= this->entries_.size()) {
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
if (to >= this->entries_.size()) {
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
BankIndexEntry t = std::move(this->entries_[from]);
|
||||
entries_.erase(entries_.begin()+from);
|
||||
entries_.insert(entries_.begin()+to,std::move(t));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
entries_.clear();
|
||||
selectedBank_ = 0;
|
||||
}
|
||||
int64_t addBank(int64_t afterId,const std::string& name)
|
||||
{
|
||||
BankIndexEntry bank;
|
||||
bank.name(name);
|
||||
bank.instanceId(++nextInstanceId_);
|
||||
|
||||
for (size_t i = 0; i < this->entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].instanceId() == afterId)
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
entries_.insert(entries_.begin()+(i+1), bank);
|
||||
return bank.instanceId();
|
||||
if (presets_[i]->preset().name() == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// else at the end.
|
||||
entries_.push_back(bank);
|
||||
return bank.instanceId();
|
||||
}
|
||||
BankIndexEntry* getEntryByName(const std::string &name)
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); ++i)
|
||||
bool renamePreset(int64_t instanceId, const std::string &name)
|
||||
{
|
||||
if (entries_[i].name() == name)
|
||||
if (hasName(name))
|
||||
{
|
||||
return &entries_[i];
|
||||
throw PiPedalStateException("A preset by that name already exists.");
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
BankIndexEntry&getBankIndexEntry(int64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].instanceId() == instanceId)
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
return entries_[i];
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
{
|
||||
presets_[i]->preset().name(name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
throw PiPedalArgumentException("Bank not found.");
|
||||
}
|
||||
const BankIndexEntry&getBankIndexEntry(int64_t instanceId) const
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].instanceId() == instanceId)
|
||||
{
|
||||
return entries_[i];
|
||||
}
|
||||
}
|
||||
throw PiPedalArgumentException("Bank not found.");
|
||||
}
|
||||
|
||||
};
|
||||
BankFileEntry &getItem(int64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
{
|
||||
return *(presets_[i].get());
|
||||
}
|
||||
}
|
||||
throw PiPedalArgumentException("Instance not found.");
|
||||
}
|
||||
int64_t deletePreset(int64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i]->instanceId() == instanceId)
|
||||
{
|
||||
presets_.erase(presets_.begin() + i);
|
||||
int64_t newSelection;
|
||||
if (i < presets_.size())
|
||||
{
|
||||
newSelection = presets_[i]->instanceId();
|
||||
}
|
||||
else if (presets_.size() > 1)
|
||||
{
|
||||
newSelection = presets_[0]->instanceId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// zero length? We can never have a zero-length bank.
|
||||
// Add a default preset and make it the selected preset.
|
||||
Pedalboard pedalboard = Pedalboard::MakeDefault();
|
||||
this->addPreset(pedalboard);
|
||||
newSelection = presets_[0]->instanceId();
|
||||
}
|
||||
if (instanceId == this->selectedPreset_)
|
||||
{
|
||||
this->selectedPreset_ = newSelection;
|
||||
}
|
||||
return newSelection;
|
||||
}
|
||||
}
|
||||
throw PiPedalStateException("Preset not found.");
|
||||
}
|
||||
|
||||
DECLARE_JSON_MAP(BankFile);
|
||||
};
|
||||
|
||||
class BankIndexEntry
|
||||
{
|
||||
int64_t instanceId_ = 0;
|
||||
std::string name_;
|
||||
|
||||
public:
|
||||
GETTER_SETTER(instanceId);
|
||||
GETTER_SETTER_REF(name);
|
||||
|
||||
DECLARE_JSON_MAP(BankIndexEntry);
|
||||
};
|
||||
|
||||
class BankIndex
|
||||
{
|
||||
int64_t selectedBank_ = 0;
|
||||
int64_t nextInstanceId_ = 0;
|
||||
std::vector<BankIndexEntry> entries_;
|
||||
|
||||
public:
|
||||
GETTER_SETTER(selectedBank);
|
||||
GETTER_SETTER_VEC(entries);
|
||||
|
||||
DECLARE_JSON_MAP(BankIndex);
|
||||
|
||||
bool hasName(const std::string &name) const
|
||||
{
|
||||
for (size_t i = 0; i < this->entries_.size(); ++i)
|
||||
{
|
||||
if (this->entries_[i].name() == name)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void move(size_t from, size_t to)
|
||||
{
|
||||
if (from >= this->entries_.size())
|
||||
{
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
if (to >= this->entries_.size())
|
||||
{
|
||||
throw std::invalid_argument("Argument out of range.");
|
||||
}
|
||||
BankIndexEntry t = std::move(this->entries_[from]);
|
||||
entries_.erase(entries_.begin() + from);
|
||||
entries_.insert(entries_.begin() + to, std::move(t));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
entries_.clear();
|
||||
selectedBank_ = 0;
|
||||
}
|
||||
int64_t addBank(int64_t afterId, const std::string &name)
|
||||
{
|
||||
BankIndexEntry bank;
|
||||
bank.name(name);
|
||||
bank.instanceId(++nextInstanceId_);
|
||||
|
||||
for (size_t i = 0; i < this->entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].instanceId() == afterId)
|
||||
{
|
||||
entries_.insert(entries_.begin() + (i + 1), bank);
|
||||
return bank.instanceId();
|
||||
}
|
||||
}
|
||||
// else at the end.
|
||||
entries_.push_back(bank);
|
||||
return bank.instanceId();
|
||||
}
|
||||
BankIndexEntry *getEntryByName(const std::string &name)
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].name() == name)
|
||||
{
|
||||
return &entries_[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
BankIndexEntry &getBankIndexEntry(int64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].instanceId() == instanceId)
|
||||
{
|
||||
return entries_[i];
|
||||
}
|
||||
}
|
||||
throw PiPedalArgumentException("Bank not found.");
|
||||
}
|
||||
const BankIndexEntry &getBankIndexEntry(int64_t instanceId) const
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); ++i)
|
||||
{
|
||||
if (entries_[i].instanceId() == instanceId)
|
||||
{
|
||||
return entries_[i];
|
||||
}
|
||||
}
|
||||
throw PiPedalArgumentException("Bank not found.");
|
||||
}
|
||||
};
|
||||
#undef GETTER_SETTER
|
||||
#undef GETTER_SETTER_VEC
|
||||
#undef GETTER_SETTER_REF
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+60
-28
@@ -33,6 +33,7 @@
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <sched.h>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -59,7 +60,7 @@ void PrintHelp()
|
||||
pp << Indent(0) << "Syntax\n\n";
|
||||
pp << Indent(2) << "pipedal_latency_test [<options>] <input-device> [<output-device>]\n\n";
|
||||
pp << "where <input-device> is the name of an ALSA capture device and <output-device> is the name of a playback device. "
|
||||
"If <output-device> is omitted, the input device will be used for both capture and playback. Typically the device names start with 'hw:'.\n\n";
|
||||
"If <output-device> is omitted, the input device will be used for both capture and playback. Typically the device names start with 'hw:'.\n\n";
|
||||
pp << Indent(0) << "Options\n\n";
|
||||
pp << Indent(15);
|
||||
|
||||
@@ -85,13 +86,13 @@ void PrintHelp()
|
||||
<< "PiPedal Latency Tester measures internal buffer delays as well as operating system and "
|
||||
<< "signal delays in hardware peripherals. Latency figures will therefore be somewhat higher than "
|
||||
<< "most reported latency figures which typically only include internal buffer delays.\n\n";
|
||||
|
||||
pp
|
||||
<< "The tests run over a variety of buffer sizes. A nominal compute load is provided in order to put some "
|
||||
"stress on the audio system.\n\n"
|
||||
|
||||
<< "You may need to stop the pipedald audio service in order to access the ALSA device:\n\n"
|
||||
<< Indent(6) << "sudo systemctl stop pipedald\n\n";
|
||||
pp
|
||||
<< "The tests run over a variety of buffer sizes. A nominal compute load is provided in order to put some "
|
||||
"stress on the audio system.\n\n"
|
||||
|
||||
<< "You may need to stop the pipedald audio service in order to access the ALSA device:\n\n"
|
||||
<< Indent(6) << "sudo systemctl stop pipedald\n\n";
|
||||
|
||||
pp << Indent(0) << "Examples\n\n";
|
||||
pp << Indent(2) << "pipedal_latency_test --list\n\n";
|
||||
@@ -123,7 +124,6 @@ void ListDevices()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using ChannelsT = std::vector<int>;
|
||||
|
||||
class AlsaTester : private AudioDriverHost
|
||||
@@ -169,12 +169,13 @@ public:
|
||||
delete[] inputBuffers;
|
||||
delete[] outputBuffers;
|
||||
}
|
||||
std::vector<std::string> SelectChannels(const std::vector<std::string>&available, const std::vector<int>& selection)
|
||||
std::vector<std::string> SelectChannels(const std::vector<std::string> &available, const std::vector<int> &selection)
|
||||
{
|
||||
if (selection.size() == 0) return available;
|
||||
if (selection.size() == 0)
|
||||
return available;
|
||||
|
||||
std::vector<std::string> result;
|
||||
for (int sel: selection)
|
||||
for (int sel : selection)
|
||||
{
|
||||
if (sel < 0 || sel >= available.size())
|
||||
{
|
||||
@@ -195,14 +196,13 @@ public:
|
||||
JackConfiguration jackConfiguration;
|
||||
jackConfiguration.AlsaInitialize(serverSettings);
|
||||
|
||||
auto & availableInputs = jackConfiguration.inputAudioPorts();
|
||||
auto & availableOutputs = jackConfiguration.outputAudioPorts();
|
||||
|
||||
auto &availableInputs = jackConfiguration.inputAudioPorts();
|
||||
auto &availableOutputs = jackConfiguration.outputAudioPorts();
|
||||
|
||||
std::vector<std::string> inputAudioPorts, outputAudioPorts;
|
||||
|
||||
inputAudioPorts = SelectChannels(availableInputs,this->inputChannels);
|
||||
outputAudioPorts = SelectChannels(availableOutputs,this->outputChannels);
|
||||
inputAudioPorts = SelectChannels(availableInputs, this->inputChannels);
|
||||
outputAudioPorts = SelectChannels(availableOutputs, this->outputChannels);
|
||||
|
||||
JackChannelSelection channelSelection(
|
||||
inputAudioPorts, outputAudioPorts,
|
||||
@@ -360,7 +360,6 @@ public:
|
||||
}
|
||||
virtual void OnAudioTerminated()
|
||||
{
|
||||
|
||||
}
|
||||
virtual void OnProcess(size_t nFrames)
|
||||
{
|
||||
@@ -413,7 +412,7 @@ TestResult RunLatencyTest(
|
||||
const ChannelsT &outputChannels,
|
||||
uint32_t sampleRate, int bufferSize, int buffers)
|
||||
{
|
||||
AlsaTester tester(inputDeviceId, outputDeviceId, inputChannels, outputChannels, sampleRate, bufferSize, buffers);
|
||||
AlsaTester tester(inputDeviceId, outputDeviceId, inputChannels, outputChannels, sampleRate, bufferSize, buffers);
|
||||
return tester.Test();
|
||||
}
|
||||
|
||||
@@ -432,6 +431,28 @@ static std::string overheadDisplay(float value)
|
||||
return s.str();
|
||||
}
|
||||
|
||||
static bool testRealtimePriorityPrivileges()
|
||||
{
|
||||
|
||||
struct sched_param currentParam;
|
||||
int currentPolicy = sched_getscheduler(0);
|
||||
if (currentPolicy == -1) {
|
||||
return false;
|
||||
}
|
||||
if (sched_getparam(0, ¤tParam) != 0) {
|
||||
return false;
|
||||
}
|
||||
struct sched_param param;
|
||||
param.sched_priority = 85;
|
||||
if (sched_setscheduler(0, SCHED_RR, ¶m) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Restore normal priority
|
||||
sched_setscheduler(0, currentPolicy, ¤tParam);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RunLatencyTest(
|
||||
const std::string &inputDeviceId,
|
||||
const std::string &outputDeviceId,
|
||||
@@ -439,8 +460,20 @@ void RunLatencyTest(
|
||||
const ChannelsT &outputChannels,
|
||||
uint32_t sampleRate)
|
||||
{
|
||||
|
||||
PrettyPrinter pp;
|
||||
pp << "Input: " << inputDeviceId << " Output: " << outputDeviceId << " Rate: " << sampleRate << "\n\n";
|
||||
|
||||
if (!testRealtimePriorityPrivileges())
|
||||
{
|
||||
pp << "Unable to enable realtime scheduling. Add your user id to the pipedal_d group to fix this problem:" << "\n\n";
|
||||
pp.AddIndent(4);
|
||||
pp << "sudo usermod -a -G pipedal_d <your user id>" << "\n\n";
|
||||
pp.AddIndent(-4);
|
||||
pp << "You will need to log out or reboot your system in order for the change to take effect.\n\n";
|
||||
throw std::runtime_error("Unable to set relatime thread priority.");
|
||||
}
|
||||
|
||||
pp << "Input: " << inputDeviceId << " Output: " << outputDeviceId << " Rate: " << sampleRate << "\n\n";
|
||||
|
||||
const int SIZE_COLUMN_WIDTH = 8;
|
||||
const int BUFFERS_COLUMN_WIDTH = 20;
|
||||
@@ -467,7 +500,7 @@ void RunLatencyTest(
|
||||
|
||||
for (auto bufferCount : bufferCounts)
|
||||
{
|
||||
auto result = RunLatencyTest(inputDeviceId, outputDeviceId, inputChannels,outputChannels, sampleRate, bufferSize, bufferCount);
|
||||
auto result = RunLatencyTest(inputDeviceId, outputDeviceId, inputChannels, outputChannels, sampleRate, bufferSize, bufferCount);
|
||||
|
||||
pp.Column(column);
|
||||
column += BUFFERS_COLUMN_WIDTH;
|
||||
@@ -495,8 +528,7 @@ void RunLatencyTest(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ChannelsT ParseChannels(const std::string&channels)
|
||||
ChannelsT ParseChannels(const std::string &channels)
|
||||
{
|
||||
ChannelsT result;
|
||||
std::stringstream s(channels);
|
||||
@@ -504,9 +536,11 @@ ChannelsT ParseChannels(const std::string&channels)
|
||||
while (true)
|
||||
{
|
||||
int c = s.peek();
|
||||
if (c == -1) break;
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
if (c == ',') {
|
||||
if (c == ',')
|
||||
{
|
||||
s.get();
|
||||
c = s.peek();
|
||||
}
|
||||
@@ -518,14 +552,12 @@ ChannelsT ParseChannels(const std::string&channels)
|
||||
while (s.peek() >= '0' && s.peek() <= '9')
|
||||
{
|
||||
c = s.get();
|
||||
v = v*10 + c-'0';
|
||||
v = v * 10 + c - '0';
|
||||
}
|
||||
result.push_back(v);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
@@ -567,7 +599,7 @@ std:
|
||||
inputChannels = ParseChannels(strInputChannels);
|
||||
outputChannels = ParseChannels(strOutputChannels);
|
||||
|
||||
std::string inDev = parser.Arguments()[0];
|
||||
std::string inDev = parser.Arguments()[0];
|
||||
std::string outDev = parser.Arguments().size() == 2 ? parser.Arguments()[1] : inDev;
|
||||
RunLatencyTest(inDev, outDev, inputChannels, outputChannels, sampleRate);
|
||||
}
|
||||
|
||||
+22
-2
@@ -887,7 +887,7 @@ int64_t PiPedalModel::SavePluginPresetAs(int64_t instanceId, const std::string &
|
||||
return presetId;
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::SaveCurrentPresetAs(int64_t clientId, const std::string &name, int64_t saveAfterInstanceId)
|
||||
int64_t PiPedalModel::SaveCurrentPresetAs(int64_t clientId, int64_t bankInstanceId,const std::string &name, int64_t saveAfterInstanceId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
@@ -897,7 +897,7 @@ int64_t PiPedalModel::SaveCurrentPresetAs(int64_t clientId, const std::string &n
|
||||
|
||||
UpdateVst3Settings(pedalboard);
|
||||
pedalboard.name(name);
|
||||
int64_t result = storage.SaveCurrentPresetAs(pedalboard, name, saveAfterInstanceId);
|
||||
int64_t result = storage.SaveCurrentPresetAs(pedalboard, bankInstanceId, name, saveAfterInstanceId);
|
||||
FirePresetsChanged(clientId);
|
||||
return result;
|
||||
}
|
||||
@@ -3257,3 +3257,23 @@ bool PiPedalModel::HasTone3000Auth() const
|
||||
{
|
||||
return storage.GetTone3000Auth() != "";
|
||||
}
|
||||
|
||||
std::vector<PresetIndexEntry> PiPedalModel::RequestBankPresets(int64_t bankInstanceId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
|
||||
return storage.RequestBankPresets(bankInstanceId);
|
||||
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
uint64_t lastAdded = storage.ImportPresetsFromBank(bankInstanceId, presets);
|
||||
if (lastAdded != -1) {
|
||||
|
||||
}
|
||||
FirePresetsChanged(-1);
|
||||
return lastAdded;
|
||||
|
||||
}
|
||||
|
||||
@@ -378,9 +378,10 @@ namespace pipedal
|
||||
int64_t UploadPreset(const BankFile &bankFile, int64_t uploadAfter = -1);
|
||||
void UploadPluginPresets(const PluginPresets &pluginPresets);
|
||||
void SaveCurrentPreset(int64_t clientId);
|
||||
int64_t SaveCurrentPresetAs(int64_t clientId, const std::string &name, int64_t saveAfterInstanceId = -1);
|
||||
int64_t SaveCurrentPresetAs(int64_t clientId, int64_t bankInstanceId, const std::string &name, int64_t saveAfterInstanceId = -1);
|
||||
int64_t SavePluginPresetAs(int64_t instanceId, const std::string &name);
|
||||
|
||||
|
||||
void LoadPreset(int64_t clientId, int64_t instanceId);
|
||||
bool UpdatePresets(int64_t clientId, const PresetIndex &presets);
|
||||
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
||||
@@ -493,6 +494,8 @@ namespace pipedal
|
||||
|
||||
void SetSelectedPedalboardPlugin(uint64_t clientId, uint64_t pedalboardId);
|
||||
|
||||
std::vector<PresetIndexEntry> RequestBankPresets(int64_t bankInstanceId);
|
||||
int64_t ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
||||
};
|
||||
|
||||
} // namespace pipedal.
|
||||
+37
-1
@@ -46,6 +46,27 @@
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
class ImportPresetsFromBankBody {
|
||||
public:
|
||||
int64_t bankInstanceId_;
|
||||
std::vector<int64_t> presets_;
|
||||
DECLARE_JSON_MAP(ImportPresetsFromBankBody);
|
||||
};
|
||||
JSON_MAP_BEGIN(ImportPresetsFromBankBody)
|
||||
JSON_MAP_REFERENCE(ImportPresetsFromBankBody, bankInstanceId)
|
||||
JSON_MAP_REFERENCE(ImportPresetsFromBankBody, presets)
|
||||
JSON_MAP_END()
|
||||
|
||||
class RequestBankPresetsBody {
|
||||
public:
|
||||
int64_t bankInstanceId_;
|
||||
DECLARE_JSON_MAP(RequestBankPresetsBody);
|
||||
};
|
||||
JSON_MAP_BEGIN(RequestBankPresetsBody)
|
||||
JSON_MAP_REFERENCE(RequestBankPresetsBody, bankInstanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
class PathPatchPropertyChangedBody
|
||||
{
|
||||
public:
|
||||
@@ -336,6 +357,7 @@ class SaveCurrentPresetAsBody
|
||||
{
|
||||
public:
|
||||
int64_t clientId_ = -1;
|
||||
int64_t bankInstanceId_ = -1;
|
||||
std::string name_;
|
||||
int64_t saveAfterInstanceId_ = -1;
|
||||
|
||||
@@ -343,6 +365,7 @@ public:
|
||||
};
|
||||
JSON_MAP_BEGIN(SaveCurrentPresetAsBody)
|
||||
JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, clientId)
|
||||
JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, bankInstanceId)
|
||||
JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, name)
|
||||
JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, saveAfterInstanceId)
|
||||
JSON_MAP_END()
|
||||
@@ -1314,7 +1337,7 @@ public:
|
||||
{
|
||||
SaveCurrentPresetAsBody body;
|
||||
pReader->read(&body);
|
||||
int64_t result = this->model.SaveCurrentPresetAs(this->clientId, body.name_, body.saveAfterInstanceId_);
|
||||
int64_t result = this->model.SaveCurrentPresetAs(this->clientId, body.bankInstanceId_,body.name_, body.saveAfterInstanceId_);
|
||||
Reply(replyTo, "saveCurrentPresetsAs", result);
|
||||
}
|
||||
else if (message == "setSelectedPedalboardPlugin")
|
||||
@@ -1794,6 +1817,19 @@ public:
|
||||
{
|
||||
std::vector<AlsaSequencerPortSelection> result = model.GetAlsaSequencerPorts();
|
||||
this->Reply(replyTo,"getAlsaSequencerPorts", result);
|
||||
} else if (message == "requestBankPresets") {
|
||||
|
||||
RequestBankPresetsBody args;
|
||||
pReader->read(&args);
|
||||
auto result = this->model.RequestBankPresets(args.bankInstanceId_);
|
||||
this->Reply(replyTo,"requestBankPresets",result);
|
||||
|
||||
}
|
||||
else if (message == "importPresetsFromBank") {
|
||||
ImportPresetsFromBankBody args;
|
||||
pReader->read(&args);
|
||||
auto result = this->model.ImportPresetsFromBank(args.bankInstanceId_, args.presets_);
|
||||
this->Reply(replyTo,"importPresetsFromBank",result);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+137
-13
@@ -225,7 +225,6 @@ static void CopyDirectory(const std::filesystem::path &source, const std::filesy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Storage::MaybeCopyDefaultPresets()
|
||||
{
|
||||
auto presetsDirectory = this->GetPresetsDirectory();
|
||||
@@ -239,13 +238,17 @@ void Storage::MaybeCopyDefaultPresets()
|
||||
}
|
||||
|
||||
static void removeFileNoThrow(const std::filesystem::path &path)
|
||||
{
|
||||
try {
|
||||
{
|
||||
try
|
||||
{
|
||||
fs::remove(path);
|
||||
} catch (const std::exception&)
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Storage::UpgradeFactoryPresets()
|
||||
{
|
||||
auto presetsDirectory = this->GetPresetsDirectory();
|
||||
@@ -520,7 +523,6 @@ void Storage::SavePluginPresetIndex()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Storage::SaveBankIndex()
|
||||
{
|
||||
pipedal::ofstream_synced os;
|
||||
@@ -653,17 +655,133 @@ void Storage::SaveCurrentPreset(const Pedalboard &pedalboard)
|
||||
item.preset(pedalboard);
|
||||
SaveCurrentBank();
|
||||
}
|
||||
int64_t Storage::SaveCurrentPresetAs(const Pedalboard &pedalboard, const std::string &name, int64_t saveAfterInstanceId)
|
||||
int64_t Storage::SaveCurrentPresetAs(const Pedalboard &pedalboard, int64_t bankInstanceId, const std::string &name, int64_t saveAfterInstanceId)
|
||||
{
|
||||
Pedalboard newPedalboard = pedalboard;
|
||||
newPedalboard.name(name);
|
||||
|
||||
int64_t newInstanceId = currentBank.addPreset(newPedalboard, saveAfterInstanceId);
|
||||
currentBank.selectedPreset(newInstanceId);
|
||||
SaveCurrentBank();
|
||||
return newInstanceId;
|
||||
if (bankInstanceId == this->bankIndex.selectedBank())
|
||||
{
|
||||
int64_t newInstanceId = currentBank.addPreset(newPedalboard, saveAfterInstanceId);
|
||||
currentBank.selectedPreset(newInstanceId);
|
||||
SaveCurrentBank();
|
||||
return newInstanceId;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto indexEntry = this->bankIndex.getBankIndexEntry(bankInstanceId);
|
||||
|
||||
try
|
||||
{
|
||||
BankFile bankFile;
|
||||
LoadBankFile(indexEntry.name(), &(bankFile));
|
||||
int64_t newInstanceId = bankFile.addPreset(newPedalboard, -1);
|
||||
SaveBankFile(indexEntry.name(), bankFile);
|
||||
return -1;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw std::logic_error(SS("Bank file corrupted. " << e.what() << "(" << GetBankFileName(indexEntry.name()) << ")"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string stripNumericSuffix(const std::string &name) {
|
||||
// remove (digit*) from the end of the string.
|
||||
// Find the last '(' character
|
||||
size_t pos = name.find_last_of('(');
|
||||
if (pos == std::string::npos) {
|
||||
return name;
|
||||
}
|
||||
|
||||
// Check if everything between '(' and ')' is digits
|
||||
size_t len = name.length()-1;
|
||||
if (name[len] != ')')
|
||||
{
|
||||
return name;
|
||||
}
|
||||
bool allDigits = true;
|
||||
for (size_t i = pos + 1; i < len - 1; ++i) {
|
||||
if (name[i] < '0' || name[i] > '9') {
|
||||
allDigits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allDigits) {
|
||||
return name;
|
||||
}
|
||||
|
||||
// Remove trailing spaces before the '('
|
||||
while (pos > 0 && name[pos - 1] == ' ') {
|
||||
--pos;
|
||||
}
|
||||
|
||||
return name.substr(0, pos);
|
||||
}
|
||||
static std::string makeUniqueName(const std::string &name, const std::set<std::string>&existingNames)
|
||||
{
|
||||
if (!existingNames.contains(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
std::string baseName = stripNumericSuffix(name);
|
||||
|
||||
size_t i = 2;
|
||||
while (true) {
|
||||
std::string newName = SS(baseName << " (" << i << ")");
|
||||
if (!existingNames.contains(newName)) {
|
||||
return newName;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
int64_t Storage::ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets)
|
||||
{
|
||||
if (bankIndex.selectedBank() == bankInstanceId) {
|
||||
throw std::runtime_error("Can't import to self.");
|
||||
}
|
||||
std::set<int64_t> presetsSet { presets.begin(), presets.end()};
|
||||
auto indexEntry = this->bankIndex.getBankIndexEntry(bankInstanceId);
|
||||
|
||||
std::set<std::string> existingNames;
|
||||
|
||||
for (auto&preset: this->currentBank.presets()) {
|
||||
existingNames.insert(preset->preset().name());
|
||||
}
|
||||
BankFile bankFile;
|
||||
LoadBankFile(indexEntry.name(),&bankFile);
|
||||
int64_t lastPresetId = -1;
|
||||
for (auto &presetEntry: bankFile.presets()) {
|
||||
if (presetsSet.contains(presetEntry->instanceId())) {
|
||||
std::string uniqueName = makeUniqueName(presetEntry->preset().name(),existingNames);
|
||||
existingNames.insert(uniqueName);
|
||||
Pedalboard t = presetEntry->preset();
|
||||
t.name(uniqueName);
|
||||
lastPresetId = this->currentBank.addPreset(t);
|
||||
}
|
||||
}
|
||||
SaveCurrentBank();
|
||||
return lastPresetId;
|
||||
}
|
||||
|
||||
std::vector<PresetIndexEntry> Storage::RequestBankPresets(int64_t bankInstanceId)
|
||||
{
|
||||
auto indexEntry = this->bankIndex.getBankIndexEntry(bankInstanceId);
|
||||
|
||||
std::vector<PresetIndexEntry> result;
|
||||
BankFile bankFile;
|
||||
LoadBankFile(indexEntry.name(),&bankFile);
|
||||
for (auto &preset: bankFile.presets()) {
|
||||
result.push_back(
|
||||
PresetIndexEntry(preset->instanceId(),preset->preset().name())
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Storage::SetPresetIndex(const PresetIndex &presets)
|
||||
{
|
||||
// painful because we must move unique_ptrs.
|
||||
@@ -826,25 +944,30 @@ int64_t Storage::CreateNewPreset()
|
||||
}
|
||||
}
|
||||
newPedalboard.name(name);
|
||||
return this->currentBank.addPreset(newPedalboard, -1);
|
||||
auto t = this->currentBank.addPreset(newPedalboard, -1);
|
||||
SaveCurrentBank();
|
||||
return t;
|
||||
}
|
||||
|
||||
int64_t Storage::CopyPreset(int64_t fromId, int64_t toId)
|
||||
{
|
||||
auto &fromItem = this->currentBank.getItem(fromId);
|
||||
int64_t result;
|
||||
if (toId == -1)
|
||||
{
|
||||
Pedalboard newPedalboard = fromItem.preset();
|
||||
std::string name = GetPresetCopyName(fromItem.preset().name());
|
||||
newPedalboard.name(name);
|
||||
return this->currentBank.addPreset(newPedalboard, fromId);
|
||||
result = this->currentBank.addPreset(newPedalboard, fromId);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &toItem = this->currentBank.getItem(toId);
|
||||
toItem.preset(fromItem.preset());
|
||||
return toId;
|
||||
result = toId;
|
||||
}
|
||||
SaveCurrentBank();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Storage::SetJackChannelSelection(const JackChannelSelection &channelSelection)
|
||||
@@ -2861,6 +2984,7 @@ std::string Storage::FromAbstractPathJson(const std::string &pathJson)
|
||||
return v.to_string();
|
||||
}
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(UserSettings)
|
||||
JSON_MAP_REFERENCE(UserSettings, governor)
|
||||
JSON_MAP_REFERENCE(UserSettings, showStatusMonitor)
|
||||
|
||||
+5
-1
@@ -149,7 +149,7 @@ public:
|
||||
int64_t GetBankByMidiBankNumber(uint8_t bankNumber);
|
||||
const Pedalboard& GetCurrentPreset();
|
||||
void SaveCurrentPreset(const Pedalboard&pedalboard);
|
||||
int64_t SaveCurrentPresetAs(const Pedalboard&pedalboard, const std::string&namne,int64_t saveAfterInstanceId = -1);
|
||||
int64_t SaveCurrentPresetAs(const Pedalboard&pedalboard, int64_t bankInstanceId,const std::string&namne,int64_t saveAfterInstanceId = -1);
|
||||
int64_t GetCurrentPresetId() const;
|
||||
|
||||
void GetPresetIndex(PresetIndex*pResult);
|
||||
@@ -268,6 +268,10 @@ public:
|
||||
void LoadTone3000Auth();
|
||||
void SetTone3000Auth(const std::string&apiKey);
|
||||
std::string GetTone3000Auth() const;
|
||||
|
||||
std::vector<PresetIndexEntry> RequestBankPresets(int64_t bankInstanceId);
|
||||
int64_t ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user