4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
26 #include "condition.h"
30 #include "edlsession.h"
32 #include "filesystem.h"
34 #include "indexable.h"
36 #include "localsession.h"
40 #include "pluginclient.h"
41 #include "pluginserver.h"
42 #include "preferences.h"
44 #include "transportque.inc"
55 PluginClientThread::PluginClientThread(PluginClient *client)
58 this->client = client;
60 init_complete = new Condition(0, "PluginClientThread::init_complete");
63 PluginClientThread::~PluginClientThread()
66 //printf("PluginClientThread::~PluginClientThread %p %d\n", this, __LINE__);
67 delete window; window = 0;
68 //printf("PluginClientThread::~PluginClientThread %p %d\n", this, __LINE__);
72 void PluginClientThread::run()
76 if(client->window_x < 0) client->window_x = info.get_abs_cursor_x();
77 if(client->window_y < 0) client->window_y = info.get_abs_cursor_y();
79 window = (PluginClientWindow*)client->new_window();
82 window->lock_window("PluginClientThread::run");
83 window->create_objects();
84 VFrame *picon = client->server->get_picon();
85 if( picon ) window->set_icon(picon);
86 window->unlock_window();
88 /* Only set it here so tracking doesn't update it until everything is created. */
89 client->thread = this;
90 init_complete->unlock();
92 result = window->run_window();
93 window->lock_window("PluginClientThread::run");
94 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
95 window->hide_window(1);
96 window->unlock_window();
97 window->done_event(result);
98 // Can't save defaults in the destructor because it's not called immediately
100 /* if(client->defaults) */ client->save_defaults_xml();
101 /* This is needed when the GUI is closed from itself */
102 if(result) client->client_side_close();
107 client->thread = this;
108 init_complete->unlock();
112 BC_WindowBase* PluginClientThread::get_window()
117 PluginClient* PluginClientThread::get_client()
127 PluginClientFrame::PluginClientFrame(int data_size,
131 this->data_size = data_size;
133 this->period_n = period_n;
134 this->period_d = period_d;
137 PluginClientFrame::~PluginClientFrame()
146 PluginClientWindow::PluginClientWindow(PluginClient *client,
147 int w, int h, int min_w, int min_h, int allow_resize)
148 : BC_Window(client->gui_string,
149 client->window_x /* - w / 2 */, client->window_y /* - h / 2 */,
150 w, h, min_w, min_h, allow_resize, 0, 1)
152 this->client = client;
155 PluginClientWindow::PluginClientWindow(const char *title,
156 int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
157 : BC_Window(title, x, y, w, h, min_w, min_h, allow_resize, 0, 1)
162 PluginClientWindow::~PluginClientWindow()
167 int PluginClientWindow::translation_event()
171 client->window_x = get_x();
172 client->window_y = get_y();
178 int PluginClientWindow::close_event()
180 /* Set result to 1 to indicate a client side close */
185 void PluginClientWindow::param_updated()
187 printf("PluginClientWindow::param_updated %d undefined\n", __LINE__);
191 PluginParam::PluginParam(PluginClient *plugin, PluginClientWindow *gui,
192 int x1, int x2, int x3, int y, int text_w,
193 int *output_i, float *output_f, int *output_q,
194 const char *title, float min, float max)
196 this->output_i = output_i;
197 this->output_f = output_f;
198 this->output_q = output_q;
199 this->title = cstrdup(title);
200 this->plugin = plugin;
205 this->text_w = text_w;
215 PluginParam::~PluginParam()
225 void PluginParam::initialize()
229 (BC_Pot::calculate_h() -
230 BC_Title::calculate_h(gui, _(title), MEDIUMFONT)) / 2;
231 gui->add_tool(title_ = new BC_Title(x1, y2, _(title)));
235 gui->add_tool(fpot = new PluginFPot(this, x2, y));
240 gui->add_tool(ipot = new PluginIPot(this, x2, y));
245 gui->add_tool(qpot = new PluginQPot(this, x2, y));
249 (BC_Pot::calculate_h() -
250 BC_TextBox::calculate_h(gui, MEDIUMFONT, 1, 1)) / 2;
253 gui->add_tool(text = new PluginText(this, x3, y3, *output_i));
257 gui->add_tool(text = new PluginText(this, x3, y3, *output_f));
261 gui->add_tool(text = new PluginText(this, x3, y3, *output_q));
264 set_precision(precision);
267 void PluginParam::update(int skip_text, int skip_pot)
273 text->update((int64_t)*output_i);
277 text->update((int64_t)*output_q);
281 text->update((float)*output_f);
289 ipot->update((int64_t)*output_i);
293 qpot->update((int64_t)*output_q);
297 fpot->update((float)*output_f);
302 void PluginParam::set_precision(int digits)
304 this->precision = digits;
309 text->set_precision(digits);
312 fpot->set_precision(1.0f / pow(10, digits));
317 PluginFPot::PluginFPot(PluginParam *param, int x, int y)
328 int PluginFPot::handle_event()
330 *param->output_f = get_value();
332 param->plugin->send_configure_change();
333 param->gui->param_updated();
337 PluginIPot::PluginIPot(PluginParam *param, int x, int y)
348 int PluginIPot::handle_event()
350 *param->output_i = get_value();
352 param->plugin->send_configure_change();
353 param->gui->param_updated();
358 PluginQPot::PluginQPot(PluginParam *param, int x, int y)
367 int PluginQPot::handle_event()
369 *param->output_q = get_value();
371 param->plugin->send_configure_change();
372 param->gui->param_updated();
376 PluginText::PluginText(PluginParam *param, int x, int y, int value)
388 PluginText::PluginText(PluginParam *param, int x, int y, float value)
401 int PluginText::handle_event()
405 *param->output_i = atoi(get_text());
410 *param->output_f = atof(get_text());
415 *param->output_q = atoi(get_text());
418 param->plugin->send_configure_change();
419 param->gui->param_updated();
427 PluginClient::PluginClient(PluginServer *server)
430 this->server = server;
431 smp = server->preferences->project_smp;
433 update_timer = new Timer;
434 // Virtual functions don't work here.
437 PluginClient::~PluginClient()
445 // Virtual functions don't work here.
446 if(defaults) delete defaults;
447 frame_buffer.remove_all_objects();
451 int PluginClient::reset()
460 realtime_priority = 0;
462 total_in_buffers = 0;
463 total_out_buffers = 0;
467 direction = PLAY_FORWARD;
474 void PluginClient::hide_gui()
476 if(thread && thread->window)
478 //printf("PluginClient::delete_thread %d\n", __LINE__);
479 /* This is needed when the GUI is closed from elsewhere than itself */
480 /* Since we now use autodelete, this is all that has to be done, thread will take care of itself ... */
481 /* Thread join will wait if this was not called from the thread itself or go on if it was */
482 thread->window->lock_window("PluginClient::hide_gui");
483 thread->window->set_done(0);
484 //printf("PluginClient::hide_gui %d thread->window=%p\n", __LINE__, thread->window);
485 thread->window->unlock_window();
489 // For realtime plugins initialize buffers
490 int PluginClient::plugin_init_realtime(int realtime_priority,
491 int total_in_buffers,
495 // Get parameters for all
496 master_gui_on = get_gui_status();
500 // get parameters depending on video or audio
501 init_realtime_parameters();
503 this->realtime_priority = realtime_priority;
504 this->total_in_buffers = this->total_out_buffers = total_in_buffers;
505 this->out_buffer_size = this->in_buffer_size = buffer_size;
509 int PluginClient::plugin_start_loop(int64_t start,
514 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
515 // __LINE__, start, end, buffer_size, total_buffers);
516 this->source_start = start;
517 this->total_len = end - start;
520 this->in_buffer_size = this->out_buffer_size = buffer_size;
521 this->total_in_buffers = this->total_out_buffers = total_buffers;
526 int PluginClient::plugin_process_loop()
528 return process_loop();
531 int PluginClient::plugin_stop_loop()
536 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
538 return server->start_progress(string, length);
542 // Non realtime parameters
543 int PluginClient::plugin_get_parameters()
545 int result = get_parameters();
546 if(defaults) save_defaults();
550 // ========================= main loop
552 int PluginClient::is_multichannel() { return 0; }
553 int PluginClient::is_synthesis() { return 0; }
554 int PluginClient::is_realtime() { return 0; }
555 int PluginClient::is_fileio() { return 0; }
556 int PluginClient::delete_buffer_ptrs() { return 0; }
557 const char* PluginClient::plugin_title() { return _("Untitled"); }
559 Theme* PluginClient::new_theme() { return 0; }
561 int PluginClient::load_configuration()
566 Theme* PluginClient::get_theme()
568 return server->get_theme();
571 int PluginClient::show_gui()
573 load_configuration();
574 thread = new PluginClientThread(this);
576 thread->init_complete->lock("PluginClient::show_gui");
577 // Must wait before sending any hide_gui
578 if( !thread->window ) return 1;
579 thread->window->init_wait();
583 void PluginClient::raise_window()
585 if(thread && thread->window)
587 thread->window->lock_window("PluginClient::raise_window");
588 thread->window->raise_window();
589 thread->window->flush();
590 thread->window->unlock_window();
594 int PluginClient::set_string()
598 thread->window->lock_window("PluginClient::set_string");
599 thread->window->put_title(gui_string);
600 thread->window->unlock_window();
609 void PluginClient::begin_process_buffer()
611 // Delete all unused GUI frames
612 frame_buffer.remove_all_objects();
616 void PluginClient::end_process_buffer()
618 if(frame_buffer.size())
626 void PluginClient::plugin_update_gui()
631 // Delete unused GUI frames
632 while(frame_buffer.size() > MAX_FRAME_BUFFER)
633 frame_buffer.remove_object_number(0);
637 void PluginClient::update_gui()
641 int PluginClient::get_gui_update_frames()
643 if(frame_buffer.size())
645 PluginClientFrame *frame = frame_buffer.get(0);
646 int total_frames = update_timer->get_difference() *
650 if(total_frames) update_timer->subtract(total_frames *
655 // printf("PluginClient::get_gui_update_frames %d %ld %d %d %d\n",
657 // update_timer->get_difference(),
658 // frame->period_n * 1000 / frame->period_d,
660 // frame_buffer.size());
663 for(int i = 0; i < frame_buffer.size(); i++)
664 if(frame_buffer.get(i)->force) total_frames++;
665 total_frames = MIN(frame_buffer.size(), total_frames);
676 PluginClientFrame* PluginClient::get_gui_frame()
678 if(frame_buffer.size())
680 PluginClientFrame *frame = frame_buffer.get(0);
681 frame_buffer.remove_number(0);
690 void PluginClient::add_gui_frame(PluginClientFrame *frame)
692 frame_buffer.append(frame);
695 void PluginClient::send_render_gui()
697 server->send_render_gui(&frame_buffer);
700 void PluginClient::send_render_gui(void *data)
702 server->send_render_gui(data);
705 void PluginClient::send_render_gui(void *data, int size)
707 server->send_render_gui(data, size);
710 void PluginClient::plugin_render_gui(void *data, int size)
712 render_gui(data, size);
716 void PluginClient::plugin_render_gui(void *data)
721 void PluginClient::render_gui(void *data)
725 thread->get_window()->lock_window("PluginClient::render_gui");
727 // Set all previous frames to draw immediately
728 for(int i = 0; i < frame_buffer.size(); i++)
729 frame_buffer.get(i)->force = 1;
731 ArrayList<PluginClientFrame*> *src =
732 (ArrayList<PluginClientFrame*>*)data;
734 // Shift GUI data to GUI client
737 this->frame_buffer.append(src->get(0));
738 src->remove_number(0);
741 // Start the timer for the current buffer
742 update_timer->update();
743 thread->get_window()->unlock_window();
747 void PluginClient::render_gui(void *data, int size)
749 printf("PluginClient::render_gui %d\n", __LINE__);
759 int PluginClient::is_audio() { return 0; }
760 int PluginClient::is_video() { return 0; }
761 int PluginClient::is_theme() { return 0; }
762 int PluginClient::uses_gui() { return 1; }
763 int PluginClient::is_transition() { return 0; }
764 int PluginClient::load_defaults()
766 // printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
770 int PluginClient::save_defaults()
773 // printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
777 void PluginClient::load_defaults_xml()
779 char path[BCTEXTLEN];
780 server->get_defaults_path(path);
782 fs.complete_path(path);
784 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
789 int fd = open(path, O_RDONLY);
790 if( fd >= 0 && !fstat(fd, &st) ) {
791 int64_t sz = st.st_size;
792 data = new char[sz+1];
793 len = read(fd, data, sz);
796 if( data && len >= 0 ) {
798 // Get window extents
800 for( int state=0; i<len && state>=0; ++i ) {
801 if( !data[i] || data[i] == '<' ) break;
802 if( !isdigit(data[i]) ) continue;
804 window_x = atoi(data+i);
808 window_y = atoi(data+i);
811 while( i<len && isdigit(data[i]) ) ++i;
813 KeyFrame keyframe(data+i, len-i);
814 read_data(&keyframe);
819 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
822 void PluginClient::save_defaults_xml()
824 char path[BCTEXTLEN];
825 server->get_defaults_path(path);
827 fs.complete_path(path);
830 KeyFrame temp_keyframe;
831 save_data(&temp_keyframe);
833 const char *data = temp_keyframe.get_data();
834 int len = strlen(data);
835 FILE *fp = fopen(path, "w");
838 fprintf(fp, "%d\n%d\n", window_x, window_y);
839 if( len > 0 && !fwrite(data, len, 1, fp) ) {
840 fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
841 __LINE__, path, len, strerror(errno));
849 int PluginClient::is_defaults()
851 return using_defaults;
854 BC_Hash* PluginClient::get_defaults()
858 PluginClientThread* PluginClient::get_thread()
863 BC_WindowBase* PluginClient::new_window()
865 printf("PluginClient::new_window undefined in %s.\n", plugin_title());
868 int PluginClient::get_parameters() { return 0; }
869 int PluginClient::get_samplerate() { return get_project_samplerate(); }
870 double PluginClient::get_framerate() { return get_project_framerate(); }
871 int PluginClient::init_realtime_parameters() { return 0; }
872 int PluginClient::delete_nonrealtime_parameters() { return 0; }
873 int PluginClient::start_loop() { return 0; };
874 int PluginClient::process_loop() { return 0; };
875 int PluginClient::stop_loop() { return 0; };
877 void PluginClient::set_interactive()
882 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
884 return recommended_size;
887 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
889 return recommended_size;
892 int PluginClient::get_gui_status()
894 return server->get_gui_status();
897 // close event from client side
898 void PluginClient::client_side_close()
900 // Last command executed
901 server->client_side_close();
904 int PluginClient::stop_gui_client()
906 if(!client_gui_on) return 0;
911 int PluginClient::get_project_samplerate()
913 return server->get_project_samplerate();
916 double PluginClient::get_project_framerate()
918 return server->get_project_framerate();
921 const char *PluginClient::get_source_path()
923 if( server->plugin ) return 0;
924 int64_t source_position = server->plugin->startproject;
925 Edit *edit = server->plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
926 Indexable *indexable = edit ? edit->get_source() : 0;
927 return indexable ? indexable->path : 0;
931 void PluginClient::update_display_title()
933 server->generate_display_title(gui_string);
937 char* PluginClient::get_gui_string()
943 char* PluginClient::get_path()
948 char* PluginClient::get_plugin_dir()
950 return server->preferences->plugin_dir;
953 int PluginClient::set_string_client(char *string)
955 strcpy(gui_string, string);
961 int PluginClient::get_interpolation_type()
963 return server->get_interpolation_type();
967 float PluginClient::get_red()
969 EDL *edl = get_edl();
970 return edl->local_session->use_max ?
971 edl->local_session->red_max :
972 edl->local_session->red;
975 float PluginClient::get_green()
977 EDL *edl = get_edl();
978 return edl->local_session->use_max ?
979 edl->local_session->green_max :
980 edl->local_session->green;
983 float PluginClient::get_blue()
985 EDL *edl = get_edl();
986 return edl->local_session->use_max ?
987 edl->local_session->blue_max :
988 edl->local_session->blue;
992 int64_t PluginClient::get_source_position()
994 return source_position;
997 int64_t PluginClient::get_source_start()
1002 int64_t PluginClient::get_total_len()
1007 int PluginClient::get_direction()
1013 int64_t PluginClient::local_to_edl(int64_t position)
1018 int64_t PluginClient::edl_to_local(int64_t position)
1023 int PluginClient::get_use_opengl()
1025 return server->get_use_opengl();
1028 int PluginClient::get_total_buffers()
1030 return total_in_buffers;
1033 int PluginClient::get_buffer_size()
1035 return in_buffer_size;
1038 int PluginClient::get_project_smp()
1040 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
1044 const char* PluginClient::get_defaultdir()
1046 return File::get_plugin_path();
1050 int PluginClient::send_hide_gui()
1052 // Stop the GUI server and delete GUI messages
1057 int PluginClient::send_configure_change()
1060 server->mwindow->undo->update_undo_before(_("tweek"), this);
1061 #ifdef USE_KEYFRAME_SPANNING
1063 save_data(&keyframe);
1064 server->apply_keyframe(&keyframe);
1066 KeyFrame* keyframe = server->get_keyframe();
1067 // Call save routine in plugin
1068 save_data(keyframe);
1071 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
1072 server->sync_parameters();
1077 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
1079 if(is_local) position = local_to_edl(position);
1080 return server->get_prev_keyframe(position);
1083 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
1085 if(is_local) position = local_to_edl(position);
1086 return server->get_next_keyframe(position);
1089 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
1091 server->get_camera(x, y, z, position, direction);
1094 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
1096 server->get_projector(x, y, z, position, direction);
1100 void PluginClient::output_to_track(float ox, float oy, float &tx, float &ty)
1102 float projector_x, projector_y, projector_z;
1103 int64_t position = get_source_position();
1104 get_projector(&projector_x, &projector_y, &projector_z, position);
1105 EDL *edl = get_edl();
1106 projector_x += edl->session->output_w / 2;
1107 projector_y += edl->session->output_h / 2;
1108 Track *track = server->plugin ? server->plugin->track : 0;
1109 int track_w = track ? track->track_w : edl->session->output_w;
1110 int track_h = track ? track->track_h : edl->session->output_h;
1111 tx = (ox - projector_x) / projector_z + track_w / 2;
1112 ty = (oy - projector_y) / projector_z + track_h / 2;
1115 void PluginClient::track_to_output(float tx, float ty, float &ox, float &oy)
1117 float projector_x, projector_y, projector_z;
1118 int64_t position = get_source_position();
1119 get_projector(&projector_x, &projector_y, &projector_z, position);
1120 EDL *edl = get_edl();
1121 projector_x += edl->session->output_w / 2;
1122 projector_y += edl->session->output_h / 2;
1123 Track *track = server->plugin ? server->plugin->track : 0;
1124 int track_w = track ? track->track_w : edl->session->output_w;
1125 int track_h = track ? track->track_h : edl->session->output_h;
1126 ox = (tx - track_w / 2) * projector_z + projector_x;
1127 oy = (ty - track_h / 2) * projector_z + projector_y;
1131 EDL *PluginClient::get_edl()
1133 return server->mwindow ? server->mwindow->edl : server->edl;
1136 int PluginClient::gui_open()
1138 return server->gui_open();