lv2 rework, sams ffmpeg icons, elision patch
authorGood Guy <[email protected]>
Fri, 25 May 2018 23:10:42 +0000 (17:10 -0600)
committerGood Guy <[email protected]>
Fri, 25 May 2018 23:10:42 +0000 (17:10 -0600)
36 files changed:
cinelerra-5.1/cinelerra/Makefile
cinelerra-5.1/cinelerra/bdcreate.C
cinelerra-5.1/cinelerra/commercials.C
cinelerra-5.1/cinelerra/devicempeginput.C
cinelerra-5.1/cinelerra/filexml.C
cinelerra-5.1/cinelerra/filexml.h
cinelerra-5.1/cinelerra/forkbase.C
cinelerra-5.1/cinelerra/forkbase.h
cinelerra-5.1/cinelerra/lv2ui.C
cinelerra-5.1/cinelerra/pluginlv2.C [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2.h [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2.inc [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2client.C
cinelerra-5.1/cinelerra/pluginlv2client.h
cinelerra-5.1/cinelerra/pluginlv2client.inc
cinelerra-5.1/cinelerra/pluginlv2config.C
cinelerra-5.1/cinelerra/pluginlv2config.h
cinelerra-5.1/cinelerra/pluginlv2gui.C
cinelerra-5.1/cinelerra/pluginlv2gui.h
cinelerra-5.1/cinelerra/pluginlv2gui.inc
cinelerra-5.1/cinelerra/pluginlv2ui.C [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2ui.h [new file with mode: 0644]
cinelerra-5.1/cinelerra/pluginlv2ui.inc [new file with mode: 0644]
cinelerra-5.1/guicast/condition.C
cinelerra-5.1/guicast/mutex.h
cinelerra-5.1/picon/cinfinity/ff_entropy.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity/ff_fillborders.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity/ff_normalize.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity/ff_setrange.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity/ff_vfrdet.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity2/ff_entropy.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity2/ff_fillborders.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity2/ff_normalize.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity2/ff_setrange.png [new file with mode: 0644]
cinelerra-5.1/picon/cinfinity2/ff_vfrdet.png [new file with mode: 0644]
cinelerra-5.1/plugins/Makefile

index 4af6b1a17eca753403ac3905b676472ce9f67f9d..a179559ff9de5cdd335b0a81775833fe08b290a8 100644 (file)
@@ -224,6 +224,7 @@ OBJS = \
        $(OBJDIR)/pluginclient.o \
        $(OBJDIR)/plugindialog.o \
        $(OBJDIR)/pluginfclient.o \
+       $(OBJDIR)/pluginlv2.o \
        $(OBJDIR)/pluginlv2config.o \
        $(OBJDIR)/pluginlv2client.o \
        $(OBJDIR)/pluginlv2gui.o \
@@ -379,7 +380,8 @@ ifneq ($(WANT_LV2UI),no)
 LV2UI = $(OBJDIR)/lv2ui
 LV2OBJS = \
        $(OBJDIR)/lv2ui.o \
-       $(OBJDIR)/pluginlv2gui.o \
+       $(OBJDIR)/pluginlv2.o \
+       $(OBJDIR)/pluginlv2ui.o \
        $(OBJDIR)/pluginlv2config.o \
        $(OBJDIR)/forkbase.o
 endif
@@ -415,7 +417,8 @@ CFLAGS += -DUSE_ALPHA
 else
 
 LDFLAGS1 = -export-dynamic
-LDFLAGS2 =
+# avoid the intel lock elision bug, if possible
+LDFLAGS2 = $(lastword $(wildcard /usr/lib/noelision /lib/noelision /usr/lib64/noelision /lib/noelision))
 LINKER = g++ -o $(OUTPUT)
 
 endif
@@ -482,7 +485,9 @@ ifneq ($(WANT_LV2UI),no)
 GTK2_INCS := `pkg-config --cflags gtk+-2.0`
 GTK2_LIBS := `pkg-config --libs gtk+-2.0`
 
+$(OBJDIR)/pluginlv2ui.o:       pluginlv2ui.C
 $(OBJDIR)/lv2ui.o:     lv2ui.C
+$(OBJDIR)/pluginlv2ui.o $(OBJDIR)/lv2ui.o:
        $(CXX) `cat $(OBJDIR)/c_flags` $(GTK2_INCS) -DMSGQUAL=$* -c $< -o $@
 
 $(OBJDIR)/lv2ui: $(LV2OBJS)
index c7cbfbc58943d75eeb3c6304960ea6e92ee711fc..27f728ad6dc80c1a21d20723d5eec697edf30a34 100644 (file)
@@ -229,7 +229,7 @@ int CreateBD_Thread::create_bd_jobs(ArrayList<BatchRenderJob*> *jobs, const char
        fprintf(fp,"sz=`du -cb $1/bd.m2ts* | tail -1 | sed -e 's/[ \t].*//'`\n");
        fprintf(fp,"blks=$((sz/2048 + 4096))\n");
        fprintf(fp,"rm -f %s\n", udfs);
-       fprintf(fp,"mkudffs %s $blks\n", udfs);
+       fprintf(fp,"mkudffs -b 2048 %s $blks\n", udfs);
        fprintf(fp,"mount %s%s\n", mopts, mntpt);
        fprintf(fp,"bdwrite %s $1/bd.m2ts*\n",mntpt);
        fprintf(fp,"umount %s\n",mntpt);
index a81aafe8ee0357d295499fe10c5e97272d3fc96c..3a3de58615e59836ad0e5a830c1623644a3a33e5 100644 (file)
@@ -804,16 +804,18 @@ run()
 void SdbPacketQueue::
 put_packet(SdbPacket *p)
 {
-       mLock holds(this);
+       lock("SdbPacketQueue::put_packet");
        append(p);
+       unlock();
 }
 
 SdbPacket *SdbPacketQueue::
 get_packet()
 {
-       mLock holds(this);
+       lock("SdbPacketQueue::get_packet");
        SdbPacket *p = first;
        remove_pointer(p);
+       unlock();
        return p;
 }
 
index b87bed33bb8ba2435c2fddbbccc0f096c1f4cb1f..056da30ac357d3f89085bf3f940889b867f3462f 100644 (file)
@@ -415,36 +415,40 @@ int DeviceMPEGInput::set_channel(Channel *channel)
 
 void DeviceMPEGInput::set_captioning(int strk)
 {
-       mLock holds(decoder_lock);
+       decoder_lock->lock("DeviceMPEGInput::set_captioning");
        captioning = strk;
        if( src && video_stream >= 0 )
                src->show_subtitle(video_stream, strk);
+       decoder_lock->unlock();
 }
 
 int DeviceMPEGInput::drop_frames(int frames)
 {
-       mLock holds(decoder_lock);
+       decoder_lock->lock("DeviceMPEGInput::drop_frames");
        double result = -1.;
        if( src && video_stream >= 0 )
                result = src->drop_frames(frames,video_stream);
+       decoder_lock->unlock();
        return result;
 }
 
 double DeviceMPEGInput::audio_timestamp()
 {
-       mLock holds(decoder_lock);
+       decoder_lock->lock("DeviceMPEGInput::audio_timestamp");
        double result = -1.;
        if( src && audio_stream >= 0 )
                result = src->get_audio_time(audio_stream);
+       decoder_lock->unlock();
        return result;
 }
 
 double DeviceMPEGInput::video_timestamp()
 {
-       mLock holds(decoder_lock);
+       decoder_lock->lock("DeviceMPEGInput::video_timestamp");
        double ret = -1.;
        if( src && video_stream >= 0 )
                ret = src->get_video_time(video_stream);
+       decoder_lock->unlock();
        return ret;
 }
 
@@ -540,7 +544,7 @@ int DeviceMPEGInput::get_video_pid(int track)
 int DeviceMPEGInput::get_video_info(int track, int &pid, double &framerate,
                 int &width, int &height, char *title)
 {
-       //mLock holds(decoder_lock);  caller of callback holds lock
+       //caller of callback holds decoder_lock;
        if( !src ) return 1;
        pid = src->video_pid(track);
        framerate = src->frame_rate(track);
index 065dce7db07758c48a49b9a6366a3dac0e0180e1..5390617b05782be862a806c66c9579abe9b6ec41 100644 (file)
@@ -73,9 +73,10 @@ XMLBuffer::~XMLBuffer()
        if( destroy ) delete [] bfr;
 }
 
-unsigned char *&XMLBuffer::demand(long len)
+int XMLBuffer::demand(long len)
 {
        if( len > bsz ) {
+               if( !destroy ) return 0;
                long sz = inp-bfr;
                len += sz/2 + BCTEXTLEN;
                unsigned char *np = new unsigned char[len];
@@ -85,13 +86,13 @@ unsigned char *&XMLBuffer::demand(long len)
                lmt = np + len;  bsz = len;
                delete [] bfr;   bfr = np;
        }
-       return bfr;
+       return 1;
 }
 
 int XMLBuffer::write(const char *bp, int len)
 {
-       if( !destroy && lmt-inp < len ) len = lmt-inp;
        if( len <= 0 ) return 0;
+       if( !destroy && lmt-inp < len ) len = lmt-inp;
        demand(otell()+len);
        memmove(inp,bp,len);
        inp += len;
index a701b649e0cc13352f0137f661131409ba8fc5af..af45e3088bd8adde783af10b37ed613fae204d14 100644 (file)
@@ -38,7 +38,7 @@ class XMLBuffer
        unsigned char *inp, *outp, *bfr, *lmt;
        int destroy;
 
-       unsigned char *&demand(long len);
+       int demand(long len);
 public:
        XMLBuffer(long buf_size=0x1000, long max_size=LONG_MAX, int del=1);
        XMLBuffer(long buf_size, char *buf, int del=0); // writing
@@ -56,10 +56,7 @@ public:
 
        int cur()  { return outp>=inp ? -1 : *outp; }
        int next() { return outp>=inp ? -1 : *outp++; }
-       int next(int ch) {
-               demand(otell()+1);
-               return *inp++ = ch;
-       }
+       int next(int ch) { return !demand(otell()+1) ? -1 : *inp++ = ch; }
 
        static char *decode_data(char *bp, const char *sp, int n=-1);
        static char *encode_data(char *bp, const char *sp, int n=-1);
index 8e87cb3d0678f4bf9319b9f55b7129c968b36454..174019ddd6c27f1d07c604b6c08200bfc8103650 100644 (file)
@@ -32,8 +32,9 @@
 #include <unistd.h>
 
 ForkBase::ForkBase()
+ : Mutex("ForkBase::lock")
 {
-       pid = 0;
+       ppid = pid = 0;
        child = 0;
 
        child_fd = -1;
@@ -47,7 +48,6 @@ ForkBase::ForkBase()
        parent_bytes = 0;
        parent_allocated = 0;
        parent_data = 0;
-
 }
 
 ForkBase::~ForkBase()
@@ -58,6 +58,12 @@ ForkBase::~ForkBase()
        if( parent_fd >= 0 ) close(parent_fd);
 }
 
+// return 1 parent is running
+int ForkChild::is_running()
+{
+       return !ppid || !kill(ppid, 0) ? 1 : 0;
+}
+
 int ForkChild::child_iteration()
 {
        int ret = read_child(100);
@@ -67,22 +73,22 @@ int ForkChild::child_iteration()
 
 void ForkParent::start_child()
 {
-       lock->lock("ForkParent::new_child");
+       lock("ForkParent::new_child");
        int sockets[2]; // Create the process & socket pair.
        socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
        child_fd = sockets[0];  parent_fd = sockets[1];
+       ppid = getpid();
        pid = fork();
        if( !pid ) {    // child process
-               BC_Signals::reset_locks();
-               BC_Signals::set_sighup_exit(1);
-               TheList::reset();
                ForkChild *child = new_fork();
                child->child_fd = child_fd;
                child->parent_fd = parent_fd;
+               child->ppid = ppid;
                child->run();
+               delete child;
                _exit(0);
        }
-       lock->unlock();
+       unlock();
 }
 
 // Return -1 if the parent is dead
@@ -101,13 +107,14 @@ int ForkBase::read_timeout(int ms, int fd, void *data, int bytes)
                FD_ZERO(&rfds);
                FD_SET(fd, &rfds);
                int result = select(fd+1, &rfds, 0, 0, &timeout_struct);
+               if( result < 0 ) perror("read_timeout select");
                if( result < 0 || !is_running() ) return -1;
                if( !result && !bytes_read ) return 0;
                int fragment = read(fd, bp + bytes_read, bytes - bytes_read);
+               if( fragment < 0 ) perror("read_timeout read");
                if( fragment < 0 || !is_running() ) return -1;
                if( fragment > 0 ) bytes_read += fragment;
        }
-
        return 1;
 }
 
@@ -130,10 +137,14 @@ int ForkBase::read_parent(int ms)
                        delete [] parent_data;
                        parent_data = new uint8_t[parent_allocated = parent_bytes];
                }
-               if( parent_bytes )
+               if( parent_bytes ) {
                        ret = read_timeout(1000, parent_fd, parent_data, parent_bytes);
+                       if( !ret ) {
+                               printf("read_parent timeout: %d\n", parent_fd);
+                               ret = -1;
+                       }
+               }
        }
-//if( ret < 0 ) printf("read_parent timeout\n");
        return ret;
 }
 
@@ -148,28 +159,47 @@ int ForkBase::read_child(int ms)
                        delete [] child_data;
                        child_data = new uint8_t[child_allocated = child_bytes];
                }
-               if( child_bytes )
+               if( child_bytes ) {
                        ret = read_timeout(1000, child_fd, child_data, child_bytes);
+                       if( !ret ) {
+                               printf("read_child timeout: %d\n", child_fd);
+                               ret = -1;
+                       }
+               }
        }
-//if( ret < 0 ) printf("read_child timeout\n");
        return ret;
 }
 
+void ForkBase::send_bfr(int fd, const void *bfr, int len)
+{
+       int ret = 0;
+       for( int retries=10; --retries>=0 && (ret=write(fd, bfr, len)) < 0; ) {
+               printf("send_bfr socket(%d) write error: %d/%d bytes\n%m\n", fd,ret,len);
+               usleep(100000);
+       }
+       if( ret < len )
+               printf("send_bfr socket(%d) write short: %d/%d bytes\n%m\n", fd,ret,len);
+}
+
 int ForkBase::send_parent(int64_t token, const void *data, int bytes)
 {
+       lock("ForkBase::send_parent");
        token_bfr_t bfr;  memset(&bfr, 0, sizeof(bfr));
        bfr.token = token;  bfr.bytes = bytes;
-       write(child_fd, &bfr, sizeof(bfr));
-       if( data && bytes ) write(child_fd, data, bytes);
+       send_bfr(child_fd, &bfr, sizeof(bfr));
+       if( data && bytes ) send_bfr(child_fd, data, bytes);
+       unlock();
        return 0;
 }
 
 int ForkBase::send_child(int64_t token, const void *data, int bytes)
 {
+       lock("ForkBase::send_child");
        token_bfr_t bfr;  memset(&bfr, 0, sizeof(bfr));
        bfr.token = token;  bfr.bytes = bytes;
-       write(parent_fd, &bfr, sizeof(bfr));
-       if( data && bytes ) write(parent_fd, data, bytes);
+       send_bfr(parent_fd, &bfr, sizeof(bfr));
+       if( data && bytes ) send_bfr(parent_fd, data, bytes);
+       unlock();
        return 0;
 }
 
@@ -191,13 +221,19 @@ int ForkChild::handle_child()
 ForkParent::ForkParent()
  : Thread(1, 0, 0)
 {
-       lock = new Mutex("ForkParent::lock");
        done = -1;
 }
 
 ForkParent::~ForkParent()
 {
-       delete lock;
+}
+
+// return 1 child is running
+int ForkParent::is_running()
+{
+       int status = 0;
+       if( waitpid(pid, &status, WNOHANG) < 0 ) return 0;
+       return !kill(pid, 0) ? 1 : 0;
 }
 
 // Return -1,0,1 if dead,timeout,success
@@ -225,8 +261,9 @@ void ForkParent::stop()
 {
        if( is_running() ) {
                send_child(EXIT_CODE, 0, 0);
-               int status = 0;
-               waitpid(pid, &status, 0);
+               int retry = 10;
+               while( --retry>=0 && is_running() ) usleep(100000);
+               if( retry < 0 ) kill(pid, SIGKILL);
        }
        join();
 }
index 5502413df63d28b36effaa46f9393ccb44aeb1a6..2ca84b71d4c6c56ffc71db925e0840de2ac642ff 100644 (file)
@@ -30,7 +30,7 @@
 
 #include <stdint.h>
 
-class ForkBase
+class ForkBase : public Mutex
 {
 public:
        enum { EXIT_CODE=0x7fff };
@@ -39,14 +39,15 @@ public:
        ForkBase();
        virtual ~ForkBase();
 
-       int is_running();
+       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 send_parent(int64_t value, const void *data, int bytes);
        int read_child(int ms);
        int send_child(int64_t value, const void *data, int bytes);
 
-       int done, pid;
+       int done, ppid, pid;
        ForkChild *child;
 
        int child_fd;
@@ -67,9 +68,10 @@ class ForkChild : public ForkBase
 public:
        ForkChild();
        virtual ~ForkChild();
-       virtual void run() = 0;
        virtual int handle_child();
        int child_iteration();
+       int is_running();
+       virtual void run() {}
 };
 
 class ForkParent : public Thread, public ForkBase
@@ -79,14 +81,13 @@ public:
        virtual ~ForkParent();
        virtual int handle_parent();
        virtual ForkChild *new_fork() = 0;
+       int is_running();
 
        void start_child();
        void start();
        void stop();
        void run();
        int parent_iteration();
-
-       Mutex *lock;
 };
 
 #endif
index 21acda44bcfff8a3b47f794f03c99eac8a895e41..3a06102a4926ff4c1ab3f97a4cd94316d1272c9c 100644 (file)
 #include <stdio.h>
+#include <signal.h>
 
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 
 #include "bcsignals.h"
 #include "pluginlv2client.h"
-#include "pluginlv2gui.h"
+#include "pluginlv2ui.h"
 
-static void lilv_destroy(GtkWidget* widget, gpointer data)
+int PluginLV2UI::run(int ac, char **av)
 {
-       PluginLV2GUI *the = (PluginLV2GUI*)data;
-       the->done = 1;
-}
-
-void PluginLV2GUI::start()
-{
-       GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-       g_signal_connect(window, "destroy", G_CALLBACK(lilv_destroy), this);
-       gtk_window_set_title(GTK_WINDOW(window), title);
-
-       GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
-       gtk_window_set_role(GTK_WINDOW(window), "plugin_ui");
-       gtk_container_add(GTK_CONTAINER(window), 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);
-       lv2ui_instantiate(alignment);
-       GtkWidget* widget = (GtkWidget*)suil_instance_get_widget(sinst);
-       gtk_container_add(GTK_CONTAINER(alignment), widget);
-       gtk_window_set_resizable(GTK_WINDOW(window), lv2ui_resizable());
-       gtk_widget_show_all(vbox);
-       gtk_widget_grab_focus(widget);
-
-       gtk_window_present(GTK_WINDOW(window));
-       running = -1;
-}
-
-void PluginLV2GUI::stop()
-{
-       running = 0;
-}
-
-void PluginLV2GUI::host_update(PluginLV2ChildGUI *child)
-{
-//printf("update\n");
-       last = updates;
-       if( !child ) return;
-// ignore reset update
-       if( child->lv2_gui->running < 0 ) { child->lv2_gui->running = 1;  return; }
-       child->send_parent(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
-}
-
-void PluginLV2GUI::run_gui(PluginLV2ChildGUI *child)
-{
-       while( !done ) {
-               if( gtk_events_pending() ) {
-                       gtk_main_iteration();
-                       continue;
-               }
-               if( running && updates != last )
-                       host_update(child);
-               if( redraw ) {
-                       redraw = 0;
-                       update_lv2(config.ctls, 1);
-               }
-               if( !child ) usleep(10000);
-               else if( child->child_iteration() < 0 )
-                       done = 1;
+       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 PluginLV2ChildGUI::handle_child()
+int PluginLV2ChildUI::run(int ac, char **av)
 {
-       if( !lv2_gui ) return 0;
-
-       switch( child_token ) {
-       case LV2_OPEN: {
-               char *path = (char *)child_data;
-               if( lv2_gui->init_gui(path) ) exit(1);
-               break; }
-       case LV2_LOAD: {
-               lv2_gui->update_lv2((float*)child_data, 1);
-               break; }
-       case LV2_UPDATE: {
-               lv2_gui->update_lv2((float*)child_data, 0);
-               break; }
-       case LV2_START: {
-               lv2_gui->start();
-               break; }
-       case LV2_SET: {
-               if( !lv2_gui ) break;
-               control_t *bfr = (control_t *)child_data;
-               lv2_gui->config.ctls[bfr->idx] = bfr->value;
-               lv2_gui->redraw = 1;
-               break; }
-       case EXIT_CODE:
-               return -1;
-       default:
-               return 0;
-       }
-       return 1;
+       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 PluginLV2GUI::run(int ac, char **av)
-{
-       if( ac < 3 ) {
-               if( init_gui(av[1]) ) {
-                       fprintf(stderr," init_ui failed\n");
-                       return 1;
-               }
-               start();
-               run_gui();
-               stop();
-       }
-       else {
-               PluginLV2ChildGUI child;
-               child.lv2_gui = this;
-               child.child_fd = atoi(av[1]);
-               child.parent_fd = atoi(av[2]);
-               run_gui(&child);
-               stop();
-               child.lv2_gui = 0;
-       }
-       return 0;
-}
 
 int main(int ac, char **av)
 {
+// to grab this task in the debugger
+const char *cp = getenv("BUG");
+static int zbug = !cp ? 0 : atoi(cp);  volatile int bug = zbug;
+while( bug ) usleep(10000);
        BC_Signals signals;
        if( getenv("BC_TRAP_LV2_SEGV") ) {
                signals.initialize("/tmp/lv2ui_%d.dmp");
-               BC_Signals::set_catch_segv(1);
+               BC_Signals::set_catch_segv(1);
        }
        gtk_set_locale();
        gtk_init(&ac, &av);
-// to grab this task in the debugger
-//static int zbug = 1;  volatile int bug = zbug;
-//while( bug ) usleep(10000);
-       return PluginLV2GUI().run(ac, av);
+       return ac < 3 ?
+               PluginLV2UI().run(ac, av) :
+               PluginLV2ChildUI().run(ac, av);
 }
 
diff --git a/cinelerra-5.1/cinelerra/pluginlv2.C b/cinelerra-5.1/cinelerra/pluginlv2.C
new file mode 100644 (file)
index 0000000..698be88
--- /dev/null
@@ -0,0 +1,393 @@
+#ifdef HAVE_LV2
+
+#include "bctrace.h"
+#include "bcwindowbase.h"
+#include "pluginlv2.h"
+#include "samples.h"
+
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+PluginLV2::PluginLV2()
+{
+       shm_bfr = 0;
+       use_shm = 1;
+       shmid = -1;
+       in_buffers = 0;   iport = 0;
+       out_buffers = 0;  oport = 0;
+       nb_inputs = 0;
+       nb_outputs = 0;
+       max_bufsz = 0;
+       ui_features = 0;
+
+       world = 0;
+       lilv = 0;
+       lilv_uis = 0;
+       inst = 0;
+       sinst = 0;
+       ui_host = 0;
+
+       lv2_InputPort = 0;
+       lv2_OutputPort = 0;
+       lv2_AudioPort = 0;
+       lv2_ControlPort = 0;
+       lv2_CVPort = 0;
+       lv2_Optional = 0;
+       atom_AtomPort = 0;
+       atom_Sequence = 0;
+       powerOf2BlockLength = 0;
+       fixedBlockLength = 0;
+       boundedBlockLength = 0;
+       seq_out = 0;
+}
+
+PluginLV2::~PluginLV2()
+{
+       reset_lv2();
+       if( world )     lilv_world_free(world);
+}
+
+void PluginLV2::reset_lv2()
+{
+       if( inst ) lilv_instance_deactivate(inst);
+       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_AudioPort);        lv2_AudioPort = 0;
+       lilv_node_free(lv2_ControlPort);      lv2_ControlPort = 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;
+       lilv_node_free(atom_Sequence);        atom_Sequence = 0;
+       lilv_node_free(boundedBlockLength);   boundedBlockLength = 0;
+       lilv_node_free(fixedBlockLength);     fixedBlockLength = 0;
+       lilv_node_free(powerOf2BlockLength);  powerOf2BlockLength = 0;
+
+       delete [] (char *)seq_out;            seq_out = 0;
+       uri_table.remove_all_objects();
+       features.remove_all_objects();        ui_features = 0;
+       del_buffer();
+}
+
+
+int PluginLV2::load_lv2(const char *path, char *title)
+{
+       if( !world ) {
+               world = lilv_world_new();
+               if( !world ) {
+                       printf("lv2: lilv_world_new failed\n");
+                       return 1;
+               }
+               lilv_world_load_all(world);
+       }
+
+       LilvNode *uri = lilv_new_uri(world, path);
+       if( !uri ) {
+               printf("lv2: lilv_new_uri(%s) failed\n", path);
+               return 1;
+       }
+
+       const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
+       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);
+               return 1;
+       }
+
+       if( title ) {
+               LilvNode *name = lilv_plugin_get_name(lilv);
+               const char *nm = lilv_node_as_string(name);
+               sprintf(title, "L2_%s", nm);
+               lilv_node_free(name);
+       }
+       return 0;
+}
+
+int PluginLV2::init_lv2(PluginLV2ClientConfig &conf, int sample_rate)
+{
+       reset_lv2();
+
+       lv2_AudioPort       = lilv_new_uri(world, LV2_CORE__AudioPort);
+       lv2_ControlPort     = lilv_new_uri(world, LV2_CORE__ControlPort);
+       lv2_CVPort          = lilv_new_uri(world, LV2_CORE__CVPort);
+       lv2_InputPort       = lilv_new_uri(world, LV2_CORE__InputPort);
+       lv2_OutputPort      = lilv_new_uri(world, LV2_CORE__OutputPort);
+       lv2_Optional        = lilv_new_uri(world, LV2_CORE__connectionOptional);
+       atom_AtomPort       = lilv_new_uri(world, LV2_ATOM__AtomPort);
+       atom_Sequence       = lilv_new_uri(world, LV2_ATOM__Sequence);
+       powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
+       fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
+       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);
+       nb_inputs = nb_outputs = 0;
+
+       for( int i=0; i<conf.nb_ports; ++i ) {
+               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
+               if( !lp ) continue;
+               int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
+               if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
+                   !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
+                       printf("lv2: not input, not output, and not optional: %s\n", conf.names[i]);
+                       continue;
+               }
+               if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
+                       conf.append(new PluginLV2Client_Opt(&conf, i));
+                       continue;
+               }
+               if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
+                   lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
+                       if( is_input ) ++nb_inputs; else ++nb_outputs;
+                       continue;
+               }
+       }
+
+       map.handle = (void*)&uri_table;
+       map.map = uri_table_map;
+       features.append(new Lv2Feature(LV2_URID_MAP_URI, &map));
+       unmap.handle = (void*)&uri_table;
+       unmap.unmap  = uri_table_unmap;
+       features.append(new Lv2Feature(LV2_URID_UNMAP_URI, &unmap));
+       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(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;
+       }
+
+       lilv_instance_activate(inst);
+// not sure what to do with these
+       max_bufsz = nb_inputs &&
+               (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
+                lilv_plugin_has_feature(lilv, fixedBlockLength) ||
+                lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
+       return 0;
+}
+
+LV2_URID PluginLV2::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
+{
+       return ((PluginLV2UriTable *)handle)->map(uri);
+}
+
+const char *PluginLV2::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
+{
+       return ((PluginLV2UriTable *)handle)->unmap(urid);
+}
+
+void PluginLV2::connect_ports(PluginLV2ClientConfig &conf, int typ)
+{
+       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) ) {
+                       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;
+                       }
+                       else if( lilv_port_is_a(lilv, lp, lv2_OutputPort)) {
+                               lilv_instance_connect_port(inst, oport[och]=i, out_buffers[och]);
+                               ++och;
+                       }
+                       continue;
+               }
+               if( (typ & TYP_ATOM) &&
+                   lilv_port_is_a(lilv, lp, atom_AtomPort) ) {
+                       if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
+                               lilv_instance_connect_port(inst, i, &seq_in);
+                       else
+                               lilv_instance_connect_port(inst, i, seq_out);
+                       continue;
+               }
+       }
+
+       seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
+       seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
+       seq_in[1].atom.size = 0;
+       seq_in[1].atom.type = 0;
+       seq_out->atom.size  = LV2_SEQ_SIZE;
+       seq_out->atom.type  = uri_table.map(LV2_ATOM__Chunk);
+}
+
+void PluginLV2::del_buffer()
+{
+       if( shmid >= 0 )
+               shm_buffer(-1);
+
+       delete [] in_buffers;  in_buffers = 0;
+       delete [] out_buffers;  out_buffers = 0;
+}
+
+void PluginLV2::new_buffer(int64_t sz)
+{
+       uint8_t *bp = 0;
+       if( use_shm ) {  // currently, always uses shm
+               shmid = shmget(IPC_PRIVATE, sz, IPC_CREAT | 0777);
+               if( shmid >= 0 ) {
+                       bp = (unsigned char*)shmat(shmid, NULL, 0);
+                       if( bp == (void *) -1 ) { perror("shmat"); bp = 0; }
+                       shmctl(shmid, IPC_RMID, 0); // delete when last ref gone
+               }
+               else {
+                       perror("PluginLV2::allocate_buffer: shmget failed\n");
+                       BC_Trace::dump_shm_stats(stdout);
+               }
+       }
+
+       shm_bfr = (shm_bfr_t *) bp;
+       if( shm_bfr ) shm_bfr->sz = sz;
+}
+
+shm_bfr_t *PluginLV2::shm_buffer(int shmid)
+{
+       if( this->shmid != shmid ) {
+               if( this->shmid >= 0 ) {
+                       shmdt(shm_bfr);  this->shmid = -1;
+                       shm_bfr = 0;
+               }
+               if( shmid >= 0 ) {
+                       shm_bfr = (shm_bfr_t *)shmat(shmid, NULL, 0);
+                       if( shm_bfr == (void *)-1 ) { perror("shmat");  shm_bfr = 0; }
+                       this->shmid = shm_bfr ? shmid : -1;
+               }
+       }
+       return shm_bfr;
+}
+
+void PluginLV2::init_buffer(int samples)
+{
+       int64_t sz = sizeof(shm_bfr_t) +
+               sizeof(iport[0])*nb_inputs + sizeof(oport[0])*nb_outputs +
+               sizeof(*in_buffers[0]) *samples * nb_inputs +
+               sizeof(*out_buffers[0])*samples * nb_outputs;
+
+       if( shm_bfr ) {
+               if( shm_bfr->sz < sz ||
+                   shm_bfr->nb_inputs != nb_inputs ||
+                   shm_bfr->nb_outputs != nb_outputs )
+                       del_buffer();
+       }
+
+       if( !shm_bfr )
+               new_buffer(sz);
+
+       shm_bfr->samples = samples;
+       shm_bfr->done = 0;
+       shm_bfr->nb_inputs = nb_inputs;
+       shm_bfr->nb_outputs = nb_outputs;
+
+       map_buffer();
+}
+
+// shm_bfr layout:
+// struct shm_bfr {
+//   int64_t sz;
+//   int samples, done;
+//   int nb_inputs, nb_outputs;
+//   int iport[nb_inputs], 
+//   float in_buffers[samples][nb_inputs];
+//   int oport[nb_outputs];
+//   float out_buffers[samples][nb_outputs];
+// };
+
+void PluginLV2::map_buffer()
+{
+       uint8_t *bp = (uint8_t *)(shm_bfr + 1);
+
+       nb_inputs = shm_bfr->nb_inputs;
+       iport = (int *)bp;
+       bp += sizeof(iport[0])*nb_inputs;
+       in_buffers = new float*[nb_inputs];
+       int samples = shm_bfr->samples;
+       for(int i=0; i<nb_inputs; ++i ) {
+               in_buffers[i] = (float *)bp;
+               bp += sizeof(*in_buffers[0])*samples;
+       }
+
+       nb_outputs = shm_bfr->nb_outputs;
+       oport = (int *)bp;
+       bp += sizeof(oport[0])*nb_outputs;
+       out_buffers = new float*[nb_outputs];
+       for( int i=0; i<nb_outputs; ++i ) {
+               out_buffers[i] = (float *)bp;
+               bp += sizeof(*out_buffers[0])*samples;
+       }
+}
+
+
+#include "file.h"
+#include "pluginlv2ui.h"
+
+PluginLV2ChildUI::PluginLV2ChildUI()
+ : ForkChild()
+{
+}
+
+PluginLV2ChildUI::~PluginLV2ChildUI()
+{
+}
+
+void PluginLV2ChildUI::run()
+{
+       ArrayList<char *> av;
+       av.set_array_delete();
+       char arg[BCTEXTLEN];
+       const char *exec_path = File::get_cinlib_path();
+       snprintf(arg, sizeof(arg), "%s/%s", exec_path, "lv2ui");
+       av.append(cstrdup(arg));
+       sprintf(arg, "%d", child_fd);
+       av.append(cstrdup(arg));
+       sprintf(arg, "%d", parent_fd);
+       av.append(cstrdup(arg));
+       sprintf(arg, "%d", ppid);
+       av.append(cstrdup(arg));
+       av.append(0);
+       execv(av[0], &av.values[0]);
+       fprintf(stderr, "execv failed: %s\n %m\n", av.values[0]);
+       av.remove_all_objects();
+       _exit(1);
+}
+
+
+PluginLV2UI::PluginLV2UI()
+ : PluginLV2()
+{
+       lilv_ui = 0;
+       lilv_type = 0;
+       uri_map = 0;
+
+       done = 0;
+       running = 0;
+       redraw = 0;
+       host_updates = updates = 0;
+       host_hidden = hidden = 1;
+       title[0] = 0;
+
+// only gtk-2
+       gtk_type = "http://lv2plug.in/ns/extensions/ui#GtkUI";
+       top_level = 0;
+}
+
+PluginLV2UI::~PluginLV2UI ()
+{
+       reset_gui();
+}
+
+#endif
diff --git a/cinelerra-5.1/cinelerra/pluginlv2.h b/cinelerra-5.1/cinelerra/pluginlv2.h
new file mode 100644 (file)
index 0000000..9b449b4
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __PLUGINLV2_H__
+#define __PLUGINLV2_H__
+
+#define LV2_SEQ_SIZE  9624
+#include "forkbase.h"
+#include "pluginlv2config.h"
+#include "samples.inc"
+
+#include <lilv/lilv.h>
+#define NS_EXT "http://lv2plug.in/ns/ext/"
+
+typedef struct {
+       int64_t sz;
+       int samples, done;
+       int nb_inputs, nb_outputs;
+} shm_bfr_t;
+
+#define TYP_AUDIO   1
+#define TYP_CONTROL 2
+#define TYP_ATOM    4
+#define TYP_ALL    ~0
+
+class PluginLV2
+{
+public:
+       PluginLV2();
+       virtual ~PluginLV2();
+
+       shm_bfr_t *shm_bfr;
+       int use_shm, shmid;
+       float **in_buffers, **out_buffers;
+       int *iport, *oport;
+       int nb_inputs, nb_outputs;
+       int max_bufsz, ui_features;
+
+       void reset_lv2();
+       int load_lv2(const char *path,char *title=0);
+       int init_lv2(PluginLV2ClientConfig &conf, int sample_rate);
+
+       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 del_buffer();
+       void new_buffer(int64_t sz);
+       shm_bfr_t *shm_buffer(int shmid);
+       void init_buffer(int samples);
+       void map_buffer();
+
+       LilvWorld         *world;
+       const LilvPlugin  *lilv;
+       LilvUIs           *lilv_uis;
+
+       PluginLV2UriTable  uri_table;
+       LV2_URID_Map       map;
+       LV2_Feature        map_feature;
+       LV2_URID_Unmap     unmap;
+       LV2_Feature        unmap_feature;
+       Lv2Features        features;
+       LV2_Atom_Sequence  seq_in[2];
+       LV2_Atom_Sequence  *seq_out;
+
+       LilvInstance *inst;
+       SuilInstance *sinst;
+       SuilHost *ui_host;
+
+       LilvNode *atom_AtomPort;
+       LilvNode *atom_Sequence;
+       LilvNode *lv2_AudioPort;
+       LilvNode *lv2_CVPort;
+       LilvNode *lv2_ControlPort;
+       LilvNode *lv2_Optional;
+       LilvNode *lv2_InputPort;
+       LilvNode *lv2_OutputPort;
+       LilvNode *powerOf2BlockLength;
+       LilvNode *fixedBlockLength;
+       LilvNode *boundedBlockLength;
+};
+
+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_LOAD,
+       LV2_UPDATE,
+       LV2_SHOW,
+       LV2_HIDE,
+       LV2_SET,
+       LV2_SHMID,
+       NB_COMMANDS };
+
+#endif
diff --git a/cinelerra-5.1/cinelerra/pluginlv2.inc b/cinelerra-5.1/cinelerra/pluginlv2.inc
new file mode 100644 (file)
index 0000000..a6506ad
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __PLUGINLV2_INC__
+#define __PLUGINLV2_INC__
+
+class PluginLV2;
+
+#endif
index a2c0b51c524b8ce31f36d9fbc8a6b14443a5337c..50df5ae664b7b49f22fa4758fb618ff103ba1f32 100644 (file)
  *
  */
 
+#include "bchash.h"
 #include "clip.h"
 #include "cstrdup.h"
-#include "bchash.h"
+#include "file.h"
 #include "filexml.h"
 #include "language.h"
+#include "mainerror.h"
 #include "mwindow.h"
+#include "plugin.h"
 #include "pluginlv2client.h"
 #include "pluginlv2config.h"
+#include "pluginlv2ui.inc"
 #include "pluginserver.h"
+#include "pluginset.h"
 #include "samples.h"
+#include "track.h"
 
 #include <ctype.h>
 #include <string.h>
 
+PluginLV2UIs PluginLV2ParentUI::plugin_lv2;
 
-PluginLV2ClientUI::
-PluginLV2ClientUI(PluginLV2ClientWindow *gui, int x, int y)
- : BC_GenericButton(x, y, _("UI"))
-{
-       this->gui = gui;
-}
-
-PluginLV2ClientUI::
-~PluginLV2ClientUI()
-{
-}
-
-int PluginLV2ClientUI::handle_event()
-{
-       if( !gui->plugin->open_lv2_gui(gui) )
-               flicker(8, 64);
-       return 1;
-}
-
-PluginLV2ClientReset::
-PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y)
- : BC_GenericButton(x, y, _("Reset"))
-{
-       this->gui = gui;
-}
-
-PluginLV2ClientReset::
-~PluginLV2ClientReset()
-{
-}
-
-int PluginLV2ClientReset::handle_event()
+PluginLV2UIs::PluginLV2UIs()
+ : Mutex("PluginLV2UIs")
 {
-       PluginLV2Client *plugin = gui->plugin;
-       plugin->init_lv2();
-       gui->selected = 0;
-       gui->update_selected();
-       gui->panel->update();
-       plugin->send_configure_change();
-       return 1;
 }
 
-PluginLV2ClientText::
-PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w)
- : BC_TextBox(x, y, w, 1, (char *)"")
+PluginLV2UIs::~PluginLV2UIs()
 {
-       this->gui = gui;
+       del_uis();
 }
 
-PluginLV2ClientText::
-~PluginLV2ClientText()
+void PluginLV2UIs::del_uis()
 {
+       while( size() ) remove_object();
 }
 
-int PluginLV2ClientText::handle_event()
-{
-       return 0;
-}
-
-
-PluginLV2ClientApply::
-PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y)
- : BC_GenericButton(x, y, _("Apply"))
+PluginLV2ParentUI *PluginLV2UIs::del_ui(PluginLV2Client *client)
 {
-       this->gui = gui;
-}
-
-PluginLV2ClientApply::
-~PluginLV2ClientApply()
-{
-}
-
-int PluginLV2ClientApply::handle_event()
-{
-       const char *text = gui->text->get_text();
-       if( text && gui->selected ) {
-               gui->selected->update(atof(text));
-               gui->update_selected();
-               gui->plugin->send_configure_change();
+       lock("PluginLV2UIs::del_ui client");
+       int i = size();
+       while( --i >= 0 && get(i)->client != client );
+       PluginLV2ParentUI *ui = 0;
+       if( i >= 0 ) {
+               if( (ui=get(i))->gui ) ui->client = 0;
+               else { remove_object_number(i);  ui = 0; }
        }
-       return 1;
-}
-
-
-
-PluginLV2Client_OptPanel::
-PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui, int x, int y, int w, int h)
- : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1])
-{
-       this->gui = gui;
-       update();  // init col/wid/columns
-}
-
-PluginLV2Client_OptPanel::
-~PluginLV2Client_OptPanel()
-{
-}
-
-int PluginLV2Client_OptPanel::selection_changed()
-{
-       PluginLV2Client_Opt *opt = 0;
-       BC_ListBoxItem *item = get_selection(0, 0);
-       if( item ) {
-               PluginLV2Client_OptName *opt_name = (PluginLV2Client_OptName *)item;
-               opt = opt_name->opt;
-       }
-       gui->update(opt);
-       return 1;
-}
-
-void PluginLV2Client_OptPanel::update()
-{
-       opts.remove_all();
-       vals.remove_all();
-       PluginLV2ClientConfig &conf = gui->plugin->config;
-       for( int i=0; i<conf.size(); ++i ) {
-               PluginLV2Client_Opt *opt = conf[i];
-               opts.append(opt->item_name);
-               vals.append(opt->item_value);
+       unlock();
+       return ui;
+}
+PluginLV2ParentUI *PluginLV2UIs::del_ui(PluginLV2ClientWindow *gui)
+{
+       lock("PluginLV2UIs::del_ui gui");
+       int i = size();
+       while( --i >= 0 && get(i)->gui != gui );
+       PluginLV2ParentUI *ui = 0;
+       if( i >= 0 ) {
+               if( (ui=get(i))->client ) ui->gui = 0;
+               else { remove_object_number(i);  ui = 0; }
        }
-       const char *cols[] = { "option", "value", };
-       const int col1_w = 150;
-       int wids[] = { col1_w, get_w()-col1_w };
-       BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0]));
+       unlock();
+       return ui;
 }
 
-PluginLV2ClientWindow::PluginLV2ClientWindow(PluginLV2Client *plugin)
- : PluginClientWindow(plugin, 500, 300, 500, 300, 1)
+PluginLV2ParentUI *PluginLV2UIs::add_ui(PluginLV2ParentUI *ui, PluginLV2Client *client)
 {
-       this->plugin = plugin;
-       selected = 0;
+       ui->start_child();
+       ui->start_parent(client);
+       append(ui);
+       return ui;
 }
 
-PluginLV2ClientWindow::~PluginLV2ClientWindow()
+PluginLV2ParentUI *PluginLV2UIs::search_ui(Plugin *plugin)
 {
-}
-
+       int64_t position = plugin->startproject;
+       PluginSet *plugin_set = plugin->plugin_set;
+       int set_no = plugin_set->get_number();
+       int track_no = plugin_set->track->number_of();
 
-void PluginLV2ClientWindow::create_objects()
-{
-       BC_Title *title;
-       int x = 10, y = 10, x1;
-       add_subwindow(title = new BC_Title(x, y, plugin->title));
-#ifdef HAVE_LV2UI
-       x1 = get_w() - BC_GenericButton::calculate_w(this, _("UI")) - 8;
-       add_subwindow(ui = new PluginLV2ClientUI(this, x1, y));
-#else
-       ui = 0;
-#endif
-       y += title->get_h() + 10;
-       add_subwindow(varbl = new BC_Title(x, y, ""));
-       add_subwindow(range = new BC_Title(x+160, y, ""));
-       x1 = get_w() - BC_GenericButton::calculate_w(this, _("Reset")) - 8;
-       add_subwindow(reset = new PluginLV2ClientReset(this, x1, y));
-       y += title->get_h() + 10;
-       x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8;
-       add_subwindow(apply = new PluginLV2ClientApply(this, x1, y));
-       add_subwindow(text = new PluginLV2ClientText(this, x, y, x1-x - 8));
-       y += title->get_h() + 10;
-       add_subwindow(pot = new PluginLV2ClientPot(this, x, y));
-       x1 = x + pot->get_w() + 10;
-       add_subwindow(slider = new PluginLV2ClientSlider(this, x1, y+10));
-       y += pot->get_h() + 10;
-
-       plugin->init_lv2();
-       plugin->load_configuration();
-       plugin->config.update();
-
-       int panel_x = x, panel_y = y;
-       int panel_w = get_w()-10 - panel_x;
-       int panel_h = get_h()-10 - panel_y;
-       panel = new PluginLV2Client_OptPanel(this, panel_x, panel_y, panel_w, panel_h);
-       add_subwindow(panel);
-       panel->update();
-       show_window(1);
-}
-
-int PluginLV2ClientWindow::resize_event(int w, int h)
-{
-       int x1;
-#ifdef HAVE_LV2UI
-       x1 = w - ui->get_w() - 8;
-       ui->reposition_window(x1, ui->get_y());
-#endif
-       x1 = w - reset->get_w() - 8;
-       reset->reposition_window(x1, reset->get_y());
-       x1 = w - apply->get_w() - 8;
-       apply->reposition_window(x1, apply->get_y());
-       text->reposition_window(text->get_x(), text->get_y(), x1-text->get_x() - 8);
-       x1 = pot->get_x() + pot->get_w() + 10;
-       int w1 = w - slider->get_x() - 20;
-       slider->set_pointer_motion_range(w1);
-       slider->reposition_window(x1, slider->get_y(), w1, slider->get_h());
-       int panel_x = panel->get_x(), panel_y = panel->get_y();
-       panel->reposition_window(panel_x, panel_y, w-10-panel_x, h-10-panel_y);
-       return 1;
+       PluginLV2ParentUI *ui = 0;
+       for( int i=size(); !ui && --i>=0; ) {
+               PluginLV2ParentUI *parent_ui = get(i);
+               if( parent_ui->position != position ) continue;
+               if( parent_ui->set_no != set_no ) continue;
+               if( parent_ui->track_no == track_no ) ui = parent_ui;
+       }
+       return ui;
 }
 
-PluginLV2ClientPot::PluginLV2ClientPot(PluginLV2ClientWindow *gui, int x, int y)
- : BC_FPot(x, y, 0.f, 0.f, 0.f)
+PluginLV2ParentUI *PluginLV2UIs::find_ui(Plugin *plugin)
 {
-       this->gui = gui;
+       if( !plugin ) return 0;
+       lock("PluginLV2UIs::find_ui");
+       PluginLV2ParentUI *ui = search_ui(plugin);
+       unlock();
+       return ui;
 }
-
-int PluginLV2ClientPot::handle_event()
+PluginLV2ParentUI *PluginLV2Client::find_ui()
 {
-       if( gui->selected ) {
-               gui->selected->update(get_value());
-               gui->update_selected();
-               gui->plugin->send_configure_change();
-       }
-       return 1;
+       return PluginLV2ParentUI::plugin_lv2.find_ui(server->plugin);
 }
-
-PluginLV2ClientSlider::PluginLV2ClientSlider(PluginLV2ClientWindow *gui, int x, int y)
- : BC_FSlider(x, y, 0, gui->get_w()-x-20, gui->get_w()-x-20, 0.f, 0.f, 0.f)
+PluginLV2ParentUI *PluginLV2ClientWindow::find_ui()
 {
-       this->gui = gui;
+       return PluginLV2ParentUI::plugin_lv2.find_ui(client->server->plugin);
 }
 
-int PluginLV2ClientSlider::handle_event()
+PluginLV2ParentUI *PluginLV2UIs::get_ui(PluginLV2Client *client)
 {
-       if( gui->selected ) {
-               gui->selected->update(get_value());
-               gui->update_selected();
-               gui->plugin->send_configure_change();
-       }
-       return 1;
+       lock("PluginLV2UIs::get_ui");
+       Plugin *plugin = client->server->plugin;
+       PluginLV2ParentUI *ui = search_ui(plugin);
+       if( !ui ) ui = add_ui(new PluginLV2ParentUI(plugin), client);
+       unlock();
+       return ui;
 }
-
-void PluginLV2ClientWindow::update_selected()
+PluginLV2ParentUI *PluginLV2Client::get_ui()
 {
-       update(selected);
-       if( selected && plugin->parent_gui ) {
-               control_t bfr;
-               bfr.idx = selected->idx;
-               bfr.value = selected->get_value();
-               plugin->parent_gui->send_child(LV2_SET, &bfr, sizeof(bfr));
-       }
+       PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.get_ui(this);
+       ui->client = this;
+       return ui;
 }
-
-int PluginLV2ClientWindow::scalar(float f, char *rp)
+PluginLV2ParentUI *PluginLV2ClientWindow::get_ui()
 {
-       const char *cp = 0;
-            if( f == FLT_MAX ) cp = "FLT_MAX";
-       else if( f == FLT_MIN ) cp = "FLT_MIN";
-       else if( f == -FLT_MAX ) cp = "-FLT_MAX";
-       else if( f == -FLT_MIN ) cp = "-FLT_MIN";
-       else if( f == 0 ) cp = signbit(f) ? "-0" : "0";
-       else if( isnan(f) ) cp = signbit(f) ? "-NAN" : "NAN";
-       else if( isinf(f) ) cp = signbit(f) ? "-INF" : "INF";
-       else return sprintf(rp, "%g", f);
-       return sprintf(rp, "%s", cp);
-}
-
-void PluginLV2ClientWindow::update(PluginLV2Client_Opt *opt)
-{
-       if( selected != opt ) {
-               if( selected ) selected->item_name->set_selected(0);
-               selected = opt;
-               if( selected ) selected->item_name->set_selected(1);
-       }
-       char var[BCSTRLEN];  var[0] = 0;
-       char val[BCSTRLEN];  val[0] = 0;
-       char rng[BCTEXTLEN]; rng[0] = 0;
-       if( opt ) {
-               sprintf(var,"%s:", opt->conf->names[opt->idx]);
-               char *cp = rng;
-               cp += sprintf(cp,"( ");
-               float min = opt->conf->mins[opt->idx];
-               cp += scalar(min, cp);
-               cp += sprintf(cp, " .. ");
-               float max = opt->conf->maxs[opt->idx];
-               cp += scalar(max, cp);
-               cp += sprintf(cp, " )");
-               float v = opt->get_value();
-               sprintf(val, "%f", v);
-               slider->update(slider->get_w(), v, min, max);
-               pot->update(v, min, max);
-       }
-       else {
-               slider->update(slider->get_w(), 0.f, 0.f, 0.f);
-               pot->update(0.f, 0.f, 0.f);
-       }
-       varbl->update(var);
-       range->update(rng);
-       text->update(val);
-       panel->update();
+       PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.get_ui(client);
+       ui->gui = this;
+       return ui;
 }
 
 
 PluginLV2Client::PluginLV2Client(PluginServer *server)
- : PluginAClient(server)
-{
-       in_buffers = 0;
-       out_buffers = 0;
-       nb_in_bfrs = 0;
-       nb_out_bfrs = 0;
-       bfrsz = 0;
-       nb_inputs = 0;
-       nb_outputs = 0;
-       max_bufsz = 0;
-
-       world = 0;
-       instance = 0;
-       lv2_InputPort = 0;
-       lv2_OutputPort = 0;
-       lv2_AudioPort = 0;
-       lv2_CVPort = 0;
-       lv2_ControlPort = 0;
-       lv2_Optional = 0;
-       atom_AtomPort = 0;
-       atom_Sequence = 0;
-       powerOf2BlockLength = 0;
-       fixedBlockLength = 0;
-       boundedBlockLength = 0;
-       seq_out = 0;
-       parent_gui = 0;
+ : PluginAClient(server), PluginLV2()
+{
+       title[0] = 0;
 }
 
 PluginLV2Client::~PluginLV2Client()
 {
-       reset_lv2();
-       lilv_world_free(world);
+       PluginLV2ParentUI::plugin_lv2.del_ui(this);
 }
 
-void PluginLV2Client::reset_lv2()
-{
-       delete parent_gui;                    parent_gui = 0;
-       if( instance ) lilv_instance_deactivate(instance);
-       lilv_instance_free(instance);         instance = 0;
-       lilv_node_free(powerOf2BlockLength);  powerOf2BlockLength = 0;
-       lilv_node_free(fixedBlockLength);     fixedBlockLength = 0;
-       lilv_node_free(boundedBlockLength);   boundedBlockLength = 0;
-       lilv_node_free(atom_Sequence);        atom_Sequence = 0;
-       lilv_node_free(atom_AtomPort);        atom_AtomPort = 0;
-       lilv_node_free(lv2_Optional);         lv2_Optional = 0;
-       lilv_node_free(lv2_ControlPort);      lv2_ControlPort = 0;
-       lilv_node_free(lv2_AudioPort);        lv2_AudioPort = 0;
-       lilv_node_free(lv2_CVPort);           lv2_CVPort = 0;
-       lilv_node_free(lv2_OutputPort);       lv2_OutputPort = 0;
-       lilv_node_free(lv2_InputPort);        lv2_InputPort = 0;
-       delete [] (char *)seq_out;            seq_out = 0;
-       uri_table.remove_all_objects();
-       delete_buffers();
-       nb_inputs = 0;
-       nb_outputs = 0;
-       max_bufsz = 0;
-       config.reset();
-       config.remove_all_objects();
-}
-
-int PluginLV2Client::load_lv2(const char *path)
-{
-       if( !world ) {
-               world = lilv_world_new();
-               if( !world ) {
-                       printf("lv2: lilv_world_new failed");
-                       return 1;
-               }
-               lilv_world_load_all(world);
-       }
-
-       LilvNode *uri = lilv_new_uri(world, path);
-       if( !uri ) {
-               printf("lv2: lilv_new_uri(%s) failed", path);
-               return 1;
-       }
-
-       const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
-       lilv = lilv_plugins_get_by_uri(all_plugins, uri);
-       lilv_node_free(uri);
-       if( !lilv ) {
-               printf("lv2: lilv_plugins_get_by_uriPlugin(%s) failed", path);
-               return 1;
-       }
-
-       LilvNode *name = lilv_plugin_get_name(lilv);
-       const char *nm = lilv_node_as_string(name);
-       snprintf(title,sizeof(title),"L2_%s",nm);
-       lilv_node_free(name);
-       return 0;
-}
+NEW_WINDOW_MACRO(PluginLV2Client, PluginLV2ClientWindow)
 
 int PluginLV2Client::init_lv2()
 {
-       reset_lv2();
-
-       lv2_InputPort       = lilv_new_uri(world, LV2_CORE__InputPort);
-       lv2_OutputPort      = lilv_new_uri(world, LV2_CORE__OutputPort);
-       lv2_AudioPort       = lilv_new_uri(world, LV2_CORE__AudioPort);
-       lv2_ControlPort     = lilv_new_uri(world, LV2_CORE__ControlPort);
-       lv2_CVPort          = lilv_new_uri(world, LV2_CORE__CVPort);
-       lv2_Optional        = lilv_new_uri(world, LV2_CORE__connectionOptional);
-       atom_AtomPort       = lilv_new_uri(world, LV2_ATOM__AtomPort);
-       atom_Sequence       = lilv_new_uri(world, LV2_ATOM__Sequence);
-       powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
-       fixedBlockLength    = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
-       boundedBlockLength  = lilv_new_uri(world, LV2_BUF_SIZE__boundedBlockLength);
-       seq_out = (LV2_Atom_Sequence *) new char[sizeof(LV2_Atom_Sequence) + LV2_SEQ_SIZE];
-
-       config.init_lv2(lilv);
-       nb_inputs = nb_outputs = 0;
-
-       for( int i=0; i<config.nb_ports; ++i ) {
-               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
-               int is_input = lilv_port_is_a(lilv, lp, lv2_InputPort);
-               if( !is_input && !lilv_port_is_a(lilv, lp, lv2_OutputPort) &&
-                   !lilv_port_has_property(lilv, lp, lv2_Optional) ) {
-                       printf("lv2: not input, not output, and not optional: %s\n", config.names[i]);
-                       continue;
-               }
-               if( is_input && lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
-                       config.append(new PluginLV2Client_Opt(&config, i));
-                       continue;
-               }
-               if( lilv_port_is_a(lilv, lp, lv2_AudioPort) ||
-                   lilv_port_is_a(lilv, lp, lv2_CVPort ) ) {
-                       if( is_input ) ++nb_inputs; else ++nb_outputs;
-                       continue;
-               }
-       }
-
-       map.handle = (void*)&uri_table;
-       map.map = uri_table_map;
-       features.append(new Lv2Feature(LV2_URID_MAP_URI, &map));
-       unmap.handle = (void*)&uri_table;
-       unmap.unmap  = uri_table_unmap;
-       features.append(new Lv2Feature(LV2_URID_UNMAP_URI, &unmap));
-       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(0);
-
-       instance = lilv_plugin_instantiate(lilv, sample_rate, features);
-       if( !instance ) {
-               printf("lv2: lilv_plugin_instantiate failed: %s\n", server->title);
-               return 1;
-       }
-       lilv_instance_activate(instance);
-// not sure what to do with these
-       max_bufsz = nb_inputs &&
-               (lilv_plugin_has_feature(lilv, powerOf2BlockLength) ||
-                lilv_plugin_has_feature(lilv, fixedBlockLength) ||
-                lilv_plugin_has_feature(lilv, boundedBlockLength)) ? 4096 : 0;
-       return 0;
-}
-
-LV2_URID PluginLV2Client::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
-{
-       return ((PluginLV2UriTable *)handle)->map(uri);
+       int sample_rate = get_project_samplerate();
+       return PluginLV2::init_lv2(config, sample_rate);
 }
 
-const char *PluginLV2Client::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
-{
-       return ((PluginLV2UriTable *)handle)->unmap(urid);
-}
-
-NEW_WINDOW_MACRO(PluginLV2Client, PluginLV2ClientWindow)
-
 int PluginLV2Client::load_configuration()
 {
        int64_t src_position =  get_source_position();
@@ -522,34 +195,9 @@ void PluginLV2Client::update_gui()
 
 void PluginLV2Client::update_lv2()
 {
-       if( !parent_gui ) return;
-       parent_gui->send_child(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
-}
-
-void PluginLV2Client::lv2_update()
-{
-       PluginClientThread *thread = get_thread();
-       if( !thread ) return;
-       PluginLV2ClientWindow *gui = (PluginLV2ClientWindow*)thread->get_window();
-       gui->lock_window("PluginLV2ParentGUI::handle_parent");
-       int ret = config.update();
-       if( ret ) gui->update(0);
-       gui->unlock_window();
-       if( ret ) send_configure_change();
-}
-
-void PluginLV2Client::lv2_update(float *vals)
-{
-       int nb_ports = config.nb_ports;
-       float *ctls = config.ctls;
-       for( int i=0; i<nb_ports; ++i ) *ctls++ = *vals++;
-       lv2_update();
-}
-
-void PluginLV2Client::lv2_set(int idx, float val)
-{
-       config[idx]->set_value(val);
-       lv2_update();
+       PluginLV2ParentUI *ui = find_ui();
+       if( !ui ) return;
+       ui->send_child(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
 }
 
 
@@ -598,141 +246,65 @@ void PluginLV2Client::read_data(KeyFrame *keyframe)
        }
 }
 
-void PluginLV2Client::connect_ports()
+void PluginLV2Client::load_buffer(int samples, Samples **input, int ich)
 {
-       int ich = 0, och = 0;
-       for( int i=0; i<config.nb_ports; ++i ) {
-               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
-               if( 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(instance, i, in_buffers[ich++]);
-                       else if( lilv_port_is_a(lilv, lp, lv2_OutputPort))
-                               lilv_instance_connect_port(instance, i, out_buffers[och++]);
-                       continue;
-               }
-               if( lilv_port_is_a(lilv, lp, atom_AtomPort) ) {
-                       if( lilv_port_is_a(lilv, lp, lv2_InputPort) )
-                               lilv_instance_connect_port(instance, i, &seq_in);
-                       else
-                               lilv_instance_connect_port(instance, i, seq_out);
-                       continue;
-               }
-               if( lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
-                       lilv_instance_connect_port(instance, i, &config.ctls[i]);
-                       continue;
-               }
+       for( int i=0; i<nb_inputs; ++i ) {
+               int k = i < ich ? i : 0;
+               double *inp = input[k]->get_data();
+               float *ip = in_buffers[i];
+               for( int j=samples; --j>=0; *ip++=*inp++ );
        }
-
-       seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body);
-       seq_in[0].atom.type = uri_table.map(LV2_ATOM__Sequence);
-       seq_in[1].atom.size = 0;
-       seq_in[1].atom.type = 0;
-       seq_out->atom.size  = LV2_SEQ_SIZE;
-       seq_out->atom.type  = uri_table.map(LV2_ATOM__Chunk);
+       for( int i=0; i<nb_outputs; ++i )
+               bzero(out_buffers[i], samples*sizeof(float));
 }
 
-void PluginLV2Client::init_plugin(int size)
+int PluginLV2Client::unload_buffer(int samples, Samples **output, int och)
 {
-       if( !instance )
-               init_lv2();
-
-       load_configuration();
-
-       if( bfrsz < size )
-               delete_buffers();
-
-       bfrsz = MAX(size, bfrsz);
-       if( !in_buffers ) {
-               in_buffers = new float*[nb_in_bfrs=nb_inputs];
-               for(int i=0; i<nb_in_bfrs; ++i )
-                       in_buffers[i] = new float[bfrsz];
-       }
-       if( !out_buffers ) {
-               out_buffers = new float*[nb_out_bfrs=nb_outputs];
-               for( int i=0; i<nb_out_bfrs; ++i )
-                       out_buffers[i] = new float[bfrsz];
+       if( nb_outputs < och ) och = nb_outputs;
+       for( int i=0; i<och; ++i ) {
+               double *outp = output[i]->get_data();
+               float *op = out_buffers[i];
+               for( int j=samples; --j>=0; *outp++=*op++ );
        }
+       return samples;
 }
 
-void PluginLV2Client::delete_buffers()
+void PluginLV2Client::process_buffer(int size)
 {
-       if( in_buffers ) {
-               for( int i=0; i<nb_in_bfrs; ++i ) delete [] in_buffers[i];
-               delete [] in_buffers;  in_buffers = 0;  nb_in_bfrs = 0;
-       }
-       if( out_buffers ) {
-               for( int i=0; i<nb_out_bfrs; ++i ) delete [] out_buffers[i];
-               delete [] out_buffers;  out_buffers = 0;  nb_out_bfrs = 0;
-       }
-       bfrsz = 0;
-}
-
-int PluginLV2Client::open_lv2_gui(PluginLV2ClientWindow *gui)
-{
-#ifdef HAVE_LV2UI
-       if( parent_gui ) {
-               if( !parent_gui->done ) return 0;
-               delete parent_gui;
-       }
-       parent_gui = new PluginLV2ParentGUI(gui);
-       parent_gui->start_child();
-       parent_gui->start_parent();
-       return 1;
-#else
-       return 0;
-#endif
+       PluginLV2ParentUI *ui = get_ui();
+       if( !ui ) return;
+       shm_bfr->done = 0;
+       ui->send_child(LV2_SHMID, &shmid, sizeof(shmid));
+// timeout 10*duration, min 2sec, max 10sec
+       double sample_rate = get_project_samplerate();
+       double t = !sample_rate ? 2. : 10. * size / sample_rate;
+       bclamp(t, 2., 10.);
+       ui->output_bfr->timed_lock(t*1e6, "PluginLV2Client::process_buffer");
+       if( !shm_bfr->done )
+               eprintf("timeout: %s",server->title);
 }
 
 int PluginLV2Client::process_realtime(int64_t size,
        Samples *input_ptr, Samples *output_ptr)
 {
-       init_plugin(size);
-
-       for( int i=0; i<nb_in_bfrs; ++i ) {
-               double *inp = input_ptr->get_data();
-               float *ip = in_buffers[i];
-               for( int j=size; --j>=0; *ip++=*inp++ );
-       }
-       for( int i=0; i<nb_out_bfrs; ++i )
-               bzero(out_buffers[i], size*sizeof(float));
-
-       connect_ports();
-       lilv_instance_run(instance, size);
-
-       double *outp = output_ptr->get_data();
-       float *op = out_buffers[0];
-       for( int i=size; --i>=0; *outp++=*op++ );
-       return size;
+       load_configuration();
+       init_buffer(size);
+       load_buffer(size, &input_ptr, 1);
+       process_buffer(size);
+       return unload_buffer(size, &output_ptr, 1);
 }
 
 int PluginLV2Client::process_realtime(int64_t size,
        Samples **input_ptr, Samples **output_ptr)
 {
-       init_plugin(size);
-
-       for( int i=0; i<nb_in_bfrs; ++i ) {
-               int k = i < PluginClient::total_in_buffers ? i : 0;
-               double *inp = input_ptr[k]->get_data();
-               float *ip = in_buffers[i];
-               for( int j=size; --j>=0; *ip++=*inp++ );
-       }
-       for( int i=0; i<nb_out_bfrs; ++i )
-               bzero(out_buffers[i], size*sizeof(float));
-
-       connect_ports();
-       lilv_instance_run(instance, size);
-
-       int nbfrs = PluginClient::total_out_buffers;
-       if( nb_out_bfrs < nbfrs ) nbfrs = nb_out_bfrs;
-       for( int i=0; i<nbfrs; ++i ) {
-               double *outp = output_ptr[i]->get_data();
-               float *op = out_buffers[i];
-               for( int j=size; --j>=0; *outp++=*op++ );
-       }
-       return size;
+       load_configuration();
+       init_buffer(size);
+       load_buffer(size, input_ptr, PluginClient::total_in_buffers);
+       process_buffer(size);
+       return unload_buffer(size, output_ptr, PluginClient::total_out_buffers);
 }
 
+
 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name)
 {
        return new PluginServer(mwindow, name, PLUGIN_TYPE_LV2);
@@ -741,11 +313,8 @@ PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name)
 PluginClient *PluginServer::new_lv2_plugin()
 {
        PluginLV2Client *client = new PluginLV2Client(this);
-//for some lv2 clients
-       if( client->sample_rate < 64 ) client->sample_rate = 64;
-       if( client->project_sample_rate < 64 ) client->project_sample_rate = 64;
-       if( client->load_lv2(path) ) { delete client;  client = 0; }
-       else client->init_lv2();
+       if( client->load_lv2(path, client->title) ) { delete client;  return client = 0; }
+       client->init_lv2();
        return client;
 }
 
@@ -771,48 +340,68 @@ int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp
        return 0;
 }
 
-ForkChild *PluginLV2ParentGUI::new_fork()
+PluginLV2ParentUI::PluginLV2ParentUI(Plugin *plugin)
 {
-#ifdef HAVE_LV2UI
-       return new PluginLV2ChildGUI();
-#else
-       return 0;
-#endif
-}
+       this->position = plugin->startproject;
+       PluginSet *plugin_set = plugin->plugin_set;
+       if( plugin_set ) {
+               this->set_no = plugin_set->get_number();
+               this->track_no = plugin_set->track->number_of();
+       }
+       else
+               this->track_no = this->set_no = -1;
 
-PluginLV2ParentGUI::PluginLV2ParentGUI(PluginLV2ClientWindow *gui)
-{
-       this->gui = gui;
+       output_bfr = new Condition(0, "PluginLV2ParentUI::output_bfr", 1);
+       client = 0;
+       gui = 0;
+       hidden = 1;
 }
 
-PluginLV2ParentGUI::~PluginLV2ParentGUI()
+PluginLV2ParentUI::~PluginLV2ParentUI()
 {
        stop();
+       delete output_bfr;
 }
 
-void PluginLV2ParentGUI::start_parent()
+void PluginLV2ParentUI::start_parent(PluginLV2Client *client)
 {
        start();
-       const char *path = gui->plugin->server->path;
-       send_child(LV2_OPEN, path, strlen(path)+1);
-       PluginLV2ClientConfig &conf = gui->plugin->config;
-       send_child(LV2_START, 0, 0);
+       const char *path = client->server->path;
+       int len = sizeof(open_bfr_t) + strlen(path);
+       char bfr[len];  memset(bfr, 0, len);
+       open_bfr_t *open_bfr = (open_bfr_t *)bfr;
+       open_bfr->sample_rate = client->get_project_samplerate();
+       strcpy(open_bfr->path, path);
+       send_child(LV2_OPEN, open_bfr, len);
+       PluginLV2ClientConfig &conf = client->config;
        send_child(LV2_LOAD, conf.ctls, conf.nb_ports*sizeof(float));
 }
 
-int PluginLV2ParentGUI::handle_parent()
+int PluginLV2ParentUI::handle_parent()
 {
        int result = 1;
 
        switch( parent_token ) {
-       case LV2_UPDATE:
-               gui->plugin->lv2_update((float *)parent_data);
-               break;
+       case LV2_UPDATE: {
+               if( !gui ) break;
+               gui->lv2_update((float *)parent_data);
+               break; }
+       case LV2_HIDE: {
+               hidden = 1;
+               break; }
+       case LV2_SHOW: {
+               hidden = 0;
+               break; }
        case LV2_SET: {
-               control_t *ctl = (control_t *)parent_data;
-               gui->plugin->lv2_set(ctl->idx, ctl->value);
+               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: {
+               output_bfr->unlock();
                result = -1;
                break; }
        default:
@@ -823,12 +412,35 @@ int PluginLV2ParentGUI::handle_parent()
        return result;
 }
 
+int PluginLV2ParentUI::show()
+{
+       if( !hidden ) return 1;
+       send_child(LV2_SHOW, 0, 0);
+       return 0;
+}
+
+int PluginLV2ParentUI::hide()
+{
+       if( hidden ) return 1;
+       send_child(LV2_HIDE, 0, 0);
+       return 0;
+}
+
+
 // stub in parent
-int PluginLV2ChildGUI::handle_child()
+int PluginLV2ChildUI::handle_child() { return 0; }
+void PluginLV2UI::reset_gui() {}
+
+ForkChild *PluginLV2ParentUI::new_fork()
 {
+#ifdef HAVE_LV2UI
+       return new PluginLV2ChildUI();
+#else
        return 0;
+#endif
 }
 
+
 #else
 #include "mwindow.h"
 #include "pluginserver.h"
index 5100a712c1520efba92404a580bde34138d02893..da703e8ede7cbba8cf5902e1c5ea24ae52ed04ad 100644 (file)
+#ifndef __PLUGINLV2CLIENT_H__
+#define __PLUGINLV2CLIENT_H__
 
-/*
- * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 PLUGINLV2CLIENT_H
-#define PLUGINLV2CLIENT_H
-
+#include "condition.inc"
+#include "mutex.h"
 #include "pluginaclient.h"
+#include "plugin.inc"
+#include "pluginlv2.h"
 #include "pluginlv2config.h"
 #include "pluginlv2client.inc"
 #include "pluginlv2gui.h"
+#include "pluginlv2ui.inc"
 #include "samples.inc"
 
-#define LV2_SEQ_SIZE  9624
-
-class PluginLV2Client_OptPanel : public BC_ListBox
+class PluginLV2UIs : public ArrayList<PluginLV2ParentUI *>, public Mutex
 {
 public:
-       PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui, int x, int y, int w, int h);
-       ~PluginLV2Client_OptPanel();
+       PluginLV2UIs();
+       ~PluginLV2UIs();
 
-       PluginLV2ClientWindow *gui;
-       ArrayList<BC_ListBoxItem*> items[2];
-       ArrayList<BC_ListBoxItem*> &opts;
-       ArrayList<BC_ListBoxItem*> &vals;
+       void del_uis();
+       PluginLV2ParentUI *del_ui(PluginLV2Client *client);
+       PluginLV2ParentUI *del_ui(PluginLV2ClientWindow *gui);
+       PluginLV2ParentUI *add_ui(PluginLV2ParentUI *ui, PluginLV2Client *client);
+       PluginLV2ParentUI *search_ui(Plugin *plugin);
+       PluginLV2ParentUI *find_ui(Plugin *plugin);
+       PluginLV2ParentUI *get_ui(PluginLV2Client *client);
 
-       int selection_changed();
-       void update();
 };
 
-class PluginLV2ClientText : public BC_TextBox {
-public:
-       PluginLV2ClientWindow *gui;
-
-       PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w);
-       ~PluginLV2ClientText();
-       int handle_event();
-};
-
-class PluginLV2ClientReset : public BC_GenericButton
+class PluginLV2ParentUI : public ForkParent
 {
 public:
+       PluginLV2ParentUI(Plugin *plugin);
+       ~PluginLV2ParentUI();
+       ForkChild* new_fork();
+       void start_parent(PluginLV2Client *client);
+       int handle_parent();
+
+       Condition *output_bfr;
+       PluginLV2Client *client;
        PluginLV2ClientWindow *gui;
 
-       PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y);
-       ~PluginLV2ClientReset();
-       int handle_event();
-};
+       int hidden;
+       int show();
+       int hide();
 
-class PluginLV2ClientUI : public BC_GenericButton {
-public:
-       PluginLV2ClientWindow *gui;
-
-       PluginLV2ClientUI(PluginLV2ClientWindow *gui, int x, int y);
-       ~PluginLV2ClientUI();
-       int handle_event();
-};
-
-class PluginLV2ClientApply : public BC_GenericButton {
-public:
-       PluginLV2ClientWindow *gui;
+//from Plugin::identitical_location
+       int64_t position;
+       int set_no;
+       int track_no;
 
-       PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y);
-       ~PluginLV2ClientApply();
-       int handle_event();
+       static PluginLV2UIs plugin_lv2;
 };
 
-class PluginLV2ClientPot : public BC_FPot
-{
-public:
-       PluginLV2ClientPot(PluginLV2ClientWindow *gui, int x, int y);
-       int handle_event();
-       PluginLV2ClientWindow *gui;
-};
-
-class PluginLV2ClientSlider : public BC_FSlider
-{
-public:
-       PluginLV2ClientSlider(PluginLV2ClientWindow *gui, int x, int y);
-       int handle_event();
-       PluginLV2ClientWindow *gui;
-};
-
-class PluginLV2ClientWindow : public PluginClientWindow
-{
-public:
-       PluginLV2ClientWindow(PluginLV2Client *plugin);
-       ~PluginLV2ClientWindow();
-
-       void create_objects();
-       int resize_event(int w, int h);
-       void update_selected();
-       void update_selected(float v);
-       int scalar(float f, char *rp);
-       void update(PluginLV2Client_Opt *opt);
-
-       PluginLV2Client *plugin;
-       PluginLV2ClientUI *ui;
-       PluginLV2ClientReset *reset;
-       PluginLV2ClientApply *apply;
-       PluginLV2ClientPot *pot;
-       PluginLV2ClientSlider *slider;
-       PluginLV2ClientText *text;
-       BC_Title *varbl, *range;
-       PluginLV2Client_OptPanel *panel;
-       PluginLV2Client_Opt *selected;
-};
-
-
-class PluginLV2Client : public PluginAClient
+class PluginLV2Client : public PluginAClient, public PluginLV2
 {
 public:
        PluginLV2Client(PluginServer *server);
@@ -144,56 +73,17 @@ public:
        char* to_string(char *string, const char *input);
        void save_data(KeyFrame *keyframe);
        void read_data(KeyFrame *keyframe);
-       void reset_lv2();
-       int load_lv2(const char *path);
-       int init_lv2();
-       int open_lv2_gui(PluginLV2ClientWindow *gui);
+       void load_buffer(int samples, Samples **input, int ich);
+       int unload_buffer(int samples, Samples **output, int och);
+       void process_buffer(int size);
        void update_gui();
        void update_lv2();
-       void lv2_update();
-       void lv2_update(float *vals);
-       void lv2_set(int idx, float val);
+       int init_lv2();
+       PluginLV2ParentUI *find_ui();
+       PluginLV2ParentUI *get_ui();
 
        PLUGIN_CLASS_MEMBERS(PluginLV2ClientConfig)
        char title[BCSTRLEN];
-       int bfrsz, nb_in_bfrs, nb_out_bfrs;
-       float **in_buffers, **out_buffers;
-
-       void delete_buffers();
-       void init_plugin(int size);
-       void connect_ports();
-       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);
-
-// lv2
-       LilvWorld         *world;
-       const LilvPlugin  *lilv;
-       int nb_inputs, nb_outputs;
-       int max_bufsz;
-
-       PluginLV2UriTable  uri_table;
-       LV2_URID_Map       map;
-       LV2_Feature        map_feature;
-       LV2_URID_Unmap     unmap;
-       LV2_Feature        unmap_feature;
-       Lv2Features        features;
-       LV2_Atom_Sequence  seq_in[2];
-       LV2_Atom_Sequence  *seq_out;
-
-       LilvInstance *instance;
-       LilvNode *atom_AtomPort;
-       LilvNode *atom_Sequence;
-       LilvNode *lv2_AudioPort;
-       LilvNode *lv2_CVPort;
-       LilvNode *lv2_ControlPort;
-       LilvNode *lv2_Optional;
-       LilvNode *lv2_InputPort;
-       LilvNode *lv2_OutputPort;
-       LilvNode *powerOf2BlockLength;
-       LilvNode *fixedBlockLength;
-       LilvNode *boundedBlockLength;
-
-       PluginLV2ParentGUI *parent_gui;
 };
 
 #endif
index 4950519c31a54346633896914326ffb7807228d2..5b85e82a6246b5b3ef22f0d330a0bc80986f0d98 100644 (file)
  *
  */
 
-#ifndef PLUGINLV2CLIENT_INC
-#define PLUGINLV2CLIENT_INC
+#ifndef __PLUGINLV2CLIENT_INC__
+#define __PLUGINLV2CLIENT_INC__
 
-class PluginLV2Client_OptPanel;
-class PluginLV2ClientText;
-class PluginLV2ClientReset;
-class PluginLV2ClientApply;
-class PluginLV2ClientPot;
-class PluginLV2ClientSlider;
-class PluginLV2ClientWindow;
+class PluginLV2UIs;
+class PluginLV2ParentUI;
 class PluginLV2Client;
 
 #endif
index 776f9d67b15b53982b14d593a8dbf965465067f4..66c9a498b8e17811d6d1314b81b6fd42debe4266 100644 (file)
@@ -29,6 +29,7 @@
 #include <string.h>
 
 PluginLV2UriTable::PluginLV2UriTable()
+ : Mutex("PluginLV2UriTable::PluginLV2UriTable")
 {
        set_array_delete();
 }
@@ -40,18 +41,21 @@ PluginLV2UriTable::~PluginLV2UriTable()
 
 LV2_URID PluginLV2UriTable::map(const char *uri)
 {
-       mLock locker(uri_table_lock);
-       for( int i=0; i<size(); ++i )
-               if( !strcmp(uri, get(i)) ) return i+1;
-       append(cstrdup(uri));
-       return size();
+       lock("PluginLV2UriTable::map");
+       int i = 0, n = size();
+       while( i<n && strcmp(uri, get(i)) ) ++i;
+       if( i >= n ) append(cstrdup(uri));
+       unlock();
+       return i+1;
 }
 
 const char *PluginLV2UriTable::unmap(LV2_URID urid)
 {
-       mLock locker(uri_table_lock);
+       lock("PluginLV2UriTable::unmap");
        int idx = urid - 1;
-       return idx>=0 && idx<size() ? get(idx) : 0;
+       const char *ret = idx>=0 && idx<size() ? get(idx) : 0;
+       unlock();
+       return ret;
 }
 
 PluginLV2Client_OptName:: PluginLV2Client_OptName(PluginLV2Client_Opt *opt)
index c1ed9b92460bb318d79aec26f58e074410a32278..c9b8b0661a5745fe231dfdf666ac1aa139babd9c 100644 (file)
@@ -67,9 +67,8 @@ public:
        operator LV2_Feature **() { return (LV2_Feature **)&values[0]; }
 };
 
-class PluginLV2UriTable : public ArrayList<const char *>
+class PluginLV2UriTable : public ArrayList<const char *>, public Mutex
 {
-       Mutex uri_table_lock;
 public:
        PluginLV2UriTable();
        ~PluginLV2UriTable();
index baa03f195dc16a043ec3288a2a61fa9195c25465..9e17f9cd8e5da8bb57f7e3865cefb2656021097d 100644 (file)
-#ifdef HAVE_LV2UI
 
-#include "file.h"
+/*
+ * CINELERRA
+ * Copyright (C) 2018 GG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ *
+ */
+
+#include "clip.h"
+#include "cstrdup.h"
+#include "bchash.h"
+#include "filexml.h"
 #include "language.h"
+#include "mwindow.h"
+#include "pluginlv2client.h"
+#include "pluginlv2config.h"
 #include "pluginlv2gui.h"
+#include "pluginserver.h"
+#include "samples.h"
 
 #include <ctype.h>
 #include <string.h>
 
 
-PluginLV2ChildGUI::PluginLV2ChildGUI()
+PluginLV2ClientUI::PluginLV2ClientUI(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("UI"))
 {
-       lv2_gui = 0;
+       this->gui = gui;
 }
 
-PluginLV2ChildGUI::~PluginLV2ChildGUI()
+PluginLV2ClientUI::~PluginLV2ClientUI()
 {
-       delete lv2_gui;
 }
 
-void PluginLV2ChildGUI::run()
+int PluginLV2ClientUI::handle_event()
 {
-       ArrayList<char *> av;
-       av.set_array_delete();
-       char arg[BCTEXTLEN];
-       const char *exec_path = File::get_cinlib_path();
-       snprintf(arg, sizeof(arg), "%s/%s", exec_path, "lv2ui");
-       av.append(cstrdup(arg));
-       sprintf(arg, "%d", child_fd);
-       av.append(cstrdup(arg));
-       sprintf(arg, "%d", parent_fd);
-       av.append(cstrdup(arg));
-       av.append(0);
-       execv(av[0], &av.values[0]);
-       fprintf(stderr, "execv failed: %s\n %m\n", av.values[0]);
-       av.remove_all_objects();
-       _exit(1);
+       PluginLV2ParentUI *ui = gui->get_ui();
+       if( ui->show() )
+               flicker(8, 64);
+       return 1;
 }
 
+PluginLV2ClientReset::
+PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+       this->gui = gui;
+}
 
-#define NS_EXT "http://lv2plug.in/ns/ext/"
-
-PluginLV2GUI::PluginLV2GUI()
+PluginLV2ClientReset::
+~PluginLV2ClientReset()
 {
-       world = 0;
-       lilv = 0;
-       uri_map = 0;
-       ext_data = 0;
-       inst = 0;
-       sinst = 0;
-       ui_host = 0;
-       uis = 0;
-       ui = 0;
-       ui_type = 0;
-       lv2_InputPort = 0;
-       lv2_ControlPort = 0;
-
-       updates = 0;
-       last = 0;
-       done = 0;
-       running = 0;
-       redraw = 0;
-
-// only gtk-2
-       gtk_type = "http://lv2plug.in/ns/extensions/ui#GtkUI";
 }
 
-PluginLV2GUI::~PluginLV2GUI ()
+int PluginLV2ClientReset::handle_event()
 {
-       reset_gui();
-       if( world ) lilv_world_free(world);
+       PluginLV2Client *client = gui->client;
+       client->config.init_lv2(client->lilv);
+       client->config.update();
+       client->update_lv2();
+       gui->update(0);
+       client->send_configure_change();
+       return 1;
 }
 
-void PluginLV2GUI::reset_gui()
+PluginLV2ClientText::PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w)
+ : BC_TextBox(x, y, w, 1, (char *)"")
 {
-       if( inst ) lilv_instance_deactivate(inst);
-       if( uri_map )   { delete uri_map;             uri_map = 0; }
-       if( ext_data )  { delete ext_data;            ext_data = 0; }
-       if( inst )      { lilv_instance_free(inst);   inst = 0; }
-       if( sinst )     { suil_instance_free(sinst);  sinst = 0; }
-       if( ui_host )   { suil_host_free(ui_host);    ui_host = 0; }
-       if( uis )       { lilv_uis_free(uis);         uis = 0; }
-       if( lv2_InputPort )  { lilv_node_free(lv2_InputPort);   lv2_InputPort = 0; }
-       if( lv2_ControlPort ) { lilv_node_free(lv2_ControlPort);  lv2_ControlPort = 0; }
-       ui_features.remove_all_objects();
-       uri_table.remove_all_objects();
-       config.reset();
-       config.remove_all_objects();
+       this->gui = gui;
 }
 
-int PluginLV2GUI::init_gui(const char *path)
+PluginLV2ClientText::~PluginLV2ClientText()
 {
-       reset_gui();
-       if( !world )
-               world = lilv_world_new();
-       if( !world ) {
-               printf("lv2_gui: lilv_world_new failed");
-               return 1;
-       }
-       lilv_world_load_all(world);
-       LilvNode *uri = lilv_new_uri(world, path);
-       if( !uri ) {
-               printf("lv2_gui: lilv_new_uri(%s) failed", path);
-               return 1;
-       }
+}
 
-       const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
-       lilv = lilv_plugins_get_by_uri(all_plugins, uri);
-       lilv_node_free(uri);
-       if( !lilv ) {
-               printf("lv2_gui: lilv_plugins_get_by_uriPlugin(%s) failed", path);
-               return 1;
-       }
+int PluginLV2ClientText::handle_event()
+{
+       return 0;
+}
 
-       LilvNode *name = lilv_plugin_get_name(lilv);
-       const char *nm = lilv_node_as_string(name);
-       snprintf(title,sizeof(title),"L2_%s",nm);
-       lilv_node_free(name);
 
-       config.init_lv2(lilv);
+PluginLV2ClientApply::PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Apply"))
+{
+       this->gui = gui;
+}
 
-       lv2_InputPort  = lilv_new_uri(world, LV2_CORE__InputPort);
-       lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
+PluginLV2ClientApply::~PluginLV2ClientApply()
+{
+}
 
-       for( int i=0; i<config.nb_ports; ++i ) {
-               const LilvPort *lp = lilv_plugin_get_port_by_index(lilv, i);
-               if( lilv_port_is_a(lilv, lp, lv2_InputPort) &&
-                   lilv_port_is_a(lilv, lp, lv2_ControlPort) ) {
-                       config.append(new PluginLV2Client_Opt(&config, i));
-               }
+int PluginLV2ClientApply::handle_event()
+{
+       const char *text = gui->text->get_text();
+       if( text && gui->selected ) {
+               gui->selected->update(atof(text));
+               gui->update_selected();
+               gui->client->send_configure_change();
        }
+       return 1;
+}
 
-       uri_map = new LV2_URI_Map_Feature();
-       uri_map->callback_data = (LV2_URI_Map_Callback_Data)this;
-       uri_map->uri_to_id = uri_to_id;
-       ui_features.append(new Lv2Feature(NS_EXT "uri-map", uri_map));
-       map.handle = (void*)&uri_table;
-       map.map = uri_table_map;
-       ui_features.append(new Lv2Feature(LV2_URID__map, &map));
-       unmap.handle = (void*)&uri_table;
-       unmap.unmap  = uri_table_unmap;
-       ui_features.append(new Lv2Feature(LV2_URID__unmap, &unmap));
-       ui_features.append(0);
-
-       int sample_rate = 64; // cant be too low
-       inst = lilv_plugin_instantiate(lilv, sample_rate, ui_features);
-       if( !inst ) {
-               printf("lv2_gui: lilv_plugin_instantiate failed: %s\n", title);
-               return 1;
-       }
 
-       uis = lilv_plugin_get_uis(lilv);
-       if( gtk_type ) {
-               LilvNode *gui_type = lilv_new_uri(world, gtk_type);
-               LILV_FOREACH(uis, i, uis) {
-                       const LilvUI *gui = lilv_uis_get(uis, i);
-                       if( lilv_ui_is_supported(gui, suil_ui_supported, gui_type, &ui_type)) {
-                               ui = gui;
-                               break;
-                       }
-               }
-               lilv_node_free(gui_type);
+PluginLV2Client_OptPanel::PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui,
+               int x, int y, int w, int h)
+ : BC_ListBox(x, y, w, h, LISTBOX_TEXT), opts(items[0]), vals(items[1])
+{
+       this->gui = gui;
+       update();  // init col/wid/columns
+}
+
+PluginLV2Client_OptPanel::~PluginLV2Client_OptPanel()
+{
+}
+
+int PluginLV2Client_OptPanel::selection_changed()
+{
+       PluginLV2Client_Opt *opt = 0;
+       BC_ListBoxItem *item = get_selection(0, 0);
+       if( item ) {
+               PluginLV2Client_OptName *opt_name = (PluginLV2Client_OptName *)item;
+               opt = opt_name->opt;
        }
-       if( !ui )
-               ui = lilv_uis_get(uis, lilv_uis_begin(uis));
-       if( !ui ) {
-               printf("lv2_gui: init_ui failed: %s\n", title);
-               return 1;
+       gui->update(opt);
+       return 1;
+}
+
+void PluginLV2Client_OptPanel::update()
+{
+       opts.remove_all();
+       vals.remove_all();
+       PluginLV2ClientConfig &conf = gui->client->config;
+       for( int i=0; i<conf.size(); ++i ) {
+               PluginLV2Client_Opt *opt = conf[i];
+               opts.append(opt->item_name);
+               vals.append(opt->item_value);
        }
+       const char *cols[] = { "option", "value", };
+       const int col1_w = 150;
+       int wids[] = { col1_w, get_w()-col1_w };
+       BC_ListBox::update(&items[0], &cols[0], &wids[0], sizeof(items)/sizeof(items[0]));
+}
 
-       lilv_instance_activate(inst);
-       return 0;
+PluginLV2ClientPot::PluginLV2ClientPot(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_FPot(x, y, 0.f, 0.f, 0.f)
+{
+       this->gui = gui;
 }
 
-void PluginLV2GUI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr)
+int PluginLV2ClientPot::handle_event()
 {
-       if( idx >= config.nb_ports ) return;
-       for( int i=0, sz=config.size(); i<sz; ++i ) {
-               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;
-                       break;
-               }
+       if( gui->selected ) {
+               gui->selected->update(get_value());
+               gui->update_selected();
+               gui->client->send_configure_change();
        }
+       return 1;
 }
-void PluginLV2GUI::write_from_ui(void *the, uint32_t idx,
-               uint32_t bfrsz, uint32_t typ, const void *bfr)
+
+PluginLV2ClientSlider::PluginLV2ClientSlider(PluginLV2ClientWindow *gui, int x, int y)
+ : BC_FSlider(x, y, 0, gui->get_w()-x-20, gui->get_w()-x-20, 0.f, 0.f, 0.f)
 {
-       ((PluginLV2GUI*)the)->update_value(idx, bfrsz, typ, bfr);
+       this->gui = gui;
 }
 
-
-uint32_t PluginLV2GUI::port_index(void* obj, const char* sym)
+int PluginLV2ClientSlider::handle_event()
 {
-       PluginLV2GUI *the = (PluginLV2GUI*)obj;
-       for( int i=0, sz=the->config.size(); i<sz; ++i ) {
-               PluginLV2Client_Opt *opt = the->config[i];
-               if( !strcmp(sym, opt->sym) ) return opt->idx;
+       if( gui->selected ) {
+               gui->selected->update(get_value());
+               gui->update_selected();
+               gui->client->send_configure_change();
        }
-       return UINT32_MAX;
+       return 1;
 }
 
-void PluginLV2GUI::update_control(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr)
+PluginLV2ClientWindow::PluginLV2ClientWindow(PluginLV2Client *client)
+ : PluginClientWindow(client, 500, 300, 500, 300, 1)
 {
-       if( !sinst || idx >= config.nb_ports ) return;
-       suil_instance_port_event(sinst, idx, bfrsz, typ, bfr);
+       this->client = client;
+       selected = 0;
 }
 
+void PluginLV2ClientWindow::done_event(int result)
+{
+       PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.del_ui(this);
+       if( ui ) ui->hide();
+}
 
-#if 0
-void PluginLV2GUI::touch(void *obj, uint32_t pidx, bool grabbed)
+PluginLV2ClientWindow::~PluginLV2ClientWindow()
 {
-       PluginLV2GUI* 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);
+       done_event(0);
 }
+
+
+void PluginLV2ClientWindow::create_objects()
+{
+       BC_Title *title;
+       int x = 10, y = 10, x1;
+       add_subwindow(title = new BC_Title(x, y, client->title));
+#ifdef HAVE_LV2UI
+       x1 = get_w() - BC_GenericButton::calculate_w(this, _("UI")) - 8;
+       add_subwindow(ui = new PluginLV2ClientUI(this, x1, y));
+#else
+       ui = 0;
 #endif
+       y += title->get_h() + 10;
+       add_subwindow(varbl = new BC_Title(x, y, ""));
+       add_subwindow(range = new BC_Title(x+160, y, ""));
+       x1 = get_w() - BC_GenericButton::calculate_w(this, _("Reset")) - 8;
+       add_subwindow(reset = new PluginLV2ClientReset(this, x1, y));
+       y += title->get_h() + 10;
+       x1 = get_w() - BC_GenericButton::calculate_w(this, _("Apply")) - 8;
+       add_subwindow(apply = new PluginLV2ClientApply(this, x1, y));
+       add_subwindow(text = new PluginLV2ClientText(this, x, y, x1-x - 8));
+       y += title->get_h() + 10;
+       add_subwindow(pot = new PluginLV2ClientPot(this, x, y));
+       x1 = x + pot->get_w() + 10;
+       add_subwindow(slider = new PluginLV2ClientSlider(this, x1, y+10));
+       y += pot->get_h() + 10;
+
+       client->init_lv2();
+       client->load_configuration();
+       client->config.update();
+
+       int panel_x = x, panel_y = y;
+       int panel_w = get_w()-10 - panel_x;
+       int panel_h = get_h()-10 - panel_y;
+       panel = new PluginLV2Client_OptPanel(this, panel_x, panel_y, panel_w, panel_h);
+       add_subwindow(panel);
+       panel->update();
+       show_window(1);
+}
 
-uint32_t PluginLV2GUI::uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri)
+int PluginLV2ClientWindow::resize_event(int w, int h)
 {
-       return ((PluginLV2UriTable *)handle)->map(uri);
+       int x1;
+#ifdef HAVE_LV2UI
+       x1 = w - ui->get_w() - 8;
+       ui->reposition_window(x1, ui->get_y());
+#endif
+       x1 = w - reset->get_w() - 8;
+       reset->reposition_window(x1, reset->get_y());
+       x1 = w - apply->get_w() - 8;
+       apply->reposition_window(x1, apply->get_y());
+       text->reposition_window(text->get_x(), text->get_y(), x1-text->get_x() - 8);
+       x1 = pot->get_x() + pot->get_w() + 10;
+       int w1 = w - slider->get_x() - 20;
+       slider->set_pointer_motion_range(w1);
+       slider->reposition_window(x1, slider->get_y(), w1, slider->get_h());
+       int panel_x = panel->get_x(), panel_y = panel->get_y();
+       panel->reposition_window(panel_x, panel_y, w-10-panel_x, h-10-panel_y);
+       return 1;
 }
 
-LV2_URID PluginLV2GUI::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
+void PluginLV2ClientWindow::update_selected()
 {
-       return ((PluginLV2UriTable *)handle)->map(uri);
+       update(selected);
+       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));
 }
 
-const char *PluginLV2GUI::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
+int PluginLV2ClientWindow::scalar(float f, char *rp)
 {
-       return ((PluginLV2UriTable *)handle)->unmap(urid);
+       const char *cp = 0;
+            if( f == FLT_MAX ) cp = "FLT_MAX";
+       else if( f == FLT_MIN ) cp = "FLT_MIN";
+       else if( f == -FLT_MAX ) cp = "-FLT_MAX";
+       else if( f == -FLT_MIN ) cp = "-FLT_MIN";
+       else if( f == 0 ) cp = signbit(f) ? "-0" : "0";
+       else if( isnan(f) ) cp = signbit(f) ? "-NAN" : "NAN";
+       else if( isinf(f) ) cp = signbit(f) ? "-INF" : "INF";
+       else return sprintf(rp, "%g", f);
+       return sprintf(rp, "%s", cp);
 }
 
-void PluginLV2GUI::lv2ui_instantiate(void *parent)
+void PluginLV2ClientWindow::update(PluginLV2Client_Opt *opt)
 {
-       if ( !ui_host ) {
-               ui_host = suil_host_new(
-                       PluginLV2GUI::write_from_ui,
-                       PluginLV2GUI::port_index,
-                       0, 0);
-//             suil_host_set_touch_func(ui_host,
-//                     PluginLV2GUI::touch);
+       if( selected != opt ) {
+               if( selected ) selected->item_name->set_selected(0);
+               selected = opt;
+               if( selected ) selected->item_name->set_selected(1);
+       }
+       char var[BCSTRLEN];  var[0] = 0;
+       char val[BCSTRLEN];  val[0] = 0;
+       char rng[BCTEXTLEN]; rng[0] = 0;
+       if( opt ) {
+               sprintf(var,"%s:", opt->conf->names[opt->idx]);
+               char *cp = rng;
+               cp += sprintf(cp,"( ");
+               float min = opt->conf->mins[opt->idx];
+               cp += scalar(min, cp);
+               cp += sprintf(cp, " .. ");
+               float max = opt->conf->maxs[opt->idx];
+               cp += scalar(max, cp);
+               cp += sprintf(cp, " )");
+               float v = opt->get_value();
+               sprintf(val, "%f", v);
+               slider->update(slider->get_w(), v, min, max);
+               pot->update(v, min, max);
+       }
+       else {
+               slider->update(slider->get_w(), 0.f, 0.f, 0.f);
+               pot->update(0.f, 0.f, 0.f);
        }
+       varbl->update(var);
+       range->update(rng);
+       text->update(val);
+       panel->update();
+}
 
-       ui_features.remove();
-       LV2_Handle lilv_handle = lilv_instance_get_handle(inst);
-       ui_features.append(new Lv2Feature(NS_EXT "instance-access", lilv_handle));
-       const LV2_Descriptor *lilv_desc = lilv_instance_get_descriptor(inst);
-       ext_data = new LV2_Extension_Data_Feature();
-       ext_data->data_access = lilv_desc->extension_data;
-       ui_features.append(new Lv2Feature(LV2_DATA_ACCESS_URI, ext_data));
-       ui_features.append(new Lv2Feature(LV2_UI__parent, parent));
-       ui_features.append(new Lv2Feature(LV2_UI__idleInterface, 0));
-       ui_features.append(0);
-
-       const char* bundle_uri  = lilv_node_as_uri(lilv_ui_get_bundle_uri(ui));
-       char*       bundle_path = lilv_file_uri_parse(bundle_uri, NULL);
-       const char* binary_uri  = lilv_node_as_uri(lilv_ui_get_binary_uri(ui));
-       char*       binary_path = lilv_file_uri_parse(binary_uri, NULL);
-       sinst = suil_instance_new(ui_host, this, gtk_type,
-               lilv_node_as_uri(lilv_plugin_get_uri(lilv)),
-               lilv_node_as_uri(lilv_ui_get_uri(ui)),
-               lilv_node_as_uri(ui_type),
-               bundle_path, binary_path, ui_features);
-
-       lilv_free(binary_path);
-       lilv_free(bundle_path);
+void PluginLV2ClientWindow::lv2_update()
+{
+       lock_window("PluginLV2ClientWindow::lv2_update");
+       PluginLV2ClientConfig &conf = client->config;
+       int ret = conf.update();
+       if( ret > 0 ) update(0);
+       unlock_window();
+       if( ret > 0 )
+               client->send_configure_change();
 }
 
-bool PluginLV2GUI::lv2ui_resizable()
+void PluginLV2ClientWindow::lv2_update(float *vals)
 {
-       if( !ui ) return false;
-        const LilvNode* s   = lilv_ui_get_uri(ui);
-        LilvNode *p   = lilv_new_uri(world, LV2_CORE__optionalFeature);
-        LilvNode *fs  = lilv_new_uri(world, LV2_UI__fixedSize);
-        LilvNode *nrs = lilv_new_uri(world, LV2_UI__noUserResize);
-        LilvNodes *fs_matches = lilv_world_find_nodes(world, s, p, fs);
-        LilvNodes *nrs_matches = lilv_world_find_nodes(world, s, p, nrs);
-        lilv_nodes_free(nrs_matches);
-        lilv_nodes_free(fs_matches);
-        lilv_node_free(nrs);
-        lilv_node_free(fs);
-        lilv_node_free(p);
-        return !fs_matches && !nrs_matches;
+       PluginLV2ClientConfig &conf = client->config;
+       int nb_ports = conf.nb_ports;
+       float *ctls = conf.ctls;
+       for( int i=0; i<nb_ports; ++i ) *ctls++ = *vals++;
+       lv2_update();
 }
 
-int PluginLV2GUI::update_lv2(float *vals, int force)
+void PluginLV2ClientWindow::lv2_set(int idx, float val)
 {
-       int ret = 0;
-       float *ctls = (float *)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);
-               ++ret;
-       }
-       for( int i=0; i<config.nb_ports; ++i ) ctls[i] = vals[i];
-       return ret;
+       PluginLV2ClientConfig &conf = client->config;
+       conf[idx]->set_value(val);
+       lv2_update();
 }
 
-#endif /* HAVE_LV2UI */
index eed7143a011183191dbdf7d81cf8a0086a8e0901..a3e6624dfd3baedbcf2c0b4bbd2836159d48e653 100644 (file)
+#ifndef __PLUGINLV2GUI_H__
+#define __PLUGINLV2GUI_H__
 
-/*
- * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 __PLUGINLV2UI_H__
-#define __PLUGINLV2UI_H__
-
+#include "guicast.h"
 #include "forkbase.h"
 #include "pluginlv2gui.inc"
-#include "pluginlv2client.h"
+#include "pluginlv2ui.h"
+#include "pluginaclient.h"
+
+class PluginLV2ClientUI : public BC_GenericButton {
+public:
+       PluginLV2ClientWindow *gui;
+
+       PluginLV2ClientUI(PluginLV2ClientWindow *gui, int x, int y);
+       ~PluginLV2ClientUI();
+       int handle_event();
+};
 
-class PluginLV2GUI
+class PluginLV2ClientReset : public BC_GenericButton
 {
 public:
-       PluginLV2GUI();
-       ~PluginLV2GUI();
-
-       void reset_gui(void);
-       int init_gui(const char *path);
-       void update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr);
-       static void write_from_ui(void *the, uint32_t 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 uint32_t port_index(void *obj,const char *sym);
-       static void touch(void *obj,uint32_t pidx,bool grabbed);
-       static uint32_t uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri);
-       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 lv2ui_instantiate(void *parent);
-       bool lv2ui_resizable();
-       void host_update(PluginLV2ChildGUI *child);
-       int run(int ac, char **av);
-
-       PluginLV2ClientConfig config;
-       PluginLV2UriTable  uri_table;
-       LV2_URI_Map_Feature *uri_map;
-       LV2_Extension_Data_Feature *ext_data;
-       LV2_URID_Map       map;
-       LV2_URID_Unmap     unmap;
-       Lv2Features        ui_features;
-       LilvNode *lv2_InputPort;
-       LilvNode *lv2_ControlPort;
-
-       LilvWorld *world;
-        const LilvPlugin *lilv;
-       LilvInstance *inst;
-        LilvUIs* uis;
-       const LilvUI *ui;
-        const LilvNode *ui_type;
-
-#ifdef HAVE_LV2UI
-       SuilInstance *sinst;
-       SuilHost *ui_host;
-#endif
+       PluginLV2ClientWindow *gui;
 
-       char title[BCSTRLEN];
-       const char *gtk_type;
-       uint32_t last, updates;
-       int done, running;
+       PluginLV2ClientReset(PluginLV2ClientWindow *gui, int x, int y);
+       ~PluginLV2ClientReset();
+       int handle_event();
+};
 
-       void start();
-       void stop();
-       int update_lv2(float *vals, int force);
-       int redraw;
+class PluginLV2ClientText : public BC_TextBox {
+public:
+       PluginLV2ClientWindow *gui;
 
-       void run_gui(PluginLV2ChildGUI *child=0);
+       PluginLV2ClientText(PluginLV2ClientWindow *gui, int x, int y, int w);
+       ~PluginLV2ClientText();
+       int handle_event();
 };
 
-enum { NO_COMMAND,
-       LV2_OPEN,
-       LV2_LOAD,
-       LV2_UPDATE,
-       LV2_START,
-       LV2_SET,
-       NB_COMMANDS };
+class PluginLV2ClientApply : public BC_GenericButton {
+public:
+       PluginLV2ClientWindow *gui;
 
-typedef struct { int idx;  float value; } control_t;
+       PluginLV2ClientApply(PluginLV2ClientWindow *gui, int x, int y);
+       ~PluginLV2ClientApply();
+       int handle_event();
+};
 
-class PluginLV2ParentGUI : public ForkParent
+class PluginLV2Client_OptPanel : public BC_ListBox
 {
 public:
-       PluginLV2ParentGUI(PluginLV2ClientWindow *gui);
-       ~PluginLV2ParentGUI();
-       ForkChild* new_fork();
-       void start_parent();
+       PluginLV2Client_OptPanel(PluginLV2ClientWindow *gui, int x, int y, int w, int h);
+       ~PluginLV2Client_OptPanel();
+
+       PluginLV2ClientWindow *gui;
+       ArrayList<BC_ListBoxItem*> items[2];
+       ArrayList<BC_ListBoxItem*> &opts;
+       ArrayList<BC_ListBoxItem*> &vals;
+
+       int selection_changed();
+       void update();
+};
 
-       int handle_parent();
+class PluginLV2ClientPot : public BC_FPot
+{
+public:
+       PluginLV2ClientPot(PluginLV2ClientWindow *gui, int x, int y);
+       int handle_event();
        PluginLV2ClientWindow *gui;
 };
 
-class PluginLV2ChildGUI : public ForkChild
+class PluginLV2ClientSlider : public BC_FSlider
 {
 public:
-       PluginLV2ChildGUI();
-       ~PluginLV2ChildGUI();
+       PluginLV2ClientSlider(PluginLV2ClientWindow *gui, int x, int y);
+       int handle_event();
+       PluginLV2ClientWindow *gui;
+};
 
-       int handle_child();
-       void run();
-       int run(int ac, char **av);
+class PluginLV2ClientWindow : public PluginClientWindow
+{
+public:
+       PluginLV2ClientWindow(PluginLV2Client *client);
+       ~PluginLV2ClientWindow();
+       void done_event(int result);
+
+       void create_objects();
+       int resize_event(int w, int h);
+       void update_selected();
+       void update_selected(float v);
+       int scalar(float f, char *rp);
+       void update(PluginLV2Client_Opt *opt);
+       void lv2_update();
+       void lv2_update(float *vals);
+       void lv2_set(int idx, float val);
+       PluginLV2ParentUI *find_ui();
+       PluginLV2ParentUI *get_ui();
+
+       PluginLV2Client *client;
+       PluginLV2ClientUI *ui;
+       PluginLV2ClientReset *reset;
+       PluginLV2ClientApply *apply;
+       PluginLV2ClientPot *pot;
+       PluginLV2ClientSlider *slider;
+       PluginLV2ClientText *text;
+       BC_Title *varbl, *range;
+       PluginLV2Client_OptPanel *panel;
+       PluginLV2Client_Opt *selected;
 
-       PluginLV2GUI *lv2_gui;
-// Command tokens
 };
 
 #endif
index 033986c3ce1836989238872f5b412e3e865e4f49..f282cc59ce3fe7b36a8dbe0b9e9ca77fce17c7ca 100644 (file)
@@ -1,8 +1,14 @@
 #ifndef __PLUGINLV2GUI_INC__
 #define __PLUGINLV2GUI_INC__
 
-class PluginLV2GUI;
-class PluginLV2ParentGUI;
-class PluginLV2ChildGUI;
+class PluginLV2ClientUI;
+class PluginLV2ClientReset;
+class PluginLV2ClientText;
+class PluginLV2ClientApply;
+class PluginLV2Client_OptPanel;
+class PluginLV2ClientPot;
+class PluginLV2ClientSlider;
+class PluginLV2ClientWindow;
+class PluginLV2ParentUI;
 
 #endif
diff --git a/cinelerra-5.1/cinelerra/pluginlv2ui.C b/cinelerra-5.1/cinelerra/pluginlv2ui.C
new file mode 100644 (file)
index 0000000..904f954
--- /dev/null
@@ -0,0 +1,310 @@
+#ifdef HAVE_LV2UI
+
+// shared between parent/child fork
+#include "language.h"
+#include "pluginlv2ui.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include <ctype.h>
+#include <string.h>
+
+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;
+       for( int i=0, sz=config.size(); i<sz; ++i ) {
+               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;
+                       break;
+               }
+       }
+}
+void PluginLV2UI::write_from_ui(void *the, uint32_t idx,
+               uint32_t bfrsz, uint32_t typ, const void *bfr)
+{
+       ((PluginLV2UI*)the)->update_value(idx, bfrsz, typ, bfr);
+}
+
+uint32_t PluginLV2UI::port_index(void* obj, const char* sym)
+{
+       PluginLV2UI *the = (PluginLV2UI*)obj;
+       for( int i=0, sz=the->config.size(); i<sz; ++i ) {
+               PluginLV2Client_Opt *opt = the->config[i];
+               if( !strcmp(sym, opt->sym) ) return opt->idx;
+       }
+       return UINT32_MAX;
+}
+
+void PluginLV2UI::update_control(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr)
+{
+       if( !sinst || idx >= config.nb_ports ) return;
+       suil_instance_port_event(sinst, idx, bfrsz, typ, bfr);
+}
+
+
+#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);
+}
+
+LV2_URID PluginLV2UI::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
+{
+       return ((PluginLV2UriTable *)handle)->map(uri);
+}
+
+const char *PluginLV2UI::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
+{
+       return ((PluginLV2UriTable *)handle)->unmap(urid);
+}
+
+void PluginLV2UI::lv2ui_instantiate(void *parent)
+{
+       if ( !ui_host ) {
+               ui_host = suil_host_new(
+                       PluginLV2UI::write_from_ui,
+                       PluginLV2UI::port_index,
+                       0, 0);
+//             suil_host_set_touch_func(ui_host,
+//                     PluginLV2GUI::touch);
+       }
+
+       features.remove();  // remove terminating zero
+       ui_features = features.size();
+       LV2_Handle lilv_handle = lilv_instance_get_handle(inst);
+       features.append(new Lv2Feature(NS_EXT "instance-access", lilv_handle));
+       const LV2_Descriptor *lilv_desc = lilv_instance_get_descriptor(inst);
+       ext_data = new LV2_Extension_Data_Feature();
+       ext_data->data_access = lilv_desc->extension_data;
+       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(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,
+               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),
+               bundle_path, binary_path, features);
+
+       lilv_free(binary_path);
+       lilv_free(bundle_path);
+}
+
+bool PluginLV2UI::lv2ui_resizable()
+{
+       if( !lilv_ui ) return false;
+       const LilvNode* s   = lilv_ui_get_uri(lilv_ui);
+       LilvNode *p   = lilv_new_uri(world, LV2_CORE__optionalFeature);
+       LilvNode *fs  = lilv_new_uri(world, LV2_UI__fixedSize);
+       LilvNode *nrs = lilv_new_uri(world, LV2_UI__noUserResize);
+       LilvNodes *fs_matches = lilv_world_find_nodes(world, s, p, fs);
+       LilvNodes *nrs_matches = lilv_world_find_nodes(world, s, p, nrs);
+       lilv_nodes_free(nrs_matches);
+       lilv_nodes_free(fs_matches);
+       lilv_node_free(nrs);
+       lilv_node_free(fs);
+       lilv_node_free(p);
+       return !fs_matches && !nrs_matches;
+}
+
+int PluginLV2UI::update_lv2(float *vals, int force)
+{
+       int ret = 0;
+       float *ctls = (float *)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);
+               ++ret;
+       }
+       for( int i=0; i<config.nb_ports; ++i ) ctls[i] = vals[i];
+       return ret;
+}
+
+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()
+{
+       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);
+
+       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);
+       lv2ui_instantiate(alignment);
+       GtkWidget* widget = (GtkWidget*)suil_instance_get_widget(sinst);
+       gtk_container_add(GTK_CONTAINER(alignment), widget);
+       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);
+       gtk_window_present(GTK_WINDOW(top_level));
+}
+
+
+void PluginLV2UI::host_update(PluginLV2ChildUI *child)
+{
+//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);
+       }
+       if( running < 0 ) { running = 1;  return; }
+       child->send_parent(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
+}
+
+void PluginLV2UI::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;
+}
+
+
+// child main
+int PluginLV2UI::run_ui(PluginLV2ChildUI *child)
+{
+       running = 1;
+       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( !child ) usleep(10000);
+               else if( child->child_iteration() < 0 )
+                       done = 1;
+       }
+       running = 0;
+       return 0;
+}
+
+void PluginLV2UI::run_buffer(int shmid)
+{
+       if( !shm_buffer(shmid) ) return;
+       map_buffer();
+       int samples = shm_bfr->samples;
+       connect_ports(config);
+       lilv_instance_run(inst, samples);
+       shm_bfr->done = 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 *ctls = (float *)child_data;
+               update_lv2(ctls, 1);
+               break; }
+       case LV2_UPDATE: {
+               float *ctls = (float *)child_data;
+               if( update_lv2(ctls, 0) > 0 )
+                       ++updates;
+               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;
+               break; }
+       case LV2_SHMID: {
+               int shmid = *(int *)child_data;
+               run_buffer(shmid);
+               send_parent(LV2_SHMID, 0, 0);
+               break; }
+       case EXIT_CODE:
+               return -1;
+       }
+       return 1;
+}
+
+#endif /* HAVE_LV2UI */
diff --git a/cinelerra-5.1/cinelerra/pluginlv2ui.h b/cinelerra-5.1/cinelerra/pluginlv2ui.h
new file mode 100644 (file)
index 0000000..75fe826
--- /dev/null
@@ -0,0 +1,95 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 __PLUGINLV2UI_H__
+#define __PLUGINLV2UI_H__
+
+#ifdef HAVE_LV2UI
+
+#include "forkbase.h"
+#include "pluginlv2.h"
+#include "pluginlv2client.h"
+#include "pluginlv2gui.inc"
+#include "pluginlv2ui.inc"
+
+typedef struct _GtkWidget GtkWidget;
+
+class PluginLV2UI : public PluginLV2
+{
+public:
+       PluginLV2UI();
+       ~PluginLV2UI();
+
+       const LilvUI *lilv_ui;
+       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;
+
+       char title[BCSTRLEN];
+       PluginLV2ClientConfig config;
+       uint32_t host_updates, updates;
+       int host_hidden, hidden;
+       int done, running;
+       const char *gtk_type;
+       GtkWidget *top_level;
+
+       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;
+
+       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,
+               uint32_t bfrsz, uint32_t typ, const void *bfr);
+       static uint32_t port_index(void* obj, const char* sym);
+
+//     static void touch(void *obj,uint32_t pidx,bool grabbed);
+       static uint32_t uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri);
+       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 lv2ui_instantiate(void *parent);
+       bool lv2ui_resizable();
+       void start_gui();
+       int run_ui(PluginLV2ChildUI *child=0);
+       void run_buffer(int shmid);
+       void host_update(PluginLV2ChildUI *child);
+       int run(int ac, char **av);
+};
+
+class PluginLV2ChildUI : public ForkChild, public PluginLV2UI
+{
+public:
+       PluginLV2ChildUI();
+       ~PluginLV2ChildUI();
+       void run();
+
+       int handle_child();
+       int run(int ac, char **av);
+};
+#endif
+#endif
diff --git a/cinelerra-5.1/cinelerra/pluginlv2ui.inc b/cinelerra-5.1/cinelerra/pluginlv2ui.inc
new file mode 100644 (file)
index 0000000..5b8309b
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __PLUGINLV2UI_INC__
+#define __PLUGINLV2UI_INC__
+
+class PluginLV2UI;
+class PluginLV2ChildUI;
+
+#endif
index 6bd8169e4a4a5e31be0b98b6973543bd293d4f7e..e57110cab9bb76a15299c195bceef055dca32d3e 100644 (file)
@@ -92,11 +92,11 @@ int Condition::timed_lock(int microseconds, const char *location)
        struct timeval now;
        gettimeofday(&now, 0);
 #if 1
-       struct timespec timeout;
-       timeout.tv_sec = now.tv_sec + microseconds / 1000000;
-       timeout.tv_nsec = now.tv_usec * 1000 + (microseconds % 1000000) * 1000;
-       while(value <= 0 && result != ETIMEDOUT)
-       {
+       int64_t nsec = now.tv_usec * 1000 + (microseconds % 1000000) * 1000;
+       int64_t sec = nsec / 1000000000;  nsec %= 1000000000;
+       sec += now.tv_sec + microseconds / 1000000;
+       struct timespec timeout;  timeout.tv_sec = sec;   timeout.tv_nsec = nsec;
+       while( value <= 0 && result != ETIMEDOUT ) {
                result = pthread_cond_timedwait(&cond, &mutex, &timeout);
        }
 
index ab153add45b218170eb639e1391598bf71d47998..c61317eed575155ce5174fbfa427ec62a9b2f8ac 100644 (file)
@@ -53,13 +53,4 @@ public:
        const char *title;
 };
 
-class mLock
-{
-       Mutex &mutex;
-public:
-       mLock(Mutex &m) : mutex(m) { mutex.lock(); }
-       mLock(Mutex *m) : mutex(*m) { mutex.lock(); }
-       ~mLock() { mutex.unlock(); }
-};
-
 #endif
diff --git a/cinelerra-5.1/picon/cinfinity/ff_entropy.png b/cinelerra-5.1/picon/cinfinity/ff_entropy.png
new file mode 100644 (file)
index 0000000..c1d5b4b
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity/ff_entropy.png differ
diff --git a/cinelerra-5.1/picon/cinfinity/ff_fillborders.png b/cinelerra-5.1/picon/cinfinity/ff_fillborders.png
new file mode 100644 (file)
index 0000000..2958473
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity/ff_fillborders.png differ
diff --git a/cinelerra-5.1/picon/cinfinity/ff_normalize.png b/cinelerra-5.1/picon/cinfinity/ff_normalize.png
new file mode 100644 (file)
index 0000000..fade41f
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity/ff_normalize.png differ
diff --git a/cinelerra-5.1/picon/cinfinity/ff_setrange.png b/cinelerra-5.1/picon/cinfinity/ff_setrange.png
new file mode 100644 (file)
index 0000000..4794bc6
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity/ff_setrange.png differ
diff --git a/cinelerra-5.1/picon/cinfinity/ff_vfrdet.png b/cinelerra-5.1/picon/cinfinity/ff_vfrdet.png
new file mode 100644 (file)
index 0000000..5f5e96f
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity/ff_vfrdet.png differ
diff --git a/cinelerra-5.1/picon/cinfinity2/ff_entropy.png b/cinelerra-5.1/picon/cinfinity2/ff_entropy.png
new file mode 100644 (file)
index 0000000..b89d9d3
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity2/ff_entropy.png differ
diff --git a/cinelerra-5.1/picon/cinfinity2/ff_fillborders.png b/cinelerra-5.1/picon/cinfinity2/ff_fillborders.png
new file mode 100644 (file)
index 0000000..6ee43f4
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity2/ff_fillborders.png differ
diff --git a/cinelerra-5.1/picon/cinfinity2/ff_normalize.png b/cinelerra-5.1/picon/cinfinity2/ff_normalize.png
new file mode 100644 (file)
index 0000000..e7f1133
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity2/ff_normalize.png differ
diff --git a/cinelerra-5.1/picon/cinfinity2/ff_setrange.png b/cinelerra-5.1/picon/cinfinity2/ff_setrange.png
new file mode 100644 (file)
index 0000000..a922c42
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity2/ff_setrange.png differ
diff --git a/cinelerra-5.1/picon/cinfinity2/ff_vfrdet.png b/cinelerra-5.1/picon/cinfinity2/ff_vfrdet.png
new file mode 100644 (file)
index 0000000..7e1b817
Binary files /dev/null and b/cinelerra-5.1/picon/cinfinity2/ff_vfrdet.png differ
index bd7d85910e4f4a305a1070d0268b62121c0c1f95..6ed357c71455c4958e148fe9d28dbefd1db58db5 100644 (file)
@@ -171,7 +171,7 @@ all:        $(PLUGIN_DIR) $(DIRS) $(DATA) $(LADSPA_DIR)
 $(PLUGIN_DIR):
        mkdir -p $@
 
-$(DATA):
+$(DATA):       $(PLUGIN_DIR)
        cp -a $(notdir $@) $(PLUGIN_DIR)/.
 
 $(LADSPA_DIR):