[SCM] calf/master: + First implementation of XML-based GUI (for monosynth only so far)
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:36:49 UTC 2013
The following commit has been merged in the master branch:
commit a0619044c5c694e4197d13a78c82e1caacf2f804
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Wed Dec 26 00:13:25 2007 +0000
+ First implementation of XML-based GUI (for monosynth only so far)
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@44 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/ChangeLog b/ChangeLog
index e69de29..f92fb5e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -0,0 +1,3 @@
+Version 0.0.9
+
++ started creating an XML-based GUI (for monosynth only in this version)
diff --git a/src/calf/giface.h b/src/calf/giface.h
index 0c6694b..e618f06 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -102,6 +102,7 @@ struct plugin_ctl_iface
virtual float get_param_value(int param_no) = 0;
virtual void set_param_value(int param_no, float value) = 0;
virtual int get_param_count() = 0;
+ virtual const char *get_gui_xml() = 0;
virtual ~plugin_ctl_iface() {}
};
@@ -128,6 +129,7 @@ public:
uint32_t process_audio(uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
static int get_in_channels();
static int get_out_channels();
+ static const char *get_xml_iface() { return NULL; }
};
struct ladspa_info
@@ -172,6 +174,9 @@ struct ladspa_instance: public Module, public plugin_ctl_iface
{
return Module::param_count;
}
+ virtual const char *get_gui_xml() {
+ return Module::get_gui_xml();
+ }
};
template<class Module>
@@ -437,7 +442,7 @@ struct ladspa_wrapper
std::string generate_rdf() {
return synth::generate_ladspa_rdf(info, Module::param_props, (const char **)descriptor.PortNames, Module::param_count, Module::in_count + Module::out_count);
- };
+ }
};
template<class Module>
diff --git a/src/calf/gui.h b/src/calf/gui.h
index 78ebee3..c459956 100644
--- a/src/calf/gui.h
+++ b/src/calf/gui.h
@@ -22,6 +22,8 @@
#ifndef __CALF_GUI_H
#define __CALF_GUI_H
+#include <expat.h>
+#include <map>
#include <vector>
#include <gtk/gtk.h>
#if USE_PHAT
@@ -32,16 +34,36 @@ namespace synth {
class plugin_gui;
-struct param_control
+struct control_base
{
+ typedef std::map<std::string, std::string> xml_attribute_map;
+ xml_attribute_map attribs;
plugin_gui *gui;
+ void require_attribute(const char *name);
+ void require_int_attribute(const char *name);
+ int get_int(const char *name, int def_value = 0);
+ float get_float(const char *name, float def_value = 0.f);
+};
+
+#define _GUARD_CHANGE_ if (in_change) return; guard_change __gc__(this);
+
+struct param_control: public control_base
+{
int param_no;
GtkWidget *label, *widget;
+ int in_change;
- param_control() { gui = NULL; param_no = -1; label = NULL; }
+ struct guard_change {
+ param_control *pc;
+ guard_change(param_control *_pc) : pc(_pc) { pc->in_change++; }
+ ~guard_change() { pc->in_change--; }
+ };
+
+ param_control() { gui = NULL; param_no = -1; label = NULL; in_change = 0;}
inline parameter_properties &get_props();
- virtual GtkWidget *create_label(int param_idx);
+ virtual void init_xml(const char *element) {}
+ virtual GtkWidget *create_label();
virtual void update_label();
/// called to create a widget for a control
virtual GtkWidget *create(plugin_gui *_gui, int _param_no)=0;
@@ -49,9 +71,65 @@ struct param_control
virtual void get()=0;
/// called to transfer the value from parameter(s) to control
virtual void set()=0;
+ virtual void hook_params();
virtual ~param_control() {}
};
+struct control_container: public control_base
+{
+ GtkContainer *container;
+
+ virtual GtkWidget *create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes)=0;
+ virtual void add(GtkWidget *w, control_base *base) { gtk_container_add(container, w); }
+ virtual ~control_container() {}
+};
+
+struct table_container: public control_container
+{
+ virtual GtkWidget *create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes);
+ virtual void add(GtkWidget *w, control_base *base);
+};
+
+struct alignment_container: public control_container
+{
+ virtual GtkWidget *create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes);
+};
+
+struct frame_container: public control_container
+{
+ virtual GtkWidget *create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes);
+};
+
+struct box_container: public control_container
+{
+ virtual void add(GtkWidget *w, control_base *base);
+};
+
+struct vbox_container: public box_container
+{
+ virtual GtkWidget *create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes);
+};
+
+struct hbox_container: public box_container
+{
+ virtual GtkWidget *create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes);
+};
+
+struct label_param_control: public param_control
+{
+ virtual GtkWidget *create(plugin_gui *_gui, int _param_no);
+ virtual void get() {}
+ virtual void set() {}
+};
+
+struct value_param_control: public param_control
+{
+ virtual GtkWidget *create(plugin_gui *_gui, int _param_no);
+ virtual void get() {}
+ virtual void set();
+};
+
+
struct hscale_param_control: public param_control
{
GtkHScale *scale;
@@ -59,6 +137,7 @@ struct hscale_param_control: public param_control
virtual GtkWidget *create(plugin_gui *_gui, int _param_no);
virtual void get();
virtual void set();
+ virtual void init_xml(const char *element);
static void hscale_value_changed(GtkHScale *widget, gpointer value);
static gchar *hscale_format_value(GtkScale *widget, double arg1, gpointer value);
};
@@ -101,17 +180,31 @@ class plugin_gui
{
protected:
int param_count;
+ std::multimap<int, param_control *> par2ctl;
+ XML_Parser parser;
+ param_control *current_control;
+ std::vector<control_container *> container_stack;
+ control_container *top_container;
+ std::map<std::string, int> param_name_map;
public:
plugin_gui_window *window;
- GtkWidget *table;
+ GtkWidget *container;
const char *effect_name;
plugin_ctl_iface *plugin;
std::vector<param_control *> params;
plugin_gui(plugin_gui_window *_window);
- GtkWidget *create(plugin_ctl_iface *_plugin, const char *title);
+ GtkWidget *create(plugin_ctl_iface *_plugin);
+ GtkWidget *create_from_xml(plugin_ctl_iface *_plugin, const char *xml);
+ param_control *create_control_from_xml(const char *element, const char *attributes[]);
+ control_container *create_container_from_xml(const char *element, const char *attributes[]);
+ void add_param_ctl(int param, param_control *ctl) { par2ctl.insert(std::pair<int, param_control *>(param, ctl)); }
void refresh();
+ void xml_element_start(const char *element, const char *attributes[]);
+ void set_param_value(int param_no, float value, param_control *originator = NULL);
+ static void xml_element_start(void *data, const char *element, const char *attributes[]);
+ static void xml_element_end(void *data, const char *element);
#if USE_PHAT
static void knob_value_changed(PhatKnob *widget, gpointer value);
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index e2abeef..b445b89 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -304,6 +304,9 @@ public:
params[param_no] = value;
changed = true;
}
+ virtual const char *get_gui_xml() {
+ return Module::get_gui_xml();
+ }
};
extern jack_host_base *create_jack_host(const char *name);
diff --git a/src/calf/modules.h b/src/calf/modules.h
index 409f50c..3d3ae69 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -42,6 +42,7 @@ public:
inline void activate() {}
inline void deactivate() {}
inline void set_sample_rate(uint32_t sr) { }
+ inline static const char *get_gui_xml() { return NULL; }
};
class amp_audio_module: public null_audio_module
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index 329fa35..44e58e7 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -64,6 +64,7 @@ public:
synth::adsr envelope;
static parameter_properties param_props[];
+ static const char *get_gui_xml();
void set_sample_rate(uint32_t sr);
void delayed_note_on();
void note_on(int note, int vel)
diff --git a/src/gui.cpp b/src/gui.cpp
index 472fa88..90457c4 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -30,7 +30,7 @@ using namespace std;
/******************************** controls ********************************/
-GtkWidget *param_control::create_label(int param_idx)
+GtkWidget *param_control::create_label()
{
label = gtk_label_new ("");
gtk_label_set_width_chars (GTK_LABEL (label), 12);
@@ -44,6 +44,12 @@ void param_control::update_label()
gtk_label_set_text (GTK_LABEL (label), props.to_string(gui->plugin->get_param_value(param_no)).c_str());
}
+void param_control::hook_params()
+{
+ if (param_no != -1)
+ gui->add_param_ctl(param_no, this);
+}
+
// combo box
GtkWidget *combo_box_param_control::create(plugin_gui *_gui, int _param_no)
@@ -62,6 +68,7 @@ GtkWidget *combo_box_param_control::create(plugin_gui *_gui, int _param_no)
void combo_box_param_control::set()
{
+ _GUARD_CHANGE_
parameter_properties &props = get_props();
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), (int)gui->plugin->get_param_value(param_no) - (int)props.min);
}
@@ -69,7 +76,7 @@ void combo_box_param_control::set()
void combo_box_param_control::get()
{
parameter_properties &props = get_props();
- gui->plugin->set_param_value(param_no, gtk_combo_box_get_active (GTK_COMBO_BOX(widget)) + props.min);
+ gui->set_param_value(param_no, gtk_combo_box_get_active (GTK_COMBO_BOX(widget)) + props.min, this);
}
void combo_box_param_control::combo_value_changed(GtkComboBox *widget, gpointer value)
@@ -93,18 +100,31 @@ GtkWidget *hscale_param_control::create(plugin_gui *_gui, int _param_no)
return widget;
}
+void hscale_param_control::init_xml(const char *element)
+{
+ if (attribs.count("width"))
+ gtk_widget_set_size_request (widget, get_int("width", 200), -1);
+ if (attribs.count("position"))
+ {
+ string v = attribs["position"];
+ if (v == "top") gtk_scale_set_value_pos(GTK_SCALE(widget), GTK_POS_TOP);
+ if (v == "bottom") gtk_scale_set_value_pos(GTK_SCALE(widget), GTK_POS_BOTTOM);
+ }
+}
+
void hscale_param_control::set()
{
+ _GUARD_CHANGE_
parameter_properties &props = get_props();
gtk_range_set_value (GTK_RANGE (widget), props.to_01 (gui->plugin->get_param_value(param_no)));
- hscale_value_changed (GTK_HSCALE (widget), (gpointer)this);
+ // hscale_value_changed (GTK_HSCALE (widget), (gpointer)this);
}
void hscale_param_control::get()
{
parameter_properties &props = get_props();
float cvalue = props.from_01 (gtk_range_get_value (GTK_RANGE (widget)));
- gui->plugin->set_param_value(param_no, cvalue);
+ gui->set_param_value(param_no, cvalue, this);
}
void hscale_param_control::hscale_value_changed(GtkHScale *widget, gpointer value)
@@ -124,6 +144,36 @@ gchar *hscale_param_control::hscale_format_value(GtkScale *widget, double arg1,
return g_strdup (props.to_string (cvalue).c_str());
}
+// label
+
+GtkWidget *label_param_control::create(plugin_gui *_gui, int _param_no)
+{
+ gui = _gui, param_no = _param_no;
+ string text = "<no name>";
+ if (param_no != -1)
+ text = get_props().name;
+ widget = gtk_label_new(text.c_str());
+ return widget;
+}
+
+// value
+
+GtkWidget *value_param_control::create(plugin_gui *_gui, int _param_no)
+{
+ gui = _gui, param_no = _param_no;
+ widget = gtk_label_new ("");
+ gtk_label_set_width_chars (GTK_LABEL (widget), 12);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.5);
+ return widget;
+}
+
+void value_param_control::set()
+{
+ _GUARD_CHANGE_
+ parameter_properties &props = get_props();
+ gtk_label_set_text (GTK_LABEL (widget), props.to_string(gui->plugin->get_param_value(param_no)).c_str());
+}
+
// check box
GtkWidget *toggle_param_control::create(plugin_gui *_gui, int _param_no)
@@ -145,12 +195,12 @@ void toggle_param_control::toggle_value_changed(GtkCheckButton *widget, gpointer
void toggle_param_control::get()
{
const parameter_properties &props = get_props();
- plugin_ctl_iface &pif = *gui->plugin;
- pif.set_param_value(param_no, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) + props.min);
+ gui->set_param_value(param_no, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) + props.min, this);
}
void toggle_param_control::set()
{
+ _GUARD_CHANGE_
const parameter_properties &props = get_props();
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), (int)gui->plugin->get_param_value(param_no) - (int)props.min);
}
@@ -173,11 +223,14 @@ void knob_param_control::get()
{
const parameter_properties &props = get_props();
float value = props.from_01(phat_knob_get_value(PHAT_KNOB(widget)));
- gui->plugin->set_param_value(param_no, value);
+ gui->set_param_value(param_no, value, this);
+ if (label)
+ update_label();
}
void knob_param_control::set()
{
+ _GUARD_CHANGE_
const parameter_properties &props = get_props();
phat_knob_set_value(PHAT_KNOB(widget), props.to_01 (gui->plugin->get_param_value(param_no)));
knob_value_changed(PHAT_KNOB(widget), (gpointer)this);
@@ -186,11 +239,7 @@ void knob_param_control::set()
void knob_param_control::knob_value_changed(PhatKnob *widget, gpointer value)
{
param_control *jhp = (param_control *)value;
- plugin_ctl_iface &pif = *jhp->gui->plugin;
- const parameter_properties &props = jhp->get_props();
- float cvalue = props.from_01 (phat_knob_get_value (widget));
- pif.set_param_value(jhp->param_no, cvalue);
- jhp->update_label();
+ jhp->get();
}
#endif
@@ -207,7 +256,7 @@ static void action_destroy_notify(gpointer data)
delete (activate_preset_params *)data;
}
-GtkWidget *plugin_gui::create(plugin_ctl_iface *_plugin, const char *title)
+GtkWidget *plugin_gui::create(plugin_ctl_iface *_plugin)
{
plugin = _plugin;
param_count = plugin->get_param_count();
@@ -216,14 +265,14 @@ GtkWidget *plugin_gui::create(plugin_ctl_iface *_plugin, const char *title)
params[i] = NULL;
}
- table = gtk_table_new (param_count, 3, FALSE);
+ container = gtk_table_new (param_count, 3, FALSE);
for (int i = 0; i < param_count; i++) {
int trow = i;
parameter_properties &props = *plugin->get_param_props(i);
GtkWidget *label = gtk_label_new (props.name);
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, trow, trow + 1, GTK_FILL, GTK_FILL, 2, 2);
+ gtk_table_attach (GTK_TABLE (container), label, 0, 1, trow, trow + 1, GTK_FILL, GTK_FILL, 2, 2);
GtkWidget *widget = NULL;
@@ -233,22 +282,22 @@ GtkWidget *plugin_gui::create(plugin_ctl_iface *_plugin, const char *title)
{
params[i] = new combo_box_param_control();
widget = params[i]->create(this, i);
- gtk_table_attach (GTK_TABLE (table), widget, 1, 3, trow, trow + 1, GTK_EXPAND, GTK_SHRINK, 0, 0);
+ gtk_table_attach (GTK_TABLE (container), widget, 1, 3, trow, trow + 1, GTK_EXPAND, GTK_SHRINK, 0, 0);
}
else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
(props.flags & PF_CTLMASK) == PF_CTL_TOGGLE)
{
params[i] = new toggle_param_control();
widget = params[i]->create(this, i);
- gtk_table_attach (GTK_TABLE (table), widget, 1, 3, trow, trow + 1, GTK_EXPAND, GTK_SHRINK, 0, 0);
+ gtk_table_attach (GTK_TABLE (container), widget, 1, 3, trow, trow + 1, GTK_EXPAND, GTK_SHRINK, 0, 0);
}
#if USE_PHAT
else if ((props.flags & PF_CTLMASK) != PF_CTL_FADER)
{
params[i] = new knob_param_control();
widget = params[i]->create(this, i);
- gtk_table_attach (GTK_TABLE (table), widget, 1, 2, trow, trow + 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
- gtk_table_attach (GTK_TABLE (table), params[i]->create_label(i), 2, 3, trow, trow + 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), GTK_SHRINK, 0, 0);
+ gtk_table_attach (GTK_TABLE (container), widget, 1, 2, trow, trow + 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_table_attach (GTK_TABLE (container), params[i]->create_label(), 2, 3, trow, trow + 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), GTK_SHRINK, 0, 0);
}
#endif
else
@@ -256,13 +305,248 @@ GtkWidget *plugin_gui::create(plugin_ctl_iface *_plugin, const char *title)
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
params[i] = new hscale_param_control();
widget = params[i]->create(this, i);
- gtk_table_attach (GTK_TABLE (table), widget, 1, 3, trow, trow + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_SHRINK, 0, 0);
+ gtk_table_attach (GTK_TABLE (container), widget, 1, 3, trow, trow + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_SHRINK, 0, 0);
}
params[i]->set();
}
+ return container;
+}
+
+void control_base::require_attribute(const char *name)
+{
+ if (attribs.count(name) == 0) {
+ g_error("Missing attribute: %s", name);
+ }
+}
+
+void control_base::require_int_attribute(const char *name)
+{
+ if (attribs.count(name) == 0) {
+ g_error("Missing attribute: %s", name);
+ }
+ if (attribs[name].empty() || attribs[name].find_first_not_of("0123456789") != string::npos) {
+ g_error("Wrong data type on attribute: %s (required integer)", name);
+ }
+}
+
+int control_base::get_int(const char *name, int def_value)
+{
+ if (attribs.count(name) == 0)
+ return def_value;
+ const std::string &v = attribs[name];
+ if (v.empty() || v.find_first_not_of("-+0123456789") != string::npos)
+ return def_value;
+ return atoi(v.c_str());
+}
+
+float control_base::get_float(const char *name, float def_value)
+{
+ if (attribs.count(name) == 0)
+ return def_value;
+ const std::string &v = attribs[name];
+ if (v.empty() || v.find_first_not_of("-+0123456789.") != string::npos)
+ return def_value;
+ stringstream ss(v);
+ float value;
+ ss >> value;
+ return value;
+}
+
+/******************************** GtkTable container ********************************/
+
+GtkWidget *table_container::create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes)
+{
+ require_int_attribute("rows");
+ require_int_attribute("cols");
+ GtkWidget *table = gtk_table_new(get_int("rows", 1), get_int("cols", 1), false);
+ container = GTK_CONTAINER(table);
return table;
}
+void table_container::add(GtkWidget *widget, control_base *base)
+{
+ base->require_int_attribute("attach-x");
+ base->require_int_attribute("attach-y");
+ int x = base->get_int("attach-x"), y = base->get_int("attach-y");
+ int w = base->get_int("attach-w", 1), h = base->get_int("attach-h", 1);
+ int fillx = (base->get_int("fill-x", 1) ? GTK_FILL : 0) | (base->get_int("expand-x", 1) ? GTK_EXPAND : 0) | (base->get_int("shrink-x", 0) ? GTK_SHRINK : 0);
+ int filly = (base->get_int("fill-y", 1) ? GTK_FILL : 0) | (base->get_int("expand-y", 1) ? GTK_EXPAND : 0) | (base->get_int("shrink-y", 0) ? GTK_SHRINK : 0);
+ int padx = base->get_int("pad-x", 2);
+ int pady = base->get_int("pad-y", 2);
+ gtk_table_attach(GTK_TABLE(container), widget, x, x + w, y, y + h, (GtkAttachOptions)fillx, (GtkAttachOptions)filly, padx, pady);
+}
+
+/******************************** alignment contaner ********************************/
+
+GtkWidget *alignment_container::create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes)
+{
+ GtkWidget *align = gtk_alignment_new(get_float("align-x", 0.5), get_float("align-y", 0.5), get_float("scale-x", 0), get_float("scale-y", 0));
+ container = GTK_CONTAINER(align);
+ return align;
+}
+
+/******************************** GtkFrame contaner ********************************/
+
+GtkWidget *frame_container::create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes)
+{
+ GtkWidget *frame = gtk_frame_new(attribs["label"].c_str());
+ container = GTK_CONTAINER(frame);
+ return frame;
+}
+
+/******************************** GtkBox type of containers ********************************/
+
+void box_container::add(GtkWidget *w, control_base *base)
+{
+ gtk_container_add_with_properties(container, w, "expand", get_int("expand", 1), "fill", get_int("fill", 1), NULL);
+}
+
+/******************************** GtkHBox container ********************************/
+
+GtkWidget *hbox_container::create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes)
+{
+ GtkWidget *hbox = gtk_hbox_new(false, get_int("spacing", 2));
+ container = GTK_CONTAINER(hbox);
+ return hbox;
+}
+
+/******************************** GtkVBox container ********************************/
+
+GtkWidget *vbox_container::create(plugin_gui *_gui, const char *element, xml_attribute_map &attributes)
+{
+ GtkWidget *vbox = gtk_vbox_new(false, get_int("spacing", 2));
+ container = GTK_CONTAINER(vbox);
+ return vbox;
+}
+
+/******************************** GUI proper ********************************/
+
+param_control *plugin_gui::create_control_from_xml(const char *element, const char *attributes[])
+{
+ if (!strcmp(element, "knob"))
+ return new knob_param_control;
+ if (!strcmp(element, "hscale"))
+ return new hscale_param_control;
+ if (!strcmp(element, "combo"))
+ return new combo_box_param_control;
+ if (!strcmp(element, "toggle"))
+ return new toggle_param_control;
+ if (!strcmp(element, "label"))
+ return new label_param_control;
+ if (!strcmp(element, "value"))
+ return new value_param_control;
+ return NULL;
+}
+
+control_container *plugin_gui::create_container_from_xml(const char *element, const char *attributes[])
+{
+ if (!strcmp(element, "table"))
+ return new table_container;
+ if (!strcmp(element, "vbox"))
+ return new vbox_container;
+ if (!strcmp(element, "hbox"))
+ return new hbox_container;
+ if (!strcmp(element, "align"))
+ return new alignment_container;
+ if (!strcmp(element, "frame"))
+ return new frame_container;
+ return NULL;
+}
+
+void plugin_gui::xml_element_start(void *data, const char *element, const char *attributes[])
+{
+ plugin_gui *gui = (plugin_gui *)data;
+ gui->xml_element_start(element, attributes);
+}
+
+void plugin_gui::xml_element_start(const char *element, const char *attributes[])
+{
+ control_base::xml_attribute_map xam;
+ while(*attributes)
+ {
+ xam[attributes[0]] = attributes[1];
+ attributes += 2;
+ }
+
+ control_container *cc = create_container_from_xml(element, attributes);
+ if (cc != NULL)
+ {
+ cc->attribs = xam;
+ cc->create(this, element, xam);
+ gtk_container_set_border_width(cc->container, cc->get_int("border"));
+
+ container_stack.push_back(cc);
+ current_control = NULL;
+ return;
+ }
+ if (!container_stack.empty())
+ {
+ current_control = create_control_from_xml(element, attributes);
+ if (current_control)
+ {
+ current_control->attribs = xam;
+ int param_no = -1;
+ if (xam.count("param"))
+ {
+ map<string, int>::iterator it = param_name_map.find(xam["param"]);
+ if (it == param_name_map.end())
+ g_error("Unknown parameter %s", xam["param"].c_str());
+ else
+ param_no = it->second;
+ }
+ current_control->create(this, param_no);
+ current_control->init_xml(element);
+ current_control->set();
+ current_control->hook_params();
+ params.push_back(current_control);
+ return;
+ }
+ }
+ g_error("Unxpected element %s in GUI definition\n", element);
+}
+
+void plugin_gui::xml_element_end(void *data, const char *element)
+{
+ plugin_gui *gui = (plugin_gui *)data;
+ if (gui->current_control)
+ {
+ (*gui->container_stack.rbegin())->add(gui->current_control->widget, gui->current_control);
+ gui->current_control = NULL;
+ return;
+ }
+ unsigned int ss = gui->container_stack.size();
+ if (ss > 1) {
+ gui->container_stack[ss - 2]->add(GTK_WIDGET(gui->container_stack[ss - 1]->container), gui->container_stack[ss - 1]);
+ }
+ else
+ gui->top_container = gui->container_stack[0];
+ gui->container_stack.pop_back();
+}
+
+
+GtkWidget *plugin_gui::create_from_xml(plugin_ctl_iface *_plugin, const char *xml)
+{
+ current_control = NULL;
+ top_container = NULL;
+ parser = XML_ParserCreate("UTF-8");
+ plugin = _plugin;
+ container_stack.clear();
+
+ param_name_map.clear();
+ int size = plugin->get_param_count();
+ for (int i = 0; i < size; i++)
+ param_name_map[plugin->get_param_props(i)->short_name] = i;
+
+ XML_SetUserData(parser, this);
+ XML_SetElementHandler(parser, xml_element_start, xml_element_end);
+ XML_Status status = XML_Parse(parser, xml, strlen(xml), 1);
+ if (status == XML_STATUS_ERROR)
+ g_error("Parse error: %s in XML", XML_ErrorString(XML_GetErrorCode(parser)));
+
+ XML_ParserFree(parser);
+ return GTK_WIDGET(top_container->container);
+}
+
void plugin_gui::refresh()
{
for (unsigned int i = 0; i < params.size(); i++)
@@ -272,6 +556,19 @@ void plugin_gui::refresh()
}
}
+void plugin_gui::set_param_value(int param_no, float value, param_control *originator)
+{
+ plugin->set_param_value(param_no, value);
+ std::multimap<int, param_control *>::iterator it = par2ctl.find(param_no);
+ while(it != par2ctl.end() && it->first == param_no)
+ {
+ if (it->second != originator)
+ it->second->set();
+ it++;
+ }
+}
+
+
/******************************* Actions **************************************************/
static void store_preset_action(GtkAction *action, plugin_gui_window *gui_win)
@@ -389,16 +686,21 @@ void plugin_gui_window::create(plugin_ctl_iface *_jh, const char *title, const c
gtk_widget_size_request(GTK_WIDGET(toplevel), &req2);
// printf("size request %dx%d\n", req2.width, req2.height);
- GtkWidget *table = gui->create(_jh, effect);
+ GtkWidget *container;
+ const char *xml = _jh->get_gui_xml();
+ if (xml)
+ container = gui->create_from_xml(_jh, xml);
+ else
+ container = gui->create(_jh);
GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_NONE);
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), table);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), container);
gtk_box_pack_start(GTK_BOX(vbox), sw, true, true, 0);
gtk_widget_show_all(GTK_WIDGET(sw));
- gtk_widget_size_request(table, &req);
+ gtk_widget_size_request(container, &req);
// printf("size request %dx%d\n", req.width, req.height);
gtk_window_resize(GTK_WINDOW(toplevel), max(req.width + 10, req2.width), req.height + req2.height + 10);
// gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(sw), GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, req.height, 20, 100, 100)));
diff --git a/src/monosynth.cpp b/src/monosynth.cpp
index d6024a3..a20809c 100644
--- a/src/monosynth.cpp
+++ b/src/monosynth.cpp
@@ -49,6 +49,129 @@ const char *monosynth_filter_choices[] = {
"2x6dB/oct Bandpass",
};
+static const char *monosynth_gui_xml =
+ "<vbox border=\"10\">"
+ "<hbox spacing=\"10\">"
+ "<frame label=\"Oscillators\">"
+ "<vbox border=\"10\">"
+ "<table rows=\"2\" cols=\"2\">"
+ "<label attach-x=\"0\" attach-y=\"0\" param=\"o1_wave\" />"
+ "<label attach-x=\"1\" attach-y=\"0\" param=\"o2_wave\" />"
+ "<combo attach-x=\"0\" attach-y=\"1\" param=\"o1_wave\" />"
+ "<combo attach-x=\"1\" attach-y=\"1\" param=\"o2_wave\" />"
+ "</table>"
+ "<label param=\"o12_mix\"/>"
+ "<hscale param=\"o12_mix\" position=\"bottom\"/>"
+ "<hbox>"
+ "<vbox>"
+ " <label param=\"o12_detune\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"o12_detune\" expand=\"0\" fill=\"0\"/></align><value param=\"o12_detune\"/>"
+ "</vbox>"
+ "<align align-x=\"0.5\" align-y=\"0.5\">"
+ " <vbox>"
+ " <label param=\"phase_mode\" />"
+ " <combo param=\"phase_mode\"/>"
+ " </vbox>"
+ "</align>"
+ "<vbox>"
+ " <label param=\"o2_xpose\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"o2_xpose\" expand=\"0\" fill=\"0\"/></align><value param=\"o2_xpose\"/>"
+ "</vbox>"
+ "</hbox>"
+ "</vbox>"
+ "</frame>"
+ "<frame label=\"Filter\">"
+ "<vbox border=\"10\">"
+ "<align align-x=\"0.5\" align-y=\"0.5\">"
+ "<hbox>"
+ "<label param=\"filter\" /><combo param=\"filter\" />"
+ "</hbox>"
+ "</align>"
+ "<hbox>"
+ "<vbox>"
+ " <label param=\"cutoff\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"cutoff\" expand=\"0\" fill=\"0\"/></align><value param=\"cutoff\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"res\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"res\" expand=\"0\" fill=\"0\"/></align><value param=\"res\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"filter_sep\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"filter_sep\" expand=\"0\" fill=\"0\"/></align><value param=\"filter_sep\"/>"
+ "</vbox>"
+ "</hbox>"
+ "</vbox>"
+ "</frame>"
+ "</hbox>"
+ "<hbox spacing=\"10\">"
+ "<frame label=\"Envelope\">"
+ "<vbox border=\"10\" spacing=\"10\">"
+ "<hbox>"
+ "<vbox>"
+ " <label param=\"adsr_a\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"adsr_a\" expand=\"0\" fill=\"0\"/></align><value param=\"adsr_a\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"adsr_d\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"adsr_d\" expand=\"0\" fill=\"0\"/></align><value param=\"adsr_d\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"adsr_s\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"adsr_s\" expand=\"0\" fill=\"0\"/></align><value param=\"adsr_s\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"adsr_r\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"adsr_r\" expand=\"0\" fill=\"0\"/></align><value param=\"adsr_r\"/>"
+ "</vbox>"
+ "</hbox>"
+ "<hbox>"
+ "<vbox>"
+ " <label param=\"env2cutoff\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"env2cutoff\" expand=\"0\" fill=\"0\"/></align><value param=\"env2cutoff\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"env2res\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"env2res\" expand=\"0\" fill=\"0\"/></align><value param=\"env2res\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"env2amp\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"env2amp\" expand=\"0\" fill=\"0\"/></align><value param=\"env2amp\"/>"
+ "</vbox>"
+ "</hbox>"
+ "</vbox>"
+ "</frame>"
+ "<frame label=\"Settings\">"
+ "<vbox border=\"10\" spacing=\"10\">"
+ "<hbox>"
+ "<vbox>"
+ "<label param=\"key_follow\" />"
+ "<align align-x=\"0.5\" align-y=\"0.5\"><toggle param=\"key_follow\" /></align>"
+ "</vbox>"
+ "<vbox>"
+ "<label param=\"legato\" expand=\"0\"/>"
+ "<combo param=\"legato\" expand=\"0\" fill=\"0\"/>"
+ "</vbox>"
+ "</hbox>"
+ "<hbox>"
+ "<vbox>"
+ " <label param=\"portamento\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"portamento\" /></align><value param=\"portamento\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"vel2filter\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"vel2filter\" /></align><value param=\"vel2filter\"/>"
+ "</vbox>"
+ "<vbox>"
+ " <label param=\"vel2amp\" />"
+ " <align align-x=\"0.5\" align-y=\"0.5\"><knob param=\"vel2amp\" /></align><value param=\"vel2amp\"/>"
+ "</vbox>"
+ "</hbox>"
+ "</vbox>"
+ "</frame>"
+ "</hbox>"
+ "</vbox>";
+
parameter_properties monosynth_audio_module::param_props[] = {
{ wave_saw, 0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o1_wave", "Osc1 Wave" },
{ wave_sqr, 0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o2_wave", "Osc2 Wave" },
@@ -77,6 +200,11 @@ parameter_properties monosynth_audio_module::param_props[] = {
{ 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2amp", "Vel->Amp" },
};
+const char *monosynth_audio_module::get_gui_xml()
+{
+ return monosynth_gui_xml;
+}
+
void monosynth_audio_module::activate() {
running = false;
output_pos = 0;
diff --git a/src/preset.cpp b/src/preset.cpp
index 3eeb605..440d7b8 100644
--- a/src/preset.cpp
+++ b/src/preset.cpp
@@ -212,6 +212,7 @@ void preset_list::load(const char *filename)
if (status == XML_STATUS_ERROR)
throw preset_exception(string("Parse error: ") + XML_ErrorString(XML_GetErrorCode(parser))+ " in ", filename, errno);
close(fd);
+ XML_ParserFree(parser);
}
void preset_list::save(const char *filename)
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list