lilv_instance_free(inst); inst = 0;
lilv_uis_free(lilv_uis); lilv_uis = 0;
- lilv_node_free(lv2_InputPort); lv2_InputPort = 0;
- lilv_node_free(lv2_OutputPort); lv2_OutputPort = 0;
+ lilv_node_free(lv2_InputPort); lv2_InputPort = 0;
+ lilv_node_free(lv2_OutputPort); lv2_OutputPort = 0;
lilv_node_free(lv2_AudioPort); lv2_AudioPort = 0;
lilv_node_free(lv2_ControlPort); lv2_ControlPort = 0;
- lilv_node_free(lv2_CVPort); lv2_CVPort = 0;
+ lilv_node_free(lv2_CVPort); lv2_CVPort = 0;
lilv_node_free(lv2_Optional); lv2_Optional = 0;
lilv_node_free(atom_AtomPort); atom_AtomPort = 0;
boundedBlockLength = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
- conf.init_lv2(lilv);
+ conf.init_lv2(lilv, this);
nb_inputs = nb_outputs = 0;
for( int i=0; i<conf.nb_ports; ++i ) {
return ((PluginLV2UriTable *)handle)->unmap(urid);
}
-void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int typ)
+void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int ports)
{
int ich = 0, och = 0;
for( int i=0; i<conf.nb_ports; ++i ) {
const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
if( !lp ) continue;
- if( (typ & TYP_CONTROL) &&
- lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
+ int port = conf.ports[i];
+ if( !(port & ports) ) continue;
+ if( (port & PORTS_CONTROL) ) {
lilv_instance_connect_port(inst, i, &conf.ctls[i]);
continue;
}
- if( (typ & TYP_AUDIO) &&
- ( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
- lilv_port_is_a(lilv, lp, lv2_CVPort) ) ) {
- if( lilv_port_is_a(lilv, lp, lv2_InputPort) ) {
- lilv_instance_connect_port(inst, iport[ich]=i, in_buffers[ich]);
- ++ich;
+ if( (port & PORTS_AUDIO) ) {
+ if( (port & PORTS_INPUT) ) {
+ lilv_instance_connect_port(inst, i, in_buffers[ich]);
+ iport[ich++] = i;
}
- else if( lilv_port_is_a(lilv, lp, lv2_OutputPort)) {
- lilv_instance_connect_port(inst, oport[och]=i, out_buffers[och]);
- ++och;
+ else if( (port & PORTS_OUTPUT) ) {
+ lilv_instance_connect_port(inst, i, out_buffers[och]);
+ oport[och++] = i;
}
continue;
}
- if( (typ & TYP_ATOM) &&
- lilv_port_is_a(lilv, lp, atom_AtomPort) ) {
- if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
+ if( (port & PORTS_ATOM) ) {
+ if( (port & PORTS_INPUT) )
lilv_instance_connect_port(inst, i, &seq_in);
- else
+ else if( (port & PORTS_OUTPUT) )
lilv_instance_connect_port(inst, i, seq_out);
continue;
}
lilv_type = 0;
uri_map = 0;
- done = 0;
+ done = -1;
running = 0;
- redraw = 0;
- host_updates = updates = 0;
- host_hidden = hidden = 1;
+ updates = 0;
+ hidden = 1;
title[0] = 0;
+ child = 0;
// only gtk-2
gtk_type = "http://lv2plug.in/ns/extensions/ui#GtkUI";
int nb_inputs, nb_outputs;
} shm_bfr_t;
-#define TYP_AUDIO 1
-#define TYP_CONTROL 2
-#define TYP_ATOM 4
-#define TYP_ALL ~0
+#define PORTS_AUDIO 0x01
+#define PORTS_CONTROL 0x02
+#define PORTS_ATOM 0x04
+#define PORTS_ALL (PORTS_AUDIO | PORTS_CONTROL | PORTS_ATOM)
+#define PORTS_INPUT 0x08
+#define PORTS_OUTPUT 0x10
+#define PORTS_UPDATE 0x20
class PluginLV2
{
static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri);
static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid);
- void connect_ports(PluginLV2ClientConfig &conf, int typ=TYP_ALL);
+ void connect_ports(PluginLV2ClientConfig &conf, int ports);
void del_buffer();
void new_buffer(int64_t sz);
shm_bfr_t *shm_buffer(int shmid);
};
typedef struct { int sample_rate; char path[1]; } open_bfr_t;
-typedef struct { int idx; float value; } control_bfr_t;
enum { NO_COMMAND,
LV2_OPEN,
LV2_UPDATE,
LV2_SHOW,
LV2_HIDE,
- LV2_SET,
LV2_SHMID,
NB_COMMANDS };
case LV2_SHOW: {
hidden = 0;
break; }
- case LV2_SET: {
- if( !gui ) break;
- control_bfr_t *ctl = (control_bfr_t *)parent_data;
- gui->lv2_set(ctl->idx, ctl->value);
- break; }
case LV2_SHMID: {
output_bfr->unlock();
break; }
case EXIT_CODE: {
+ hidden = 1;
output_bfr->unlock();
result = -1;
break; }
#include "arraylist.h"
#include "cstrdup.h"
#include "language.h"
+#include "pluginlv2.h"
#include "pluginlv2config.h"
#include <ctype.h>
mins = 0;
maxs = 0;
ctls = 0;
+ ports = 0;
nb_ports = 0;
}
delete [] names[i];
delete [] syms[i];
}
- delete [] names; names = 0;
- delete [] mins; mins = 0;
- delete [] maxs; maxs = 0;
- delete [] ctls; ctls = 0;
+ delete [] names; names = 0;
+ delete [] mins; mins = 0;
+ delete [] maxs; maxs = 0;
+ delete [] ctls; ctls = 0;
+ delete [] ports; ports = 0;
nb_ports = 0;
}
mins = new float[nb_ports];
maxs = new float[nb_ports];
ctls = new float[nb_ports];
+ ports = new int[nb_ports];
}
for( int i=0; i<nb_ports; ++i ) {
delete [] names[i]; names[i] = cstrdup(that.names[i]);
mins[i] = that.mins[i];
maxs[i] = that.maxs[i];
ctls[i] = that.ctls[i];
+ ports[i] = ports[i];
}
remove_all_objects();
for( int i=0; i<that.size(); ++i ) {
copy_from(prev);
}
-void PluginLV2ClientConfig::init_lv2(const LilvPlugin *lilv)
+void PluginLV2ClientConfig::init_lv2(const LilvPlugin *lilv, PluginLV2 *lv2)
{
reset();
nb_ports = lilv_plugin_get_num_ports(lilv);
mins = new float[nb_ports];
maxs = new float[nb_ports];
ctls = new float[nb_ports];
+ ports = new int[nb_ports];
lilv_plugin_get_port_ranges_float(lilv, mins, maxs, ctls);
for( int i=0; i<nb_ports; ++i ) {
const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
lilv_node_free(pnm);
const LilvNode *sym = lilv_port_get_symbol(lilv, lp);
syms[i] = cstrdup(lilv_node_as_string(sym));
+ int port = 0;
+ if( lilv_port_is_a(lilv, lp, lv2->lv2_AudioPort) ) port |= PORTS_AUDIO;
+ if( lilv_port_is_a(lilv, lp, lv2->lv2_ControlPort) ) port |= PORTS_CONTROL;
+ if( lilv_port_is_a(lilv, lp, lv2->lv2_InputPort) ) port |= PORTS_INPUT;
+ if( lilv_port_is_a(lilv, lp, lv2->lv2_OutputPort) ) port |= PORTS_OUTPUT;
+ if( lilv_port_is_a(lilv, lp, lv2->atom_AtomPort) ) port |= PORTS_ATOM;
+ ports[i] = port;
}
}
#include "guicast.h"
#include "mutex.h"
#include "pluginaclient.h"
+#include "pluginlv2.inc"
#include "pluginlv2config.inc"
#include "samples.inc"
void interpolate(PluginLV2ClientConfig &prev, PluginLV2ClientConfig &next,
int64_t prev_frame, int64_t next_frame, int64_t current_frame);
void reset();
- void init_lv2(const LilvPlugin *lilv);
+ void init_lv2(const LilvPlugin *lilv, PluginLV2 *lv2);
int update();
void dump(FILE *fp);
- int nb_ports;
+ int nb_ports, *ports;
const char **names, **syms;
float *mins, *maxs, *ctls;
};
int PluginLV2ClientReset::handle_event()
{
PluginLV2Client *client = gui->client;
- client->config.init_lv2(client->lilv);
+ client->config.init_lv2(client->lilv, client);
client->config.update();
client->update_lv2();
gui->update(0);
if( !selected ) return;
PluginLV2ParentUI *ui = find_ui();
if( !ui ) return;
- control_bfr_t ctl_bfr;
- ctl_bfr.idx = selected->idx;
- ctl_bfr.value = selected->get_value();
- ui->send_child(LV2_SET, &ctl_bfr, sizeof(ctl_bfr));
+ PluginLV2ClientConfig &conf = client->config;
+ ui->send_child(LV2_UPDATE, conf.ctls, sizeof(float)*conf.nb_ports);
}
int PluginLV2ClientWindow::scalar(float f, char *rp)
PluginLV2Client_Opt *opt = config[i];
if( opt->idx == idx ) {
opt->set_value(*(const float*)bfr);
-//printf("set %s = %f\n", opt->get_symbol(), opt->get_value());
- ++updates;
+ updates = UPDATE_HOST;
break;
}
}
return !fs_matches && !nrs_matches;
}
-int PluginLV2UI::update_lv2(float *vals, int force)
+int PluginLV2UI::send_host(int64_t token, const void *data, int bytes)
+{
+ return !child ? 0 : child->send_parent(token, data, bytes);
+}
+
+int PluginLV2UI::update_lv2_input(float *vals, int force)
{
int ret = 0;
- float *ctls = (float *)config.ctls;
+ float *ctls = config.ctls;
for( int i=0; i<config.size(); ++i ) {
int idx = config[i]->idx;
float val = vals[idx];
if( !force && ctls[idx] == val ) continue;
- update_control(idx, sizeof(val), 0, &val);
+ ctls[idx] = val;
+ update_control(idx, sizeof(ctls[idx]), 0, &ctls[idx]);
++ret;
}
- for( int i=0; i<config.nb_ports; ++i ) ctls[i] = vals[i];
return ret;
}
+void PluginLV2UI::update_lv2_output()
+{
+ int *ports = config.ports;
+ float *ctls = config.ctls;
+ for( int i=0; i<config.nb_ports; ++i ) {
+ if( !(ports[i] & PORTS_UPDATE) ) continue;
+ ports[i] &= ~PORTS_UPDATE;
+ update_control(i, sizeof(ctls[i]), 0, &ctls[i]);
+ }
+}
+
static void lilv_destroy(GtkWidget* widget, gpointer data)
{
PluginLV2UI *the = (PluginLV2UI*)data;
- the->hidden = 1;
the->top_level = 0;
- ++the->updates;
}
void PluginLV2UI::start_gui()
{
+ if( !hidden ) return;
top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(top_level, "destroy", G_CALLBACK(lilv_destroy), this);
gtk_window_set_title(GTK_WINDOW(top_level), title);
gtk_window_set_resizable(GTK_WINDOW(top_level), lv2ui_resizable());
gtk_widget_show_all(vbox);
gtk_widget_grab_focus(widget);
- float *ctls = (float *)config.ctls;
- update_lv2(ctls, 1);
- connect_ports(config, TYP_CONTROL);
- lilv_instance_run(inst, 0);
+ update_lv2_input(config.ctls, 1);
+ connect_ports(config, PORTS_CONTROL);
+ updates = 0;
+ run_lilv(0);
gtk_window_present(GTK_WINDOW(top_level));
+ send_host(LV2_SHOW, 0, 0);
+ hidden = 0;
}
-
-void PluginLV2UI::host_update(PluginLV2ChildUI *child)
+void PluginLV2UI::update_host()
{
-//printf("update\n");
- host_updates = updates;
- if( !child ) return;
- if( host_hidden != hidden ) {
- host_hidden = hidden;
- if( hidden ) reset_gui();
- child->send_parent(hidden ? LV2_HIDE : LV2_SHOW, 0, 0);
- }
+// ignore update
if( running < 0 ) { running = 1; return; }
- child->send_parent(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
+ send_host(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
}
void PluginLV2UI::reset_gui()
{
+ if( hidden ) return;
if( sinst ) { suil_instance_free(sinst); sinst = 0; }
if( ui_host ) { suil_host_free(ui_host); ui_host = 0; }
if( top_level ) { gtk_widget_destroy(top_level); top_level = 0; }
while( features.size() > ui_features ) features.remove_object();
features.append(0);
hidden = 1;
+ send_host(LV2_HIDE, 0, 0);
}
// child main
int PluginLV2UI::run_ui(PluginLV2ChildUI *child)
{
+ this->child = child;
running = 1;
+ done = 0;
while( !done ) {
if( gtk_events_pending() ) {
gtk_main_iteration();
continue;
}
- if( running && host_updates != updates )
- host_update(child);
- if( redraw ) {
- redraw = 0;
- update_lv2(config.ctls, 1);
+ if( !top_level && !hidden )
+ reset_gui();
+ if( updates ) {
+ if( (updates & UPDATE_PORTS) )
+ update_lv2_output();
+ if( (updates & UPDATE_HOST) )
+ update_host();
+ updates = 0;
}
if( !child ) usleep(10000);
else if( child->child_iteration() < 0 )
return 0;
}
-void PluginLV2UI::run_buffer(int shmid)
+void PluginLV2UI::run_lilv(int samples)
+{
+ float ctls[config.nb_ports];
+ for( int i=0; i<config.nb_ports; ++i ) ctls[i] = config.ctls[i];
+
+ lilv_instance_run(inst, samples);
+
+ for( int i=0; i<config.nb_ports; ++i ) {
+ if( !(config.ports[i] & PORTS_OUTPUT) ) continue;
+ if( !(config.ports[i] & PORTS_CONTROL) ) continue;
+ if( config.ctls[i] == ctls[i] ) continue;
+ config.ports[i] |= PORTS_UPDATE;
+ updates |= UPDATE_PORTS;
+ }
+}
+
+void PluginLV2ChildUI::run_buffer(int shmid)
{
if( !shm_buffer(shmid) ) return;
map_buffer();
- int samples = shm_bfr->samples;
- connect_ports(config);
- lilv_instance_run(inst, samples);
+ connect_ports(config, PORTS_ALL);
+ run_lilv(shm_bfr->samples);
shm_bfr->done = 1;
}
if( init_ui(open_bfr->path, open_bfr->sample_rate) ) exit(1);
break; }
case LV2_LOAD: {
- float *ctls = (float *)child_data;
- update_lv2(ctls, 1);
+ float *vals = (float *)child_data;
+ update_lv2_input(vals, 1);
break; }
case LV2_UPDATE: {
- float *ctls = (float *)child_data;
- if( update_lv2(ctls, 0) > 0 )
- ++updates;
+ float *vals = (float *)child_data;
+ update_lv2_input(vals, 0);
break; }
case LV2_SHOW: {
start_gui();
- hidden = 0; ++updates;
break; }
case LV2_HIDE: {
- hidden = 1; ++updates;
- break; }
- case LV2_SET: {
- control_bfr_t *ctl_bfr = (control_bfr_t *)child_data;
- config.ctls[ctl_bfr->idx] = ctl_bfr->value;
- redraw = 1;
+ reset_gui();
break; }
case LV2_SHMID: {
int shmid = *(int *)child_data;
typedef struct _GtkWidget GtkWidget;
+#define UPDATE_HOST 1
+#define UPDATE_PORTS 2
+
class PluginLV2UI : public PluginLV2
{
public:
char title[BCSTRLEN];
PluginLV2ClientConfig config;
- uint32_t host_updates, updates;
- int host_hidden, hidden;
+ int updates, hidden;
int done, running;
const char *gtk_type;
GtkWidget *top_level;
+ PluginLV2ChildUI *child;
void reset_gui();
int init_ui(const char *path, int sample_rate);
void start();
void stop();
- int update_lv2(float *vals, int force);
- int redraw;
+ int send_host(int64_t token, const void *data, int bytes);
+ int update_lv2_input(float *vals, int force);
+ void update_lv2_output();
+ void run_lilv(int samples);
void update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr);
void update_control(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr);
static void write_from_ui(void *the, uint32_t idx,
bool lv2ui_resizable();
void start_gui();
int run_ui(PluginLV2ChildUI *child=0);
- void run_buffer(int shmid);
- void host_update(PluginLV2ChildUI *child);
+ void update_host();
int run(int ac, char **av);
};
PluginLV2ChildUI();
~PluginLV2ChildUI();
void run();
+ void run_buffer(int shmid);
int handle_child();
int run(int ac, char **av);