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
29 #include "mainerror.h"
32 #include "pluginlv2client.h"
33 #include "pluginlv2config.h"
34 #include "pluginlv2ui.inc"
35 #include "pluginserver.h"
36 #include "pluginset.h"
43 PluginLV2UIs PluginLV2ParentUI::plugin_lv2;
45 PluginLV2UIs::PluginLV2UIs()
46 : Mutex("PluginLV2UIs")
50 PluginLV2UIs::~PluginLV2UIs()
55 void PluginLV2UIs::del_uis()
57 while( size() ) remove_object();
60 PluginLV2ParentUI *PluginLV2UIs::del_ui(PluginLV2Client *client)
62 lock("PluginLV2UIs::del_ui client");
64 while( --i >= 0 && get(i)->client != client );
65 PluginLV2ParentUI *ui = 0;
67 if( (ui=get(i))->gui ) ui->client = 0;
68 else { remove_object_number(i); ui = 0; }
73 PluginLV2ParentUI *PluginLV2UIs::del_ui(PluginLV2ClientWindow *gui)
75 lock("PluginLV2UIs::del_ui gui");
77 while( --i >= 0 && get(i)->gui != gui );
78 PluginLV2ParentUI *ui = 0;
80 if( (ui=get(i))->client ) ui->gui = 0;
81 else { remove_object_number(i); ui = 0; }
87 PluginLV2ParentUI *PluginLV2UIs::add_ui(PluginLV2ParentUI *ui, PluginLV2Client *client)
90 ui->start_parent(client);
95 PluginLV2ParentUI *PluginLV2UIs::search_ui(Plugin *plugin)
97 int64_t position = plugin->startproject;
98 PluginSet *plugin_set = plugin->plugin_set;
99 int set_no = plugin_set->get_number();
100 int track_no = plugin_set->track->number_of();
102 PluginLV2ParentUI *ui = 0;
103 for( int i=size(); !ui && --i>=0; ) {
104 PluginLV2ParentUI *parent_ui = get(i);
105 if( parent_ui->position != position ) continue;
106 if( parent_ui->set_no != set_no ) continue;
107 if( parent_ui->track_no == track_no ) ui = parent_ui;
112 PluginLV2ParentUI *PluginLV2UIs::find_ui(Plugin *plugin)
114 if( !plugin ) return 0;
115 lock("PluginLV2UIs::find_ui");
116 PluginLV2ParentUI *ui = search_ui(plugin);
120 PluginLV2ParentUI *PluginLV2Client::find_ui()
122 return PluginLV2ParentUI::plugin_lv2.find_ui(server->plugin);
124 PluginLV2ParentUI *PluginLV2ClientWindow::find_ui()
126 return PluginLV2ParentUI::plugin_lv2.find_ui(client->server->plugin);
129 PluginLV2ParentUI *PluginLV2UIs::get_ui(PluginLV2Client *client)
131 lock("PluginLV2UIs::get_ui");
132 Plugin *plugin = client->server->plugin;
133 PluginLV2ParentUI *ui = search_ui(plugin);
134 if( !ui ) ui = add_ui(new PluginLV2ParentUI(plugin), client);
138 PluginLV2ParentUI *PluginLV2Client::get_ui()
140 PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.get_ui(this);
144 PluginLV2ParentUI *PluginLV2ClientWindow::get_ui()
146 PluginLV2ParentUI *ui = PluginLV2ParentUI::plugin_lv2.get_ui(client);
152 PluginLV2Client::PluginLV2Client(PluginServer *server)
153 : PluginAClient(server), PluginLV2()
158 PluginLV2Client::~PluginLV2Client()
160 PluginLV2ParentUI::plugin_lv2.del_ui(this);
163 NEW_WINDOW_MACRO(PluginLV2Client, PluginLV2ClientWindow)
165 int PluginLV2Client::init_lv2()
167 int sample_rate = get_project_samplerate();
168 return PluginLV2::init_lv2(config, sample_rate);
171 int PluginLV2Client::load_configuration()
173 int64_t src_position = get_source_position();
174 KeyFrame *prev_keyframe = get_prev_keyframe(src_position);
175 PluginLV2ClientConfig curr_config;
176 curr_config.copy_from(config);
177 read_data(prev_keyframe);
178 int ret = !config.equivalent(curr_config) ? 1 : 0;
182 void PluginLV2Client::update_gui()
184 PluginClientThread *thread = get_thread();
185 if( !thread ) return;
186 PluginLV2ClientWindow *gui = (PluginLV2ClientWindow*)thread->get_window();
187 gui->lock_window("PluginFClient::update_gui");
188 load_configuration();
189 if( config.update() > 0 ) {
190 gui->update_selected();
193 gui->unlock_window();
196 void PluginLV2Client::update_lv2()
198 PluginLV2ParentUI *ui = find_ui();
200 ui->send_child(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
204 int PluginLV2Client::is_realtime() { return 1; }
205 int PluginLV2Client::is_multichannel() { return nb_inputs > 1 || nb_outputs > 1 ? 1 : 0; }
206 const char* PluginLV2Client::plugin_title() { return title; }
207 int PluginLV2Client::uses_gui() { return 1; }
208 int PluginLV2Client::is_synthesis() { return 1; }
210 char* PluginLV2Client::to_string(char *string, const char *input)
213 for( const char *cp=input; *cp; ++cp )
214 *bp++ = isalnum(*cp) ? *cp : '_';
219 void PluginLV2Client::save_data(KeyFrame *keyframe)
222 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
223 char name[BCTEXTLEN]; to_string(name, plugin_title());
224 output.tag.set_title(name);
225 for( int i=0; i<config.size(); ++i ) {
226 PluginLV2Client_Opt *opt = config[i];
227 output.tag.set_property(opt->get_symbol(), opt->get_value());
230 output.terminate_string();
233 void PluginLV2Client::read_data(KeyFrame *keyframe)
236 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
237 char name[BCTEXTLEN]; to_string(name, plugin_title());
239 while( !input.read_tag() ) {
240 if( !input.tag.title_is(name) ) continue;
241 for( int i=0; i<config.size(); ++i ) {
242 PluginLV2Client_Opt *opt = config[i];
243 float value = input.tag.get_property(opt->get_symbol(), 0.);
244 opt->set_value(value);
249 void PluginLV2Client::load_buffer(int samples, Samples **input, int ich)
251 for( int i=0; i<nb_inputs; ++i ) {
252 int k = i < ich ? i : 0;
253 double *inp = input[k]->get_data();
254 float *ip = in_buffers[i];
255 for( int j=samples; --j>=0; *ip++=*inp++ );
257 for( int i=0; i<nb_outputs; ++i )
258 bzero(out_buffers[i], samples*sizeof(float));
261 int PluginLV2Client::unload_buffer(int samples, Samples **output, int och)
263 if( nb_outputs < och ) och = nb_outputs;
264 for( int i=0; i<och; ++i ) {
265 double *outp = output[i]->get_data();
266 float *op = out_buffers[i];
267 for( int j=samples; --j>=0; *outp++=*op++ );
272 void PluginLV2Client::process_buffer(int size)
274 PluginLV2ParentUI *ui = get_ui();
277 ui->send_child(LV2_SHMID, &shmid, sizeof(shmid));
278 // timeout 10*duration, min 2sec, max 10sec
279 double sample_rate = get_project_samplerate();
280 double t = !sample_rate ? 2. : 10. * size / sample_rate;
282 ui->output_bfr->timed_lock(t*1e6, "PluginLV2Client::process_buffer");
284 eprintf("timeout: %s",server->title);
287 int PluginLV2Client::process_realtime(int64_t size,
288 Samples *input_ptr, Samples *output_ptr)
290 if( load_configuration() )
293 load_buffer(size, &input_ptr, 1);
294 process_buffer(size);
295 return unload_buffer(size, &output_ptr, 1);
298 int PluginLV2Client::process_realtime(int64_t size,
299 Samples **input_ptr, Samples **output_ptr)
301 if( load_configuration() )
304 load_buffer(size, input_ptr, PluginClient::total_in_buffers);
305 process_buffer(size);
306 return unload_buffer(size, output_ptr, PluginClient::total_out_buffers);
310 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name)
312 return new PluginServer(mwindow, name, PLUGIN_TYPE_LV2);
315 PluginClient *PluginServer::new_lv2_plugin()
317 PluginLV2Client *client = new PluginLV2Client(this);
318 if( client->load_lv2(path, client->title) ) { delete client; return client = 0; }
323 int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp)
325 printf("init lv2 index:\n");
326 LilvWorld *world = lilv_world_new();
327 lilv_world_load_all(world);
328 const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world);
330 LILV_FOREACH(plugins, i, all_plugins) {
331 const LilvPlugin *lilv = lilv_plugins_get(all_plugins, i);
332 const char *uri = lilv_node_as_uri(lilv_plugin_get_uri(lilv));
333 PluginServer server(mwindow, uri, PLUGIN_TYPE_LV2);
334 int result = server.open_plugin(1, preferences, 0, 0);
336 server.write_table(fp, uri, PLUGIN_LV2_ID, 0);
337 server.close_plugin();
341 lilv_world_free(world);
345 PluginLV2ParentUI::PluginLV2ParentUI(Plugin *plugin)
347 this->position = plugin->startproject;
348 PluginSet *plugin_set = plugin->plugin_set;
350 this->set_no = plugin_set->get_number();
351 this->track_no = plugin_set->track->number_of();
354 this->track_no = this->set_no = -1;
356 output_bfr = new Condition(0, "PluginLV2ParentUI::output_bfr", 1);
362 PluginLV2ParentUI::~PluginLV2ParentUI()
368 void PluginLV2ParentUI::start_parent(PluginLV2Client *client)
371 const char *path = client->server->path;
372 int len = sizeof(open_bfr_t) + strlen(path);
373 char bfr[len]; memset(bfr, 0, len);
374 open_bfr_t *open_bfr = (open_bfr_t *)bfr;
375 open_bfr->sample_rate = client->get_project_samplerate();
376 strcpy(open_bfr->path, path);
377 send_child(LV2_OPEN, open_bfr, len);
378 PluginLV2ClientConfig &conf = client->config;
379 send_child(LV2_LOAD, conf.ctls, conf.nb_ports*sizeof(float));
382 int PluginLV2ParentUI::handle_parent()
386 switch( parent_token ) {
389 gui->lv2_update((float *)parent_data);
398 output_bfr->unlock();
402 output_bfr->unlock();
413 int PluginLV2ParentUI::show()
415 if( !hidden ) return 1;
416 send_child(LV2_SHOW, 0, 0);
420 int PluginLV2ParentUI::hide()
422 if( hidden ) return 1;
423 send_child(LV2_HIDE, 0, 0);
429 int PluginLV2ChildUI::handle_child() { return 0; }
430 void PluginLV2UI::reset_gui() {}
432 ForkChild *PluginLV2ParentUI::new_fork()
435 return new PluginLV2ChildUI();
444 #include "pluginserver.h"
446 PluginServer* MWindow::new_lv2_server(MWindow *mwindow, const char *name) { return 0; }
447 PluginClient *PluginServer::new_lv2_plugin() { return 0; }
448 int MWindow::init_lv2_index(MWindow *mwindow, Preferences *preferences, FILE *fp) { return 0; }
450 #endif /* HAVE_LV2 */