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:
Carl Hetherington 2010-12-07 02:56:11 +00:00
parent 25a702798e
commit 40c162d609
13 changed files with 524 additions and 318 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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);
};

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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) {