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