no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / pluginclient.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 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 "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "bcsignals.h"
25 #include "attachmentpoint.h"
26 #include "clip.h"
27 #include "condition.h"
28 #include "edits.h"
29 #include "edit.h"
30 #include "edl.h"
31 #include "edlsession.h"
32 #include "file.h"
33 #include "filesystem.h"
34 #include "filexml.h"
35 #include "indexable.h"
36 #include "language.h"
37 #include "localsession.h"
38 #include "mainundo.h"
39 #include "mwindow.h"
40 #include "plugin.h"
41 #include "pluginclient.h"
42 #include "pluginserver.h"
43 #include "preferences.h"
44 #include "renderengine.h"
45 #include "track.h"
46 #include "tracks.h"
47 #include "transportque.h"
48
49 #include <stdio.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <fcntl.h>
53 #include <string.h>
54 #include <ctype.h>
55 #include <errno.h>
56
57 PluginClientFrame::PluginClientFrame()
58 {
59         position = -1;
60 }
61
62 PluginClientFrame::~PluginClientFrame()
63 {
64 }
65
66
67 PluginClientThread::PluginClientThread(PluginClient *client)
68  : Thread(1, 0, 0)
69 {
70         this->client = client;
71         window = 0;
72         init_complete = new Condition(0, "PluginClientThread::init_complete");
73 }
74
75 PluginClientThread::~PluginClientThread()
76 {
77         delete window;
78         delete init_complete;
79 }
80
81 void PluginClientThread::run()
82 {
83         BC_DisplayInfo info;
84         int result = 0;
85         if(client->window_x < 0) client->window_x = info.get_abs_cursor_x();
86         if(client->window_y < 0) client->window_y = info.get_abs_cursor_y();
87         if(!window)
88                 window = (PluginClientWindow*)client->new_window();
89
90         if(window) {
91                 window->lock_window("PluginClientThread::run");
92                 window->create_objects();
93                 VFrame *picon = client->server->get_picon();
94                 if( picon ) window->set_icon(picon);
95                 window->unlock_window();
96
97 /* Only set it here so tracking doesn't update it until everything is created. */
98                 client->thread = this;
99                 init_complete->unlock();
100
101                 result = window->run_window();
102                 window->lock_window("PluginClientThread::run");
103 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
104                 window->hide_window(1);
105                 client->save_defaults_xml(); // needs window lock
106                 window->unlock_window();
107                 window->done_event(result);
108 /* This is needed when the GUI is closed from itself */
109                 if(result) client->client_side_close();
110         }
111         else
112 // No window
113         {
114                 client->thread = this;
115                 init_complete->unlock();
116         }
117 }
118
119 BC_WindowBase* PluginClientThread::get_window()
120 {
121         return window;
122 }
123
124 PluginClient* PluginClientThread::get_client()
125 {
126         return client;
127 }
128
129
130 PluginClientWindow::PluginClientWindow(PluginClient *client,
131         int w, int h, int min_w, int min_h, int allow_resize)
132  : BC_Window(client->gui_string,
133         client->window_x /* - w / 2 */, client->window_y /* - h / 2 */,
134         w, h, min_w, min_h, allow_resize, 0, 1)
135 {
136         char title[BCTEXTLEN];
137
138         this->client = client;
139
140 // *** CONTEXT_HELP ***
141         if(client) {
142                 strcpy(title, client->plugin_title());
143                 if(! strcmp(title, "Overlay")) {
144                         // "Overlay" plugin title is ambiguous
145                         if(client->is_audio()) strcat(title, " \\(Audio\\)");
146                         if(client->is_video()) strcat(title, " \\(Video\\)");
147                 }
148                 if(client->server->is_ffmpeg()) {
149                         // FFmpeg plugins can be audio or video
150                         if(client->is_audio())
151                                 strcpy(title, "FFmpeg Audio Plugins");
152                         if(client->is_video())
153                                 strcpy(title, "FFmpeg Video Plugins");
154                 }
155                 context_help_set_keyword(title);
156         }
157 }
158
159 PluginClientWindow::PluginClientWindow(const char *title,
160         int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
161  : BC_Window(title, x, y, w, h, min_w, min_h, allow_resize, 0, 1)
162 {
163         this->client = 0;
164 // *** CONTEXT_HELP ***
165         context_help_set_keyword(title);
166 }
167
168 PluginClientWindow::~PluginClientWindow()
169 {
170 }
171
172
173 int PluginClientWindow::translation_event()
174 {
175         if(client)
176         {
177                 client->window_x = get_x();
178                 client->window_y = get_y();
179         }
180
181         return 1;
182 }
183
184 int PluginClientWindow::close_event()
185 {
186 /* Set result to 1 to indicate a client side close */
187         set_done(1);
188         return 1;
189 }
190
191 void PluginClientWindow::param_updated()
192 {
193     printf("PluginClientWindow::param_updated %d undefined\n", __LINE__);
194 }
195
196 //phyllis
197 PluginParam::PluginParam(PluginClient *plugin, PluginClientWindow *gui,
198     int x1, int x2, int x3, int y, int text_w,
199     int *output_i, float *output_f, int *output_q,
200     const char *title, float min, float max)
201 {
202     this->output_i = output_i;
203     this->output_f = output_f;
204     this->output_q = output_q;
205     this->title = cstrdup(title);
206     this->plugin = plugin;
207     this->gui = gui;
208     this->x1 = x1;
209     this->x2 = x2;
210     this->x3 = x3;
211     this->text_w = text_w;
212     this->y = y;
213     this->min = min;
214     this->max = max;
215     fpot = 0;
216     ipot = 0;
217     qpot = 0;
218     text = 0;
219     precision = 2;
220 }
221 PluginParam::~PluginParam()
222 {
223     delete fpot;
224     delete ipot;
225     delete qpot;
226     delete text;
227     delete title;
228 }
229
230
231 void PluginParam::initialize()
232 {
233     BC_Title *title_;
234     int y2 = y +
235         (BC_Pot::calculate_h() -
236         BC_Title::calculate_h(gui, _(title), MEDIUMFONT)) / 2;
237     gui->add_tool(title_ = new BC_Title(x1, y2, _(title)));
238
239     if(output_f)
240     {
241         gui->add_tool(fpot = new PluginFPot(this, x2, y));
242     }
243
244     if(output_i)
245     {
246         gui->add_tool(ipot = new PluginIPot(this, x2, y));
247     }
248
249     if(output_q)
250     {
251         gui->add_tool(qpot = new PluginQPot(this, x2, y));
252     }
253
254     int y3 = y +
255         (BC_Pot::calculate_h() -
256         BC_TextBox::calculate_h(gui, MEDIUMFONT, 1, 1)) / 2;
257     if(output_i)
258     {
259         gui->add_tool(text = new PluginText(this, x3, y3, *output_i));
260     }
261     if(output_f)
262     {
263         gui->add_tool(text = new PluginText(this, x3, y3, *output_f));
264     }
265     if(output_q)
266     {
267         gui->add_tool(text = new PluginText(this, x3, y3, *output_q));
268     }
269
270     set_precision(precision);
271 }
272
273 void PluginParam::update(int skip_text, int skip_pot)
274 {
275     if(!skip_text)
276     {
277         if(output_i)
278         {
279             text->update((int64_t)*output_i);
280         }
281         if(output_q)
282         {
283             text->update((int64_t)*output_q);
284         }
285         if(output_f)
286         {
287             text->update((float)*output_f);
288         }
289     }
290
291     if(!skip_pot)
292     {
293         if(ipot)
294         {
295             ipot->update((int64_t)*output_i);
296         }
297         if(qpot)
298         {
299             qpot->update((int64_t)*output_q);
300         }
301         if(fpot)
302         {
303             fpot->update((float)*output_f);
304         }
305     }
306 }
307
308 void PluginParam::set_precision(int digits)
309 {
310     this->precision = digits;
311     if(fpot)
312     {
313         if(text)
314         {
315             text->set_precision(digits);
316         }
317
318         fpot->set_precision(1.0f / pow(10, digits));
319     }
320 }
321
322
323 PluginFPot::PluginFPot(PluginParam *param, int x, int y)
324  : BC_FPot(x,
325         y,
326         *param->output_f,
327         param->min,
328         param->max)
329 {
330     this->param = param;
331     set_use_caption(0);
332 }
333
334 int PluginFPot::handle_event()
335 {
336         *param->output_f = get_value();
337     param->update(0, 1);
338         param->plugin->send_configure_change();
339     param->gui->param_updated();
340     return 1;
341 }
342
343 PluginIPot::PluginIPot(PluginParam *param, int x, int y)
344  : BC_IPot(x,
345         y,
346         *param->output_i,
347         (int)param->min,
348         (int)param->max)
349 {
350     this->param = param;
351     set_use_caption(0);
352 }
353
354 int PluginIPot::handle_event()
355 {
356         *param->output_i = get_value();
357     param->update(0, 1);
358         param->plugin->send_configure_change();
359     param->gui->param_updated();
360     return 1;
361 }
362
363
364 PluginQPot::PluginQPot(PluginParam *param, int x, int y)
365  : BC_QPot(x,
366         y,
367         *param->output_q)
368 {
369     this->param = param;
370     set_use_caption(0);
371 }
372
373 int PluginQPot::handle_event()
374 {
375         *param->output_q = get_value();
376     param->update(0, 1);
377         param->plugin->send_configure_change();
378     param->gui->param_updated();
379     return 1;
380 }
381
382 PluginText::PluginText(PluginParam *param, int x, int y, int value)
383  : BC_TextBox(x,
384     y,
385     param->text_w,
386     1,
387     (int64_t)value,
388     1,
389     MEDIUMFONT)
390 {
391     this->param = param;
392 }
393
394 PluginText::PluginText(PluginParam *param, int x, int y, float value)
395  : BC_TextBox(x,
396     y,
397     param->text_w,
398     1,
399     (float)value,
400     1,
401     MEDIUMFONT,
402     param->precision)
403 {
404     this->param = param;
405 }
406
407 int PluginText::handle_event()
408 {
409     if(param->output_i)
410     {
411         *param->output_i = atoi(get_text());
412     }
413
414     if(param->output_f)
415     {
416         *param->output_f = atof(get_text());
417     }
418
419     if(param->output_q)
420     {
421         *param->output_q = atoi(get_text());
422     }
423     param->update(1, 0);
424     param->plugin->send_configure_change();
425     param->gui->param_updated();
426     return 1;
427 }
428
429
430 PluginClient::PluginClient(PluginServer *server)
431 {
432         reset();
433         this->server = server;
434         smp = server->preferences->project_smp;
435         defaults = 0;
436         update_timer = new Timer;
437 // Virtual functions don't work here.
438 }
439
440 PluginClient::~PluginClient()
441 {
442         if( thread ) {
443                 hide_gui();
444                 thread->join();
445                 delete thread;
446         }
447
448 // Virtual functions don't work here.
449         if(defaults) delete defaults;
450         delete update_timer;
451 }
452
453 int PluginClient::reset()
454 {
455         window_x = -1;
456         window_y = -1;
457         interactive = 0;
458         show_initially = 0;
459         wr = rd = 0;
460         master_gui_on = 0;
461         client_gui_on = 0;
462         realtime_priority = 0;
463         gui_string[0] = 0;
464         total_in_buffers = 0;
465         total_out_buffers = 0;
466         source_position = 0;
467         source_start = 0;
468         total_len = 0;
469         direction = PLAY_FORWARD;
470         thread = 0;
471         using_defaults = 0;
472         return 0;
473 }
474
475
476 void PluginClient::hide_gui()
477 {
478         if(thread && thread->window)
479         {
480                 thread->window->lock_window("PluginClient::hide_gui");
481                 thread->window->set_done(0);
482                 thread->window->unlock_window();
483         }
484 }
485
486 // For realtime plugins initialize buffers
487 int PluginClient::plugin_init_realtime(int realtime_priority,
488         int total_in_buffers,
489         int buffer_size)
490 {
491
492 // Get parameters for all
493         master_gui_on = get_gui_status();
494
495
496
497 // get parameters depending on video or audio
498         init_realtime_parameters();
499
500         this->realtime_priority = realtime_priority;
501         this->total_in_buffers = this->total_out_buffers = total_in_buffers;
502         this->out_buffer_size = this->in_buffer_size = buffer_size;
503         return 0;
504 }
505
506 int PluginClient::plugin_start_loop(int64_t start,
507         int64_t end,
508         int64_t buffer_size,
509         int total_buffers)
510 {
511 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
512 // __LINE__, start, end, buffer_size, total_buffers);
513         this->source_start = start;
514         this->total_len = end - start;
515         this->start = start;
516         this->end = end;
517         this->in_buffer_size = this->out_buffer_size = buffer_size;
518         this->total_in_buffers = this->total_out_buffers = total_buffers;
519         start_loop();
520         return 0;
521 }
522
523 int PluginClient::plugin_process_loop()
524 {
525         return process_loop();
526 }
527
528 int PluginClient::plugin_stop_loop()
529 {
530         return stop_loop();
531 }
532
533 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
534 {
535         return server->start_progress(string, length);
536 }
537
538
539 // Non realtime parameters
540 int PluginClient::plugin_get_parameters()
541 {
542         int result = get_parameters();
543         if(defaults) save_defaults();
544         return result;
545 }
546
547 // ========================= main loop
548
549 int PluginClient::is_multichannel() { return 0; }
550 int PluginClient::is_synthesis() { return 0; }
551 int PluginClient::is_realtime() { return 0; }
552 int PluginClient::is_fileio() { return 0; }
553 const char* PluginClient::plugin_title() { return _("Untitled"); }
554
555 Theme* PluginClient::new_theme() { return 0; }
556
557 int PluginClient::load_configuration()
558 {
559         return 0;
560 }
561
562 Theme* PluginClient::get_theme()
563 {
564         return server->get_theme();
565 }
566
567 int PluginClient::show_gui()
568 {
569         load_configuration();
570         thread = new PluginClientThread(this);
571         thread->start();
572         thread->init_complete->lock("PluginClient::show_gui");
573 // Must wait before sending any hide_gui
574         if( !thread->window ) return 1;
575         thread->window->init_wait();
576         return 0;
577 }
578
579 void PluginClient::raise_window()
580 {
581         if(thread && thread->window)
582         {
583                 thread->window->lock_window("PluginClient::raise_window");
584                 thread->window->raise_window();
585                 thread->window->flush();
586                 thread->window->unlock_window();
587         }
588 }
589
590 int PluginClient::set_string()
591 {
592         if(thread)
593         {
594                 thread->window->lock_window("PluginClient::set_string");
595                 thread->window->put_title(gui_string);
596                 thread->window->unlock_window();
597         }
598         return 0;
599 }
600
601
602
603
604
605 PluginClientFrames::PluginClientFrames()
606 {
607         count = 0;
608 }
609 PluginClientFrames::~PluginClientFrames()
610 {
611 }
612
613 int PluginClientFrames::fwd_cmpr(PluginClientFrame *a, PluginClientFrame *b)
614 {
615         double d = a->position - b->position;
616         return d < 0 ? -1 : !d ? 0 : 1;
617 }
618
619 int PluginClientFrames::rev_cmpr(PluginClientFrame *a, PluginClientFrame *b)
620 {
621         double d = b->position - a->position;
622         return d < 0 ? -1 : !d ? 0 : 1;
623 }
624
625 void PluginClientFrames::reset()
626 {
627         destroy();
628         count = 0;
629 }
630
631 void PluginClientFrames::add_gui_frame(PluginClientFrame *frame)
632 {
633         append(frame);
634         ++count;
635 }
636
637 void PluginClientFrames::concatenate(PluginClientFrames *frames)
638 {
639         concat(*frames);
640         count += frames->count;
641         frames->count = 0;
642 }
643
644 void PluginClientFrames::sort_position(int dir)
645 {
646 // enforce order
647         if( dir == PLAY_REVERSE )
648                 rev_sort();
649         else
650                 fwd_sort();
651 }
652
653 // pop frames until buffer passes position=pos in direction=dir
654 // dir==0, pop frame; pos<0, pop all frames
655 // delete past frames, return last popped frame
656 PluginClientFrame* PluginClientFrames::get_gui_frame(double pos, int dir)
657 {
658         if( dir ) {
659                 while( first != last ) {
660                         if( pos >= 0 && dir*(first->next->position - pos) > 0 ) break;
661                         delete first;  --count;
662                 }
663         }
664         PluginClientFrame *frame = first;
665         if( frame ) { remove_pointer(frame);  --count; }
666         return frame;
667 }
668
669 PluginClientFrame* PluginClient::get_gui_frame(double pos, int dir)
670 {
671         return client_frames.get_gui_frame(pos, dir);
672 }
673 PluginClientFrame* PluginClient::next_gui_frame()
674 {
675         return client_frames.first;
676 }
677
678
679 void PluginClient::plugin_update_gui()
680 {
681         update_gui();
682 }
683
684 void PluginClient::update_gui()
685 {
686 }
687
688 int PluginClient::pending_gui_frame()
689 {
690         PluginClientFrame *frame = client_frames.first;
691         if( !frame ) return 0;
692         double tracking_position = get_tracking_position();
693         int direction = get_tracking_direction();
694         int ret = !(direction == PLAY_REVERSE ?
695                 frame->position < tracking_position :
696                 frame->position > tracking_position);
697         return ret;
698 }
699
700 int PluginClient::pending_gui_frames()
701 {
702         PluginClientFrame *frame = client_frames.first;
703         if( !frame ) return 0;
704         double tracking_position = get_tracking_position();
705         int direction = get_tracking_direction();
706         int count = 0;
707         while( frame && !(direction == PLAY_REVERSE ?
708             frame->position < tracking_position :
709             frame->position > tracking_position) ) {
710                 ++count;  frame=frame->next;
711         }
712         return count;
713 }
714
715 void PluginClient::add_gui_frame(PluginClientFrame *frame)
716 {
717         client_frames.add_gui_frame(frame);
718 }
719 int PluginClient::get_gui_frames()
720 {
721         return client_frames.total();
722 }
723
724 double PluginClient::get_tracking_position()
725 {
726         return server->mwindow->get_tracking_position();
727 }
728
729 int PluginClient::get_tracking_direction()
730 {
731         return server->mwindow->get_tracking_direction();
732 }
733
734 void PluginClient::send_render_gui()
735 {
736         server->send_render_gui(&client_frames);
737 }
738
739 void PluginClient::send_render_gui(void *data)
740 {
741         server->send_render_gui(data);
742 }
743
744 void PluginClient::send_render_gui(void *data, int size)
745 {
746         server->send_render_gui(data, size);
747 }
748
749
750 void PluginClient::plugin_reset_gui_frames()
751 {
752         if( !thread ) return;
753         BC_WindowBase *window = thread->get_window();
754         if( !window ) return;
755         window->lock_window("PluginClient::plugin_reset_gui_frames");
756         client_frames.reset();
757         window->unlock_window();
758 }
759
760 void PluginClient::plugin_render_gui_frames(PluginClientFrames *frames)
761 {
762         if( !thread ) return;
763         BC_WindowBase *window = thread->get_window();
764         if( !window ) return;
765         window->lock_window("PluginClient::render_gui");
766         while( client_frames.count > MAX_FRAME_BUFFER )
767                 delete get_gui_frame(0, 0);
768 // append client frames to gui client_frames, consumes frames
769         client_frames.concatenate(frames);
770         client_frames.sort_position(get_tracking_direction());
771         update_timer->update();
772         window->unlock_window();
773 }
774
775 void PluginClient::plugin_render_gui(void *data)
776 {
777         render_gui(data);
778 }
779
780 void PluginClient::plugin_render_gui(void *data, int size)
781 {
782         render_gui(data, size);
783 }
784
785 void PluginClient::render_gui(void *data)
786 {
787         printf("PluginClient::render_gui %d\n", __LINE__);
788 }
789
790 void PluginClient::render_gui(void *data, int size)
791 {
792         printf("PluginClient::render_gui %d\n", __LINE__);
793 }
794
795 void PluginClient::reset_gui_frames()
796 {
797         server->reset_gui_frames();
798 }
799
800 int PluginClient::is_audio() { return 0; }
801 int PluginClient::is_video() { return 0; }
802 int PluginClient::is_theme() { return 0; }
803 int PluginClient::uses_gui() { return 1; }
804 int PluginClient::is_transition() { return 0; }
805 int PluginClient::load_defaults()
806 {
807 //      printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
808         return 0;
809 }
810
811 int PluginClient::save_defaults()
812 {
813         save_defaults_xml();
814 //      printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
815         return 0;
816 }
817
818 void PluginClient::load_defaults_xml()
819 {
820         char path[BCTEXTLEN];
821         server->get_defaults_path(path);
822         FileSystem fs;
823         fs.complete_path(path);
824         using_defaults = 1;
825 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
826
827         char *data = 0;
828         int64_t len = -1;
829         struct stat st;
830         int fd = open(path, O_RDONLY);
831         if( fd >= 0 && !fstat(fd, &st) ) {
832                 int64_t sz = st.st_size;
833                 data = new char[sz+1];
834                 len = read(fd, data, sz);
835                 close(fd);
836         }
837         if( data && len >= 0 ) {
838                 data[len] = 0;
839 // Get window extents
840                 int i = 0;
841                 for( int state=0; i<len && state>=0; ++i ) {
842                         if( !data[i] || data[i] == '<' ) break;
843                         if( !isdigit(data[i]) ) continue;
844                         if( !state ) {
845                                 window_x = atoi(data+i);
846                                 state = 1;
847                         }
848                         else {
849                                 window_y = atoi(data+i);
850                                 state = -1;
851                         }
852                         while( i<len && isdigit(data[i]) ) ++i;
853                 }
854                 KeyFrame keyframe(data+i, len-i);
855                 read_data(&keyframe);
856         }
857         delete [] data;
858
859         using_defaults = 0;
860 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
861 }
862
863 void PluginClient::save_defaults_xml()
864 {
865         char path[BCTEXTLEN];
866         server->get_defaults_path(path);
867         FileSystem fs;
868         fs.complete_path(path);
869         using_defaults = 1;
870
871         KeyFrame temp_keyframe;
872         save_data(&temp_keyframe);
873
874         const char *data = temp_keyframe.get_data();
875         int len = strlen(data);
876         FILE *fp = fopen(path, "w");
877
878         if( fp ) {
879                 fprintf(fp, "%d\n%d\n", window_x, window_y);
880                 if( len > 0 && !fwrite(data, len, 1, fp) ) {
881                         fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
882                                 __LINE__, path, len, strerror(errno));
883                 }
884                 fclose(fp);
885         }
886
887         using_defaults = 0;
888 }
889
890 int PluginClient::is_defaults()
891 {
892         return using_defaults;
893 }
894
895 BC_Hash* PluginClient::get_defaults()
896 {
897         return defaults;
898 }
899 PluginClientThread* PluginClient::get_thread()
900 {
901         return thread;
902 }
903
904 BC_WindowBase* PluginClient::new_window()
905 {
906         printf("PluginClient::new_window undefined in %s.\n", plugin_title());
907         return 0;
908 }
909 int PluginClient::get_parameters() { return 0; }
910 int PluginClient::get_samplerate() { return get_project_samplerate(); }
911 double PluginClient::get_framerate() { return get_project_framerate(); }
912 int PluginClient::init_realtime_parameters() { return 0; }
913 int PluginClient::delete_nonrealtime_parameters() { return 0; }
914 int PluginClient::start_loop() { return 0; };
915 int PluginClient::process_loop() { return 0; };
916 int PluginClient::stop_loop() { return 0; };
917
918 void PluginClient::set_interactive()
919 {
920         interactive = 1;
921 }
922
923 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
924 {
925         return recommended_size;
926 }
927
928 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
929 {
930         return recommended_size;
931 }
932
933 int PluginClient::get_gui_status()
934 {
935         return server->get_gui_status();
936 }
937
938 // close event from client side
939 void PluginClient::client_side_close()
940 {
941 // Last command executed
942         server->client_side_close();
943 }
944
945 int PluginClient::stop_gui_client()
946 {
947         if(!client_gui_on) return 0;
948         client_gui_on = 0;
949         return 0;
950 }
951
952 int PluginClient::get_project_samplerate()
953 {
954         return server->get_project_samplerate();
955 }
956
957 double PluginClient::get_project_framerate()
958 {
959         return server->get_project_framerate();
960 }
961
962 const char *PluginClient::get_source_path()
963 {
964         Plugin *plugin = server->edl->tracks->plugin_exists(server->plugin_id);
965         int64_t source_position = plugin->startproject;
966         Edit *edit = plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
967         Indexable *indexable = edit ? edit->get_source() : 0;
968         return indexable ? indexable->path : 0;
969 }
970
971
972 void PluginClient::update_display_title()
973 {
974         server->generate_display_title(gui_string);
975         set_string();
976 }
977
978 char* PluginClient::get_gui_string()
979 {
980         return gui_string;
981 }
982
983
984 char* PluginClient::get_path()
985 {
986         return server->path;
987 }
988
989 char* PluginClient::get_plugin_dir()
990 {
991         return server->preferences->plugin_dir;
992 }
993
994 int PluginClient::set_string_client(char *string)
995 {
996         strcpy(gui_string, string);
997         set_string();
998         return 0;
999 }
1000
1001
1002 int PluginClient::get_interpolation_type()
1003 {
1004         return server->get_interpolation_type();
1005 }
1006
1007
1008 float PluginClient::get_red()
1009 {
1010         EDL *edl = get_edl();
1011         return edl->local_session->use_max ?
1012                 edl->local_session->red_max :
1013                 edl->local_session->red;
1014 }
1015
1016 float PluginClient::get_green()
1017 {
1018         EDL *edl = get_edl();
1019         return edl->local_session->use_max ?
1020                 edl->local_session->green_max :
1021                 edl->local_session->green;
1022 }
1023
1024 float PluginClient::get_blue()
1025 {
1026         EDL *edl = get_edl();
1027         return edl->local_session->use_max ?
1028                 edl->local_session->blue_max :
1029                 edl->local_session->blue;
1030 }
1031
1032
1033 int64_t PluginClient::get_source_position()
1034 {
1035         return source_position;
1036 }
1037
1038 int64_t PluginClient::get_source_start()
1039 {
1040         return source_start;
1041 }
1042
1043 int64_t PluginClient::get_total_len()
1044 {
1045         return total_len;
1046 }
1047
1048 int PluginClient::get_direction()
1049 {
1050         return direction;
1051 }
1052
1053 int64_t PluginClient::local_to_edl(int64_t position)
1054 {
1055         return position;
1056 }
1057
1058 int64_t PluginClient::edl_to_local(int64_t position)
1059 {
1060         return position;
1061 }
1062
1063 int PluginClient::get_use_opengl()
1064 {
1065         return server->get_use_opengl();
1066 }
1067
1068 int PluginClient::to_ram(VFrame *vframe)
1069 {
1070         return server->to_ram(vframe);
1071 }
1072
1073 int PluginClient::get_total_buffers()
1074 {
1075         return total_in_buffers;
1076 }
1077
1078 int PluginClient::get_buffer_size()
1079 {
1080         return in_buffer_size;
1081 }
1082
1083 int PluginClient::get_project_smp()
1084 {
1085 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
1086         return smp;
1087 }
1088
1089 const char* PluginClient::get_defaultdir()
1090 {
1091         return File::get_plugin_path();
1092 }
1093
1094
1095 int PluginClient::send_hide_gui()
1096 {
1097 // Stop the GUI server and delete GUI messages
1098         client_gui_on = 0;
1099         return 0;
1100 }
1101
1102 int PluginClient::send_configure_change()
1103 {
1104         if(server->mwindow)
1105                 server->mwindow->undo->update_undo_before(_("tweek"), this);
1106 #ifdef USE_KEYFRAME_SPANNING
1107         EDL *edl = server->edl;
1108         Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
1109         KeyFrames *keyframes = plugin ? plugin->keyframes : 0;
1110         KeyFrame keyframe(edl, keyframes);
1111         save_data(&keyframe);
1112         server->apply_keyframe(plugin, &keyframe);
1113 #else
1114         KeyFrame* keyframe = server->get_keyframe();
1115 // Call save routine in plugin
1116         save_data(keyframe);
1117 #endif
1118         if(server->mwindow)
1119                 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
1120         server->sync_parameters();
1121         return 0;
1122 }
1123
1124 // virtual default spanning keyframe update.  If a range is selected,
1125 // then changed parameters are copied to (prev + selected) keyframes.
1126 // redefine per client for custom keyframe updates, see tracer, sketcher, crikey
1127 void PluginClient::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
1128 {
1129         src->span_keyframes(start, end);
1130 }
1131
1132
1133 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
1134 {
1135         if(is_local) position = local_to_edl(position);
1136         return server->get_prev_keyframe(position);
1137 }
1138
1139 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
1140 {
1141         if(is_local) position = local_to_edl(position);
1142         return server->get_next_keyframe(position);
1143 }
1144
1145 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
1146 {
1147         server->get_camera(x, y, z, position, direction);
1148 }
1149
1150 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
1151 {
1152         server->get_projector(x, y, z, position, direction);
1153 }
1154
1155
1156 void PluginClient::output_to_track(float ox, float oy, float &tx, float &ty)
1157 {
1158         float projector_x, projector_y, projector_z;
1159         int64_t position = get_source_position();
1160         get_projector(&projector_x, &projector_y, &projector_z, position);
1161         EDL *edl = get_edl();
1162         projector_x += edl->session->output_w / 2;
1163         projector_y += edl->session->output_h / 2;
1164         Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
1165         Track *track = plugin ? plugin->track : 0;
1166         int track_w = track ? track->track_w : edl->session->output_w;
1167         int track_h = track ? track->track_h : edl->session->output_h;
1168         tx = (ox - projector_x) / projector_z + track_w / 2;
1169         ty = (oy - projector_y) / projector_z + track_h / 2;
1170 }
1171
1172 void PluginClient::track_to_output(float tx, float ty, float &ox, float &oy)
1173 {
1174         float projector_x, projector_y, projector_z;
1175         int64_t position = get_source_position();
1176         get_projector(&projector_x, &projector_y, &projector_z, position);
1177         EDL *edl = get_edl();
1178         projector_x += edl->session->output_w / 2;
1179         projector_y += edl->session->output_h / 2;
1180         Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
1181         Track *track = plugin ? plugin->track : 0;
1182         int track_w = track ? track->track_w : edl->session->output_w;
1183         int track_h = track ? track->track_h : edl->session->output_h;
1184         ox = (tx - track_w / 2) * projector_z + projector_x;
1185         oy = (ty - track_h / 2) * projector_z + projector_y;
1186 }
1187
1188
1189 EDL *PluginClient::get_edl()
1190 {
1191         return server->mwindow ? server->mwindow->edl : server->edl;
1192 }
1193
1194 int PluginClient::gui_open()
1195 {
1196         return server->gui_open();
1197 }
1198
1199