#ifdef HAVE_LV2 #include "bctrace.h" #include "bcwindowbase.h" #include "pluginlv2.h" #include "samples.h" #include #include 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; imap(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; iatom.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; inb_outputs; oport = (int *)bp; bp += sizeof(oport[0])*nb_outputs; out_buffers = new float*[nb_outputs]; for( int i=0; i 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