Move RDF-based preset stuff into LadspaPlugin, to make way for a set of evil hacks to make VST chunk-based presets work (for some values of `work').
May fix #3577. git-svn-id: svn://localhost/ardour2/branches/3.0@8202 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
25a702798e
commit
40c162d609
|
@ -324,8 +324,8 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox
|
|||
|
||||
bool configure_handler (GdkEventConfigure*, Gtk::Socket*);
|
||||
void save_plugin_setting ();
|
||||
void create_preset_store ();
|
||||
void preset_chosen ();
|
||||
void update_presets ();
|
||||
};
|
||||
#endif // VST_SUPPORT
|
||||
|
||||
|
|
|
@ -35,7 +35,14 @@ VSTPluginUI::VSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<
|
|||
: PlugUIBase (pi),
|
||||
vst (vp)
|
||||
{
|
||||
create_preset_store ();
|
||||
preset_model = ListStore::create (preset_columns);
|
||||
|
||||
CellRenderer* renderer = manage (new CellRendererText());
|
||||
vst_preset_combo.pack_start (*renderer, true);
|
||||
vst_preset_combo.add_attribute (*renderer, "text", 0);
|
||||
vst_preset_combo.set_model (preset_model);
|
||||
|
||||
update_presets ();
|
||||
|
||||
fst_run_editor (vst->fst());
|
||||
|
||||
|
@ -63,8 +70,19 @@ VSTPluginUI::~VSTPluginUI ()
|
|||
void
|
||||
VSTPluginUI::preset_chosen ()
|
||||
{
|
||||
// we can't dispatch directly here, too many plugins only expects one GUI thread.
|
||||
vst->fst()->want_program = vst_preset_combo.get_active_row_number ();
|
||||
int const r = vst_preset_combo.get_active_row_number ();
|
||||
|
||||
if (r < vst->first_user_preset_index()) {
|
||||
/* This is a plugin-provided preset.
|
||||
We can't dispatch directly here; too many plugins expects only one GUI thread.
|
||||
*/
|
||||
vst->fst()->want_program = r;
|
||||
} else {
|
||||
/* This is a user preset. This method knows about the direct dispatch restriction, too */
|
||||
TreeModel::iterator i = vst_preset_combo.get_active ();
|
||||
plugin->load_preset ((*i)[preset_columns.name]);
|
||||
}
|
||||
|
||||
socket.grab_focus ();
|
||||
}
|
||||
|
||||
|
@ -138,37 +156,23 @@ VSTPluginUI::configure_handler (GdkEventConfigure* ev, Gtk::Socket *socket)
|
|||
}
|
||||
|
||||
void
|
||||
VSTPluginUI::create_preset_store ()
|
||||
VSTPluginUI::update_presets ()
|
||||
{
|
||||
FST *fst = vst->fst();
|
||||
int vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
|
||||
std::vector<Plugin::PresetRecord> presets = plugin->get_presets ();
|
||||
|
||||
preset_model = ListStore::create (preset_columns);
|
||||
preset_model->clear ();
|
||||
|
||||
for (int i = 0; i < fst->plugin->numPrograms; ++i) {
|
||||
char buf[100];
|
||||
TreeModel::Row row = *(preset_model->append());
|
||||
|
||||
snprintf (buf, 90, "preset %d", i);
|
||||
|
||||
if (vst_version >= 2) {
|
||||
fst->plugin->dispatcher (fst->plugin, 29, i, 0, buf, 0.0);
|
||||
}
|
||||
|
||||
row[preset_columns.name] = buf;
|
||||
row[preset_columns.number] = i;
|
||||
int j = 0;
|
||||
for (std::vector<Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
|
||||
TreeModel::Row row = *(preset_model->append ());
|
||||
row[preset_columns.name] = i->label;
|
||||
row[preset_columns.number] = j++;
|
||||
}
|
||||
|
||||
if (fst->plugin->numPrograms > 0) {
|
||||
fst->plugin->dispatcher( fst->plugin, effSetProgram, 0, 0, NULL, 0.0 );
|
||||
if (presets.size() > 0) {
|
||||
vst->fst()->plugin->dispatcher (vst->fst()->plugin, effSetProgram, 0, 0, NULL, 0);
|
||||
}
|
||||
|
||||
vst_preset_combo.set_model (preset_model);
|
||||
|
||||
CellRenderer* renderer = manage (new CellRendererText());
|
||||
vst_preset_combo.pack_start (*renderer, true);
|
||||
vst_preset_combo.add_attribute (*renderer, "text", 0);
|
||||
|
||||
if (vst->fst()->current_program != -1) {
|
||||
vst_preset_combo.set_active (vst->fst()->current_program);
|
||||
} else {
|
||||
|
|
|
@ -99,8 +99,9 @@ class LadspaPlugin : public ARDOUR::Plugin
|
|||
|
||||
XMLNode& get_state();
|
||||
int set_state (const XMLNode&, int version);
|
||||
bool save_preset (std::string name);
|
||||
void remove_preset (std::string name);
|
||||
|
||||
std::vector<PresetRecord> get_presets ();
|
||||
bool load_preset (const std::string& uri);
|
||||
|
||||
bool has_editor() const { return false; }
|
||||
|
||||
|
@ -134,6 +135,11 @@ class LadspaPlugin : public ARDOUR::Plugin
|
|||
void run_in_place (pframes_t nsamples);
|
||||
void latency_compute_run ();
|
||||
int set_state_2X (const XMLNode&, int version);
|
||||
std::string do_save_preset (std::string name);
|
||||
void do_remove_preset (std::string name);
|
||||
std::string preset_envvar () const;
|
||||
std::string preset_source (std::string) const;
|
||||
bool write_preset_file (std::string);
|
||||
};
|
||||
|
||||
class LadspaPluginInfo : public PluginInfo {
|
||||
|
|
|
@ -153,6 +153,8 @@ class LV2Plugin : public ARDOUR::Plugin
|
|||
void init (LV2World& world, SLV2Plugin plugin, framecnt_t rate);
|
||||
void run (pframes_t nsamples);
|
||||
void latency_compute_run ();
|
||||
std::string do_save_preset (std::string);
|
||||
void do_remove_preset (std::string);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -128,28 +128,32 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
virtual bool parameter_is_input(uint32_t) const = 0;
|
||||
virtual bool parameter_is_output(uint32_t) const = 0;
|
||||
|
||||
virtual bool save_preset (std::string) = 0;
|
||||
virtual void remove_preset (std::string) = 0;
|
||||
virtual bool load_preset (const std::string& uri);
|
||||
bool save_preset (std::string);
|
||||
void remove_preset (std::string);
|
||||
virtual bool load_preset (const std::string& uri) = 0;
|
||||
|
||||
struct PresetRecord {
|
||||
PresetRecord(const std::string& u, const std::string& l) : uri(u), label(l) {}
|
||||
PresetRecord (const std::string& u, const std::string& l) : uri(u), label(l) {}
|
||||
std::string uri;
|
||||
std::string label;
|
||||
};
|
||||
|
||||
virtual std::vector<PresetRecord> get_presets();
|
||||
virtual std::string current_preset() const { return std::string(); }
|
||||
const PresetRecord * preset_by_label (const std::string &);
|
||||
const PresetRecord * preset_by_uri (const std::string &);
|
||||
|
||||
/** Return this plugin's presets; should add them to _presets */
|
||||
virtual std::vector<PresetRecord> get_presets () = 0;
|
||||
virtual std::string current_preset () const { return std::string(); }
|
||||
|
||||
/** Emitted when a preset is added or removed, respectively */
|
||||
PBD::Signal0<void> PresetAdded;
|
||||
PBD::Signal0<void> PresetRemoved;
|
||||
|
||||
/* XXX: no-one listens to this */
|
||||
static PBD::Signal0<bool> PresetFileExists;
|
||||
|
||||
const PresetRecord* preset_by_label(const std::string& label);
|
||||
const PresetRecord* preset_by_uri(const std::string& uri);
|
||||
|
||||
virtual bool has_editor() const = 0;
|
||||
|
||||
PBD::Signal0<void> PresetAdded;
|
||||
PBD::Signal0<void> PresetRemoved;
|
||||
PBD::Signal2<void,uint32_t,float> ParameterChanged;
|
||||
|
||||
/* NOTE: this block of virtual methods looks like the interface
|
||||
|
@ -183,23 +187,25 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
void set_cycles (uint32_t c) { _cycles = c; }
|
||||
cycles_t cycles() const { return _cycles; }
|
||||
|
||||
protected:
|
||||
protected:
|
||||
|
||||
friend class PluginInsert;
|
||||
friend struct PluginInsert::PluginControl;
|
||||
|
||||
virtual void set_parameter (uint32_t which, float val) = 0;
|
||||
|
||||
bool save_preset (std::string, std::string /* vst, ladspa etc. */);
|
||||
void remove_preset (std::string, std::string);
|
||||
bool write_preset_file (std::string, std::string);
|
||||
std::string preset_source (std::string, std::string) const;
|
||||
std::string preset_envvar () const;
|
||||
/** Do the actual saving of the current plugin settings to a preset of the provided name.
|
||||
* Should return a URI on success, or an empty string on failure.
|
||||
*/
|
||||
virtual std::string do_save_preset (std::string) = 0;
|
||||
/** Do the actual removal of a preset of the provided name */
|
||||
virtual void do_remove_preset (std::string) = 0;
|
||||
|
||||
ARDOUR::AudioEngine& _engine;
|
||||
ARDOUR::Session& _session;
|
||||
PluginInfoPtr _info;
|
||||
uint32_t _cycles;
|
||||
std::map<std::string,PresetRecord> presets;
|
||||
std::map<std::string, PresetRecord> _presets;
|
||||
};
|
||||
|
||||
PluginPtr find_plugin(ARDOUR::Session&, std::string unique_id, ARDOUR::PluginType);
|
||||
|
|
|
@ -80,19 +80,25 @@ class VSTPlugin : public ARDOUR::Plugin
|
|||
bool parameter_is_output(uint32_t i) const { return false; }
|
||||
|
||||
bool load_preset (const std::string& preset_label);
|
||||
bool save_preset (std::string name);
|
||||
void remove_preset (std::string name);
|
||||
virtual std::vector<PresetRecord> get_presets ();
|
||||
int first_user_preset_index () const;
|
||||
|
||||
bool has_editor () const;
|
||||
|
||||
XMLNode& get_state();
|
||||
int set_state (XMLNode const &, int);
|
||||
|
||||
AEffect* plugin() const { return _plugin; }
|
||||
FST* fst() const { return _fst; }
|
||||
AEffect * plugin () const { return _plugin; }
|
||||
FST * fst () const { return _fst; }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
void do_remove_preset (std::string name);
|
||||
std::string do_save_preset (std::string name);
|
||||
gchar* get_chunk (bool);
|
||||
int set_chunk (gchar const *, bool);
|
||||
XMLTree * presets_tree () const;
|
||||
|
||||
FSTHandle* handle;
|
||||
FST* _fst;
|
||||
AEffect* _plugin;
|
||||
|
|
|
@ -366,18 +366,6 @@ LadspaPlugin::get_state()
|
|||
return *root;
|
||||
}
|
||||
|
||||
bool
|
||||
LadspaPlugin::save_preset (string name)
|
||||
{
|
||||
return Plugin::save_preset (name, "ladspa");
|
||||
}
|
||||
|
||||
void
|
||||
LadspaPlugin::remove_preset (string name)
|
||||
{
|
||||
return Plugin::remove_preset (name, "ladspa");
|
||||
}
|
||||
|
||||
int
|
||||
LadspaPlugin::set_state (const XMLNode& node, int version)
|
||||
{
|
||||
|
@ -717,3 +705,197 @@ LadspaPluginInfo::LadspaPluginInfo()
|
|||
{
|
||||
type = ARDOUR::LADSPA;
|
||||
}
|
||||
|
||||
|
||||
vector<Plugin::PresetRecord>
|
||||
LadspaPlugin::get_presets ()
|
||||
{
|
||||
vector<PresetRecord> result;
|
||||
uint32_t id;
|
||||
std::string unique (unique_id());
|
||||
|
||||
if (!isdigit (unique[0])) {
|
||||
return result;
|
||||
}
|
||||
|
||||
id = atol (unique.c_str());
|
||||
|
||||
lrdf_uris* set_uris = lrdf_get_setting_uris(id);
|
||||
|
||||
if (set_uris) {
|
||||
for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
|
||||
if (char* label = lrdf_get_label(set_uris->items[i])) {
|
||||
PresetRecord rec(set_uris->items[i], label);
|
||||
result.push_back(rec);
|
||||
_presets.insert (make_pair (set_uris->items[i], rec));
|
||||
}
|
||||
}
|
||||
lrdf_free_uris(set_uris);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LadspaPlugin::load_preset (const string& preset_uri)
|
||||
{
|
||||
lrdf_defaults* defs = lrdf_get_setting_values(preset_uri.c_str());
|
||||
|
||||
if (defs) {
|
||||
for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) {
|
||||
// The defs->items[i].pid < defs->count check is to work around
|
||||
// a bug in liblrdf that saves invalid values into the presets file.
|
||||
if (((uint32_t) defs->items[i].pid < (uint32_t) defs->count) && parameter_is_input (defs->items[i].pid)) {
|
||||
set_parameter(defs->items[i].pid, defs->items[i].value);
|
||||
}
|
||||
}
|
||||
lrdf_free_setting_values(defs);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* XXX: should be in liblrdf */
|
||||
static void
|
||||
lrdf_remove_preset (const char *source, const char *setting_uri)
|
||||
{
|
||||
lrdf_statement p;
|
||||
lrdf_statement *q;
|
||||
lrdf_statement *i;
|
||||
char setting_uri_copy[64];
|
||||
char buf[64];
|
||||
|
||||
strncpy(setting_uri_copy, setting_uri, sizeof(setting_uri_copy));
|
||||
|
||||
p.subject = setting_uri_copy;
|
||||
strncpy(buf, LADSPA_BASE "hasPortValue", sizeof(buf));
|
||||
p.predicate = buf;
|
||||
p.object = NULL;
|
||||
q = lrdf_matches(&p);
|
||||
|
||||
p.predicate = NULL;
|
||||
p.object = NULL;
|
||||
for (i = q; i; i = i->next) {
|
||||
p.subject = i->object;
|
||||
lrdf_remove_matches(&p);
|
||||
}
|
||||
|
||||
lrdf_free_statements(q);
|
||||
|
||||
p.subject = NULL;
|
||||
strncpy(buf, LADSPA_BASE "hasSetting", sizeof(buf));
|
||||
p.predicate = buf;
|
||||
p.object = setting_uri_copy;
|
||||
lrdf_remove_matches(&p);
|
||||
|
||||
p.subject = setting_uri_copy;
|
||||
p.predicate = NULL;
|
||||
p.object = NULL;
|
||||
lrdf_remove_matches (&p);
|
||||
}
|
||||
|
||||
void
|
||||
LadspaPlugin::do_remove_preset (string name)
|
||||
{
|
||||
string const envvar = preset_envvar ();
|
||||
if (envvar.empty()) {
|
||||
warning << _("Could not locate HOME. Preset not removed.") << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin::PresetRecord const * p = preset_by_label (name);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
|
||||
string const source = preset_source (envvar);
|
||||
lrdf_remove_preset (source.c_str(), p->uri.c_str ());
|
||||
|
||||
write_preset_file (envvar);
|
||||
}
|
||||
|
||||
string
|
||||
LadspaPlugin::preset_envvar () const
|
||||
{
|
||||
char* envvar;
|
||||
if ((envvar = getenv ("HOME")) == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return envvar;
|
||||
}
|
||||
|
||||
string
|
||||
LadspaPlugin::preset_source (string envvar) const
|
||||
{
|
||||
return string_compose ("file:%1/.ladspa/rdf/ardour-presets.n3", envvar);
|
||||
}
|
||||
|
||||
bool
|
||||
LadspaPlugin::write_preset_file (string envvar)
|
||||
{
|
||||
string path = string_compose("%1/.ladspa", envvar);
|
||||
if (g_mkdir_with_parents (path.c_str(), 0775)) {
|
||||
warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
path += "/rdf";
|
||||
if (g_mkdir_with_parents (path.c_str(), 0775)) {
|
||||
warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
string const source = preset_source (envvar);
|
||||
|
||||
if (lrdf_export_by_source (source.c_str(), source.substr(5).c_str())) {
|
||||
warning << string_compose(_("Error saving presets file %1."), source) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string
|
||||
LadspaPlugin::do_save_preset (string name)
|
||||
{
|
||||
lrdf_portvalue portvalues[parameter_count()];
|
||||
lrdf_defaults defaults;
|
||||
std::string unique (unique_id());
|
||||
|
||||
if (!isdigit (unique[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t const id = atol (unique.c_str());
|
||||
|
||||
defaults.count = parameter_count();
|
||||
defaults.items = portvalues;
|
||||
|
||||
for (uint32_t i = 0; i < parameter_count(); ++i) {
|
||||
if (parameter_is_input (i)) {
|
||||
portvalues[i].pid = i;
|
||||
portvalues[i].value = get_parameter(i);
|
||||
}
|
||||
}
|
||||
|
||||
string const envvar = preset_envvar ();
|
||||
if (envvar.empty()) {
|
||||
warning << _("Could not locate HOME. Preset not saved.") << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
string const source = preset_source (envvar);
|
||||
|
||||
char* uri_char = lrdf_add_preset (source.c_str(), name.c_str(), id, &defaults);
|
||||
string uri (uri_char);
|
||||
free (uri_char);
|
||||
|
||||
if (!write_preset_file (envvar)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ LV2Plugin::get_presets()
|
|||
SLV2Value name = slv2_results_get_binding_value(presets, 1);
|
||||
PresetRecord rec(slv2_value_as_string(uri), slv2_value_as_string(name));
|
||||
result.push_back(rec);
|
||||
this->presets.insert(std::make_pair(slv2_value_as_string(uri), rec));
|
||||
_presets.insert(std::make_pair(slv2_value_as_string(uri), rec));
|
||||
}
|
||||
slv2_results_free(presets);
|
||||
return result;
|
||||
|
@ -380,14 +380,14 @@ LV2Plugin::load_preset(const string& uri)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LV2Plugin::save_preset (string /*name*/)
|
||||
std::string
|
||||
LV2Plugin::do_save_preset (string /*name*/)
|
||||
{
|
||||
return false;
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
LV2Plugin::remove_preset (string /*name*/)
|
||||
LV2Plugin::do_remove_preset (string /*name*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -78,244 +78,34 @@ Plugin::Plugin (const Plugin& other)
|
|||
, _session (other._session)
|
||||
, _info (other._info)
|
||||
, _cycles (0)
|
||||
, presets (other.presets)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Plugin::~Plugin ()
|
||||
{
|
||||
}
|
||||
|
||||
const Plugin::PresetRecord*
|
||||
Plugin::preset_by_label(const string& label)
|
||||
{
|
||||
// FIXME: O(n)
|
||||
for (map<string,PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
|
||||
if (i->second.label == label) {
|
||||
return &i->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Plugin::PresetRecord*
|
||||
Plugin::preset_by_uri(const string& uri)
|
||||
{
|
||||
map<string,PresetRecord>::const_iterator pr = presets.find(uri);
|
||||
if (pr != presets.end()) {
|
||||
return &pr->second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vector<Plugin::PresetRecord>
|
||||
Plugin::get_presets()
|
||||
{
|
||||
vector<PresetRecord> result;
|
||||
uint32_t id;
|
||||
std::string unique (unique_id());
|
||||
|
||||
/* XXX problem: AU plugins don't have numeric ID's.
|
||||
Solution: they have a different method of providing presets.
|
||||
XXX sub-problem: implement it.
|
||||
*/
|
||||
|
||||
if (!isdigit (unique[0])) {
|
||||
return result;
|
||||
}
|
||||
|
||||
id = atol (unique.c_str());
|
||||
|
||||
lrdf_uris* set_uris = lrdf_get_setting_uris(id);
|
||||
|
||||
if (set_uris) {
|
||||
for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
|
||||
if (char* label = lrdf_get_label(set_uris->items[i])) {
|
||||
PresetRecord rec(set_uris->items[i], label);
|
||||
result.push_back(rec);
|
||||
presets.insert(std::make_pair(set_uris->items[i], rec));
|
||||
}
|
||||
}
|
||||
lrdf_free_uris(set_uris);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Plugin::load_preset(const string& preset_uri)
|
||||
{
|
||||
lrdf_defaults* defs = lrdf_get_setting_values(preset_uri.c_str());
|
||||
|
||||
if (defs) {
|
||||
for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) {
|
||||
// The defs->items[i].pid < defs->count check is to work around
|
||||
// a bug in liblrdf that saves invalid values into the presets file.
|
||||
if (((uint32_t) defs->items[i].pid < (uint32_t) defs->count) && parameter_is_input (defs->items[i].pid)) {
|
||||
set_parameter(defs->items[i].pid, defs->items[i].value);
|
||||
}
|
||||
}
|
||||
lrdf_free_setting_values(defs);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* XXX: should be in liblrdf */
|
||||
static void
|
||||
lrdf_remove_preset (const char *source, const char *setting_uri)
|
||||
{
|
||||
lrdf_statement p;
|
||||
lrdf_statement *q;
|
||||
lrdf_statement *i;
|
||||
char setting_uri_copy[64];
|
||||
char buf[64];
|
||||
|
||||
strncpy(setting_uri_copy, setting_uri, sizeof(setting_uri_copy));
|
||||
|
||||
p.subject = setting_uri_copy;
|
||||
strncpy(buf, LADSPA_BASE "hasPortValue", sizeof(buf));
|
||||
p.predicate = buf;
|
||||
p.object = NULL;
|
||||
q = lrdf_matches(&p);
|
||||
|
||||
p.predicate = NULL;
|
||||
p.object = NULL;
|
||||
for (i = q; i; i = i->next) {
|
||||
p.subject = i->object;
|
||||
lrdf_remove_matches(&p);
|
||||
}
|
||||
|
||||
lrdf_free_statements(q);
|
||||
|
||||
p.subject = NULL;
|
||||
strncpy(buf, LADSPA_BASE "hasSetting", sizeof(buf));
|
||||
p.predicate = buf;
|
||||
p.object = setting_uri_copy;
|
||||
lrdf_remove_matches(&p);
|
||||
|
||||
p.subject = setting_uri_copy;
|
||||
p.predicate = NULL;
|
||||
p.object = NULL;
|
||||
lrdf_remove_matches (&p);
|
||||
}
|
||||
|
||||
void
|
||||
Plugin::remove_preset (string name, string domain)
|
||||
Plugin::remove_preset (string name)
|
||||
{
|
||||
string const envvar = preset_envvar ();
|
||||
if (envvar.empty()) {
|
||||
warning << _("Could not locate HOME. Preset not removed.") << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin::PresetRecord const * p = preset_by_label (name);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
|
||||
string const source = preset_source (envvar, domain);
|
||||
lrdf_remove_preset (source.c_str(), p->uri.c_str ());
|
||||
|
||||
presets.erase (p->uri);
|
||||
|
||||
write_preset_file (envvar, domain);
|
||||
|
||||
do_remove_preset (name);
|
||||
_presets.erase (preset_by_label (name)->uri);
|
||||
PresetRemoved (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
string
|
||||
Plugin::preset_envvar () const
|
||||
bool
|
||||
Plugin::save_preset (string name)
|
||||
{
|
||||
char* envvar;
|
||||
if ((envvar = getenv ("HOME")) == 0) {
|
||||
return "";
|
||||
string const uri = do_save_preset (name);
|
||||
|
||||
if (!uri.empty()) {
|
||||
_presets.insert (make_pair (uri, PresetRecord (uri, name)));
|
||||
PresetAdded (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
return envvar;
|
||||
}
|
||||
|
||||
string
|
||||
Plugin::preset_source (string envvar, string domain) const
|
||||
{
|
||||
return string_compose ("file:%1/.%2/rdf/ardour-presets.n3", envvar, domain);
|
||||
}
|
||||
|
||||
bool
|
||||
Plugin::write_preset_file (string envvar, string domain)
|
||||
{
|
||||
string path = string_compose("%1/.%2", envvar, domain);
|
||||
if (g_mkdir_with_parents (path.c_str(), 0775)) {
|
||||
warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
path += "/rdf";
|
||||
if (g_mkdir_with_parents (path.c_str(), 0775)) {
|
||||
warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
string const source = preset_source (envvar, domain);
|
||||
|
||||
if (lrdf_export_by_source (source.c_str(), source.substr(5).c_str())) {
|
||||
warning << string_compose(_("Error saving presets file %1."), source) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plugin::save_preset (string name, string domain)
|
||||
{
|
||||
lrdf_portvalue portvalues[parameter_count()];
|
||||
lrdf_defaults defaults;
|
||||
uint32_t id;
|
||||
std::string unique (unique_id());
|
||||
|
||||
/* XXX problem: AU plugins don't have numeric ID's.
|
||||
Solution: they have a different method of providing/saving presets.
|
||||
XXX sub-problem: implement it.
|
||||
*/
|
||||
|
||||
if (!isdigit (unique[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
id = atol (unique.c_str());
|
||||
|
||||
defaults.count = parameter_count();
|
||||
defaults.items = portvalues;
|
||||
|
||||
for (uint32_t i = 0; i < parameter_count(); ++i) {
|
||||
if (parameter_is_input (i)) {
|
||||
portvalues[i].pid = i;
|
||||
portvalues[i].value = get_parameter(i);
|
||||
}
|
||||
}
|
||||
|
||||
string const envvar = preset_envvar ();
|
||||
if (envvar.empty()) {
|
||||
warning << _("Could not locate HOME. Preset not saved.") << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
string const source = preset_source (envvar, domain);
|
||||
|
||||
char* uri = lrdf_add_preset (source.c_str(), name.c_str(), id, &defaults);
|
||||
|
||||
/* XXX: why is the uri apparently kept as the key in the `presets' map and also in the PresetRecord? */
|
||||
|
||||
presets.insert (make_pair (uri, PresetRecord (uri, name)));
|
||||
free (uri);
|
||||
|
||||
bool const r = write_preset_file (envvar, domain);
|
||||
|
||||
PresetAdded (); /* EMIT SIGNAL */
|
||||
|
||||
return r;
|
||||
return !uri.empty ();
|
||||
}
|
||||
|
||||
PluginPtr
|
||||
|
@ -393,4 +183,26 @@ Plugin::input_streams () const
|
|||
return ChanCount::ZERO;
|
||||
}
|
||||
|
||||
const Plugin::PresetRecord *
|
||||
Plugin::preset_by_label (const string& label)
|
||||
{
|
||||
// FIXME: O(n)
|
||||
for (map<string, PresetRecord>::const_iterator i = _presets.begin(); i != _presets.end(); ++i) {
|
||||
if (i->second.label == label) {
|
||||
return &i->second;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Plugin::PresetRecord *
|
||||
Plugin::preset_by_uri (const string& uri)
|
||||
{
|
||||
map<string, PresetRecord>::const_iterator pr = _presets.find (uri);
|
||||
if (pr != _presets.end()) {
|
||||
return &pr->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,6 +142,37 @@ VSTPlugin::nth_parameter (uint32_t n, bool& ok) const
|
|||
return n;
|
||||
}
|
||||
|
||||
/** Get VST chunk as base64-encoded data.
|
||||
* @param single true for single program, false for all programs.
|
||||
* @return 0-terminated base64-encoded data; must be passed to g_free () by caller.
|
||||
*/
|
||||
gchar *
|
||||
VSTPlugin::get_chunk (bool single)
|
||||
{
|
||||
guchar* data;
|
||||
int32_t data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, single ? 1 : 0, 0, &data, 0);
|
||||
if (data_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_base64_encode (data, data_size);
|
||||
}
|
||||
|
||||
/** Set VST chunk from base64-encoded data.
|
||||
* @param 0-terminated base64-encoded data.
|
||||
* @param single true for single program, false for all programs.
|
||||
* @return 0 on success, non-0 on failure
|
||||
*/
|
||||
int
|
||||
VSTPlugin::set_chunk (gchar const * data, bool single)
|
||||
{
|
||||
gsize size = 0;
|
||||
guchar* raw_data = g_base64_decode (data, &size);
|
||||
int const r = _plugin->dispatcher (_plugin, 24 /* effSetChunk */, single ? 1 : 0, size, raw_data, 0);
|
||||
g_free (raw_data);
|
||||
return r;
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
VSTPlugin::get_state()
|
||||
{
|
||||
|
@ -156,12 +187,8 @@ VSTPlugin::get_state()
|
|||
|
||||
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
|
||||
|
||||
/* fetch the current chunk */
|
||||
|
||||
guchar* data;
|
||||
int32_t data_size;
|
||||
|
||||
if ((data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, 0, 0, &data, false)) == 0) {
|
||||
gchar* data = get_chunk (false);
|
||||
if (data == 0) {
|
||||
return *root;
|
||||
}
|
||||
|
||||
|
@ -169,9 +196,8 @@ VSTPlugin::get_state()
|
|||
|
||||
XMLNode* chunk_node = new XMLNode (X_("chunk"));
|
||||
|
||||
gchar * encoded_data = g_base64_encode (data, data_size);
|
||||
chunk_node->add_content (encoded_data);
|
||||
g_free (encoded_data);
|
||||
chunk_node->add_content (data);
|
||||
g_free (data);
|
||||
|
||||
root->add_child_nocopy (*chunk_node);
|
||||
|
||||
|
@ -220,11 +246,10 @@ VSTPlugin::set_state(const XMLNode& node, int)
|
|||
|
||||
for (n = child->children ().begin (); n != child->children ().end (); ++n) {
|
||||
if ((*n)->is_content ()) {
|
||||
gsize chunk_size = 0;
|
||||
guchar * data = g_base64_decode ((*n)->content ().c_str (), &chunk_size);
|
||||
//cerr << "Dispatch setChunk for " << name() << endl;
|
||||
ret = _plugin->dispatcher (_plugin, 24 /* effSetChunk */, 0, chunk_size, data, 0);
|
||||
g_free (data);
|
||||
/* XXX: this may be dubious for the same reasons that we delay
|
||||
execution of load_preset.
|
||||
*/
|
||||
ret = set_chunk ((*n)->content().c_str(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,33 +356,96 @@ bool
|
|||
VSTPlugin::load_preset (const string& name)
|
||||
{
|
||||
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
|
||||
error << _("no support for presets using chunks at this time")
|
||||
<< endmsg;
|
||||
|
||||
XMLTree* t = presets_tree ();
|
||||
if (t == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XMLNode* root = t->root ();
|
||||
|
||||
/* Load a user preset chunk from our XML file and send it via a circuitous route to the plugin */
|
||||
|
||||
for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
|
||||
assert ((*i)->name() == X_("ChunkPreset"));
|
||||
|
||||
XMLProperty* uri = (*i)->property (X_("uri"));
|
||||
XMLProperty* label = (*i)->property (X_("label"));
|
||||
|
||||
assert (uri);
|
||||
assert (label);
|
||||
|
||||
if (label->value() == name) {
|
||||
|
||||
if (_fst->wanted_chunk) {
|
||||
g_free (_fst->wanted_chunk);
|
||||
}
|
||||
|
||||
for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j) {
|
||||
if ((*j)->is_content ()) {
|
||||
/* we can't dispatch directly here; too many plugins expect only one GUI thread */
|
||||
gsize size = 0;
|
||||
guchar* raw_data = g_base64_decode ((*j)->content().c_str(), &size);
|
||||
_fst->wanted_chunk = raw_data;
|
||||
_fst->wanted_chunk_size = size;
|
||||
_fst->want_chunk = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return Plugin::load_preset (name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VSTPlugin::save_preset (string name)
|
||||
string
|
||||
VSTPlugin::do_save_preset (string name)
|
||||
{
|
||||
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
|
||||
error << _("no support for presets using chunks at this time")
|
||||
<< endmsg;
|
||||
return false;
|
||||
|
||||
XMLTree* t = presets_tree ();
|
||||
if (t == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Add a chunk to our XML file of user presets */
|
||||
|
||||
XMLNode* p = new XMLNode (X_("ChunkPreset"));
|
||||
/* XXX: use of _presets.size() + 1 for the unique ID here is dubious at best */
|
||||
string const uri = string_compose (X_("VST:%1:%2"), unique_id (), _presets.size() + 1);
|
||||
p->add_property (X_("uri"), uri);
|
||||
p->add_property (X_("label"), name);
|
||||
gchar* data = get_chunk (true);
|
||||
p->add_content (string (data));
|
||||
g_free (data);
|
||||
t->root()->add_child_nocopy (*p);
|
||||
|
||||
sys::path f = ARDOUR::user_config_directory ();
|
||||
f /= "presets";
|
||||
f /= "vst";
|
||||
|
||||
t->write (f.to_string ());
|
||||
delete t;
|
||||
return uri;
|
||||
}
|
||||
return Plugin::save_preset (name, "vst");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
VSTPlugin::remove_preset (string name)
|
||||
VSTPlugin::do_remove_preset (string name)
|
||||
{
|
||||
if (_plugin->flags & 32 /* effFlagsProgramsChunks */) {
|
||||
|
||||
/* XXX: TODO */
|
||||
|
||||
error << _("no support for presets using chunks at this time")
|
||||
<< endmsg;
|
||||
return;
|
||||
}
|
||||
Plugin::remove_preset (name, "vst");
|
||||
}
|
||||
|
||||
string
|
||||
|
@ -472,7 +560,7 @@ VSTPlugin::name () const
|
|||
const char *
|
||||
VSTPlugin::maker () const
|
||||
{
|
||||
return "imadeit";
|
||||
return _info->creator.c_str();
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -545,6 +633,94 @@ VSTPluginInfo::load (Session& session)
|
|||
}
|
||||
}
|
||||
|
||||
vector<Plugin::PresetRecord>
|
||||
VSTPlugin::get_presets ()
|
||||
{
|
||||
vector<PresetRecord> p;
|
||||
|
||||
/* Built-in presets */
|
||||
|
||||
int const vst_version = _plugin->dispatcher (_plugin, effGetVstVersion, 0, 0, NULL, 0);
|
||||
for (int i = 0; i < _plugin->numPrograms; ++i) {
|
||||
PresetRecord r (string_compose (X_("VST:%1:%2"), unique_id (), i), "");
|
||||
|
||||
if (vst_version >= 2) {
|
||||
char buf[256];
|
||||
_plugin->dispatcher (_plugin, 29, i, 0, buf, 0);
|
||||
r.label = buf;
|
||||
} else {
|
||||
r.label = string_compose (_("Preset %1"), i);
|
||||
}
|
||||
|
||||
p.push_back (r);
|
||||
_presets.insert (make_pair (r.uri, r));
|
||||
}
|
||||
|
||||
/* User presets from our XML file */
|
||||
|
||||
XMLTree* t = presets_tree ();
|
||||
|
||||
if (t) {
|
||||
XMLNode* root = t->root ();
|
||||
for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
|
||||
|
||||
assert ((*i)->name() == X_("ChunkPreset"));
|
||||
|
||||
XMLProperty* uri = (*i)->property (X_("uri"));
|
||||
XMLProperty* label = (*i)->property (X_("label"));
|
||||
|
||||
assert (uri);
|
||||
assert (label);
|
||||
|
||||
PresetRecord r (uri->value(), label->value());
|
||||
p.push_back (r);
|
||||
_presets.insert (make_pair (r.uri, r));
|
||||
}
|
||||
}
|
||||
|
||||
delete t;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/** @return XMLTree with our user presets; could be a new one if no existing
|
||||
* one was found, or 0 if one was present but badly-formatted.
|
||||
*/
|
||||
XMLTree *
|
||||
VSTPlugin::presets_tree () const
|
||||
{
|
||||
XMLTree* t = new XMLTree;
|
||||
|
||||
sys::path p = ARDOUR::user_config_directory ();
|
||||
p /= "presets";
|
||||
|
||||
if (!is_directory (p)) {
|
||||
create_directory (p);
|
||||
}
|
||||
|
||||
p /= "vst";
|
||||
|
||||
if (!exists (p)) {
|
||||
t->set_root (new XMLNode (X_("VSTPresets")));
|
||||
return t;
|
||||
}
|
||||
|
||||
t->set_filename (p.to_string ());
|
||||
if (!t->read ()) {
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/** @return Index of the first user preset in our lists */
|
||||
int
|
||||
VSTPlugin::first_user_preset_index () const
|
||||
{
|
||||
return _plugin->numPrograms;
|
||||
}
|
||||
|
||||
VSTPluginInfo::VSTPluginInfo()
|
||||
{
|
||||
type = ARDOUR::VST;
|
||||
|
|
|
@ -83,6 +83,9 @@ struct _FST
|
|||
int vst_version;
|
||||
|
||||
int want_program;
|
||||
int want_chunk;
|
||||
unsigned char *wanted_chunk;
|
||||
int wanted_chunk_size;
|
||||
int current_program;
|
||||
float *want_params;
|
||||
float *set_params;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define FALSE 0
|
||||
#define TRUE !FALSE
|
||||
|
||||
extern char * strdup (const char *);
|
||||
|
||||
static char *read_string( FILE *fp ) {
|
||||
char buf[MAX_STRING_LEN];
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ fst_new ()
|
|||
pthread_cond_init (&fst->window_status_change, NULL);
|
||||
pthread_cond_init (&fst->plugin_dispatcher_called, NULL);
|
||||
fst->want_program = -1;
|
||||
fst->want_chunk = 0;
|
||||
fst->current_program = -1;
|
||||
return fst;
|
||||
}
|
||||
|
@ -178,6 +179,12 @@ again:
|
|||
/* did it work? */
|
||||
fst->current_program = fst->plugin->dispatcher (fst->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
|
||||
fst->want_program = -1;
|
||||
printf("old-style leaves CP=%d\n", fst->current_program);
|
||||
}
|
||||
|
||||
if (fst->want_chunk == 1) {
|
||||
fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
|
||||
fst->want_chunk = 0;
|
||||
}
|
||||
|
||||
if(fst->dispatcher_wantcall) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user