no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / pluginserver.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "amodule.h"
23 #include "atrack.h"
24 #include "attachmentpoint.h"
25 #include "autoconf.h"
26 #include "bcsignals.h"
27 #include "cplayback.h"
28 #include "cstrdup.h"
29 #include "cwindow.h"
30 #include "edl.h"
31 #include "edlsession.h"
32 #include "file.h"
33 #include "floatautos.h"
34 #include "keyframes.h"
35 #include "localsession.h"
36 #include "mainerror.h"
37 #include "mainprogress.h"
38 #include "menueffects.h"
39 #include "mwindow.h"
40 #include "mwindowgui.h"
41 #include "playbackengine.h"
42 #include "plugin.h"
43 #include "pluginaclient.h"
44 #include "pluginaclientlad.h"
45 #include "pluginfclient.h"
46 #include "pluginclient.h"
47 #include "plugincommands.h"
48 #include "pluginserver.h"
49 #include "pluginvclient.h"
50 #include "preferences.h"
51 #include "samples.h"
52 #include "sema.h"
53 #include "mainsession.h"
54 #include "theme.h"
55 #include "trackcanvas.h"
56 #include "tracks.h"
57 #include "transportque.h"
58 #include "vdevicex11.h"
59 #include "vframe.h"
60 #include "videodevice.h"
61 #include "virtualanode.h"
62 #include "virtualvnode.h"
63 #include "vmodule.h"
64 #include "vtrack.h"
65
66
67 #include<stdio.h>
68 #include<unistd.h>
69 #include<fcntl.h>
70 #include <sys/types.h>
71 #include <sys/wait.h>
72 #include<sys/stat.h>
73 #include <sys/mman.h>
74
75
76 void PluginServer::init()
77 {
78         reset_parameters();
79         this->plugin_type = PLUGIN_TYPE_UNKNOWN;
80         plugin_obj = new PluginObj();
81         modules = new ArrayList<Module*>;
82         nodes = new ArrayList<VirtualNode*>;
83         tip = 0;
84         gui_id = -1;
85         plugin_id = -1;
86 }
87
88 PluginServer::PluginServer()
89 {
90         init();
91 }
92
93 PluginServer::PluginServer(MWindow *mwindow, const char *path, int type)
94 {
95         char fpath[BCTEXTLEN];
96         init();
97         this->plugin_type = type;
98         this->mwindow = mwindow;
99         if( type == PLUGIN_TYPE_FFMPEG ) {
100                 ff_name = cstrdup(path);
101                 sprintf(fpath, "ff_%s", path);
102                 path = fpath;
103         }
104         set_path(path);
105 }
106
107 PluginServer::PluginServer(PluginServer &that)
108 {
109         reset_parameters();
110         plugin_type = that.plugin_type;
111         plugin_obj = that.plugin_obj;
112         plugin_obj->add_user();
113         title = !that.title ? 0 : cstrdup(that.title);
114         tip = !that.tip ? 0 : cstrdup(that.tip);
115         path = !that.path ? 0 : cstrdup(that.path);
116         ff_name = !that.ff_name ? 0 : cstrdup(that.ff_name);
117         modules = new ArrayList<Module*>;
118         nodes = new ArrayList<VirtualNode*>;
119
120         attachment = that.attachment;
121         realtime = that.realtime;
122         multichannel = that.multichannel;
123         preferences = that.preferences;
124         synthesis = that.synthesis;
125         audio = that.audio;
126         video = that.video;
127         theme = that.theme;
128         fileio = that.fileio;
129         uses_gui = that.uses_gui;
130         mwindow = that.mwindow;
131         keyframe = that.keyframe;
132         new_plugin = that.new_plugin;
133
134         lad_descriptor = that.lad_descriptor;
135         lad_descriptor_function = that.lad_descriptor_function;
136         lad_index = that.lad_index;
137 }
138
139 PluginServer::~PluginServer()
140 {
141         close_plugin();
142         delete [] path;
143         delete [] ff_name;
144         delete [] title;
145         delete [] tip;
146         delete modules;
147         delete nodes;
148         delete picon;
149         plugin_obj->remove_user();
150 }
151
152 // Done only once at creation
153 int PluginServer::reset_parameters()
154 {
155         mwindow = 0;
156         keyframe = 0;
157         prompt = 0;
158         cleanup_plugin();
159
160         plugin_obj = 0;
161         client = 0; 
162         new_plugin = 0;
163         lad_index = -1;
164         lad_descriptor_function = 0;
165         lad_descriptor = 0;
166         ff_name = 0;
167         use_opengl = 0;
168         vdevice = 0;
169         plugin_type = 0;
170         start_auto = end_auto = 0;
171         autos = 0;
172         reverse = 0;
173         plugin_open = 0;
174         realtime = multichannel = fileio = 0;
175         synthesis = 0;
176         audio = video = theme = 0;
177         uses_gui = 0;
178         transition = 0;
179         title = 0;
180         tip = 0;
181         path = 0;
182         data_text = 0;
183         for( int i=sizeof(args)/sizeof(args[0]); --i>=0; ) args[i] = 0;
184         total_args = 0; 
185         dir_idx = 0;
186         modules = 0;
187         nodes = 0;
188         attachmentpoint = 0;
189         edl = 0;
190         preferences = 0;
191         prompt = 0;
192         temp_frame = 0;
193         picon = 0;
194
195         return 0;
196 }
197
198 // Done every time the plugin is opened or closed
199 int PluginServer::cleanup_plugin()
200 {
201         in_buffer_size = out_buffer_size = 0;
202         total_in_buffers = total_out_buffers = 0;
203         error_flag = 0;
204         written_samples = 0;
205         shared_buffers = 0;
206         new_buffers = 0;
207         written_samples = written_frames = 0;
208         gui_on = 0;
209         plugin_id = -1;
210         plugin_open = 0;
211         return 0;
212 }
213
214 void PluginServer::set_mwindow(MWindow *mwindow)
215 {
216         this->mwindow = mwindow;
217 }
218
219 void PluginServer::set_attachmentpoint(AttachmentPoint *attachmentpoint)
220 {
221         this->attachmentpoint = attachmentpoint;
222 }
223
224 void PluginServer::set_keyframe(KeyFrame *keyframe)
225 {
226         this->keyframe = keyframe;
227 }
228
229 void PluginServer::set_prompt(MenuEffectPrompt *prompt)
230 {
231         this->prompt = prompt;
232 }
233
234 void PluginServer::set_lad_index(int i)
235 {
236         this->lad_index = i;
237 }
238
239 int PluginServer::get_lad_index()
240 {
241         return this->lad_index;
242 }
243
244 int PluginServer::is_unknown()
245 {
246         return plugin_type == PLUGIN_TYPE_UNKNOWN ? 1 : 0;
247 }
248
249 int PluginServer::is_executable()
250 {
251         return  plugin_type == PLUGIN_TYPE_EXECUTABLE ? 1 : 0;
252 }
253
254 int PluginServer::is_builtin()
255 {
256         return plugin_type == PLUGIN_TYPE_BUILTIN ? 1 : 0;
257 }
258
259 int PluginServer::is_ladspa()
260 {
261         return plugin_type == PLUGIN_TYPE_LADSPA ? 1 : 0;
262 }
263
264 int PluginServer::is_ffmpeg()
265 {
266         return plugin_type == PLUGIN_TYPE_FFMPEG ? 1 : 0;
267 }
268
269 int PluginServer::is_lv2()
270 {
271         return plugin_type == PLUGIN_TYPE_LV2 ? 1 : 0;
272 }
273
274 void PluginServer::set_path(const char *path)
275 {
276         delete [] this->path;
277         this->path = cstrdup(path);
278 }
279
280 char* PluginServer::get_path()
281 {
282         return this->path;
283 }
284
285 int PluginServer::get_synthesis()
286 {
287         return synthesis;
288 }
289
290
291 void PluginServer::set_title(const char *string)
292 {
293         delete [] title;
294         title = cstrdup(string);
295 }
296
297 void PluginServer::generate_display_title(char *string)
298 {
299         char ltitle[BCTEXTLEN];
300         if( BC_Resources::locale_utf8 )
301                 strcpy(ltitle, _(title));
302         else
303                 BC_Resources::encode(BC_Resources::encoding, 0,
304                                 _(title),strlen(title)+1, ltitle,BCTEXTLEN);
305         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
306         if( plugin && plugin->track )
307                 sprintf(string, "%s: %s", plugin->track->title, ltitle);
308         else
309                 strcpy(string, ltitle);
310 }
311
312 void *PluginObj::load(const char *plugin_dir, const char *path)
313 {
314         char dlpath[BCTEXTLEN], *dp = dlpath;
315         const char *cp = path;
316         if( *cp != '/' ) {
317                 const char *bp = plugin_dir;
318                 while( *bp ) *dp++ = *bp++;
319                 *dp++ = '/';
320         }
321         while( *cp ) *dp++ = *cp++;
322         *dp = 0;
323         return dlobj = load(dlpath);
324 }
325
326 int PluginServer::load_obj()
327 {
328         void *obj = plugin_obj->obj();
329         if( !obj ) obj =plugin_obj->load(preferences->plugin_dir, path);
330         return obj ? 1 : 0;
331 }
332
333 const char *PluginServer::load_error()
334 {
335         return plugin_obj->load_error();
336 }
337
338 void *PluginServer::get_sym(const char *sym)
339 {
340         if( !plugin_obj->obj() ) return 0;
341         return plugin_obj->load_sym(sym);
342 }
343
344 // Open plugin for signal processing
345 int PluginServer::open_plugin(int master,
346         Preferences *preferences,
347         EDL *edl,
348         Plugin *plugin)
349 {
350         if( plugin_open ) return 0;
351
352         this->preferences = preferences;
353         this->plugin_id = plugin ? plugin->orig_id : -1;
354         this->edl = edl;
355         if( !is_ffmpeg() && !is_lv2() && !is_executable() && !load_obj() ) {
356 // If the load failed, can't use error string to detect executable
357 //  because locale and language selection changes the load_error() message
358 //      if( !strstr(string, "executable") ) { set_title(path); plugin_type = PLUGIN_TYPE_EXECUTABLE; }
359                 eprintf("PluginServer::open_plugin: load_obj %s = %s\n", path, load_error());
360                 return PLUGINSERVER_NOT_RECOGNIZED;
361         }
362         if( is_unknown() || is_builtin() ) {
363                 new_plugin =
364                         (PluginClient* (*)(PluginServer*)) get_sym("new_plugin");
365                 if( new_plugin )
366                         plugin_type = PLUGIN_TYPE_BUILTIN;
367         }
368         if( is_unknown() || is_ladspa() ) {
369                 lad_descriptor_function =
370                         (LADSPA_Descriptor_Function) get_sym("ladspa_descriptor");
371                 if( lad_descriptor_function ) {
372                         if( lad_index < 0 ) return PLUGINSERVER_IS_LAD;
373                         lad_descriptor = lad_descriptor_function(lad_index);
374                         if( !lad_descriptor )
375                                 return PLUGINSERVER_NOT_RECOGNIZED;
376                         plugin_type = PLUGIN_TYPE_LADSPA;
377                 }
378         }
379         if( is_unknown() ) {
380                 fprintf(stderr, "PluginServer::open_plugin "
381                         " %d: plugin undefined in %s\n", __LINE__, path);
382                 return PLUGINSERVER_NOT_RECOGNIZED;
383         }
384         switch( plugin_type ) {
385         case PLUGIN_TYPE_EXECUTABLE:
386                 return PLUGINSERVER_OK;
387         case PLUGIN_TYPE_BUILTIN:
388                 client = new_plugin(this);
389                 break;
390         case PLUGIN_TYPE_FFMPEG:
391                 client = new_ffmpeg_plugin();
392                 break;
393         case PLUGIN_TYPE_LADSPA:
394                 client = new PluginAClientLAD(this);
395                 break;
396         case PLUGIN_TYPE_LV2:
397                 client = new_lv2_plugin();
398                 break;
399         default:
400                 client = 0;
401                 break;
402         }
403         if( !client )
404                 return PLUGINSERVER_NOT_RECOGNIZED;
405
406 // Run initialization functions
407         realtime = client->is_realtime();
408 // Don't load defaults when probing the directory.
409         if( !master ) {
410                 if( realtime )
411                         client->load_defaults_xml();
412                 else
413                         client->load_defaults();
414         }
415         audio = client->is_audio();
416         video = client->is_video();
417         theme = client->is_theme();
418         fileio = client->is_fileio();
419         uses_gui = client->uses_gui();
420         multichannel = client->is_multichannel();
421         synthesis = client->is_synthesis();
422         transition = client->is_transition();
423         set_title(client->plugin_title());
424
425 //printf("PluginServer::open_plugin 2\n");
426         plugin_open = 1;
427         return PLUGINSERVER_OK;
428 }
429
430 int PluginServer::close_plugin()
431 {
432         if( !plugin_open ) return 0;
433         delete client;
434         plugin_open = 0;
435         cleanup_plugin();
436         return 0;
437 }
438
439 void PluginServer::client_side_close()
440 {
441 // Last command executed in client thread
442         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
443         if( plugin )
444                 mwindow->hide_plugin(plugin, 1);
445         else if( prompt ) {
446                 prompt->lock_window();
447                 prompt->set_done(1);
448                 prompt->unlock_window();
449         }
450 }
451
452 void PluginServer::render_stop()
453 {
454         if( client )
455                 client->render_stop();
456         send_reset_gui_frames();
457 }
458
459 void PluginServer::write_table(FILE *fp, const char *path, int idx, int64_t mtime)
460 {
461         if( !fp ) return;
462         fprintf(fp, "%d \"%s\" \"%s\" %jd %d %d %d %d %d %d %d %d %d %d %d\n",
463                 plugin_type, path, title, mtime, idx, audio, video, theme, realtime,
464                 fileio, uses_gui, multichannel, synthesis, transition, lad_index);
465 }
466
467 int PluginServer::scan_table(char *text, int &type, char *path, char *title, int64_t &mtime)
468 {
469         int n = sscanf(text, "%d \"%[^\"]\" \"%[^\"]\" %jd", &type, path, title, &mtime);
470         return n < 4 ? 1 : 0;
471 }
472
473 int PluginServer::read_table(char *text)
474 {
475         char path[BCTEXTLEN], title[BCTEXTLEN];
476         int64_t mtime;
477         int n = sscanf(text, "%d \"%[^\"]\" \"%[^\"]\" %jd %d %d %d %d %d %d %d %d %d %d %d",
478                 &plugin_type, path, title, &mtime, &dir_idx, &audio, &video, &theme, &realtime,
479                 &fileio, &uses_gui, &multichannel, &synthesis, &transition, &lad_index);
480         if( n != 15 ) return 1;
481         set_title(title);
482         return 0;
483 }
484
485 int PluginServer::init_realtime(int realtime_sched,
486                 int total_in_buffers,
487                 int buffer_size)
488 {
489
490         if( !plugin_open ) return 0;
491
492 // set for realtime priority
493 // initialize plugin
494 // Call start_realtime
495         this->total_in_buffers = this->total_out_buffers = total_in_buffers;
496         client->plugin_init_realtime(realtime_sched,
497                 total_in_buffers,
498                 buffer_size);
499
500         return 0;
501 }
502
503
504 // Replaced by pull method but still needed for transitions
505 void PluginServer::process_transition(VFrame *input,
506                 VFrame *output,
507                 int64_t current_position,
508                 int64_t total_len)
509 {
510         if( !plugin_open ) return;
511         PluginVClient *vclient = (PluginVClient*)client;
512         to_ram(input);
513         to_ram(output);
514
515         vclient->source_position = current_position;
516         vclient->source_start = 0;
517         vclient->total_len = total_len;
518
519         vclient->input = new VFrame*[1];
520         vclient->output = new VFrame*[1];
521
522         vclient->input[0] = input;
523         vclient->output[0] = output;
524
525         vclient->process_realtime(input, output);
526         vclient->age_temp();
527         delete [] vclient->input;
528         delete [] vclient->output;
529         use_opengl = 0;
530 }
531
532 void PluginServer::process_transition(Samples *input,
533                 Samples *output,
534                 int64_t current_position,
535                 int64_t fragment_size,
536                 int64_t total_len)
537 {
538         if( !plugin_open ) return;
539         PluginAClient *aclient = (PluginAClient*)client;
540
541         aclient->source_position = current_position;
542         aclient->total_len = total_len;
543         aclient->source_start = 0;
544         aclient->process_realtime(fragment_size,
545                 input,
546                 output);
547 }
548
549
550 void PluginServer::process_buffer(VFrame **frame,
551         int64_t current_position,
552         double frame_rate,
553         int64_t total_len,
554         int direction)
555 {
556         if( !plugin_open ) return;
557         PluginVClient *vclient = (PluginVClient*)client;
558         vclient->in_buffer_size = vclient->out_buffer_size = 1;
559         vclient->source_position = current_position;
560         vclient->total_len = total_len;
561         vclient->frame_rate = frame_rate;
562         vclient->input = new VFrame*[total_in_buffers];
563         vclient->output = new VFrame*[total_in_buffers];
564         for( int i = 0; i < total_in_buffers; i++ ) {
565                 vclient->input[i] = frame[i];
566                 vclient->output[i] = frame[i];
567         }
568
569         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
570         if( plugin ) {
571                 vclient->source_start = (int64_t)plugin->startproject *
572                         frame_rate / vclient->project_frame_rate;
573         }
574         vclient->direction = direction;
575
576 //PRINT_TRACE
577 //printf("plugin=%p source_start=%ld\n", plugin, vclient->source_start);
578 //      vclient->begin_process_buffer();
579         if( multichannel )
580                 vclient->process_buffer(frame, current_position, frame_rate);
581         else
582                 vclient->process_buffer(frame[0], current_position, frame_rate);
583 //      vclient->end_process_buffer();
584
585         for( int i = 0; i < total_in_buffers; i++ )
586                 frame[i]->push_prev_effect(title);
587
588         delete [] vclient->input;
589         delete [] vclient->output;
590
591         vclient->age_temp();
592         use_opengl = 0;
593 }
594
595 void PluginServer::process_buffer(Samples **buffer,
596         int64_t current_position,
597         int64_t fragment_size,
598         int64_t sample_rate,
599         int64_t total_len,
600         int direction)
601 {
602         if( !plugin_open ) return;
603         PluginAClient *aclient = (PluginAClient*)client;
604         aclient->source_position = current_position;
605         aclient->total_len = total_len;
606         aclient->sample_rate = sample_rate;
607         aclient->in_buffer_size = aclient->out_buffer_size = fragment_size;
608         aclient->output_buffers = buffer;
609
610         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
611         if( plugin )
612                 aclient->source_start = plugin->startproject *
613                         sample_rate /
614                         aclient->project_sample_rate;
615
616         aclient->direction = direction;
617         aclient->begin_process_buffer();
618         if( multichannel ) {
619                 aclient->process_buffer(fragment_size,
620                         buffer, current_position, sample_rate);
621         }
622         else {
623                 aclient->process_buffer(fragment_size,
624                         buffer[0], current_position, sample_rate);
625         }
626         aclient->end_process_buffer();
627 }
628
629
630 void PluginServer::send_reset_gui_frames()
631 {
632         if( !attachmentpoint ) return;
633         attachmentpoint->reset_gui_frames(this);
634 }
635
636 void PluginServer::send_render_gui(void *data)
637 {
638         if( !attachmentpoint ) return;
639         attachmentpoint->render_gui(data, this);
640 }
641
642 void PluginServer::send_render_gui(void *data, int size)
643 {
644         if( !attachmentpoint ) return;
645         attachmentpoint->render_gui(data, size, this);
646 }
647
648 void PluginServer::render_gui(void *data)
649 {
650         if( !client ) return;
651         client->plugin_render_gui(data);
652 }
653
654 void PluginServer::render_gui(void *data, int size)
655 {
656         if( !client ) return;
657         client->plugin_render_gui(data, size);
658 }
659
660
661 PluginGUIs::PluginGUIs(MWindow *mwindow)
662 {
663         this->mwindow = mwindow;
664         this->next_id = 0;
665 }
666 PluginGUIs::~PluginGUIs()
667 {
668 }
669
670 void PluginGUIs::append(PluginServer *server)
671 {
672         server->gui_id = next_id++;
673         ArrayList<PluginServer*>::append(server);
674 }
675
676 PluginServer *PluginGUIs::gui_server(int gui_id)
677 {
678         for( int i=0; i<size(); ++i ) {
679                 PluginServer *plugin_server = get(i);
680                 if( plugin_server->gui_id == gui_id )
681                         return plugin_server;
682         }
683         return 0;
684 }
685
686
687 void PluginServer::reset_gui_frames()
688 {
689         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
690         if( plugin )
691                 mwindow->reset_plugin_gui_frames(plugin);
692 }
693
694 void PluginServer::reset_plugin_gui_frames()
695 {
696         if( !client ) return;
697         client->plugin_reset_gui_frames();
698 }
699
700 void PluginServer::render_gui_frames(PluginClientFrames *frames)
701 {
702         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
703         if( plugin )
704                 mwindow->render_plugin_gui_frames(frames, plugin);
705 }
706
707 void PluginServer::render_plugin_gui_frames(PluginClientFrames *frames)
708 {
709         if( !client ) return;
710         client->plugin_render_gui_frames(frames);
711 }
712
713 MainProgressBar* PluginServer::start_progress(char *string, int64_t length)
714 {
715         mwindow->gui->lock_window();
716         MainProgressBar *result = mwindow->mainprogress->start_progress(string, length);
717         mwindow->gui->unlock_window();
718         return result;
719 }
720
721 int64_t PluginServer::get_written_samples()
722 {
723         if( !plugin_open ) return 0;
724         return written_samples;
725 }
726
727 int64_t PluginServer::get_written_frames()
728 {
729         if( !plugin_open ) return 0;
730         return written_frames;
731 }
732
733
734 // ======================= Non-realtime plugin
735
736 int PluginServer::get_parameters(int64_t start, int64_t end, int channels)
737 {
738         if( !plugin_open ) return 0;
739
740         client->start = start;
741         client->end = end;
742         client->source_start = start;
743         client->total_len = end - start;
744         client->total_in_buffers = channels;
745
746 //PRINT_TRACE
747 //printf(" source_start=%ld total_len=%ld\n", client->source_start, client->total_len);
748
749         return client->plugin_get_parameters();
750 }
751
752 int PluginServer::set_interactive()
753 {
754         if( !plugin_open ) return 0;
755         client->set_interactive();
756         return 0;
757 }
758
759 void PluginServer::append_module(Module *module)
760 {
761         modules->append(module);
762 }
763
764 void PluginServer::append_node(VirtualNode *node)
765 {
766         nodes->append(node);
767 }
768
769 void PluginServer::reset_nodes()
770 {
771         nodes->remove_all();
772 }
773
774 int PluginServer::set_error()
775 {
776         error_flag = 1;
777         return 0;
778 }
779
780 int PluginServer::set_realtime_sched()
781 {
782         //struct sched_param params;
783         //params.sched_priority = 1;
784         //sched_setscheduler(0, SCHED_RR, &param);
785         return 0;
786 }
787
788
789 int PluginServer::process_loop(VFrame **buffers, int64_t &write_length)
790 {
791         if( !plugin_open ) return 1;
792         return client->plugin_process_loop(buffers, write_length);
793 }
794
795 int PluginServer::process_loop(Samples **buffers, int64_t &write_length)
796 {
797         if( !plugin_open ) return 1;
798         return client->plugin_process_loop(buffers, write_length);
799 }
800
801
802 int PluginServer::start_loop(int64_t start,
803         int64_t end,
804         int64_t buffer_size,
805         int total_buffers)
806 {
807         if( !plugin_open ) return 0;
808         client->plugin_start_loop(start, end, buffer_size, total_buffers);
809         return 0;
810 }
811
812 int PluginServer::stop_loop()
813 {
814         if( !plugin_open ) return 0;
815         return client->plugin_stop_loop();
816 }
817
818 int PluginServer::read_frame(VFrame *buffer,
819         int channel,
820         int64_t start_position)
821 {
822         ((VModule*)modules->values[channel])->render(buffer,
823                 start_position, PLAY_FORWARD,
824                 mwindow->edl->session->frame_rate, 0, 0);
825         return 0;
826 }
827
828 int PluginServer::read_samples(Samples *buffer,
829         int channel, int64_t sample_rate, int64_t start_position, int64_t len)
830 {
831 // len is now in buffer
832         if( !multichannel ) channel = 0;
833
834         if( nodes->total > channel )
835                 return ((VirtualANode*)nodes->values[channel])->read_data(buffer,
836                         len, start_position, sample_rate);
837         if( modules->total > channel )
838                 return ((AModule*)modules->values[channel])->render(buffer,
839                         len, start_position, PLAY_FORWARD, sample_rate, 0);
840         printf("PluginServer::read_samples no object available for channel=%d\n",
841                 channel);
842         return -1;
843 }
844
845
846 int PluginServer::read_samples(Samples *buffer,
847                 int channel, int64_t start_position, int64_t size)
848 {
849 // total_samples is now set in buffer
850         ((AModule*)modules->values[channel])->render(buffer,
851                 size, start_position, PLAY_FORWARD,
852                 mwindow->edl->session->sample_rate, 0);
853         return 0;
854 }
855
856 int PluginServer::read_frame(VFrame *buffer,
857                 int channel, int64_t start_position, double frame_rate,
858                 int use_opengl)
859 {
860 // Data source depends on whether we're part of a virtual console or a
861 // plugin array.
862 //     VirtualNode
863 //     Module
864 // If we're a VirtualNode, read_data in the virtual plugin node handles
865 //     backward propogation and produces the data.
866 // If we're a Module, render in the module produces the data.
867 //PRINT_TRACE
868
869         int result = -1;
870         if( !multichannel ) channel = 0;
871
872 // Push our name on the next effect stack
873         buffer->push_next_effect(title);
874 //printf("PluginServer::read_frame %p\n", buffer);
875 //buffer->dump_stacks();
876
877         if( nodes->total > channel ) {
878 //printf("PluginServer::read_frame %d\n", __LINE__);
879                 result = ((VirtualVNode*)nodes->values[channel])->read_data(buffer,
880                         start_position, frame_rate, use_opengl);
881         }
882         else
883         if( modules->total > channel ) {
884 //printf("PluginServer::read_frame %d\n", __LINE__);
885                 result = ((VModule*)modules->values[channel])->render(buffer,
886                         start_position, //                      PLAY_FORWARD,
887                         client->direction, frame_rate, 0, 0, use_opengl);
888         }
889         else {
890                 printf("PluginServer::read_frame no object available for channel=%d\n",
891                         channel);
892         }
893
894 // Pop our name from the next effect stack
895         buffer->pop_next_effect();
896
897         return result;
898 }
899
900
901 // Called by client
902 int PluginServer::get_gui_status()
903 {
904         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
905         if( plugin )
906                 return plugin->show ? GUI_ON : GUI_OFF;
907         else
908                 return GUI_OFF;
909 }
910
911 void PluginServer::raise_window()
912 {
913         if( !plugin_open ) return;
914         client->raise_window();
915 }
916
917 void PluginServer::show_gui()
918 {
919         if( !plugin_open ) return;
920         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
921         if( plugin ) {
922                 plugin->gui_id = gui_id;
923                 client->total_len = plugin->length;
924                 client->source_start = plugin->startproject;
925         }
926         if( video ) {
927                 client->source_position = Units::to_int64(
928                         mwindow->edl->local_session->get_selectionstart(1) *
929                                 mwindow->edl->session->frame_rate);
930         }
931         else
932         if( audio ) {
933                 client->source_position = Units::to_int64(
934                         mwindow->edl->local_session->get_selectionstart(1) *
935                                 mwindow->edl->session->sample_rate);
936         }
937
938         client->update_display_title();
939         client->show_gui();
940 }
941
942 void PluginServer::hide_gui()
943 {
944         if( !plugin_open ) return;
945         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
946         if( plugin ) plugin->gui_id = -1;
947         if( client->defaults ) client->save_defaults();
948         client->hide_gui();
949 }
950
951 void PluginServer::update_gui()
952 {
953         if( !plugin_open ) return;
954         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
955         if( !plugin ) return;
956
957         client->total_len = plugin->length;
958         client->source_start = plugin->startproject;
959
960         if( video ) {
961                 client->source_position = Units::to_int64(
962                         mwindow->edl->local_session->get_selectionstart(1) *
963                                 mwindow->edl->session->frame_rate);
964         }
965         else if( audio ) {
966                 client->source_position = Units::to_int64(
967                         mwindow->edl->local_session->get_selectionstart(1) *
968                                 mwindow->edl->session->sample_rate);
969         }
970
971         client->plugin_update_gui();
972 }
973
974 void PluginServer::update_title()
975 {
976         if( !plugin_open ) return;
977
978         client->update_display_title();
979 }
980
981
982 int PluginServer::set_string(char *string)
983 {
984         if( !plugin_open ) return 0;
985
986         client->set_string_client(string);
987         return 0;
988 }
989
990 int PluginServer::gui_open()
991 {
992         if( attachmentpoint ) return attachmentpoint->gui_open();
993         return 0;
994 }
995
996 void PluginServer::set_use_opengl(int value, VideoDevice *vdevice)
997 {
998         this->use_opengl = value;
999         this->vdevice = vdevice;
1000 }
1001
1002 int PluginServer::get_use_opengl()
1003 {
1004         return use_opengl;
1005 }
1006
1007 int PluginServer::to_ram(VFrame *vframe)
1008 {
1009         if( vframe->get_opengl_state() == VFrame::RAM ) return 0;
1010         if( !vdevice ) return -1;
1011         VDeviceX11 *vdevice_x11 = (VDeviceX11*) vdevice->get_output_base();
1012         int vw = vframe->get_w(), vh = vframe->get_h();
1013         vdevice_x11->do_camera(vframe, vframe, 0,0,vw,vh, 0,0,vw,vh); // copy to ram
1014         return 1;
1015 }
1016
1017 void PluginServer::run_opengl(PluginClient *plugin_client)
1018 {
1019         if( vdevice )
1020                 ((VDeviceX11*)vdevice->get_output_base())->run_plugin(plugin_client);
1021 }
1022
1023 // ============================= queries
1024
1025 void PluginServer::get_defaults_path(char *path)
1026 {
1027         char string2[BCTEXTLEN];
1028         switch( plugin_type ) {
1029         case PLUGIN_TYPE_FFMPEG:
1030         case PLUGIN_TYPE_LV2:
1031                 strcpy(string2, title);
1032                 break;
1033         case PLUGIN_TYPE_BUILTIN:
1034         case PLUGIN_TYPE_LADSPA:
1035         default: { // Get plugin name from path
1036                 char *ptr1 = strrchr(get_path(), '/');
1037                 char *ptr2 = strrchr(get_path(), '.');
1038                 if( !ptr1 ) ptr1 = get_path();
1039                 if( !ptr2 ) ptr2 = get_path() + strlen(get_path());
1040                 char *ptr3 = string2;
1041                 while( ptr1 < ptr2 ) *ptr3++ = *ptr1++;
1042                 *ptr3 = 0;
1043                 break; }
1044         }
1045         sprintf(path, "%s/%s.xml", File::get_config_path(), string2);
1046 }
1047
1048 void PluginServer::save_defaults()
1049 {
1050         if( client ) client->save_defaults();
1051 }
1052
1053 int PluginServer::get_samplerate()
1054 {
1055         if( !plugin_open ) return 0;
1056         if( audio )
1057                 return client->get_samplerate();
1058         if( mwindow )
1059                 return mwindow->edl->session->sample_rate;
1060         printf("PluginServer::get_samplerate audio and mwindow == NULL\n");
1061         return 1;
1062 }
1063
1064
1065 double PluginServer::get_framerate()
1066 {
1067         if( !plugin_open ) return 0;
1068         if( video )
1069                 return client->get_framerate();
1070         if( mwindow )
1071                 return mwindow->edl->session->frame_rate;
1072         printf("PluginServer::get_framerate video and mwindow == NULL\n");
1073         return 1;
1074 }
1075
1076 int PluginServer::get_project_samplerate()
1077 {
1078         if( mwindow )
1079                 return mwindow->edl->session->sample_rate;
1080         if( edl )
1081                 return edl->session->sample_rate;
1082         printf("PluginServer::get_project_samplerate mwindow and edl are NULL.\n");
1083         return 1;
1084 }
1085
1086 double PluginServer::get_project_framerate()
1087 {
1088         if( mwindow )
1089                 return mwindow->edl->session->frame_rate;
1090         if( edl )
1091                 return edl->session->frame_rate;
1092         printf("PluginServer::get_project_framerate mwindow and edl are NULL.\n");
1093         return 1;
1094 }
1095
1096
1097 int PluginServer::detach_buffers()
1098 {
1099         ring_buffers_out.remove_all();
1100         offset_out_render.remove_all();
1101         double_buffer_out_render.remove_all();
1102         realtime_out_size.remove_all();
1103
1104         ring_buffers_in.remove_all();
1105         offset_in_render.remove_all();
1106         double_buffer_in_render.remove_all();
1107         realtime_in_size.remove_all();
1108
1109         out_buffer_size = 0;
1110         shared_buffers = 0;
1111         total_out_buffers = 0;
1112         in_buffer_size = 0;
1113         total_in_buffers = 0;
1114         return 0;
1115 }
1116
1117 int PluginServer::arm_buffer(int buffer_number,
1118                 int64_t offset_in, int64_t offset_out,
1119                 int double_buffer_in, int double_buffer_out)
1120 {
1121         offset_in_render.values[buffer_number] = offset_in;
1122         offset_out_render.values[buffer_number] = offset_out;
1123         double_buffer_in_render.values[buffer_number] = double_buffer_in;
1124         double_buffer_out_render.values[buffer_number] = double_buffer_out;
1125         return 0;
1126 }
1127
1128
1129 int PluginServer::set_automation(FloatAutos *autos, FloatAuto **start_auto, FloatAuto **end_auto, int reverse)
1130 {
1131         this->autos = autos;
1132         this->start_auto = start_auto;
1133         this->end_auto = end_auto;
1134         this->reverse = reverse;
1135         return 0;
1136 }
1137
1138
1139
1140 void PluginServer::save_data(KeyFrame *keyframe)
1141 {
1142         if( !plugin_open ) return;
1143         client->save_data(keyframe);
1144 }
1145
1146 KeyFrame* PluginServer::get_prev_keyframe(int64_t position)
1147 {
1148         KeyFrame *result = 0;
1149         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1150         if( plugin )
1151                 result = plugin->get_prev_keyframe(position, client->direction);
1152         else
1153                 result = keyframe;
1154         return result;
1155 }
1156
1157 KeyFrame* PluginServer::get_next_keyframe(int64_t position)
1158 {
1159         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1160         KeyFrame *result = !plugin ? 0 :
1161                 plugin->get_next_keyframe(position, client->direction);
1162         return result;
1163 }
1164
1165 // Called for
1166 KeyFrame* PluginServer::get_keyframe()
1167 {
1168         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1169         if( plugin )
1170 // Realtime plugin case
1171                 return plugin->get_keyframe();
1172 // Rendered plugin case
1173         return keyframe;
1174 }
1175
1176
1177 void PluginServer::apply_keyframe(Plugin *plugin, KeyFrame *src)
1178 {
1179         KeyFrame* dst = !plugin ? keyframe :
1180                 plugin->is_transition() ? plugin->get_keyframe() : 0;
1181         if( !dst ) {
1182                 if( edl->session->span_keyframes ) {
1183                         double selection_start = edl->local_session->get_selectionstart(0);
1184                         double selection_end = edl->local_session->get_selectionend(0);
1185                         selection_start = edl->align_to_frame(selection_start, 0);
1186                         selection_end = edl->align_to_frame(selection_end, 0);
1187                         Track *track = plugin->track;
1188                         int64_t start = track->to_units(selection_start, 1);
1189                         int64_t end = track->to_units(selection_end, 1);
1190                         if( start != end ) {
1191                                 client->span_keyframes(src, start, end);
1192                                 return;
1193                         }
1194                 }
1195                 dst = get_keyframe();
1196         }
1197         if( dst )
1198                 dst->copy_data(src);
1199 }
1200
1201
1202 void PluginServer::get_camera(float *x, float *y, float *z,
1203         int64_t position, int direction)
1204 {
1205         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1206         if( plugin )
1207                 plugin->track->automation->get_camera(x, y, z, position, direction);
1208 }
1209
1210 void PluginServer::get_projector(float *x, float *y, float *z,
1211         int64_t position, int direction)
1212 {
1213         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1214         if( plugin )
1215                 plugin->track->automation->get_projector(x, y, z, position, direction);
1216 }
1217
1218
1219 int PluginServer::get_interpolation_type()
1220 {
1221         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1222         if( plugin )
1223                 return plugin->edl->session->interpolation_type;
1224         return NEAREST_NEIGHBOR;
1225 }
1226
1227 Theme* PluginServer::new_theme()
1228 {
1229         if( theme )
1230                 return client->new_theme();
1231         return 0;
1232 }
1233
1234 Theme* PluginServer::get_theme()
1235 {
1236         if( mwindow ) return mwindow->theme;
1237         printf("PluginServer::get_theme mwindow not set\n");
1238         return 0;
1239 }
1240
1241
1242 void PluginServer::get_plugin_png_name(char *png_name)
1243 {
1244         char *pp = png_name, *ep = pp + BCSTRLEN-1;
1245         char *cp = strrchr(path, '/');
1246         cp = !cp ? path : cp+1;
1247         char *sp = strrchr(cp, '.');
1248         if( !sp ) sp = cp+strlen(cp);
1249         while( pp < ep && cp < sp ) *pp++ = *cp++;
1250         snprintf(pp, ep-pp, ".png");
1251 }
1252
1253 int PluginServer::get_plugin_png_path(char *png_path, const char *plugin_icons)
1254 {
1255         char png_name[BCSTRLEN];
1256         get_plugin_png_name(png_name);
1257         char *pp = png_path, *ep = pp + BCTEXTLEN-1;
1258         pp += snprintf(pp, ep-pp, "%s/picon/%s/%s",
1259                 File::get_plugin_path(), plugin_icons, png_name);
1260         return access(png_path,R_OK) ? 1 : 0;
1261 }
1262
1263 int PluginServer::get_plugin_png_path(char *png_path)
1264 {
1265         int ret = get_plugin_png_path(png_path, mwindow->preferences->plugin_icons);
1266         if( ret ) ret = get_plugin_png_path(png_path, DEFAULT_PICON);
1267         return ret;
1268 }
1269
1270 VFrame *PluginServer::get_plugin_images()
1271 {
1272         char png_path[BCTEXTLEN];
1273         if( !get_plugin_png_path(png_path) )
1274                 return VFramePng::vframe_png(png_path,0,0);
1275         char png_name[BCSTRLEN];
1276         get_plugin_png_name(png_name);
1277         unsigned char *data = mwindow->theme->get_image_data(png_name, 0);
1278         return data ? new VFramePng(data, 0.) : 0;
1279 }
1280
1281 VFrame *PluginServer::get_picon()
1282 {
1283         if( !picon )
1284                 picon = get_plugin_images();
1285         return picon;
1286 }
1287
1288 // Called when plugin interface is tweeked
1289 void PluginServer::sync_parameters()
1290 {
1291         if( video ) mwindow->restart_brender();
1292         mwindow->sync_parameters();
1293         mwindow->update_keyframe_guis();
1294         if( mwindow->edl->session->auto_conf->plugins ) {
1295                 mwindow->gui->lock_window("PluginServer::sync_parameters");
1296                 mwindow->gui->draw_overlays(1);
1297                 mwindow->gui->unlock_window();
1298         }
1299 }
1300
1301 int64_t PluginServer::get_startproject()
1302 {
1303         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1304         return !plugin ? -1 : plugin->startproject;
1305 }
1306 int64_t PluginServer::get_endproject()
1307 {
1308         Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
1309         return !plugin ? -1 : plugin->startproject + plugin->length;
1310 }
1311
1312 void PluginServer::dump(FILE *fp)
1313 {
1314         fprintf(fp,"    PluginServer %d %p %s %s %d\n",
1315                 __LINE__, this, path, title, realtime);
1316 }