$(OBJDIR)/pluginclient.o \
$(OBJDIR)/plugindialog.o \
$(OBJDIR)/pluginfclient.o \
+ $(OBJDIR)/pluginlv2.o \
$(OBJDIR)/pluginlv2config.o \
$(OBJDIR)/pluginlv2client.o \
$(OBJDIR)/pluginlv2gui.o \
LV2UI = $(OBJDIR)/lv2ui
LV2OBJS = \
$(OBJDIR)/lv2ui.o \
- $(OBJDIR)/pluginlv2gui.o \
+ $(OBJDIR)/pluginlv2.o \
+ $(OBJDIR)/pluginlv2ui.o \
$(OBJDIR)/pluginlv2config.o \
$(OBJDIR)/forkbase.o
endif
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
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)
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);
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;
}
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;
}
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);
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];
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;
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
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);
#include <unistd.h>
ForkBase::ForkBase()
+ : Mutex("ForkBase::lock")
{
- pid = 0;
+ ppid = pid = 0;
child = 0;
child_fd = -1;
parent_bytes = 0;
parent_allocated = 0;
parent_data = 0;
-
}
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);
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
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;
}
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;
}
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;
}
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
{
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();
}
#include <stdint.h>
-class ForkBase
+class ForkBase : public Mutex
{
public:
enum { EXIT_CODE=0x7fff };
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;
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
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
#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);
}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#ifndef __PLUGINLV2_INC__
+#define __PLUGINLV2_INC__
+
+class PluginLV2;
+
+#endif
*
*/
+#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();
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);
}
}
}
-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);
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;
}
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:
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"
+#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);
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
*
*/
-#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
#include <string.h>
PluginLV2UriTable::PluginLV2UriTable()
+ : Mutex("PluginLV2UriTable::PluginLV2UriTable")
{
set_array_delete();
}
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)
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();
-#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 */
+#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
#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
--- /dev/null
+#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 */
--- /dev/null
+
+/*
+ * 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
--- /dev/null
+#ifndef __PLUGINLV2UI_INC__
+#define __PLUGINLV2UI_INC__
+
+class PluginLV2UI;
+class PluginLV2ChildUI;
+
+#endif
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);
}
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
$(PLUGIN_DIR):
mkdir -p $@
-$(DATA):
+$(DATA): $(PLUGIN_DIR)
cp -a $(notdir $@) $(PLUGIN_DIR)/.
$(LADSPA_DIR):