X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;ds=sidebyside;f=cinelerra-5.1%2Fcinelerra%2Fpluginlv2.C;h=f4f1f7946df4ce9bf77b35e5dea84aa298f900aa;hb=2e48b660e37eb5c661264d601211e16cb6cd6e89;hp=bbfd76eaae7e3771cc6ca68fdb9806b180184f31;hpb=32b57dd9cdbb2fc0000a9f72ff766e4030c50b24;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/cinelerra/pluginlv2.C b/cinelerra-5.1/cinelerra/pluginlv2.C index bbfd76ea..f4f1f794 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2.C +++ b/cinelerra-5.1/cinelerra/pluginlv2.C @@ -20,6 +20,11 @@ PluginLV2::PluginLV2() max_bufsz = 0; ui_features = 0; + samplerate = 44100; + refreshrate = 30.; + block_length = 4096; + midi_buf_size = 8192; + world = 0; lilv = 0; lilv_uis = 0; @@ -39,16 +44,29 @@ PluginLV2::PluginLV2() 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; @@ -94,7 +112,7 @@ int PluginLV2::load_lv2(const char *path, char *title) 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; } @@ -107,9 +125,11 @@ int PluginLV2::load_lv2(const char *path, char *title) 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); @@ -147,6 +167,10 @@ int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate) } } + + 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)); @@ -156,15 +180,42 @@ int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate) 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 && @@ -184,6 +235,13 @@ const char *PluginLV2::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid 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; @@ -210,7 +268,7 @@ void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int ports) 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; } @@ -330,16 +388,157 @@ void PluginLV2::map_buffer() } +// 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() @@ -363,29 +562,28 @@ 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