[SCM] calf/master: + JACK host: attempt at add/remove plugins at runtime, probably introducing more bugs in the process (at least incorrect size on remove!), fix VU meters + flanger: fix stereo phase
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:37:04 UTC 2013
The following commit has been merged in the master branch:
commit 1a04bdac130219181f48553434726782922a92ec
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Sun Feb 17 22:12:36 2008 +0000
+ JACK host: attempt at add/remove plugins at runtime, probably introducing more bugs in the process (at least incorrect size on remove!), fix VU meters
+ flanger: fix stereo phase
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@130 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/src/calf/fixed_point.h b/src/calf/fixed_point.h
index 953b47b..a9a1cf2 100644
--- a/src/calf/fixed_point.h
+++ b/src/calf/fixed_point.h
@@ -57,7 +57,7 @@ public:
}
*/
explicit inline fixed_point(double v) {
- value = (int)(v*(1<<FracBits));
+ value = (T)(v*(1<<FracBits));
}
inline void set(T value) {
diff --git a/src/calf/gui.h b/src/calf/gui.h
index 7352778..23a3fc3 100644
--- a/src/calf/gui.h
+++ b/src/calf/gui.h
@@ -238,9 +238,13 @@ public:
static void xml_element_end(void *data, const char *element);
};
+class main_window_owner_iface;
+
class main_window_iface
{
public:
+ virtual void set_owner(main_window_owner_iface *owner)=0;
+
virtual void add_plugin(plugin_ctl_iface *plugin)=0;
virtual void del_plugin(plugin_ctl_iface *plugin)=0;
@@ -250,6 +254,14 @@ public:
virtual ~main_window_iface() {}
};
+class main_window_owner_iface
+{
+public:
+ virtual void new_plugin(const char *name) = 0;
+ virtual void remove_plugin(plugin_ctl_iface *plugin) = 0;
+ virtual ~main_window_owner_iface() {}
+};
+
class plugin_gui_window
{
public:
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index e25b5f4..11f4877 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -24,17 +24,21 @@
#if USE_JACK
#include "gui.h"
+#include "utils.h"
+#include <pthread.h>
namespace synth {
class jack_host_base;
class jack_client {
+protected:
+ std::vector<jack_host_base *> plugins;
+ ptmutex mutex;
public:
jack_client_t *client;
int input_nr, output_nr, midi_nr;
std::string input_name, output_name, midi_name;
- std::vector<jack_host_base *> plugins;
int sample_rate;
jack_client()
@@ -49,9 +53,16 @@ public:
void add(jack_host_base *plugin)
{
+ ptlock lock(mutex);
plugins.push_back(plugin);
}
+ void del(int item)
+ {
+ ptlock lock(mutex);
+ plugins.erase(plugins.begin()+item);
+ }
+
void open(const char *client_name)
{
jack_status_t status;
@@ -78,6 +89,8 @@ public:
jack_deactivate(client);
}
+ void delete_plugins();
+
void connect(const std::string &p1, const std::string &p2)
{
if (jack_connect(client, p1.c_str(), p2.c_str()) != 0)
@@ -174,16 +187,20 @@ public:
void close() {
port *inputs = get_inputs(), *outputs = get_outputs();
int input_count = get_input_count(), output_count = get_output_count();
- for (int i = 0; i < input_count; i++)
+ for (int i = 0; i < input_count; i++) {
+ jack_port_unregister(client->client, inputs[i].handle);
inputs[i].data = NULL;
- for (int i = 0; i < output_count; i++)
+ }
+ for (int i = 0; i < output_count; i++) {
+ jack_port_unregister(client->client, outputs[i].handle);
outputs[i].data = NULL;
+ }
+ if (get_midi())
+ jack_port_unregister(client->client, midi_port.handle);
client = NULL;
}
virtual ~jack_host_base() {
- if (client)
- close();
}
};
@@ -194,6 +211,7 @@ struct vumeter
vumeter()
{
falloff = 0.999f;
+ level = 0;
}
inline void update(float *src, unsigned int len)
@@ -229,6 +247,12 @@ public:
midi_meter = 0;
}
+ ~jack_host()
+ {
+ if (client)
+ close();
+ }
+
virtual void init_module() {
module.set_sample_rate(client->sample_rate);
module.activate();
diff --git a/src/calf/main_win.h b/src/calf/main_win.h
index a6303fa..2093399 100644
--- a/src/calf/main_win.h
+++ b/src/calf/main_win.h
@@ -40,13 +40,23 @@ namespace synth {
main_window *main_win;
plugin_ctl_iface *plugin;
plugin_gui_window *gui_win;
- GtkWidget *name, *midi_in, *audio_in[2], *audio_out[2];
+ GtkWidget *name, *midi_in, *audio_in[2], *audio_out[2], *extra;
+ };
+
+ struct add_plugin_params
+ {
+ main_window *main_win;
+ std::string name;
+ add_plugin_params(main_window *_main_win, const std::string &_name)
+ : main_win(_main_win), name(_name) {}
};
public:
GtkWindow *toplevel;
GtkWidget *all_vbox;
GtkWidget *strips_table;
+ GtkUIManager *ui_mgr;
+ GtkActionGroup *std_actions, *plugin_actions;
jack_client *client;
std::map<plugin_ctl_iface *, plugin_strip *> plugins;
std::set<std::string> conditions;
@@ -54,14 +64,19 @@ namespace synth {
std::string prefix;
bool is_closed;
int source_id;
+ main_window_owner_iface *owner;
protected:
plugin_strip *create_strip(plugin_ctl_iface *plugin);
void update_strip(plugin_ctl_iface *plugin);
static gboolean on_idle(void *data);
+ std::string make_plugin_list(GtkActionGroup *actions);
+ static void add_plugin_action(GtkWidget *src, gpointer data);
public:
main_window();
+ void set_owner(main_window_owner_iface *_owner) { owner = _owner; }
+ void new_plugin(const char *name) { owner->new_plugin(name); }
void add_plugin(plugin_ctl_iface *plugin);
void del_plugin(plugin_ctl_iface *plugin);
void set_window(plugin_ctl_iface *iface, plugin_gui_window *window);
diff --git a/src/calf/primitives.h b/src/calf/primitives.h
index 1aaad76..096f432 100644
--- a/src/calf/primitives.h
+++ b/src/calf/primitives.h
@@ -405,8 +405,6 @@ inline int fastf2i_drm(float f)
return v;
}
-
-
};
#endif
diff --git a/src/calf/utils.h b/src/calf/utils.h
new file mode 100644
index 0000000..3f52e82
--- /dev/null
+++ b/src/calf/utils.h
@@ -0,0 +1,87 @@
+/* Calf DSP Library
+ * Utilities
+ *
+ * Copyright (C) 2008 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.
+ */
+#ifndef __CALF_UTILS_H
+#define __CALF_UTILS_H
+
+#include <pthread.h>
+
+class ptmutex
+{
+public:
+ pthread_mutex_t pm;
+
+ ptmutex(int type = PTHREAD_MUTEX_RECURSIVE)
+ {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, type);
+ pthread_mutex_init(&pm, &attr);
+ pthread_mutexattr_destroy(&attr);
+ }
+
+ bool lock()
+ {
+ return pthread_mutex_lock(&pm) == 0;
+ }
+
+ bool trylock()
+ {
+ return pthread_mutex_trylock(&pm) == 0;
+ }
+
+ void unlock()
+ {
+ pthread_mutex_unlock(&pm);
+ }
+
+ ~ptmutex()
+ {
+ pthread_mutex_destroy(&pm);
+ }
+};
+
+class ptlock
+{
+ ptmutex &mutex;
+ bool locked;
+
+public:
+ ptlock(ptmutex &_m) : mutex(_m), locked(true)
+ {
+ mutex.lock();
+ }
+ void unlock()
+ {
+ mutex.unlock();
+ locked = false;
+ }
+ void unlocked()
+ {
+ locked = false;
+ }
+ ~ptlock()
+ {
+ if (locked)
+ mutex.unlock();
+ }
+};
+
+#endif
diff --git a/src/jackhost.cpp b/src/jackhost.cpp
index 69d0d8a..3f55977 100644
--- a/src/jackhost.cpp
+++ b/src/jackhost.cpp
@@ -46,20 +46,20 @@ const char *client_name = "calfhost";
jack_host_base *synth::create_jack_host(const char *effect_name)
{
- if (!strcmp(effect_name, "reverb"))
+ if (!strcasecmp(effect_name, "reverb"))
return new jack_host<reverb_audio_module>();
- else if (!strcmp(effect_name, "flanger"))
+ else if (!strcasecmp(effect_name, "flanger"))
return new jack_host<flanger_audio_module>();
- else if (!strcmp(effect_name, "filter"))
+ else if (!strcasecmp(effect_name, "filter"))
return new jack_host<filter_audio_module>();
- else if (!strcmp(effect_name, "monosynth"))
+ else if (!strcasecmp(effect_name, "monosynth"))
return new jack_host<monosynth_audio_module>();
- else if (!strcmp(effect_name, "vintagedelay"))
+ else if (!strcasecmp(effect_name, "vintagedelay"))
return new jack_host<vintage_delay_audio_module>();
#ifdef ENABLE_EXPERIMENTAL
- else if (!strcmp(effect_name, "organ"))
+ else if (!strcasecmp(effect_name, "organ"))
return new jack_host<organ_audio_module>();
- else if (!strcmp(effect_name, "rotaryspeaker"))
+ else if (!strcasecmp(effect_name, "rotaryspeaker"))
return new jack_host<rotary_speaker_audio_module>();
#endif
else
@@ -98,6 +98,7 @@ void print_help(char *argv[])
int jack_client::do_jack_process(jack_nframes_t nframes, void *p)
{
jack_client *self = (jack_client *)p;
+ ptlock lock(self->mutex);
for(unsigned int i = 0; i < self->plugins.size(); i++)
self->plugins[i]->process(nframes);
return 0;
@@ -106,12 +107,23 @@ int jack_client::do_jack_process(jack_nframes_t nframes, void *p)
int jack_client::do_jack_bufsize(jack_nframes_t numsamples, void *p)
{
jack_client *self = (jack_client *)p;
+ ptlock lock(self->mutex);
for(unsigned int i = 0; i < self->plugins.size(); i++)
self->plugins[i]->cache_ports();
return 0;
}
-struct host_session
+void jack_client::delete_plugins()
+{
+ ptlock lock(mutex);
+ for (unsigned int i = 0; i < plugins.size(); i++) {
+ // plugins[i]->close();
+ delete plugins[i];
+ }
+ plugins.clear();
+}
+
+struct host_session: public main_window_owner_iface
{
string client_name, input_name, output_name, midi_name;
vector<string> plugin_names;
@@ -149,6 +161,8 @@ struct host_session
lash_send_config(lash_client, cfg);
}
#endif
+ virtual void new_plugin(const char *name);
+ virtual void remove_plugin(plugin_ctl_iface *plugin);
};
host_session::host_session()
@@ -159,6 +173,7 @@ host_session::host_session()
lash_source_id = 0;
restoring_session = false;
main_win = new main_window;
+ main_win->set_owner(this);
}
void host_session::open()
@@ -182,6 +197,7 @@ void host_session::open()
#endif
}
jh->open(&client);
+
plugins.push_back(jh);
client.add(jh);
main_win->add_plugin(jh);
@@ -192,9 +208,36 @@ void host_session::open()
gtk_signal_connect(GTK_OBJECT(main_win->toplevel), "destroy", G_CALLBACK(destroy), NULL);
}
+void host_session::new_plugin(const char *name)
+{
+ jack_host_base *jh = create_jack_host(name);
+ if (!jh)
+ return;
+ jh->open(&client);
+
+ plugins.push_back(jh);
+ client.add(jh);
+ main_win->add_plugin(jh);
+}
+
+void host_session::remove_plugin(plugin_ctl_iface *plugin)
+{
+ for (unsigned int i = 0; i < plugins.size(); i++)
+ {
+ if (plugins[i] == plugin)
+ {
+ client.del(i);
+ plugins.erase(plugins.begin() + i);
+ main_win->del_plugin(plugin);
+ delete plugin;
+ return;
+ }
+ }
+}
+
void host_session::activate_preset(int i, const std::string &preset)
{
- string cur_plugin = plugin_names[i];
+ string cur_plugin = plugins[i]->get_id();
preset_vector &pvec = global_presets.presets;
bool found = false;
for (unsigned int i = 0; i < pvec.size(); i++) {
@@ -275,14 +318,11 @@ void host_session::close()
{
if (lash_source_id)
g_source_remove(lash_source_id);
- client.deactivate();
- client.close();
main_win->on_closed();
main_win->close_guis();
- for (unsigned int i = 0; i < plugin_names.size(); i++) {
- plugins[i]->close();
- delete plugins[i];
- }
+ client.delete_plugins();
+ client.deactivate();
+ client.close();
}
#if USE_LASH
@@ -301,7 +341,7 @@ void host_session::update_lash()
for (unsigned int i = 0; i < plugins.size(); i++) {
char ss[32];
plugin_preset preset;
- preset.plugin = plugin_names[i];
+ preset.plugin = plugins[i]->get_id();
preset.get_from(plugins[i]);
sprintf(ss, "plugin%d", i);
string pstr = preset.to_xml();
@@ -426,10 +466,12 @@ int main(int argc, char *argv[])
sess.plugin_names.push_back(argv[optind++]);
}
}
+ /*
if (!sess.plugin_names.size()) {
print_help(argv);
return 0;
}
+ */
try {
global_presets.load_defaults();
}
diff --git a/src/main_win.cpp b/src/main_win.cpp
index 70a6cf1..49f1891 100644
--- a/src/main_win.cpp
+++ b/src/main_win.cpp
@@ -29,9 +29,34 @@
using namespace synth;
using namespace std;
+static const char *ui_xml =
+"<ui>\n"
+" <menubar>\n"
+" <menu action=\"HostMenuAction\">\n"
+" <menu action=\"AddPluginMenuAction\">\n"
+" </menu>\n"
+" <separator/>\n"
+" <menuitem action=\"exit\"/>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n"
+;
+
+static void exit_action(main_window *main)
+{
+ gtk_widget_destroy(GTK_WIDGET(main->toplevel));
+}
+
+static const GtkActionEntry actions[] = {
+ { "HostMenuAction", "", "_Host", NULL, "Host-related operations", NULL },
+ { "AddPluginMenuAction", "", "_Add plugin", NULL, "Add a plugin to the rack", NULL },
+ { "exit", "", "_Exit", NULL, "Exit application", (GCallback)exit_action },
+};
+
main_window::main_window()
{
toplevel = NULL;
+ owner = NULL;
is_closed = true;
}
@@ -39,7 +64,9 @@ void main_window::add_plugin(plugin_ctl_iface *plugin)
{
if (toplevel)
{
- plugins[plugin] = create_strip(plugin);
+ plugin_strip *strip = create_strip(plugin);
+ plugins[plugin] = strip;
+ update_strip(plugin);
}
else {
plugin_queue.push_back(plugin);
@@ -49,7 +76,51 @@ void main_window::add_plugin(plugin_ctl_iface *plugin)
void main_window::del_plugin(plugin_ctl_iface *plugin)
{
+ if (!plugins.count(plugin))
+ return;
+ plugin_strip *strip = plugins[plugin];
+ if (strip->gui_win)
+ strip->gui_win->close();
+
+ int row = -1;
+ for(GList *p = GTK_TABLE(strips_table)->children; p != NULL; p = p->next)
+ {
+ GtkTableChild *c = (GtkTableChild *)p->data;
+ if (c->widget == strip->name)
+ {
+ row = c->top_attach - 1;
+ break;
+ }
+ }
+ g_assert(row != -1);
+
+ vector<GtkWidget *> to_destroy;
+ for(GList *p = GTK_TABLE(strips_table)->children; p != NULL; p = p->next)
+ {
+ GtkTableChild *c = (GtkTableChild *)p->data;
+ if (c->top_attach >= row && c->top_attach < row + 3)
+ to_destroy.push_back(c->widget);
+ if (c->top_attach >= row + 3)
+ {
+ c->top_attach -= 3;
+ c->bottom_attach -= 3;
+ }
+ }
+
+ for (unsigned int i = 0; i < to_destroy.size(); i++)
+ gtk_container_remove(GTK_CONTAINER(strips_table), to_destroy[i]);
+ //for (unsigned int i = 0; i < to_destroy.size(); i++)
+ // gtk_widget_destroy(to_destroy[i]);
+
plugins.erase(plugin);
+ for(GList *p = GTK_TABLE(strips_table)->children; p != NULL; p = p->next)
+ {
+ GtkTableChild *c = (GtkTableChild *)p->data;
+ if (c->top_attach == 0) {
+ c->ypadding = 0;
+ gtk_widget_set_size_request(c->widget, -1, -1);
+ }
+ }
}
void main_window::set_window(plugin_ctl_iface *plugin, plugin_gui_window *gui_win)
@@ -88,6 +159,14 @@ gui_button_pressed(GtkWidget *button, main_window::plugin_strip *strip)
return TRUE;
}
+static gboolean
+extra_button_pressed(GtkWidget *button, main_window::plugin_strip *strip)
+{
+ GtkButton *tb = GTK_BUTTON(button);
+ strip->main_win->owner->remove_plugin(strip->plugin);
+ return TRUE;
+}
+
main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
{
plugin_strip *strip = new plugin_strip;
@@ -99,7 +178,9 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
g_object_get(G_OBJECT(strips_table), "n-rows", &row, "n-columns", &cols, NULL);
gtk_table_resize(GTK_TABLE(strips_table), row + 3, cols);
- gtk_table_attach_defaults(GTK_TABLE(strips_table), gtk_hseparator_new(), 0, 4, row, row + 1);
+ GtkWidget *sep = gtk_hseparator_new();
+ gtk_table_attach_defaults(GTK_TABLE(strips_table), sep, 0, 4, row, row + 1);
+ gtk_widget_show(sep);
row++;
GtkWidget *label = gtk_toggle_button_new_with_label(plugin->get_name());
@@ -107,10 +188,12 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
strip->name = label;
gtk_signal_connect(GTK_OBJECT(label), "toggled", G_CALLBACK(gui_button_pressed),
(plugin_ctl_iface *)strip);
+ gtk_widget_show(strip->name);
label = gtk_label_new(plugin->get_midi() ? "MIDI" : "");
gtk_table_attach_defaults(GTK_TABLE(strips_table), label, 1, 2, row, row + 2);
strip->midi_in = label;
+ gtk_widget_show(strip->midi_in);
for (int i = 0; i < 2; i++)
strip->audio_in[i] = strip->audio_out[i] = NULL;
@@ -122,6 +205,8 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
label = calf_vumeter_new();
gtk_table_attach_defaults(GTK_TABLE(strips_table), label, 2, 3, row + 1, row + 2);
strip->audio_in[1] = label;
+ gtk_widget_show(strip->audio_in[0]);
+ gtk_widget_show(strip->audio_in[1]);
}
if (plugin->get_output_count() == 2) {
@@ -131,7 +216,16 @@ main_window::plugin_strip *main_window::create_strip(plugin_ctl_iface *plugin)
label = calf_vumeter_new();
gtk_table_attach_defaults(GTK_TABLE(strips_table), label, 3, 4, row + 1, row + 2);
strip->audio_out[1] = label;
+ gtk_widget_show(strip->audio_out[0]);
+ gtk_widget_show(strip->audio_out[1]);
}
+ GtkWidget *extra = gtk_button_new_with_label("X");
+ gtk_table_attach_defaults(GTK_TABLE(strips_table), extra, 4, 5, row, row + 2);
+ strip->extra = extra;
+ gtk_signal_connect(GTK_OBJECT(extra), "clicked", G_CALLBACK(extra_button_pressed),
+ (plugin_ctl_iface *)strip);
+ gtk_widget_show(strip->extra);
+
return strip;
}
@@ -150,13 +244,74 @@ void main_window::open_gui(plugin_ctl_iface *plugin)
plugins[plugin]->gui_win = gui_win;
}
+static const char *plugin_pre_xml =
+"<ui>\n"
+" <menubar>\n"
+" <menu action=\"AddPluginMenuAction\">\n"
+" <placeholder name=\"plugin\">\n";
+
+static const char *plugin_post_xml =
+" </placeholder>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n"
+;
+
+void main_window::add_plugin_action(GtkWidget *src, gpointer data)
+{
+ add_plugin_params *app = (add_plugin_params *)data;
+ app->main_win->new_plugin(app->name.c_str());
+}
+
+static void action_destroy_notify(gpointer data)
+{
+ delete (main_window::add_plugin_params *)data;
+}
+
+/*
+void main_window::new_plugin(const char *plugin)
+{
+ printf("new plugin %s\n", plugin);
+}
+*/
+
+std::string main_window::make_plugin_list(GtkActionGroup *actions)
+{
+ string s = plugin_pre_xml;
+ std::vector<giface_plugin_info> plugins;
+ synth::get_all_plugins(plugins);
+ for(unsigned int i = 0; i < plugins.size(); i++)
+ {
+ string action_name = "Add" + string(plugins[i].info->label)+"Action";
+ s += string("<menuitem action=\"") + action_name + "\" />";
+ GtkActionEntry ae = { action_name.c_str(), NULL, plugins[i].info->name, NULL, NULL, (GCallback)add_plugin_action };
+ gtk_action_group_add_actions_full(actions, &ae, 1, (gpointer)new add_plugin_params(this, plugins[i].info->label), action_destroy_notify);
+ }
+ return s + plugin_post_xml;
+}
+
void main_window::create()
{
toplevel = GTK_WINDOW(gtk_window_new (GTK_WINDOW_TOPLEVEL));
is_closed = false;
all_vbox = gtk_vbox_new(0, FALSE);
- strips_table = gtk_table_new(1, 5, FALSE);
+
+ 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);
+ gtk_box_pack_start(GTK_BOX(all_vbox), gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar"), false, false, 0);
+
+ plugin_actions = gtk_action_group_new("plugins");
+ string plugin_xml = make_plugin_list(plugin_actions);
+ gtk_ui_manager_insert_action_group(ui_mgr, plugin_actions, 0);
+ gtk_ui_manager_add_ui_from_string(ui_mgr, plugin_xml.c_str(), -1, &error);
+
+
+ strips_table = gtk_table_new(1, 6, FALSE);
gtk_table_set_col_spacings(GTK_TABLE(strips_table), 10);
gtk_table_set_row_spacings(GTK_TABLE(strips_table), 5);
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list