From 02595181cff2bce97eb19634bc3855778cb8c3b6 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Sun, 10 Jun 2018 16:42:45 -0600 Subject: [PATCH] lv2 phase 2 fixups --- cinelerra-5.1/cinelerra/forkbase.C | 41 +-- cinelerra-5.1/cinelerra/forkbase.h | 13 +- cinelerra-5.1/cinelerra/lv2ui.C | 51 ++- cinelerra-5.1/cinelerra/pluginlv2.C | 217 ++++++++++++- cinelerra-5.1/cinelerra/pluginlv2.h | 64 ++++ cinelerra-5.1/cinelerra/pluginlv2client.C | 42 ++- cinelerra-5.1/cinelerra/pluginlv2client.h | 9 + cinelerra-5.1/cinelerra/pluginlv2config.h | 2 + cinelerra-5.1/cinelerra/pluginlv2gui.C | 1 - cinelerra-5.1/cinelerra/pluginlv2ui.C | 375 ++++++++++++++-------- cinelerra-5.1/cinelerra/pluginlv2ui.h | 95 +++++- 11 files changed, 681 insertions(+), 229 deletions(-) diff --git a/cinelerra-5.1/cinelerra/forkbase.C b/cinelerra-5.1/cinelerra/forkbase.C index 174019dd..5886424d 100644 --- a/cinelerra-5.1/cinelerra/forkbase.C +++ b/cinelerra-5.1/cinelerra/forkbase.C @@ -64,13 +64,6 @@ int ForkChild::is_running() return !ppid || !kill(ppid, 0) ? 1 : 0; } -int ForkChild::child_iteration() -{ - int ret = read_child(100); - if( ret <= 0 ) return ret; - return handle_child(); -} - void ForkParent::start_child() { lock("ForkParent::new_child"); @@ -94,7 +87,7 @@ void ForkParent::start_child() // Return -1 if the parent is dead // Return 0 if timeout // Return 1 if success -int ForkBase::read_timeout(int ms, int fd, void *data, int bytes) +int ForkBase::read_timeout(int64_t usec, int fd, void *data, int bytes) { fd_set rfds; struct timeval timeout_struct; @@ -102,8 +95,8 @@ int ForkBase::read_timeout(int ms, int fd, void *data, int bytes) uint8_t *bp = (uint8_t *)data; while( bytes_read < bytes ) { - timeout_struct.tv_sec = ms / 1000; - timeout_struct.tv_usec = (ms % 1000) * 1000; + timeout_struct.tv_sec = usec / 1000000; + timeout_struct.tv_usec = usec % 1000000; FD_ZERO(&rfds); FD_SET(fd, &rfds); int result = select(fd+1, &rfds, 0, 0, &timeout_struct); @@ -126,10 +119,10 @@ int ForkBase::is_running() return !pid || !kill(pid, 0) ? 1 : 0; } -int ForkBase::read_parent(int ms) +int ForkBase::read_parent(int64_t usec) { token_bfr_t bfr; - int ret = read_timeout(ms, parent_fd, &bfr, sizeof(bfr)); + int ret = read_timeout(usec, parent_fd, &bfr, sizeof(bfr)); if( ret > 0 ) { parent_token = bfr.token; parent_bytes = bfr.bytes; @@ -138,7 +131,7 @@ int ForkBase::read_parent(int ms) parent_data = new uint8_t[parent_allocated = parent_bytes]; } if( parent_bytes ) { - ret = read_timeout(1000, parent_fd, parent_data, parent_bytes); + ret = read_timeout(1000000, parent_fd, parent_data, parent_bytes); if( !ret ) { printf("read_parent timeout: %d\n", parent_fd); ret = -1; @@ -148,10 +141,10 @@ int ForkBase::read_parent(int ms) return ret; } -int ForkBase::read_child(int ms) +int ForkBase::read_child(int64_t usec) { token_bfr_t bfr; - int ret = read_timeout(ms, child_fd, &bfr, sizeof(bfr)); + int ret = read_timeout(usec, child_fd, &bfr, sizeof(bfr)); if( ret > 0 ) { child_token = bfr.token; child_bytes = bfr.bytes; @@ -160,7 +153,7 @@ int ForkBase::read_child(int ms) child_data = new uint8_t[child_allocated = child_bytes]; } if( child_bytes ) { - ret = read_timeout(1000, child_fd, child_data, child_bytes); + ret = read_timeout(1000000, child_fd, child_data, child_bytes); if( !ret ) { printf("read_child timeout: %d\n", child_fd); ret = -1; @@ -205,23 +198,17 @@ int ForkBase::send_child(int64_t token, const void *data, int bytes) ForkChild::ForkChild() { - done = 0; + parent_done = 0; } ForkChild::~ForkChild() { } -int ForkChild::handle_child() -{ - printf("ForkChild::handle_child %d\n", __LINE__); - return 0; -} - ForkParent::ForkParent() : Thread(1, 0, 0) { - done = -1; + parent_done = -1; } ForkParent::~ForkParent() @@ -253,7 +240,7 @@ int ForkParent::handle_parent() void ForkParent::start() { - done = 0; + parent_done = 0; Thread::start(); } @@ -270,7 +257,7 @@ void ForkParent::stop() void ForkParent::run() { - while( !done && parent_iteration() >= 0 ); - done = 1; + while( !parent_done && parent_iteration() >= 0 ); + parent_done = 1; } diff --git a/cinelerra-5.1/cinelerra/forkbase.h b/cinelerra-5.1/cinelerra/forkbase.h index 2ca84b71..6b09a5c2 100644 --- a/cinelerra-5.1/cinelerra/forkbase.h +++ b/cinelerra-5.1/cinelerra/forkbase.h @@ -41,13 +41,15 @@ public: virtual int is_running() = 0; void send_bfr(int fd, const void *bfr, int len); - int read_timeout(int ms, int fd, void *data, int bytes); - int read_parent(int ms); + int read_timeout(int64_t usec, int fd, void *data, int bytes); + + int read_parent(int64_t usec); int send_parent(int64_t value, const void *data, int bytes); - int read_child(int ms); + int read_child(int64_t usec); int send_child(int64_t value, const void *data, int bytes); - int done, ppid, pid; + int parent_done; + int ppid, pid; ForkChild *child; int child_fd; @@ -68,8 +70,7 @@ class ForkChild : public ForkBase public: ForkChild(); virtual ~ForkChild(); - virtual int handle_child(); - int child_iteration(); + virtual int child_iteration(int64_t usec) = 0; int is_running(); virtual void run() {} }; diff --git a/cinelerra-5.1/cinelerra/lv2ui.C b/cinelerra-5.1/cinelerra/lv2ui.C index 3a06102a..3ea5ba17 100644 --- a/cinelerra-5.1/cinelerra/lv2ui.C +++ b/cinelerra-5.1/cinelerra/lv2ui.C @@ -8,28 +8,6 @@ #include "pluginlv2client.h" #include "pluginlv2ui.h" -int PluginLV2UI::run(int ac, char **av) -{ - int sample_rate = 48000; - if( ac > 2 ) sample_rate = atoi(av[2]); - if( init_ui(av[1], sample_rate) ) { - fprintf(stderr," init_ui failed\n"); - return 1; - } - start_gui(); - return run_ui(); -} - -int PluginLV2ChildUI::run(int ac, char **av) -{ - signal(SIGINT, SIG_IGN); - ForkBase::child_fd = atoi(av[1]); - ForkBase::parent_fd = atoi(av[2]); - ForkBase::ppid = atoi(av[3]); - return run_ui(this); -} - - int main(int ac, char **av) { // to grab this task in the debugger @@ -41,10 +19,29 @@ while( bug ) usleep(10000); signals.initialize("/tmp/lv2ui_%d.dmp"); BC_Signals::set_catch_segv(1); } - gtk_set_locale(); - gtk_init(&ac, &av); - return ac < 3 ? - PluginLV2UI().run(ac, av) : - PluginLV2ChildUI().run(ac, av); + return PluginLV2ChildUI().run(ac, av); +} + +int PluginLV2ChildUI::run(int ac, char **av) +{ + this->ac = ac; + this->av = av; + + if( ac > 3 ) { + signal(SIGINT, SIG_IGN); + ForkBase::child_fd = atoi(av[1]); + ForkBase::parent_fd = atoi(av[2]); + ForkBase::ppid = atoi(av[3]); + } + else { + int sample_rate = 48000; + if( ac > 2 ) sample_rate = atoi(av[2]); + if( init_ui(av[1], sample_rate) ) { + fprintf(stderr," init_ui failed\n"); + return 1; + } + start_gui(); + } + return run_ui(); } diff --git a/cinelerra-5.1/cinelerra/pluginlv2.C b/cinelerra-5.1/cinelerra/pluginlv2.C index bbfd76ea..4ec32648 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; } @@ -147,6 +165,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 +178,41 @@ 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 = 44100; + + 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; + 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 +232,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 +265,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 +385,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 +559,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 diff --git a/cinelerra-5.1/cinelerra/pluginlv2.h b/cinelerra-5.1/cinelerra/pluginlv2.h index 01fc461f..9cd516a0 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2.h +++ b/cinelerra-5.1/cinelerra/pluginlv2.h @@ -23,6 +23,30 @@ typedef struct { #define PORTS_OUTPUT 0x10 #define PORTS_UPDATE 0x20 +class PluginLV2Options : public ArrayList +{ +public: + PluginLV2Options() {} + ~PluginLV2Options() {} + void add(LV2_URID key, unsigned sz, LV2_URID typ, void *vp) { + LV2_Options_Option *ap = &append(); + ap->context = LV2_OPTIONS_INSTANCE; ap->subject = 0; + ap->key = key; ap->size = sz; ap->type = typ; ap->value = vp; + } +}; + +class PluginLV2Work +{ +public: + PluginLV2Work(); + ~PluginLV2Work(); + void load(const void *vp, unsigned size); + + PluginLV2Work *next; + unsigned alloc, used; + char *data; +}; + class PluginLV2 { public: @@ -39,9 +63,12 @@ public: void reset_lv2(); int load_lv2(const char *path,char *title=0); int init_lv2(PluginLV2ClientConfig &conf, int sample_rate); + virtual int is_forked() { return 0; } 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); + static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, + const char *map, const char *uri); void connect_ports(PluginLV2ClientConfig &conf, int ports); void del_buffer(); void new_buffer(int64_t sz); @@ -53,14 +80,19 @@ public: const LilvPlugin *lilv; LilvUIs *lilv_uis; + LV2_URI_Map_Feature uri_map; PluginLV2UriTable uri_table; LV2_URID_Map map; LV2_Feature map_feature; LV2_URID_Unmap unmap; LV2_Feature unmap_feature; + + PluginLV2Options options; Lv2Features features; LV2_Atom_Sequence seq_in[2]; LV2_Atom_Sequence *seq_out; + float samplerate, refreshrate; + int block_length, midi_buf_size; LilvInstance *inst; SuilInstance *sinst; @@ -77,6 +109,38 @@ public: LilvNode *powerOf2BlockLength; LilvNode *fixedBlockLength; LilvNode *boundedBlockLength; + + LV2_URID atom_int; + LV2_URID atom_float; + + LV2_URID param_sampleRate; + LV2_URID bufsz_minBlockLength; + LV2_URID bufsz_maxBlockLength; + LV2_URID bufsz_sequenceSize; + LV2_URID ui_updateRate; + + pthread_t worker_thread; + LV2_Worker_Interface *worker_iface; + static void *worker_func(void *vp); + void *worker_func(); + void worker_start(); + void worker_stop(); + LV2_Worker_Status worker_schedule(uint32_t inp_size, const void *inp_data); + static LV2_Worker_Status lv2_worker_schedule(LV2_Worker_Schedule_Handle vp, + uint32_t inp_size, const void *inp_data); + LV2_Worker_Status worker_respond(uint32_t out_size, const void *out_data); + static LV2_Worker_Status lv2_worker_respond(LV2_Worker_Respond_Handle vp, + uint32_t out_size, const void *out_data); + PluginLV2Work *get_work(); + void work_stop(PluginLV2Work *&work); + void worker_responses(); + + LV2_Worker_Schedule schedule; + PluginLV2Work *work_avail, *work_input; + PluginLV2Work *work_output, **work_tail; + pthread_mutex_t worker_lock; + pthread_cond_t worker_ready; + int worker_done; }; typedef struct { int sample_rate; char path[1]; } open_bfr_t; diff --git a/cinelerra-5.1/cinelerra/pluginlv2client.C b/cinelerra-5.1/cinelerra/pluginlv2client.C index 7ccb6ef8..6163f2df 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2client.C +++ b/cinelerra-5.1/cinelerra/pluginlv2client.C @@ -307,6 +307,36 @@ int PluginLV2Client::process_realtime(int64_t size, } +PluginLV2BlackList::PluginLV2BlackList(const char *path) +{ + set_array_delete(); + char lv2_blacklist_path[BCTEXTLEN]; + sprintf(lv2_blacklist_path, "%s/%s", File::get_cindat_path(), path); + FILE *bfp = fopen(lv2_blacklist_path, "r"); + if( !bfp ) return; + while( fgets(lv2_blacklist_path, sizeof(lv2_blacklist_path), bfp) ) { + if( lv2_blacklist_path[0] == '#' ) continue; + int len = strlen(lv2_blacklist_path); + if( len > 0 && lv2_blacklist_path[len-1] == '\n' ) + lv2_blacklist_path[len-1] = 0; + if( !lv2_blacklist_path[0] ) continue; + append(cstrdup(lv2_blacklist_path)); + } + fclose(bfp); +} + +PluginLV2BlackList::~PluginLV2BlackList() +{ + remove_all_objects(); +} + +int PluginLV2BlackList::is_badboy(const char *uri) +{ + for( int i=size(); --i>=0; ) + if( !strcmp(uri, get(i)) ) return 1; + return 0; +} + PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name) { return new PluginServer(mwindow, name, PLUGIN_TYPE_LV2); @@ -323,6 +353,8 @@ PluginClient *PluginServer::new_lv2_plugin() int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp) { printf("init lv2 index:\n"); + PluginLV2BlackList blacklist("lv2_blacklist.txt"); + LilvWorld *world = lilv_world_new(); lilv_world_load_all(world); const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world); @@ -330,6 +362,8 @@ int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp LILV_FOREACH(plugins, i, all_plugins) { const LilvPlugin *lilv = lilv_plugins_get(all_plugins, i); const char *uri = lilv_node_as_uri(lilv_plugin_get_uri(lilv)); + if( blacklist.is_badboy(uri) ) continue; +printf("LOAD: %s\n", uri); PluginServer server(mwindow, uri, PLUGIN_TYPE_LV2); int result = server.open_plugin(1, preferences, 0, 0); if( !result ) { @@ -424,16 +458,14 @@ int PluginLV2ParentUI::hide() return 0; } - -// stub in parent -int PluginLV2ChildUI::handle_child() { return 0; } -void PluginLV2UI::reset_gui() {} - ForkChild *PluginLV2ParentUI::new_fork() { return new PluginLV2ChildUI(); } +// stub in parent +int PluginLV2ChildUI::child_iteration(int64_t usec) { return -1; } +int PluginLV2ChildUI::send_host(int64_t token, const void *data, int bytes) { return -1; } #else #include "mwindow.h" diff --git a/cinelerra-5.1/cinelerra/pluginlv2client.h b/cinelerra-5.1/cinelerra/pluginlv2client.h index da703e8e..1f5f3b35 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2client.h +++ b/cinelerra-5.1/cinelerra/pluginlv2client.h @@ -53,6 +53,15 @@ public: static PluginLV2UIs plugin_lv2; }; +class PluginLV2BlackList : public ArrayList +{ +public: + PluginLV2BlackList(const char *path); + ~PluginLV2BlackList(); + + int is_badboy(const char *uri); +}; + class PluginLV2Client : public PluginAClient, public PluginLV2 { public: diff --git a/cinelerra-5.1/cinelerra/pluginlv2config.h b/cinelerra-5.1/cinelerra/pluginlv2config.h index efe8d1c9..5f4f41d6 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2config.h +++ b/cinelerra-5.1/cinelerra/pluginlv2config.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ public: ~PluginLV2UriTable(); LV2_URID map(const char *uri); const char *unmap(LV2_URID urid); + operator LV2_URID_Map_Handle() { return (LV2_URID_Map_Handle)this; } }; #endif diff --git a/cinelerra-5.1/cinelerra/pluginlv2gui.C b/cinelerra-5.1/cinelerra/pluginlv2gui.C index 3c0c4566..7d9f0e9c 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2gui.C +++ b/cinelerra-5.1/cinelerra/pluginlv2gui.C @@ -229,7 +229,6 @@ void PluginLV2ClientWindow::create_objects() add_subwindow(slider = new PluginLV2ClientSlider(this, x1, y+10)); y += pot->get_h() + 10; - client->init_lv2(); client->load_configuration(); client->config.update(); diff --git a/cinelerra-5.1/cinelerra/pluginlv2ui.C b/cinelerra-5.1/cinelerra/pluginlv2ui.C index 929b5c67..b8f99ab1 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2ui.C +++ b/cinelerra-5.1/cinelerra/pluginlv2ui.C @@ -9,39 +9,6 @@ #include #include -int PluginLV2UI::init_ui(const char *path, int sample_rate) -{ - if( load_lv2(path, title) ) return 1; - if( init_lv2(config, sample_rate) ) return 1; - - lilv_uis = lilv_plugin_get_uis(lilv); - if( !lilv_uis ) { - printf("lv2: lilv_plugin_get_uis(%s) failed\n", path); - return 1; - } - - if( gtk_type ) { - LilvNode *gui_type = lilv_new_uri(world, gtk_type); - LILV_FOREACH(uis, i, lilv_uis) { - const LilvUI *ui = lilv_uis_get(lilv_uis, i); - if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) { - lilv_ui = ui; - break; - } - } - lilv_node_free(gui_type); - } - if( !lilv_ui ) - lilv_ui = lilv_uis_get(lilv_uis, lilv_uis_begin(lilv_uis)); - if( !lilv_ui ) { - printf("lv2_gui: init_ui failed: %s\n", title); - return 1; - } - - lilv_instance_activate(inst); - return 0; -} - void PluginLV2UI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr) { if( idx >= config.nb_ports ) return; @@ -49,7 +16,7 @@ void PluginLV2UI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void PluginLV2Client_Opt *opt = config[i]; if( opt->idx == idx ) { opt->set_value(*(const float*)bfr); - updates = UPDATE_HOST; + updates |= UPDATE_HOST; break; } } @@ -77,17 +44,6 @@ void PluginLV2UI::update_control(int idx, uint32_t bfrsz, uint32_t typ, const vo } -#if 0 -void PluginLV2UI::touch(void *obj, uint32_t pidx, bool grabbed) -{ - PluginLV2UI* the = (PluginLV2GUI*)obj; - int idx = pidx; - if( idx >= the->config.nb_ports ) return; -printf("%s %s(%u)\n", (grabbed? _("press") : _("release")), - the->config.names[idx], idx); -} -#endif - uint32_t PluginLV2UI::uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri) { return ((PluginLV2UriTable *)handle)->map(uri); @@ -110,8 +66,7 @@ void PluginLV2UI::lv2ui_instantiate(void *parent) PluginLV2UI::write_from_ui, PluginLV2UI::port_index, 0, 0); -// suil_host_set_touch_func(ui_host, -// PluginLV2GUI::touch); +// suil_host_set_touch_func(ui_host, cb_touch); } features.remove(); // remove terminating zero @@ -124,13 +79,15 @@ void PluginLV2UI::lv2ui_instantiate(void *parent) features.append(new Lv2Feature(LV2_DATA_ACCESS_URI, ext_data)); features.append(new Lv2Feature(LV2_UI__parent, parent)); features.append(new Lv2Feature(LV2_UI__idleInterface, 0)); + features.append(new Lv2Feature(LV2_EXTERNAL_UI_URI, &extui_host)); + features.append(new Lv2Feature(LV2_EXTERNAL_UI_URI__KX__Host, &extui_host)); features.append(0); // add new terminating zero const char* bundle_uri = lilv_node_as_uri(lilv_ui_get_bundle_uri(lilv_ui)); char* bundle_path = lilv_file_uri_parse(bundle_uri, NULL); const char* binary_uri = lilv_node_as_uri(lilv_ui_get_binary_uri(lilv_ui)); char* binary_path = lilv_file_uri_parse(binary_uri, NULL); - sinst = suil_instance_new(ui_host, this, gtk_type, + sinst = suil_instance_new(ui_host, this, ui_type, lilv_node_as_uri(lilv_plugin_get_uri(lilv)), lilv_node_as_uri(lilv_ui_get_uri(lilv_ui)), lilv_node_as_uri(lilv_type), @@ -157,11 +114,6 @@ bool PluginLV2UI::lv2ui_resizable() return !fs_matches && !nrs_matches; } -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; @@ -188,37 +140,31 @@ void PluginLV2UI::update_lv2_output() } } -static void lilv_destroy(GtkWidget* widget, gpointer data) +void PluginLV2UI::run_lilv(int samples) { - PluginLV2UI *the = (PluginLV2UI*)data; - the->top_level = 0; -} + float ctls[config.nb_ports]; + for( int i=0; istart_gui(); update_lv2_input(config.ctls, 1); - connect_ports(config, PORTS_CONTROL); + connect_ports(config, PORTS_CONTROL | PORTS_ATOM); updates = 0; run_lilv(0); - gtk_window_present(GTK_WINDOW(top_level)); send_host(LV2_SHOW, 0, 0); hidden = 0; } @@ -230,33 +176,89 @@ void PluginLV2UI::update_host() send_host(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports); } -void PluginLV2UI::reset_gui() + +static void lv2ui_extui_host_ui_closed(void *p) +{ + PluginLV2UI *ui = (PluginLV2UI *)p; + ui->hidden = -1; +} + +int PluginLV2ChildUI::init_ui(const char *path, int sample_rate) +{ + char *title = PluginLV2UI::title; + if( load_lv2(path, title) ) return 1; + if( init_lv2(config, sample_rate) ) return 1; + + lilv_uis = lilv_plugin_get_uis(lilv); + if( !lilv_uis ) { + printf("lv2: lilv_plugin_get_uis(%s) failed\n", path); + return 1; + } + + if( !gui && wgt_type ) { + LilvNode *gui_type = lilv_new_uri(world, wgt_type); + LILV_FOREACH(uis, i, lilv_uis) { + const LilvUI *ui = lilv_uis_get(lilv_uis, i); + if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) { + extui_host.ui_closed = lv2ui_extui_host_ui_closed; + gui = new PluginLV2ChildWgtUI(this); + lilv_ui = ui; + ui_type = wgt_type; + break; + } + } + lilv_node_free(gui_type); + } + if( !gui && gtk_type ) { + LilvNode *gui_type = lilv_new_uri(world, gtk_type); + LILV_FOREACH(uis, i, lilv_uis) { + const LilvUI *ui = lilv_uis_get(lilv_uis, i); + if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) { + gui = new PluginLV2ChildGtkUI(this); + lilv_ui = ui; + ui_type = gtk_type; + break; + } + } + lilv_node_free(gui_type); + ui_type = gtk_type; + } + + if( !gui ) { + printf("lv2_gui: init_ui failed: %s\n", title); + return 1; + } + + lilv_instance_activate(inst); + return 0; +} + +void PluginLV2ChildUI::reset_gui() { - if( hidden ) return; + gui->reset_gui(); 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); + hidden = 1; } - -// child main -int PluginLV2UI::run_ui(PluginLV2ChildUI *child) +// main loop +int PluginLV2ChildUI::run_ui() { - this->child = child; + double last_time = 0, fps = 30; + int64_t frame_usecs = 1e6 / fps; running = 1; done = 0; while( !done ) { - if( gtk_events_pending() ) { - gtk_main_iteration(); - continue; - } - if( !top_level && !hidden ) + if( hidden < 0 ) { + gui->top_level = 0; reset_gui(); + done = -1; + break; + } if( updates ) { if( (updates & UPDATE_PORTS) ) update_lv2_output(); @@ -264,30 +266,18 @@ int PluginLV2UI::run_ui(PluginLV2ChildUI *child) update_host(); updates = 0; } - if( !child ) usleep(10000); - else if( child->child_iteration() < 0 ) + struct timeval tv; gettimeofday(&tv, 0); + double t = tv.tv_sec + tv.tv_usec / 1e6; + double dt = t - last_time; last_time = t; + int64_t usec = frame_usecs - dt*1e6; + if( usec < 0 ) usec = 0; + if( child_iteration(usec) < 0 ) done = 1; } running = 0; return 0; } -void PluginLV2UI::run_lilv(int samples) -{ - float ctls[config.nb_ports]; - for( int i=0; idone = 1; } -int PluginLV2ChildUI::handle_child() -{ - switch( child_token ) { - case LV2_OPEN: { - open_bfr_t *open_bfr = (open_bfr_t *)child_data; - if( init_ui(open_bfr->path, open_bfr->sample_rate) ) exit(1); - break; } - case LV2_LOAD: { - float *vals = (float *)child_data; - update_lv2_input(vals, 1); - break; } - case LV2_UPDATE: { - float *vals = (float *)child_data; - update_lv2_input(vals, 0); - break; } - case LV2_SHOW: { - start_gui(); - break; } - case LV2_HIDE: { - reset_gui(); - break; } - case LV2_SHMID: { - int shmid = *(int *)child_data; - run_buffer(shmid); - send_parent(LV2_SHMID, 0, 0); - break; } - case EXIT_CODE: - return -1; +int PluginLV2ChildUI::child_iteration(int64_t usec) +{ + int ret = 0; + if( is_forked() ) + ret = read_child(usec); + else + usleep(usec); + if( ret > 0 ) { + switch( child_token ) { + case LV2_OPEN: { + open_bfr_t *open_bfr = (open_bfr_t *)child_data; + if( init_ui(open_bfr->path, open_bfr->sample_rate) ) { + printf("lv2ui: unable to init: %s\n", open_bfr->path); + exit(1); + } + break; } + case LV2_LOAD: { + float *vals = (float *)child_data; + update_lv2_input(vals, 1); + break; } + case LV2_UPDATE: { + float *vals = (float *)child_data; + update_lv2_input(vals, 0); + break; } + case LV2_SHOW: { + start_gui(); + break; } + case LV2_HIDE: { + reset_gui(); + break; } + case LV2_SHMID: { + int shmid = *(int *)child_data; + run_buffer(shmid); + send_parent(LV2_SHMID, 0, 0); + break; } + case EXIT_CODE: + return -1; + } + } + if( ret >= 0 && gui ) + gui->handle_child(); + return ret; +} + +int PluginLV2ChildUI::send_host(int64_t token, const void *data, int bytes) +{ + return is_forked() ? send_parent(token, data, bytes) : 0; +} + +PluginLV2GUI::PluginLV2GUI(PluginLV2ChildUI *child_ui) +{ + this->child_ui = child_ui; + top_level = 0; +} + +PluginLV2GUI::~PluginLV2GUI() +{ +} + +PluginLV2ChildGtkUI::PluginLV2ChildGtkUI(PluginLV2ChildUI *child_ui) + : PluginLV2GUI(child_ui) +{ + gtk_set_locale(); + gtk_init(&child_ui->ac, &child_ui->av); +} + +PluginLV2ChildGtkUI::~PluginLV2ChildGtkUI() +{ +} + +void PluginLV2ChildGtkUI::reset_gui() +{ + GtkWidget *top_level = (GtkWidget *)this->top_level; + if( top_level ) { gtk_widget_destroy(top_level); this->top_level = 0; } +} + +static void lilv_gtk_destroy(GtkWidget* widget, gpointer data) +{ + PluginLV2ChildGtkUI *gui = (PluginLV2ChildGtkUI*)data; + gui->child_ui->hidden = -1; +} + +void PluginLV2ChildGtkUI::start_gui() +{ + this->top_level = (void *)gtk_window_new(GTK_WINDOW_TOPLEVEL); + GtkWidget *top_level = (GtkWidget *)this->top_level; + g_signal_connect(top_level, "destroy", G_CALLBACK(lilv_gtk_destroy), this); + char *title = child_ui->PluginLV2UI::title; + gtk_window_set_title(GTK_WINDOW(top_level), title); + + GtkWidget *vbox = gtk_vbox_new(FALSE, 0); + gtk_window_set_role(GTK_WINDOW(top_level), "plugin_ui"); + gtk_container_add(GTK_CONTAINER(top_level), vbox); + + GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); + gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0); + gtk_widget_show(alignment); + child_ui->lv2ui_instantiate(alignment); + GtkWidget* widget = (GtkWidget*)suil_instance_get_widget(child_ui->sinst); + gtk_container_add(GTK_CONTAINER(alignment), widget); + gtk_window_set_resizable(GTK_WINDOW(top_level), child_ui->lv2ui_resizable()); + gtk_widget_show_all(vbox); + gtk_widget_grab_focus(widget); + gtk_window_present(GTK_WINDOW(top_level)); +} + +int PluginLV2ChildGtkUI::handle_child() +{ + if( gtk_events_pending() ) { + gtk_main_iteration(); } return 1; } +PluginLV2ChildWgtUI::PluginLV2ChildWgtUI(PluginLV2ChildUI *child_ui) + : PluginLV2GUI(child_ui) +{ +} + +PluginLV2ChildWgtUI::~PluginLV2ChildWgtUI() +{ +} + +void PluginLV2ChildWgtUI::reset_gui() +{ + lv2_external_ui *top_level = (lv2_external_ui *)this->top_level; + if( top_level ) { LV2_EXTERNAL_UI_HIDE(top_level); this->top_level = 0; } +} + +void PluginLV2ChildWgtUI::start_gui() +{ + child_ui->lv2ui_instantiate(0); + this->top_level = (void *)suil_instance_get_widget(child_ui->sinst); + lv2_external_ui *top_level = (lv2_external_ui *)this->top_level; + if( top_level ) LV2_EXTERNAL_UI_SHOW(top_level); +} + +int PluginLV2ChildWgtUI::handle_child() +{ + lv2_external_ui *top_level = (lv2_external_ui *)this->top_level; + if( top_level ) + LV2_EXTERNAL_UI_RUN(top_level); + return 1; +} + diff --git a/cinelerra-5.1/cinelerra/pluginlv2ui.h b/cinelerra-5.1/cinelerra/pluginlv2ui.h index c710060f..e61bd8b8 100644 --- a/cinelerra-5.1/cinelerra/pluginlv2ui.h +++ b/cinelerra-5.1/cinelerra/pluginlv2ui.h @@ -28,6 +28,29 @@ #include "pluginlv2gui.inc" #include "pluginlv2ui.inc" +//=== lv2_external_ui.h +#define LV2_EXTERNAL_UI_URI "http://lv2plug.in/ns/extensions/ui#external" +#define LV2_EXTERNAL_UI_URI__KX__Host "http://kxstudio.sf.net/ns/lv2ext/external-ui#Host" + +typedef struct _lv2_external_ui lv2_external_ui; +struct _lv2_external_ui { + void (*run)(lv2_external_ui *ui); + void (*show)(lv2_external_ui *ui); + void (*hide)(lv2_external_ui *ui); + void *self; +}; + +typedef struct _lv2_external_ui_host lv2_external_ui_host; +struct _lv2_external_ui_host { + void (*ui_closed)(void* controller); + const char *plugin_human_id; +}; + +#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr) +#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr) +#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr) +//=== + typedef struct _GtkWidget GtkWidget; #define UPDATE_HOST 1 @@ -43,26 +66,22 @@ public: const LilvNode *lilv_type; LV2_Extension_Data_Feature *ext_data; - PluginLV2UriTable uri_table; - LV2_URI_Map_Feature *uri_map; - LV2_URID_Map map; - LV2_URID_Unmap unmap; + lv2_external_ui_host extui_host; + const char *wgt_type; + const char *gtk_type; + const char *ui_type; char title[BCSTRLEN]; PluginLV2ClientConfig config; - int updates, hidden; int done, running; - const char *gtk_type; - GtkWidget *top_level; - PluginLV2ChildUI *child; + int hidden, updates; - void reset_gui(); - int init_ui(const char *path, int sample_rate); void start(); void stop(); - int send_host(int64_t token, const void *data, int bytes); int update_lv2_input(float *vals, int force); void update_lv2_output(); + virtual int send_host(int64_t token, const void *data, int bytes) = 0; + virtual int child_iteration(int64_t usec) { return -1; } void run_lilv(int samples); void update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr); @@ -77,10 +96,42 @@ public: static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid); void lv2ui_instantiate(void *parent); bool lv2ui_resizable(); - void start_gui(); - int run_ui(PluginLV2ChildUI *child=0); void update_host(); - int run(int ac, char **av); +}; + +class PluginLV2GUI +{ +public: + PluginLV2GUI(PluginLV2ChildUI *child_ui); + virtual ~PluginLV2GUI(); + virtual void reset_gui() = 0; + virtual void start_gui() = 0; + virtual int handle_child() = 0; + + PluginLV2ChildUI *child_ui; + void *top_level; +}; + +class PluginLV2ChildGtkUI : public PluginLV2GUI +{ +public: + PluginLV2ChildGtkUI(PluginLV2ChildUI *child_ui); + ~PluginLV2ChildGtkUI(); + + void reset_gui(); + void start_gui(); + int handle_child(); +}; + +class PluginLV2ChildWgtUI : public PluginLV2GUI +{ +public: + PluginLV2ChildWgtUI(PluginLV2ChildUI *child_ui); + ~PluginLV2ChildWgtUI(); + + void reset_gui(); + void start_gui(); + int handle_child(); }; class PluginLV2ChildUI : public ForkChild, public PluginLV2UI @@ -88,11 +139,23 @@ class PluginLV2ChildUI : public ForkChild, public PluginLV2UI public: PluginLV2ChildUI(); ~PluginLV2ChildUI(); - void run(); - void run_buffer(int shmid); + int init_ui(const char *path, int sample_rate); + void reset_gui(); + void start_gui(); int handle_child(); + + int is_forked() { return ppid; } + int send_host(int64_t token, const void *data, int bytes); + int child_iteration(int64_t usec); + void run(); int run(int ac, char **av); + int run_ui(); + void run_buffer(int shmid); + + int ac; + char **av; + PluginLV2GUI *gui; }; #endif -- 2.26.2