5 * Copyright (C) 2018 GG
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "edlsession.h"
29 #include "filesystem.h"
32 #include "mainerror.h"
35 #include "pluginlv2client.h"
36 #include "pluginlv2config.h"
37 #include "pluginlv2ui.inc"
38 #include "pluginserver.h"
39 #include "pluginset.h"
40 #include "preferences.h"
48 PluginLV2UIs PluginLV2ParentUI::plugin_lv2;
50 PluginLV2UIs::PluginLV2UIs()
51 : Mutex("PluginLV2UIs")
55 PluginLV2UIs::~PluginLV2UIs()
60 void PluginLV2UIs::del_uis()
62 while( size() ) remove_object();
65 PluginLV2ParentUI *PluginLV2UIs::del_ui(PluginLV2Client *client)
67 lock("PluginLV2UIs::del_ui client");
69 while( --i >= 0 && get(i)->client != client );
70 PluginLV2ParentUI *ui = 0;
72 if( (ui=get(i))->gui ) ui->client = 0;
73 else { remove_object_number(i); ui = 0; }
78 PluginLV2ParentUI *PluginLV2UIs::del_ui(PluginLV2ClientWindow *gui)
80 lock("PluginLV2UIs::del_ui gui");
82 while( --i >= 0 && get(i)->gui != gui );
83 PluginLV2ParentUI *ui = 0;
85 if( (ui=get(i))->client ) ui->gui = 0;
86 else { remove_object_number(i); ui = 0; }
92 PluginLV2ParentUI *PluginLV2UIs::add_ui(PluginLV2ParentUI *ui, PluginLV2Client *client)
95 ui->start_parent(client);
100 PluginLV2ParentUI *PluginLV2UIs::search_ui(int plugin_id)
102 PluginLV2ParentUI *ui = 0;
103 for( int i=size(); !ui && --i>=0; ) {
104 PluginLV2ParentUI *parent_ui = get(i);
105 if( parent_ui->plugin_id == plugin_id )
111 PluginLV2ParentUI *PluginLV2UIs::find_ui(int plugin_id)
113 if( plugin_id < 0 ) return 0;
114 lock("PluginLV2UIs::find_ui");
115 PluginLV2ParentUI *ui = search_ui(plugin_id);
119 PluginLV2ParentUI *PluginLV2Client::find_ui()
121 return PluginLV2ParentUI::plugin_lv2.find_ui(server->plugin_id);
123 PluginLV2ParentUI *PluginLV2ClientWindow::find_ui()
125 return PluginLV2ParentUI::plugin_lv2.find_ui(client->server->plugin_id);
128 PluginLV2ParentUI *PluginLV2UIs::get_ui(PluginLV2Client *client)
130 lock("PluginLV2UIs::get_ui");
131 int plugin_id = client->server->plugin_id;
132 PluginLV2ParentUI *ui = plugin_id >= 0 ? search_ui(plugin_id) : 0;
133 if( !ui ) ui = add_ui(new PluginLV2ParentUI(plugin_id), client);
137 PluginLV2ParentUI *PluginLV2Client::get_ui()
139 PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.get_ui(this);
143 PluginLV2ParentUI *PluginLV2ClientWindow::get_ui()
145 PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.get_ui(client);
151 PluginLV2Client::PluginLV2Client(PluginServer *server)
152 : PluginAClient(server), PluginLV2()
157 PluginLV2Client::~PluginLV2Client()
159 PluginLV2ParentUI::plugin_lv2.del_ui(this);
162 NEW_WINDOW_MACRO(PluginLV2Client, PluginLV2ClientWindow)
164 int PluginLV2Client::init_lv2()
166 int bfrsz = block_length;
167 EDL *edl = server->edl;
169 PlaybackConfig *playback_config = edl->session->playback_config;
170 bfrsz = playback_config->aconfig->fragment_size;
172 int sample_rate = get_project_samplerate();
173 if( sample_rate < 64 ) sample_rate = samplerate;
174 return PluginLV2::init_lv2(config, sample_rate, bfrsz);
177 int PluginLV2Client::load_configuration()
179 int64_t src_position = get_source_position();
180 KeyFrame *prev_keyframe = get_prev_keyframe(src_position);
181 if( prev_keyframe->is_default ) return 0;
182 PluginLV2ClientConfig curr_config;
183 curr_config.copy_from(config);
184 read_data(prev_keyframe);
185 int ret = !config.equivalent(curr_config) ? 1 : 0;
189 void PluginLV2Client::update_gui()
191 PluginClientThread *thread = get_thread();
192 if( !thread ) return;
193 PluginLV2ClientWindow *gui = (PluginLV2ClientWindow*)thread->get_window();
194 gui->lock_window("PluginFClient::update_gui");
195 load_configuration();
196 if( config.update() > 0 ) {
197 gui->update_selected();
198 update_lv2(LV2_UPDATE);
200 gui->unlock_window();
203 void PluginLV2Client::update_lv2(int token)
205 PluginLV2ParentUI *ui = find_ui();
207 ui->send_child(token, config.ctls, sizeof(float)*config.nb_ports);
211 int PluginLV2Client::is_realtime() { return 1; }
212 int PluginLV2Client::is_multichannel() { return nb_inputs > 1 || nb_outputs > 1 ? 1 : 0; }
213 const char* PluginLV2Client::plugin_title() { return title; }
214 int PluginLV2Client::uses_gui() { return 1; }
215 int PluginLV2Client::is_synthesis() { return 1; }
217 char* PluginLV2Client::to_string(char *string, const char *input)
220 for( const char *cp=input; *cp; ++cp )
221 *bp++ = isalnum(*cp) ? *cp : '_';
226 void PluginLV2Client::save_data(KeyFrame *keyframe)
229 output.set_shared_output(keyframe->xbuf);
230 char name[BCTEXTLEN]; to_string(name, plugin_title());
231 output.tag.set_title(name);
232 for( int i=0; i<config.size(); ++i ) {
233 PluginLV2Client_Opt *opt = config[i];
234 output.tag.set_property(opt->get_symbol(), opt->get_value());
237 output.terminate_string();
240 void PluginLV2Client::read_data(KeyFrame *keyframe)
243 input.set_shared_input(keyframe->xbuf);
244 char name[BCTEXTLEN]; to_string(name, plugin_title());
246 while( !input.read_tag() ) {
247 if( !input.tag.title_is(name) ) continue;
248 for( int i=0; i<config.size(); ++i ) {
249 PluginLV2Client_Opt *opt = config[i];
250 float v = opt->get_value();
251 float value = input.tag.get_property(opt->get_symbol(), v);
253 opt->set_value(value);
258 void PluginLV2Client::load_buffer(int samples, Samples **input, int ich)
260 for( int i=0; i<nb_inputs; ++i ) {
261 int k = i < ich ? i : 0;
262 double *inp = input[k]->get_data();
263 float *ip = in_buffers[i];
264 for( int j=samples; --j>=0; *ip++=*inp++ );
266 for( int i=0; i<nb_outputs; ++i )
267 bzero(out_buffers[i], samples*sizeof(float));
270 int PluginLV2Client::unload_buffer(int samples, Samples **output, int och)
272 if( nb_outputs < och ) och = nb_outputs;
273 for( int i=0; i<och; ++i ) {
274 double *outp = output[i]->get_data();
275 float *op = out_buffers[i];
276 for( int j=samples; --j>=0; *outp++=*op++ );
281 void PluginLV2Client::process_buffer(int size)
283 PluginLV2ParentUI *ui = get_ui();
286 ui->send_child(LV2_SHMID, &shmid, sizeof(shmid));
287 // timeout 10*duration, min 2sec, max 10sec
288 double sample_rate = get_project_samplerate();
289 double t = !sample_rate ? 2. : 10. * size / sample_rate;
291 ui->output_bfr->timed_lock(t*1e6, "PluginLV2Client::process_buffer");
293 eprintf("timeout: %s",server->title);
296 int PluginLV2Client::process_realtime(int64_t size,
297 Samples **input_ptr, Samples **output_ptr, int chs)
299 int64_t pos = get_source_position();
300 int64_t end = pos + size;
303 KeyFrame *prev_keyframe = get_prev_keyframe(pos);
304 if( !prev_keyframe->is_default ) {
305 read_data(prev_keyframe);
306 update_lv2(LV2_CONFIG);
308 KeyFrame *next_keyframe = get_next_keyframe(pos);
309 int64_t next_pos = next_keyframe->position;
310 if( pos >= next_pos || next_pos > end )
312 int64_t len = next_pos - pos;
313 if( len > block_length )
315 if( pos + len > end )
318 for( int i=chs; --i>=0; ) {
319 input_ptr[i]->set_offset(samples);
320 output_ptr[i]->set_offset(samples);
322 load_buffer(len, input_ptr, chs);
324 unload_buffer(len, output_ptr, chs);
328 for( int i=chs; --i>=0; )
329 output_ptr[i]->set_offset(0);
333 int PluginLV2Client::process_realtime(int64_t size,
334 Samples **input_ptr, Samples **output_ptr)
336 return process_realtime(size, input_ptr, output_ptr,
337 PluginClient::total_out_buffers);
340 int PluginLV2Client::process_realtime(int64_t size,
341 Samples *input_ptr, Samples *output_ptr)
343 return process_realtime(size, &input_ptr, &output_ptr, 1);
346 PluginLV2BlackList::PluginLV2BlackList(const char *path)
349 char lv2_blacklist_path[BCTEXTLEN];
350 sprintf(lv2_blacklist_path, "%s/%s", File::get_cindat_path(), path);
351 FILE *bfp = fopen(lv2_blacklist_path, "r");
353 while( fgets(lv2_blacklist_path, sizeof(lv2_blacklist_path), bfp) ) {
354 if( lv2_blacklist_path[0] == '#' ) continue;
355 int len = strlen(lv2_blacklist_path);
356 if( len > 0 && lv2_blacklist_path[len-1] == '\n' )
357 lv2_blacklist_path[len-1] = 0;
358 if( !lv2_blacklist_path[0] ) continue;
359 append(cstrdup(lv2_blacklist_path));
364 PluginLV2BlackList::~PluginLV2BlackList()
366 remove_all_objects();
369 int PluginLV2BlackList::is_badboy(const char *uri)
372 for( int i=size(); --i>=0; )
373 if( !fs.test_filter(uri, get(i)) ) return 1;
377 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name)
379 return new PluginServer(mwindow, name, PLUGIN_TYPE_LV2);
382 PluginClient *PluginServer::new_lv2_plugin()
384 PluginLV2Client *client = new PluginLV2Client(this);
385 if( client->load_lv2(path, client->title) ) { delete client; return client = 0; }
386 if( client->init_lv2() ) { delete client; return client = 0; };
390 int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp)
392 printf("build lv2 index for: %s\n", preferences->lv2_path);
393 PluginLV2BlackList blacklist("lv2_blacklist.txt");
395 LilvWorld *world = lilv_world_new();
396 lilv_world_load_all(world);
397 const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
399 LILV_FOREACH(plugins, i, all_plugins) {
400 const LilvPlugin *lilv = lilv_plugins_get(all_plugins, i);
401 const char *uri = lilv_node_as_uri(lilv_plugin_get_uri(lilv));
402 if( blacklist.is_badboy(uri) ) continue;
403 // TODO It would be nice to print the full path of this particular plugin
404 // in case it fails, because the systems' LV2 path might include multiple
405 // directories. But function lilv_uri_to_path does not like the uri.
407 // Don't print the newline, so called functions can concatenate their
408 // error to the name.
409 printf("LOAD: %s ", uri);
410 PluginServer server(mwindow, uri, PLUGIN_TYPE_LV2);
411 int result = server.open_plugin(1, preferences, 0, 0);
413 server.write_table(fp, uri, PLUGIN_LV2_ID, 0);
414 server.close_plugin();
419 lilv_world_free(world);
423 PluginLV2ParentUI::PluginLV2ParentUI(int plugin_id)
425 this->plugin_id = plugin_id;
426 output_bfr = new Condition(0, "PluginLV2ParentUI::output_bfr", 1);
432 PluginLV2ParentUI::~PluginLV2ParentUI()
438 void PluginLV2ParentUI::start_parent(PluginLV2Client *client)
441 const char *path = client->server->path;
442 int len = sizeof(open_bfr_t) + strlen(path);
443 char bfr[len]; memset(bfr, 0, len);
444 open_bfr_t *open_bfr = (open_bfr_t *)bfr;
445 open_bfr->sample_rate = client->get_project_samplerate();
446 PlaybackConfig *playback_config = client->server->edl->session->playback_config;
447 open_bfr->bfrsz = playback_config->aconfig->fragment_size;
448 strcpy(open_bfr->path, path);
449 send_child(LV2_OPEN, open_bfr, len);
450 PluginLV2ClientConfig &conf = client->config;
451 send_child(LV2_LOAD, conf.ctls, conf.nb_ports*sizeof(float));
454 int PluginLV2ParentUI::handle_parent()
458 switch( parent_token ) {
461 gui->lv2_update((float *)parent_data);
468 gui->lv2_ui_enable();
472 output_bfr->unlock();
476 output_bfr->unlock();
487 int PluginLV2ParentUI::show()
489 if( !hidden ) return 1;
490 send_child(LV2_SHOW, 0, 0);
494 int PluginLV2ParentUI::hide()
496 if( hidden ) return 1;
497 send_child(LV2_HIDE, 0, 0);
501 ForkChild *PluginLV2ParentUI::new_fork()
503 return new PluginLV2ChildUI();
507 int PluginLV2ChildUI::child_iteration(int64_t usec) { return -1; }
508 int PluginLV2ChildUI::send_host(int64_t token, const void *data, int bytes) { return -1; }
512 #include "pluginserver.h"
514 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name) { return 0; }
515 PluginClient *PluginServer::new_lv2_plugin() { return 0; }
516 int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp) { return 0; }
518 #endif /* HAVE_LV2 */