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