[SCM] calf/master: + autotools config fixed (fixed typo, added untested expat detection) + JACK GUI refactoring into separate "GUI window" class (not as good as should be, but still better than it was before) + preset menu updates after adding + presets are supposed to be loaded from global file in /usr/lib (still no global file, but one can't have everything :), I need to create those presets) + envelope fix (more like hack, eliminate disastrous rounding errors by using double instead of float, and treat 0% sustain specially so that the envelope doesn't get stuck in 0% sustain) - unneeded printf in monosynth (hope it won't get into commit, will revert it next time if it gets in)
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:36:46 UTC 2013
The following commit has been merged in the master branch:
commit ec0796d12af9e88c6202f936f2945d9bf0554286
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Tue Dec 18 00:07:25 2007 +0000
+ autotools config fixed (fixed typo, added untested expat detection)
+ JACK GUI refactoring into separate "GUI window" class (not as good as should be, but still better than it was before)
+ preset menu updates after adding
+ presets are supposed to be loaded from global file in /usr/lib (still no global file, but one can't have everything :), I need to create those presets)
+ envelope fix (more like hack, eliminate disastrous rounding errors by using double instead of float, and treat 0% sustain specially so that the envelope doesn't get stuck in 0% sustain)
- unneeded printf in monosynth (hope it won't get into commit, will revert it next time if it gets in)
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@27 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/Makefile.am b/Makefile.am
index d6ea7aa..7114d1d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,7 @@ SUBDIRS = $(SRCDIRS)
distdir = $(PACKAGE)-$(VERSION)
-EXTRADIST = TODO autogen.sh
+EXTRA_DIST = TODO autogen.sh calf.glade
clean-local:
rm -f *~ *.old
diff --git a/configure.in b/configure.in
index 1d722ee..3c252f6 100644
--- a/configure.in
+++ b/configure.in
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([calf],[0.0.6],[wdev at foltman.com])
+AC_INIT([calf],[0.0.7],[wdev at foltman.com])
AC_CONFIG_SRCDIR([config.h.in])
AC_CONFIG_HEADER([config.h])
@@ -30,6 +30,9 @@ AC_CHECK_HEADER(ladspa.h, LADSPA_FOUND="yes", LADSPA_FOUND="no")
AC_CHECK_HEADER(dssi.h, DSSI_FOUND="yes", DSSI_FOUND="no")
+AC_CHECK_HEADER(expat.h, true, AC_MSG_ERROR([Expat XML library not found]))
+AC_CHECK_LIB(expat, XML_Parse, true, AC_MSG_ERROR([Expat XML library not found]))
+
AC_CHECK_HEADERS([jack/jack.h], have_jack_header=yes, have_jack_header=no)
if test "$have_jack_header" = "yes"; then
diff --git a/src/Makefile.am b/src/Makefile.am
index 8c3185b..4e6478c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,7 @@ bin_PROGRAMS =
noinst_PROGRAMS = calfbenchmark
noinst_LTLIBRARIES = libcalf.la libcalfstatic.la libcalfgui.la
-AM_CXXFLAGS = -ffast-math -march=i686 -finline-limit=80
+AM_CXXFLAGS = -ffast-math -march=i686 -finline-limit=80 -DPKGLIBDIR=\"$(pkglibdir)\"
if USE_JACK
AM_CXXFLAGS += -DUSE_JACK=1 $(JACK_DEPS_CFLAGS) $(GUI_DEPS_CFLAGS)
@@ -43,19 +43,23 @@ endif
calfbenchmark_SOURCES = benchmark.cpp
calfbenchmark_LDADD =
-libcalf_la_SOURCES = modules.cpp giface.cpp synth.cpp
-libcalf_la_LDFLAGS = -rpath $(ladspadir) -version-info 0:0:0
+libcalf_la_SOURCES = modules.cpp giface.cpp synth.cpp preset.cpp
+libcalf_la_LDFLAGS = -rpath $(ladspadir) -version-info 0:0:0 -lexpat
-libcalfstatic_la_SOURCES = modules.cpp giface.cpp synth.cpp
-libcalfstatic_la_LDFLAGS = -static
+libcalfstatic_la_SOURCES = modules.cpp giface.cpp synth.cpp preset.cpp
+libcalfstatic_la_LDFLAGS = -static -lexpat
-libcalfgui_la_SOURCES = gui.cpp
+libcalfgui_la_SOURCES = gui.cpp preset_gui.cpp
libcalfgui_la_LDFLAGS = -static
clean-local:
$(RM) -f calfjackhost *~
install-data-hook:
+if USE_JACK
+ install -d -m 755 $(DESTDIR)$(pkglibdir)
+ install -c -m 644 $(top_srcdir)/calf.glade $(DESTDIR)$(pkglibdir)
+endif
if USE_LADSPA
install -d -m 755 $(DESTDIR)$(with_ladspa_dir)
install -d -m 755 $(DESTDIR)$(with_ladspa_rdf_dir)
@@ -69,6 +73,10 @@ endif
#remove calf.so, calf.rdf and - if empty - ladspa dir in usr/share
uninstall-hook:
+if USE_JACK
+ rm -f $(DESTDIR)$(pkglibdir)/calf.glade
+ rmdir $(DESTDIR)$(pkglibdir)
+endif
if USE_LADSPA
$(RM) -f $(DESTDIR)$(with_ladspa_dir)/calf.so
$(RM) -f $(DESTDIR)$(with_ladspa_rdf_dir)/calf.rdf
diff --git a/src/calf/Makefile.am b/src/calf/Makefile.am
index 6c998d4..e58384d 100644
--- a/src/calf/Makefile.am
+++ b/src/calf/Makefile.am
@@ -1,3 +1,7 @@
calfdir = $(includedir)/calf
-calf_HEADERS = audio_fx.h benchmark.h biquad.h buffer.h delay.h fft.h fixed_point.h giface.h gui.h inertia.h jackhost.h modules.h modules_dev.h modules_synths.h onepole.h organ.h osc.h primitives.h synth.h wave.h
+calf_HEADERS = audio_fx.h benchmark.h biquad.h buffer.h \
+ delay.h fft.h fixed_point.h giface.h gui.h inertia.h \
+ jackhost.h modules.h modules_dev.h modules_synths.h \
+ onepole.h organ.h osc.h preset.h preset_gui.h primitives.h \
+ synth.h wave.h
diff --git a/src/calf/gui.h b/src/calf/gui.h
index daa198c..e6d5dc9 100644
--- a/src/calf/gui.h
+++ b/src/calf/gui.h
@@ -105,18 +105,22 @@ struct knob_param_control: public param_control
};
#endif
+class plugin_gui_window;
+
class plugin_gui
{
protected:
int param_count;
public:
- GtkWidget *toplevel;
+ plugin_gui_window *window;
GtkWidget *table;
+ const char *effect_name;
plugin_ctl_iface *plugin;
std::vector<param_control *> params;
- plugin_gui(GtkWidget *_toplevel);
+ plugin_gui(plugin_gui_window *_window);
GtkWidget *create(plugin_ctl_iface *_plugin, const char *title);
+
void refresh();
#if USE_PHAT
@@ -124,6 +128,21 @@ public:
#endif
};
+class plugin_gui_window
+{
+public:
+ plugin_gui *gui;
+ GtkWindow *toplevel;
+ GtkUIManager *ui_mgr;
+ GtkActionGroup *std_actions, *preset_actions;
+
+ plugin_gui_window();
+ std::string make_gui_preset_list(GtkActionGroup *grp);
+ void fill_gui_presets();
+ void create(plugin_ctl_iface *_plugin, const char *title, const char *effect);
+ ~plugin_gui_window();
+};
+
inline parameter_properties ¶m_control::get_props()
{
return *gui->plugin->get_param_props(param_no);
diff --git a/src/calf/preset.h b/src/calf/preset.h
index e836c1f..c2aa766 100644
--- a/src/calf/preset.h
+++ b/src/calf/preset.h
@@ -53,6 +53,34 @@ struct plugin_preset
}
};
+struct preset_exception
+{
+ std::string message, param, fulltext;
+ int error;
+ preset_exception(const char *_message, const char *_param, int _error)
+ : message(_message), param(_param), error(_error)
+ {
+ }
+ const char *what() {
+ if (error)
+ fulltext = message + " " + param + " (" + strerror(error) + ")";
+ else
+ fulltext = message + " " + param;
+ return fulltext.c_str();
+ }
+ ~preset_exception()
+ {
+ }
+};
+
+extern std::string get_preset_filename();
+extern void load_presets(const char *filename);
+extern void save_presets(const char *filename);
+extern void add_preset(const plugin_preset &sp);
+
+// this global variable is a temporary measure
+extern std::vector<plugin_preset> presets;
+
};
#endif
diff --git a/src/calf/preset_gui.h b/src/calf/preset_gui.h
new file mode 100644
index 0000000..afd22f4
--- /dev/null
+++ b/src/calf/preset_gui.h
@@ -0,0 +1,44 @@
+/* Calf DSP Library
+ * GUI functions for preset management.
+ * Copyright (C) 2007 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef __CALF_PRESET_GUI_H
+#define __CALF_PRESET_GUI_H
+
+
+#include <calf/giface.h>
+#include <calf/gui.h>
+
+namespace synth {
+
+struct activate_preset_params
+{
+ plugin_gui *gui;
+ int preset;
+
+ activate_preset_params(plugin_gui *_gui, int _preset)
+ : gui(_gui), preset(_preset)
+ {
+ }
+};
+
+void store_preset(GtkWindow *toplevel, plugin_gui *gui);
+void activate_preset(GtkAction *action, activate_preset_params *params);
+
+};
+
+#endif
diff --git a/src/calf/synth.h b/src/calf/synth.h
index 3c02c90..b256008 100644
--- a/src/calf/synth.h
+++ b/src/calf/synth.h
@@ -166,8 +166,8 @@ public:
env_state state;
// note: these are *rates*, not times
- float attack, decay, sustain, release;
- float value;
+ double attack, decay, sustain, release;
+ double value;
adsr()
{
@@ -233,6 +233,10 @@ public:
break;
case SUSTAIN:
value = sustain;
+ if (value < 0.00001f) {
+ value = 0;
+ state = STOP;
+ }
break;
case RELEASE:
value -= release;
diff --git a/src/gui.cpp b/src/gui.cpp
index 45136f7..c87ebc9 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -22,9 +22,11 @@
#include <calf/giface.h>
#include <calf/gui.h>
+#include <calf/preset.h>
+#include <calf/preset_gui.h>
using namespace synth;
-
+using namespace std;
/******************************** controls ********************************/
@@ -196,12 +198,16 @@ void knob_param_control::knob_value_changed(PhatKnob *widget, gpointer value)
/******************************** GUI proper ********************************/
-plugin_gui::plugin_gui(GtkWidget *_toplevel)
-: toplevel(_toplevel)
+plugin_gui::plugin_gui(plugin_gui_window *_window)
+: window(_window)
{
}
+static void action_destroy_notify(gpointer data)
+{
+ delete (activate_preset_params *)data;
+}
GtkWidget *plugin_gui::create(plugin_ctl_iface *_plugin, const char *title)
{
@@ -267,3 +273,125 @@ void plugin_gui::refresh()
}
}
+/******************************* Actions **************************************************/
+
+static void store_preset_action(GtkAction *action, plugin_gui_window *gui_win)
+{
+ store_preset(GTK_WINDOW(gui_win->toplevel), gui_win->gui);
+}
+
+static void exit_gui(GtkAction *action, plugin_gui_window *gui_win)
+{
+ gtk_widget_destroy(GTK_WIDGET(gui_win->toplevel));
+}
+
+static const GtkActionEntry actions[] = {
+ { "HostMenuAction", "", "_Host", NULL, "Application-wide actions", NULL },
+ { "exit", "", "E_xit", NULL, "Exit the application", (GCallback)exit_gui },
+ { "PresetMenuAction", "", "_Preset", NULL, "Preset operations", NULL },
+ { "store-preset", "", "_Store preset", NULL, "Store a current setting as preset", (GCallback)store_preset_action },
+};
+
+/***************************** GUI window ********************************************/
+
+static const char *ui_xml =
+"<ui>\n"
+" <menubar>\n"
+" <menu action=\"HostMenuAction\">\n"
+" <menuitem action=\"exit\"/>\n"
+" </menu>\n"
+" <menu action=\"PresetMenuAction\">\n"
+" <menuitem action=\"store-preset\"/>\n"
+" <separator/>\n"
+" <placeholder name=\"presets\"/>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n"
+;
+
+static const char *preset_pre_xml =
+"<ui>\n"
+" <menubar>\n"
+" <menu action=\"PresetMenuAction\">\n"
+" <placeholder name=\"presets\">\n";
+
+static const char *preset_post_xml =
+" </placeholder>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n"
+;
+
+plugin_gui_window::plugin_gui_window()
+{
+ toplevel = NULL;
+ ui_mgr = NULL;
+ std_actions = NULL;
+ preset_actions = NULL;
+}
+
+string plugin_gui_window::make_gui_preset_list(GtkActionGroup *grp)
+{
+ string preset_xml = preset_pre_xml;
+ for (unsigned int i = 0; i < presets.size(); i++)
+ {
+ if (presets[i].plugin != gui->effect_name)
+ continue;
+ stringstream ss;
+ ss << "preset" << i;
+ preset_xml += " <menuitem name=\""+presets[i].name+"\" action=\""+ss.str()+"\"/>\n";
+
+ GtkActionEntry ae = { ss.str().c_str(), NULL, presets[i].name.c_str(), NULL, NULL, (GCallback)activate_preset };
+ gtk_action_group_add_actions_full(preset_actions, &ae, 1, (gpointer)new activate_preset_params(gui, i), action_destroy_notify);
+ }
+ preset_xml += preset_post_xml;
+ return preset_xml;
+}
+
+void plugin_gui_window::fill_gui_presets()
+{
+ if(preset_actions) {
+ gtk_ui_manager_remove_action_group(ui_mgr, preset_actions);
+ preset_actions = NULL;
+ }
+
+ preset_actions = gtk_action_group_new("presets");
+ string preset_xml = make_gui_preset_list(preset_actions);
+ gtk_ui_manager_insert_action_group(ui_mgr, preset_actions, 0);
+ GError *error = NULL;
+ gtk_ui_manager_add_ui_from_string(ui_mgr, preset_xml.c_str(), -1, &error);
+}
+
+void plugin_gui_window::create(plugin_ctl_iface *_jh, const char *title, const char *effect)
+{
+ toplevel = GTK_WINDOW(gtk_window_new (GTK_WINDOW_TOPLEVEL));
+ GtkVBox *vbox = GTK_VBOX(gtk_vbox_new(false, 5));
+
+ gtk_window_set_title(GTK_WINDOW (toplevel), (string(title) + " - " + effect).c_str());
+ gtk_container_add(GTK_CONTAINER(toplevel), GTK_WIDGET(vbox));
+
+ gui = new plugin_gui(this);
+ gui->effect_name = effect;
+
+ ui_mgr = gtk_ui_manager_new();
+ std_actions = gtk_action_group_new("default");
+ gtk_action_group_add_actions(std_actions, actions, sizeof(actions)/sizeof(actions[0]), this);
+ GError *error = NULL;
+ gtk_ui_manager_insert_action_group(ui_mgr, std_actions, 0);
+ gtk_ui_manager_add_ui_from_string(ui_mgr, ui_xml, -1, &error);
+ fill_gui_presets();
+
+ gtk_container_add(GTK_CONTAINER(vbox), gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar"));
+
+ GtkWidget *table = gui->create(_jh, effect);
+
+ gtk_container_add(GTK_CONTAINER(vbox), table);
+
+ gtk_widget_show_all(GTK_WIDGET(toplevel));
+
+}
+
+plugin_gui_window::~plugin_gui_window()
+{
+ delete gui;
+}
diff --git a/src/jackhost.cpp b/src/jackhost.cpp
index 50a5631..fe70d3f 100644
--- a/src/jackhost.cpp
+++ b/src/jackhost.cpp
@@ -23,8 +23,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <config.h>
-#include <fcntl.h>
-#include <expat.h>
+#include <sys/stat.h>
#include <glade/glade.h>
#include <jack/jack.h>
#include <calf/giface.h>
@@ -33,14 +32,13 @@
#include <calf/modules_dev.h>
#include <calf/gui.h>
#include <calf/preset.h>
+#include <calf/preset_gui.h>
using namespace synth;
using namespace std;
// I don't need anyone to tell me this is stupid. I already know that :)
-GtkWidget *toplevel;
-plugin_gui *gui;
-GtkUIManager *ui_mgr;
+plugin_gui_window *gui_win;
const char *effect_name = "flanger";
const char *client_name = "calfhost";
@@ -53,299 +51,6 @@ void destroy(GtkWindow *window, gpointer data)
gtk_main_quit();
}
-static const char *ui_xml =
-"<ui>\n"
-" <menubar>\n"
-" <menu action=\"HostMenuAction\">\n"
-" <menuitem action=\"exit\"/>\n"
-" </menu>\n"
-" <menu action=\"PresetMenuAction\">\n"
-" <menuitem action=\"store-preset\"/>\n"
-" <separator/>\n"
-" <placeholder name=\"presets\"/>\n"
-" </menu>\n"
-" </menubar>\n"
-"</ui>\n"
-;
-
-static const char *preset_pre_xml =
-"<ui>\n"
-" <menubar>\n"
-" <menu action=\"PresetMenuAction\">\n"
-" <placeholder name=\"presets\">\n";
-
-static const char *preset_post_xml =
-" </placeholder>\n"
-" </menu>\n"
-" </menubar>\n"
-"</ui>\n"
-;
-
-void exit_gui()
-{
- gtk_widget_destroy(toplevel);
-}
-
-vector<plugin_preset> presets;
-
-string get_preset_filename()
-{
- const char *home = getenv("HOME");
- return string(home)+"/.calfpresets";
-}
-
-enum PresetParserState
-{
- START,
- LIST,
- PRESET,
- VALUE,
-} xml_parser_state;
-
-plugin_preset parser_preset;
-
-void xml_start_element_handler(void *user_data, const char *name, const char *attrs[])
-{
- switch(xml_parser_state)
- {
- case START:
- if (!strcmp(name, "presets")) {
- xml_parser_state = LIST;
- return;
- }
- break;
- case LIST:
- if (!strcmp(name, "preset")) {
- parser_preset.bank = parser_preset.program = 0;
- parser_preset.name = "";
- parser_preset.plugin = "";
- parser_preset.blob = "";
- parser_preset.param_names.clear();
- parser_preset.values.clear();
- for(; *attrs; attrs += 2) {
- if (!strcmp(attrs[0], "bank")) parser_preset.bank = atoi(attrs[1]);
- else
- if (!strcmp(attrs[0], "program")) parser_preset.program = atoi(attrs[1]);
- else
- if (!strcmp(attrs[0], "name")) parser_preset.name = attrs[1];
- else
- if (!strcmp(attrs[0], "plugin")) parser_preset.plugin = attrs[1];
- }
- xml_parser_state = PRESET;
- return;
- }
- break;
- case PRESET:
- if (!strcmp(name, "param")) {
- std::string name;
- float value = 0.f;
- for(; *attrs; attrs += 2) {
- if (!strcmp(attrs[0], "name")) name = attrs[1];
- else
- if (!strcmp(attrs[0], "value")) {
- istringstream str(attrs[1]);
- str >> value;
- }
- }
- parser_preset.param_names.push_back(name);
- parser_preset.values.push_back(value);
- xml_parser_state = VALUE;
- return;
- }
- break;
- case VALUE:
- break;
- }
- g_warning("Invalid XML element: %s", name);
-}
-
-void xml_end_element_handler(void *user_data, const char *name)
-{
- switch(xml_parser_state)
- {
- case START:
- break;
- case LIST:
- if (!strcmp(name, "presets")) {
- xml_parser_state = START;
- return;
- }
- break;
- case PRESET:
- if (!strcmp(name, "preset")) {
- presets.push_back(parser_preset);
- xml_parser_state = LIST;
- return;
- }
- break;
- case VALUE:
- if (!strcmp(name, "param")) {
- xml_parser_state = PRESET;
- return;
- }
- break;
- }
- g_warning("Invalid XML element close: %s", name);
-}
-
-void load_presets()
-{
- xml_parser_state = START;
- XML_Parser parser = XML_ParserCreate("UTF-8");
- string filename = get_preset_filename();
- int fd = open(filename.c_str(), O_RDONLY);
- if (fd < 0) {
- g_warning("Could not save the presets in %s", filename.c_str());
- return;
- }
- XML_SetElementHandler(parser, xml_start_element_handler, xml_end_element_handler);
- char buf[4096];
- do
- {
- int len = read(fd, buf, 4096);
- // XXXKF not an optimal error/EOF handling :)
- if (len <= 0)
- break;
- XML_Parse(parser, buf, len, 0);
- } while(1);
- XML_Parse(parser, buf, 0, 1);
- close(fd);
-}
-
-void save_presets()
-{
- string xml = "<presets>\n";
- for (unsigned int i = 0; i < presets.size(); i++)
- {
- xml += presets[i].to_xml();
- }
- xml += "</presets>";
- string filename = get_preset_filename();
- int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0640);
- if (fd < 0 || ((unsigned)write(fd, xml.c_str(), xml.length()) != xml.length())) {
- g_warning("Could not save the presets in %s", filename.c_str());
- return;
- }
- close(fd);
-}
-
-GladeXML *store_preset_xml = NULL;
-GtkWidget *store_preset_dlg = NULL;
-
-void store_preset_dlg_destroy(GtkWindow *window, gpointer data)
-{
- store_preset_dlg = NULL;
-}
-
-void store_preset_ok()
-{
- plugin_preset sp;
- sp.name = gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(store_preset_xml, "preset_name")));
- sp.bank = 0;
- sp.program = 0;
- sp.plugin = effect_name;
- int count = gui->plugin->get_param_count();
- for (int i = 0; i < count; i++) {
- sp.param_names.push_back(gui->plugin->get_param_names()[i]);
- sp.values.push_back(gui->plugin->get_param_value(i));
- }
- presets.push_back(sp);
- gtk_widget_destroy(store_preset_dlg);
-}
-
-void store_preset_cancel()
-{
- gtk_widget_destroy(store_preset_dlg);
-}
-
-void store_preset()
-{
- if (store_preset_dlg)
- {
- gtk_window_present(GTK_WINDOW(store_preset_dlg));
- return;
- }
- store_preset_xml = glade_xml_new("calf.glade", NULL, NULL);
- store_preset_dlg = glade_xml_get_widget(store_preset_xml, "store_preset");
- gtk_signal_connect(GTK_OBJECT(store_preset_dlg), "destroy", G_CALLBACK(store_preset_dlg_destroy), NULL);
- gtk_signal_connect(GTK_OBJECT(glade_xml_get_widget(store_preset_xml, "ok_button")), "clicked", G_CALLBACK(store_preset_ok), NULL);
- gtk_signal_connect(GTK_OBJECT(glade_xml_get_widget(store_preset_xml, "cancel_button")), "clicked", G_CALLBACK(store_preset_cancel), NULL);
- gtk_window_set_transient_for(GTK_WINDOW(store_preset_dlg), GTK_WINDOW(toplevel));
-}
-
-static const GtkActionEntry entries[] = {
- { "HostMenuAction", "", "_Host", NULL, "Application-wide actions", NULL },
- { "exit", "", "E_xit", NULL, "Exit the application", exit_gui },
- { "PresetMenuAction", "", "_Preset", NULL, "Preset operations", NULL },
- { "store-preset", "", "_Store preset", NULL, "Store a current setting as preset", store_preset },
-};
-
-void activate_preset(GtkAction *action, int preset)
-{
- plugin_preset &p = presets[preset];
- if (p.plugin != effect_name)
- return;
- map<string, int> names;
- int count = gui->plugin->get_param_count();
- for (int i = 0; i < count; i++)
- names[gui->plugin->get_param_names()[i]] = i;
- // no support for unnamed parameters... tough luck :)
- for (unsigned int i = 0; i < min(p.param_names.size(), p.values.size()); i++)
- {
- map<string, int>::iterator pos = names.find(p.param_names[i]);
- if (pos == names.end())
- continue;
- gui->plugin->set_param_value(pos->second, p.values[i]);
- }
- gui->refresh();
-}
-
-void make_gui(jack_host_base *jh, const char *title, const char *effect)
-{
- toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- GtkVBox *vbox = GTK_VBOX(gtk_vbox_new(false, 5));
-
- gtk_window_set_title(GTK_WINDOW (toplevel), (string(title) + " - " + effect).c_str());
- gtk_container_add(GTK_CONTAINER(toplevel), GTK_WIDGET(vbox));
-
- GtkUIManager *ui_mgr = gtk_ui_manager_new();
- GtkActionGroup *act_grp = gtk_action_group_new("default");
- gtk_action_group_add_actions(act_grp, entries, sizeof(entries)/sizeof(entries[0]), jh);
- GError *error = NULL;
- gtk_ui_manager_insert_action_group(ui_mgr, act_grp, 0);
- int merge_ui = gtk_ui_manager_add_ui_from_string(ui_mgr, ui_xml, -1, &error);
-
- string preset_xml = preset_pre_xml;
- for (unsigned int i = 0; i < presets.size(); i++)
- {
- if (presets[i].plugin != effect_name)
- continue;
- stringstream ss;
- ss << "preset" << i;
- preset_xml += " <menuitem name=\""+presets[i].name+"\" action=\""+ss.str()+"\"/>\n";
-
- GtkActionEntry ae = { ss.str().c_str(), NULL, presets[i].name.c_str(), NULL, NULL, (GCallback)activate_preset };
- gtk_action_group_add_actions(act_grp, &ae, 1, (gpointer)i);
-
- }
- preset_xml += preset_post_xml;
-
- gtk_ui_manager_add_ui_from_string(ui_mgr, preset_xml.c_str(), -1, &error);
- GtkWidget *menu_bar = gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar");
-
-
- gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(menu_bar));
-
- gui = new plugin_gui(toplevel);
- GtkWidget *table = gui->create(jh, effect);
-
- gtk_container_add(GTK_CONTAINER(vbox), table);
-
- gtk_signal_connect(GTK_OBJECT(toplevel), "destroy", G_CALLBACK(destroy), NULL);
- gtk_widget_show_all(toplevel);
-
-}
-
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"version", 0, 0, 'v'},
@@ -396,7 +101,11 @@ int main(int argc, char *argv[])
}
}
try {
- load_presets();
+ struct stat st;
+ if (!stat(get_preset_filename().c_str(), &st))
+ load_presets(get_preset_filename().c_str());
+ else if (!stat(PKGLIBDIR "/presets.xml", &st))
+ load_presets(PKGLIBDIR "/presets.xml");
jack_host_base *jh = NULL;
if (!strcmp(effect_name, "reverb"))
jh = new jack_host<reverb_audio_module>();
@@ -419,11 +128,13 @@ int main(int argc, char *argv[])
return 1;
}
jh->open(client_name, input_name, output_name, midi_name);
- make_gui(jh, client_name, effect_name);
+ gui_win = new plugin_gui_window;
+ gui_win->create(jh, client_name, effect_name);
+ gtk_signal_connect(GTK_OBJECT(gui_win->toplevel), "destroy", G_CALLBACK(destroy), NULL);
gtk_main();
- delete gui;
+ delete gui_win;
jh->close();
- save_presets();
+ save_presets(get_preset_filename().c_str());
delete jh;
}
catch(std::exception &e)
diff --git a/src/preset.cpp b/src/preset.cpp
new file mode 100644
index 0000000..c1bbdce
--- /dev/null
+++ b/src/preset.cpp
@@ -0,0 +1,174 @@
+/* Calf DSP Library
+ * Preset management.
+ *
+ * Copyright (C) 2001-2007 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <expat.h>
+#include <calf/preset.h>
+
+using namespace synth;
+using namespace std;
+
+vector<plugin_preset> synth::presets;
+
+string synth::get_preset_filename()
+{
+ const char *home = getenv("HOME");
+ return string(home)+"/.calfpresets";
+}
+
+enum PresetParserState
+{
+ START,
+ LIST,
+ PRESET,
+ VALUE,
+};
+
+static PresetParserState xml_parser_state;
+static plugin_preset parser_preset;
+
+static void xml_start_element_handler(void *user_data, const char *name, const char *attrs[])
+{
+ switch(xml_parser_state)
+ {
+ case START:
+ if (!strcmp(name, "presets")) {
+ xml_parser_state = LIST;
+ return;
+ }
+ break;
+ case LIST:
+ if (!strcmp(name, "preset")) {
+ parser_preset.bank = parser_preset.program = 0;
+ parser_preset.name = "";
+ parser_preset.plugin = "";
+ parser_preset.blob = "";
+ parser_preset.param_names.clear();
+ parser_preset.values.clear();
+ for(; *attrs; attrs += 2) {
+ if (!strcmp(attrs[0], "bank")) parser_preset.bank = atoi(attrs[1]);
+ else
+ if (!strcmp(attrs[0], "program")) parser_preset.program = atoi(attrs[1]);
+ else
+ if (!strcmp(attrs[0], "name")) parser_preset.name = attrs[1];
+ else
+ if (!strcmp(attrs[0], "plugin")) parser_preset.plugin = attrs[1];
+ }
+ xml_parser_state = PRESET;
+ return;
+ }
+ break;
+ case PRESET:
+ if (!strcmp(name, "param")) {
+ std::string name;
+ float value = 0.f;
+ for(; *attrs; attrs += 2) {
+ if (!strcmp(attrs[0], "name")) name = attrs[1];
+ else
+ if (!strcmp(attrs[0], "value")) {
+ istringstream str(attrs[1]);
+ str >> value;
+ }
+ }
+ parser_preset.param_names.push_back(name);
+ parser_preset.values.push_back(value);
+ xml_parser_state = VALUE;
+ return;
+ }
+ break;
+ case VALUE:
+ break;
+ }
+ // g_warning("Invalid XML element: %s", name);
+ throw preset_exception("Invalid XML element: %s", name, 0);
+}
+
+static void xml_end_element_handler(void *user_data, const char *name)
+{
+ switch(xml_parser_state)
+ {
+ case START:
+ break;
+ case LIST:
+ if (!strcmp(name, "presets")) {
+ xml_parser_state = START;
+ return;
+ }
+ break;
+ case PRESET:
+ if (!strcmp(name, "preset")) {
+ presets.push_back(parser_preset);
+ xml_parser_state = LIST;
+ return;
+ }
+ break;
+ case VALUE:
+ if (!strcmp(name, "param")) {
+ xml_parser_state = PRESET;
+ return;
+ }
+ break;
+ }
+ throw preset_exception("Invalid XML element close: %s", name, 0);
+}
+
+void synth::load_presets(const char *filename)
+{
+ xml_parser_state = START;
+ XML_Parser parser = XML_ParserCreate("UTF-8");
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ throw preset_exception("Could not load the presets from ", filename, errno);
+ XML_SetElementHandler(parser, xml_start_element_handler, xml_end_element_handler);
+ char buf[4096];
+ do
+ {
+ int len = read(fd, buf, 4096);
+ // XXXKF not an optimal error/EOF handling :)
+ if (len <= 0)
+ break;
+ XML_Parse(parser, buf, len, 0);
+ } while(1);
+ XML_Parse(parser, buf, 0, 1);
+ close(fd);
+}
+
+void synth::save_presets(const char *filename)
+{
+ string xml = "<presets>\n";
+ for (unsigned int i = 0; i < presets.size(); i++)
+ {
+ xml += presets[i].to_xml();
+ }
+ xml += "</presets>";
+ int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0640);
+ if (fd < 0 || ((unsigned)write(fd, xml.c_str(), xml.length()) != xml.length()))
+ throw preset_exception("Could not save the presets in ", filename, errno);
+ close(fd);
+}
+
+void synth::add_preset(const plugin_preset &sp)
+{
+ presets.push_back(sp);
+}
diff --git a/src/preset_gui.cpp b/src/preset_gui.cpp
new file mode 100644
index 0000000..3736f62
--- /dev/null
+++ b/src/preset_gui.cpp
@@ -0,0 +1,97 @@
+/* Calf DSP Library
+ * GUI functions for preset management.
+ * Copyright (C) 2007 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <map>
+#include <glade/glade.h>
+#include <calf/giface.h>
+#include <calf/gui.h>
+#include <calf/preset.h>
+#include <calf/preset_gui.h>
+
+using namespace synth;
+using namespace std;
+
+// this way of filling presets menu is not that great
+
+GladeXML *store_preset_xml = NULL;
+GtkWidget *store_preset_dlg = NULL;
+
+void store_preset_dlg_destroy(GtkWindow *window, gpointer data)
+{
+ store_preset_dlg = NULL;
+}
+
+void store_preset_ok(GtkAction *action, plugin_gui *gui)
+{
+ plugin_preset sp;
+ sp.name = gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(store_preset_xml, "preset_name")));
+ sp.bank = 0;
+ sp.program = 0;
+ sp.plugin = gui->effect_name;
+ int count = gui->plugin->get_param_count();
+ for (int i = 0; i < count; i++) {
+ sp.param_names.push_back(gui->plugin->get_param_names()[i]);
+ sp.values.push_back(gui->plugin->get_param_value(i));
+ }
+ add_preset(sp);
+ gtk_widget_destroy(store_preset_dlg);
+ gui->window->fill_gui_presets();
+}
+
+void store_preset_cancel(GtkAction *action, plugin_gui *gui)
+{
+ gtk_widget_destroy(store_preset_dlg);
+}
+
+void synth::store_preset(GtkWindow *toplevel, plugin_gui *gui)
+{
+ if (store_preset_dlg)
+ {
+ gtk_window_present(GTK_WINDOW(store_preset_dlg));
+ return;
+ }
+ store_preset_xml = glade_xml_new(PKGLIBDIR "/calf.glade", NULL, NULL);
+ store_preset_dlg = glade_xml_get_widget(store_preset_xml, "store_preset");
+ gtk_signal_connect(GTK_OBJECT(store_preset_dlg), "destroy", G_CALLBACK(store_preset_dlg_destroy), NULL);
+ gtk_signal_connect(GTK_OBJECT(glade_xml_get_widget(store_preset_xml, "ok_button")), "clicked", G_CALLBACK(store_preset_ok), gui);
+ gtk_signal_connect(GTK_OBJECT(glade_xml_get_widget(store_preset_xml, "cancel_button")), "clicked", G_CALLBACK(store_preset_cancel), gui);
+ gtk_window_set_transient_for(GTK_WINDOW(store_preset_dlg), toplevel);
+}
+
+void synth::activate_preset(GtkAction *action, activate_preset_params *params)
+{
+ plugin_gui *gui = params->gui;
+ plugin_preset &p = presets[params->preset];
+ if (p.plugin != gui->effect_name)
+ return;
+ map<string, int> names;
+ int count = gui->plugin->get_param_count();
+ for (int i = 0; i < count; i++)
+ names[gui->plugin->get_param_names()[i]] = i;
+ // no support for unnamed parameters... tough luck :)
+ for (unsigned int i = 0; i < min(p.param_names.size(), p.values.size()); i++)
+ {
+ map<string, int>::iterator pos = names.find(p.param_names[i]);
+ if (pos == names.end())
+ continue;
+ gui->plugin->set_param_value(pos->second, p.values[i]);
+ }
+ gui->refresh();
+}
+
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list