max_bufsz = 0;
ui_features = 0;
+ samplerate = 44100;
+ refreshrate = 30.;
+ block_length = 4096;
+ midi_buf_size = 8192;
+
world = 0;
lilv = 0;
lilv_uis = 0;
fixedBlockLength = 0;
boundedBlockLength = 0;
seq_out = 0;
+
+ worker_thread = 0;
+ memset(&schedule, 0, sizeof(schedule));
+ schedule.handle = (LV2_Worker_Schedule_Handle)this;
+ schedule.schedule_work = lv2_worker_schedule;
+ worker_iface = 0; worker_done = -1;
+ pthread_mutex_init(&worker_lock, 0);
+ pthread_cond_init(&worker_ready, 0);
+ work_avail = 0; work_input = 0;
+ work_output = 0; work_tail = &work_output;
}
PluginLV2::~PluginLV2()
{
reset_lv2();
if( world ) lilv_world_free(world);
+ pthread_mutex_destroy(&worker_lock);
+ pthread_cond_destroy(&worker_ready);
}
void PluginLV2::reset_lv2()
{
+ worker_stop();
if( inst ) lilv_instance_deactivate(inst);
lilv_instance_free(inst); inst = 0;
lilv_uis_free(lilv_uis); lilv_uis = 0;
lilv = lilv_plugins_get_by_uri(all_plugins, uri);
lilv_node_free(uri);
if( !lilv ) {
- printf("lv2: lilv_plugins_get_by_uriPlugin(%s) failed\n", path);
+ printf("lv2: lilv_plugins_get_by_uri (%s) failed\n", path);
return 1;
}
return 0;
}
-int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate)
+int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate, int bfrsz)
{
reset_lv2();
+ double bps = 2. * sample_rate / bfrsz;
+ if( bps > refreshrate ) refreshrate = bps;
lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
}
}
+
+ uri_map.callback_data = (LV2_URI_Map_Callback_Data)this;
+ uri_map.uri_to_id = uri_to_id;
+ features.append(new Lv2Feature(NS_EXT "uri-map", &uri_map));
map.handle = (void*)&uri_table;
map.map = uri_table_map;
features.append(new Lv2Feature(LV2_URID_MAP_URI, &map));
features.append(new Lv2Feature(LV2_BUF_SIZE__powerOf2BlockLength, 0));
features.append(new Lv2Feature(LV2_BUF_SIZE__fixedBlockLength, 0));
features.append(new Lv2Feature(LV2_BUF_SIZE__boundedBlockLength, 0));
+ features.append(new Lv2Feature(LV2_WORKER__schedule, &schedule));
+
+ if( sample_rate < 64 ) sample_rate = samplerate;
+
+ atom_int = uri_table.map(LV2_ATOM__Int);
+ atom_float = uri_table.map(LV2_ATOM__Float);
+ param_sampleRate = uri_table.map(LV2_PARAMETERS__sampleRate);
+ bufsz_minBlockLength = uri_table.map(LV2_BUF_SIZE__minBlockLength);
+ bufsz_maxBlockLength = uri_table.map(LV2_BUF_SIZE__maxBlockLength);
+ bufsz_sequenceSize = uri_table.map(LV2_BUF_SIZE__sequenceSize);
+ ui_updateRate = uri_table.map(LV2_UI__updateRate);
+
+ samplerate = sample_rate;
+ block_length = bfrsz;
+ options.add(param_sampleRate, sizeof(float), atom_float, &samplerate);
+ options.add(bufsz_minBlockLength, sizeof(int), atom_int, &block_length);
+ options.add(bufsz_maxBlockLength, sizeof(int), atom_int, &block_length);
+ options.add(bufsz_sequenceSize, sizeof(int), atom_int, &midi_buf_size);
+ options.add(ui_updateRate, sizeof(float), atom_float, &refreshrate);
+ options.add(0, 0, 0, 0);
+
+ features.append(new Lv2Feature(LV2_OPTIONS__options, &options[0]));
features.append(0);
- if( sample_rate < 64 ) sample_rate = 64;
inst = lilv_plugin_instantiate(lilv, sample_rate, features);
if( !inst ) {
printf("lv2: lilv_plugin_instantiate failed\n");
return 1;
}
+ const LV2_Descriptor *lilv_desc = inst->lv2_descriptor;
+ worker_iface = !lilv_desc->extension_data ? 0 :
+ (LV2_Worker_Interface*)lilv_desc->extension_data(LV2_WORKER__interface);
+ if( worker_iface )
+ worker_start();
+
lilv_instance_activate(inst);
// not sure what to do with these
max_bufsz = nb_inputs &&
return ((PluginLV2UriTable *)handle)->unmap(urid);
}
+uint32_t PluginLV2::uri_to_id(LV2_URI_Map_Callback_Data callback_data,
+ const char *map, const char *uri)
+{
+ PluginLV2 *the = (PluginLV2 *)callback_data;
+ return the->map.map(the->uri_table, uri);
+}
+
void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int ports)
{
int ich = 0, och = 0;
if( (port & PORTS_ATOM) ) {
if( (port & PORTS_INPUT) )
lilv_instance_connect_port(inst, i, &seq_in);
- else if( (port & PORTS_OUTPUT) )
+ else
lilv_instance_connect_port(inst, i, seq_out);
continue;
}
}
+// LV2 Worker
+
+PluginLV2Work::PluginLV2Work()
+{
+ next = 0;
+ alloc = used = 0;
+ data = 0;
+}
+
+PluginLV2Work::~PluginLV2Work()
+{
+ delete [] data;
+}
+
+void PluginLV2Work::load(const void *vp, unsigned size)
+{
+ if( alloc < size ) {
+ delete [] data;
+ data = new char[alloc=size];
+ }
+ memcpy(data, vp, used=size);
+}
+
+PluginLV2Work *PluginLV2::get_work()
+{
+// must hold worker_lock
+ if( !work_avail ) return new PluginLV2Work();
+ PluginLV2Work *wp = work_avail;
+ work_avail = wp->next; wp->next = 0;
+ return wp;
+}
+
+void *PluginLV2::worker_func()
+{
+ pthread_mutex_lock(&worker_lock);
+ for(;;) {
+ while( !worker_done && !work_input )
+ pthread_cond_wait(&worker_ready, &worker_lock);
+ if( worker_done ) break;
+ PluginLV2Work *wp = work_input; work_input = wp->next;
+
+ pthread_mutex_unlock(&worker_lock);
+ worker_iface->work(inst, lv2_worker_respond, this, wp->used, wp->data);
+ pthread_mutex_lock(&worker_lock);
+ wp->next = work_avail; work_avail = wp;
+ }
+ pthread_mutex_unlock(&worker_lock);
+ return NULL;
+}
+void *PluginLV2::worker_func(void* vp)
+{
+ PluginLV2 *the = (PluginLV2 *)vp;
+ return the->worker_func();
+}
+
+void PluginLV2::worker_start()
+{
+ pthread_create(&worker_thread, 0, worker_func, this);
+}
+
+void PluginLV2::worker_stop()
+{
+ if( !worker_done ) {
+ worker_done = 1;
+ pthread_mutex_lock(&worker_lock);
+ pthread_cond_signal(&worker_ready);
+ pthread_mutex_unlock(&worker_lock);
+ pthread_join(worker_thread, 0);
+ worker_thread = 0;
+ }
+ work_stop(work_avail);
+ work_stop(work_input);
+ work_stop(work_output);
+ work_tail = &work_output;
+}
+
+void PluginLV2::work_stop(PluginLV2Work *&work)
+{
+ while( work ) {
+ PluginLV2Work *wp = work;
+ work = wp->next;
+ delete wp;
+ }
+}
+
+LV2_Worker_Status PluginLV2::worker_schedule(uint32_t inp_size, const void *inp_data)
+{
+ if( is_forked() ) {
+ if( !pthread_mutex_trylock(&worker_lock) ) {
+ PluginLV2Work *wp = get_work();
+ wp->load(inp_data, inp_size);
+ wp->next = work_input; work_input = wp;
+ pthread_cond_signal(&worker_ready);
+ pthread_mutex_unlock(&worker_lock);
+ }
+ }
+ else if( worker_iface )
+ worker_iface->work(inst, lv2_worker_respond, this, inp_size, inp_data);
+ return LV2_WORKER_SUCCESS;
+}
+LV2_Worker_Status PluginLV2::lv2_worker_schedule(LV2_Worker_Schedule_Handle vp,
+ uint32_t inp_size, const void *inp_data)
+{
+ PluginLV2 *the = (PluginLV2 *)vp;
+ return the->worker_schedule(inp_size, inp_data);
+}
+
+LV2_Worker_Status PluginLV2::worker_respond(uint32_t out_size, const void *out_data)
+{
+ pthread_mutex_lock(&worker_lock);
+ PluginLV2Work *wp = get_work();
+ wp->load(out_data, out_size);
+ *work_tail = wp; work_tail = &wp->next;
+ pthread_mutex_unlock(&worker_lock);
+ return LV2_WORKER_SUCCESS;
+}
+LV2_Worker_Status PluginLV2::lv2_worker_respond(LV2_Worker_Respond_Handle vp,
+ uint32_t out_size, const void *out_data)
+{
+ PluginLV2 *the = (PluginLV2 *)vp;
+ return the->worker_respond(out_size, out_data);
+}
+
+void PluginLV2::worker_responses()
+{
+ pthread_mutex_lock(&worker_lock);
+ while( work_output ) {
+ PluginLV2Work *rp = work_output;
+ if( !(work_output=rp->next) ) work_tail = &work_output;
+ pthread_mutex_unlock(&worker_lock);
+ worker_iface->work_response(inst, rp->used, rp->data);
+ pthread_mutex_lock(&worker_lock);
+ rp->next = work_avail; work_avail = rp;
+ }
+ pthread_mutex_unlock(&worker_lock);
+}
+
#include "file.h"
#include "pluginlv2ui.h"
PluginLV2ChildUI::PluginLV2ChildUI()
- : ForkChild()
{
+ ac = 0;
+ av = 0;
+ gui = 0;
+ hidden = 1;
}
PluginLV2ChildUI::~PluginLV2ChildUI()
{
+ delete gui;
}
void PluginLV2ChildUI::run()
_exit(1);
}
+#define LV2_EXTERNAL_UI_URI__KX__Widget "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"
PluginLV2UI::PluginLV2UI()
- : PluginLV2()
{
lilv_ui = 0;
lilv_type = 0;
- uri_map = 0;
done = -1;
running = 0;
updates = 0;
hidden = 1;
title[0] = 0;
- child = 0;
-// only gtk-2
- gtk_type = "http://lv2plug.in/ns/extensions/ui#GtkUI";
- top_level = 0;
+ memset(&uri_map, 0, sizeof(uri_map));
+ memset(&extui_host, 0, sizeof(extui_host));
+ wgt_type = LV2_EXTERNAL_UI_URI__KX__Widget;
+ gtk_type = LV2_UI__GtkUI;
+ ui_type = 0;
}
PluginLV2UI::~PluginLV2UI ()
{
- reset_gui();
}
#endif