4 * Copyright (C) 2009 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
24 #include "attachmentpoint.h"
26 #include "bcsignals.h"
27 #include "cplayback.h"
30 #include "edlsession.h"
31 #include "floatautos.h"
32 #include "keyframes.h"
33 #include "localsession.h"
34 #include "mainerror.h"
35 #include "mainprogress.h"
36 #include "menueffects.h"
38 #include "mwindowgui.h"
39 #include "playbackengine.h"
41 #include "pluginaclient.h"
42 #include "pluginaclientlad.h"
43 #include "pluginclient.h"
44 #include "plugincommands.h"
45 #include "pluginserver.h"
46 #include "pluginvclient.h"
47 #include "preferences.h"
50 #include "mainsession.h"
51 #include "trackcanvas.h"
52 #include "transportque.h"
53 #include "vdevicex11.h"
55 #include "videodevice.h"
56 #include "virtualanode.h"
57 #include "virtualvnode.h"
65 #include <sys/types.h>
71 PluginServer::PluginServer()
74 modules = new ArrayList<Module*>;
75 nodes = new ArrayList<VirtualNode*>;
78 PluginServer::PluginServer(char *path, MWindow *mwindow)
82 modules = new ArrayList<Module*>;
83 nodes = new ArrayList<VirtualNode*>;
84 this->mwindow = mwindow;
87 PluginServer::PluginServer(PluginServer &that)
93 title = new char[strlen(that.title) + 1];
94 strcpy(title, that.title);
99 path = new char[strlen(that.path) + 1];
100 strcpy(path, that.path);
103 modules = new ArrayList<Module*>;
104 nodes = new ArrayList<VirtualNode*>;
106 attachment = that.attachment;
107 realtime = that.realtime;
108 multichannel = that.multichannel;
109 preferences = that.preferences;
110 synthesis = that.synthesis;
114 fileio = that.fileio;
115 uses_gui = that.uses_gui;
116 mwindow = that.mwindow;
117 keyframe = that.keyframe;
118 new_plugin = that.new_plugin;
120 is_lad = that.is_lad;
121 lad_descriptor = that.lad_descriptor;
122 lad_descriptor_function = that.lad_descriptor_function;
123 lad_index = that.lad_index;
126 PluginServer::~PluginServer()
129 if(path) delete [] path;
130 if(title) delete [] title;
131 if(modules) delete modules;
132 if(nodes) delete nodes;
133 if(picon) delete picon;
136 // Done only once at creation
137 int PluginServer::reset_parameters()
149 audio = video = theme = 0;
152 realtime = multichannel = fileio = 0;
154 start_auto = end_auto = 0;
166 lad_descriptor_function = 0;
172 // Done every time the plugin is opened or closed
173 int PluginServer::cleanup_plugin()
175 in_buffer_size = out_buffer_size = 0;
176 total_in_buffers = total_out_buffers = 0;
181 written_samples = written_frames = 0;
188 void PluginServer::set_mwindow(MWindow *mwindow)
190 this->mwindow = mwindow;
193 void PluginServer::set_attachmentpoint(AttachmentPoint *attachmentpoint)
195 this->attachmentpoint = attachmentpoint;
198 void PluginServer::set_keyframe(KeyFrame *keyframe)
200 this->keyframe = keyframe;
203 void PluginServer::set_prompt(MenuEffectPrompt *prompt)
205 this->prompt = prompt;
208 void PluginServer::set_lad_index(int i)
213 int PluginServer::get_lad_index()
215 return this->lad_index;
218 int PluginServer::is_ladspa()
223 int PluginServer::set_path(char *path)
225 if(this->path) delete [] this->path;
226 this->path = new char[strlen(path) + 1];
227 strcpy(this->path, path);
231 char* PluginServer::get_path()
236 int PluginServer::get_synthesis()
242 void PluginServer::set_title(const char *string)
244 if(title) delete [] title;
245 title = new char[strlen(string) + 1];
246 strcpy(title, string);
249 void PluginServer::generate_display_title(char *string)
251 char ltitle[BCTEXTLEN];
252 if(BC_Resources::locale_utf8)
253 strcpy(ltitle, _(title));
255 BC_Resources::encode(BC_Resources::encoding, 0,
256 _(title),strlen(title)+1, ltitle,BCTEXTLEN);
257 if(plugin && plugin->track)
258 sprintf(string, "%s: %s", plugin->track->title, ltitle);
260 strcpy(string, ltitle);
263 void PluginServer::delete_this()
265 void *dlp = load_obj();
270 // Open plugin for signal processing
271 int PluginServer::open_plugin(int master,
272 Preferences *preferences,
276 if(plugin_open) return 0;
278 this->preferences = preferences;
279 this->plugin = plugin;
282 // add base path if not absolute path
283 char dl_path[BCTEXTLEN], *dp = dl_path;
286 char *bp = preferences->plugin_dir;
287 while( *bp ) *dp++ = *bp++;
290 while( *cp ) *dp++ = *cp++;
292 if( !load_obj(dl_path) ) {
293 // If the load failed it may still be an executable tool for a specific
294 // file format, in which case we just store the path.
296 char string[BCTEXTLEN];
297 strcpy(string, load_error());
298 if(!strstr(string, "executable"))
299 eprintf("PluginServer::open_plugin: load_obj failure = %s\n", string);
300 return PLUGINSERVER_NOT_RECOGNIZED;
303 if( !new_plugin && !lad_descriptor ) {
305 (PluginClient* (*)(PluginServer*)) load_sym("new_plugin");
307 lad_descriptor_function =
308 (LADSPA_Descriptor_Function) load_sym("ladspa_descriptor");
309 if(!lad_descriptor_function) {
310 fprintf(stderr, "PluginServer::open_plugin "
311 " %d: new_plugin undefined in %s\n", __LINE__, path);
313 return PLUGINSERVER_NOT_RECOGNIZED;
315 if( lad_index < 0 ) {
317 return PLUGINSERVER_IS_LAD;
319 lad_descriptor = lad_descriptor_function(lad_index);
320 if(!lad_descriptor) {
322 return PLUGINSERVER_NOT_RECOGNIZED;
329 (PluginClient *) new PluginAClientLAD(this) :
332 // Run initialization functions
333 realtime = client->is_realtime();
334 // Don't load defaults when probing the directory.
337 client->load_defaults_xml();
339 client->load_defaults();
341 audio = client->is_audio();
342 video = client->is_video();
343 theme = client->is_theme();
344 fileio = client->is_fileio();
345 uses_gui = client->uses_gui();
346 multichannel = client->is_multichannel();
347 synthesis = client->is_synthesis();
348 transition = client->is_transition();
349 set_title(client->plugin_title());
351 //printf("PluginServer::open_plugin 2\n");
353 return PLUGINSERVER_OK;
356 int PluginServer::close_plugin()
358 if(!plugin_open) return 0;
362 // Defaults are saved in the thread.
363 // if(client->defaults) client->save_defaults();
367 // shared object is persistent since plugin deletion would unlink its own object
373 void PluginServer::client_side_close()
375 // Last command executed in client thread
377 mwindow->hide_plugin(plugin, 1);
381 prompt->lock_window();
383 prompt->unlock_window();
387 void PluginServer::render_stop()
390 client->render_stop();
393 void PluginServer::write_table(FILE *fp, int idx)
396 fprintf(fp, "\"%s\" \"%s\" %d %d %d %d %d %d %d %d %d %d %d %d\n",
397 path, title, idx, audio, video, theme, realtime, fileio,
398 uses_gui, multichannel, synthesis, transition, is_lad, lad_index);
401 char *PluginServer::table_quoted_field(char *&sp)
404 while( *cp && (*cp == ' ' || *cp == '\t') ) ++cp;
405 if( *cp++ != '"' ) return 0;
407 while( *cp && *cp != '"' ) ++cp;
408 if( *cp != '"' ) return 0;
413 int PluginServer::read_table(char *text)
415 int n = sscanf(text, "%d %d %d %d %d %d %d %d %d %d %d %d",
416 &dir_idx, &audio, &video, &theme, &realtime, &fileio, &uses_gui,
417 &multichannel, &synthesis, &transition, &is_lad, &lad_index);
419 return n == 12 ? 0 : 1;
422 int PluginServer::init_realtime(int realtime_sched,
423 int total_in_buffers,
427 if(!plugin_open) return 0;
429 // set for realtime priority
431 // Call start_realtime
432 this->total_in_buffers = this->total_out_buffers = total_in_buffers;
433 client->plugin_init_realtime(realtime_sched,
441 // Replaced by pull method but still needed for transitions
442 void PluginServer::process_transition(VFrame *input,
444 int64_t current_position,
447 if(!plugin_open) return;
448 PluginVClient *vclient = (PluginVClient*)client;
450 vclient->source_position = current_position;
451 vclient->source_start = 0;
452 vclient->total_len = total_len;
454 vclient->input = new VFrame*[1];
455 vclient->output = new VFrame*[1];
457 vclient->input[0] = input;
458 vclient->output[0] = output;
460 vclient->process_realtime(input, output);
462 delete [] vclient->input;
463 delete [] vclient->output;
467 void PluginServer::process_transition(Samples *input,
469 int64_t current_position,
470 int64_t fragment_size,
473 if(!plugin_open) return;
474 PluginAClient *aclient = (PluginAClient*)client;
476 aclient->source_position = current_position;
477 aclient->total_len = total_len;
478 aclient->source_start = 0;
479 aclient->process_realtime(fragment_size,
485 void PluginServer::process_buffer(VFrame **frame,
486 int64_t current_position,
491 if(!plugin_open) return;
492 PluginVClient *vclient = (PluginVClient*)client;
494 vclient->source_position = current_position;
495 vclient->total_len = total_len;
496 vclient->frame_rate = frame_rate;
497 vclient->input = new VFrame*[total_in_buffers];
498 vclient->output = new VFrame*[total_in_buffers];
499 for(int i = 0; i < total_in_buffers; i++)
501 vclient->input[i] = frame[i];
502 vclient->output[i] = frame[i];
504 vclient->source_start = (int64_t)(plugin ?
505 plugin->startproject *
507 vclient->project_frame_rate :
509 vclient->direction = direction;
512 vclient->begin_process_buffer();
515 vclient->process_buffer(frame, current_position, frame_rate);
519 vclient->process_buffer(frame[0], current_position, frame_rate);
521 vclient->end_process_buffer();
523 for(int i = 0; i < total_in_buffers; i++)
524 frame[i]->push_prev_effect(title);
526 delete [] vclient->input;
527 delete [] vclient->output;
533 void PluginServer::process_buffer(Samples **buffer,
534 int64_t current_position,
535 int64_t fragment_size,
540 if(!plugin_open) return;
541 PluginAClient *aclient = (PluginAClient*)client;
543 aclient->source_position = current_position;
544 aclient->total_len = total_len;
545 aclient->sample_rate = sample_rate;
548 aclient->source_start = plugin->startproject *
550 aclient->project_sample_rate;
552 aclient->direction = direction;
553 aclient->begin_process_buffer();
556 aclient->process_buffer(fragment_size,
563 aclient->process_buffer(fragment_size,
568 aclient->end_process_buffer();
572 void PluginServer::send_render_gui(void *data)
574 //printf("PluginServer::send_render_gui 1 %p\n", attachmentpoint);
575 if(attachmentpoint) attachmentpoint->render_gui(data, this);
578 void PluginServer::send_render_gui(void *data, int size)
580 //printf("PluginServer::send_render_gui 1 %p\n", attachmentpoint);
581 if(attachmentpoint) attachmentpoint->render_gui(data, size, this);
584 void PluginServer::render_gui(void *data)
586 if(client) client->plugin_render_gui(data);
589 void PluginServer::render_gui(void *data, int size)
591 if(client) client->plugin_render_gui(data, size);
594 MainProgressBar* PluginServer::start_progress(char *string, int64_t length)
596 mwindow->gui->lock_window();
597 MainProgressBar *result = mwindow->mainprogress->start_progress(string, length);
598 mwindow->gui->unlock_window();
602 int64_t PluginServer::get_written_samples()
604 if(!plugin_open) return 0;
605 return written_samples;
608 int64_t PluginServer::get_written_frames()
610 if(!plugin_open) return 0;
611 return written_frames;
623 // ======================= Non-realtime plugin
625 int PluginServer::get_parameters(int64_t start, int64_t end, int channels)
627 if(!plugin_open) return 0;
629 client->start = start;
631 client->source_start = start;
632 client->total_len = end - start;
633 client->total_in_buffers = channels;
634 return client->plugin_get_parameters();
637 int PluginServer::set_interactive()
639 if(!plugin_open) return 0;
640 client->set_interactive();
644 void PluginServer::append_module(Module *module)
646 modules->append(module);
649 void PluginServer::append_node(VirtualNode *node)
654 void PluginServer::reset_nodes()
659 int PluginServer::set_error()
665 int PluginServer::set_realtime_sched()
667 //struct sched_param params;
668 //params.sched_priority = 1;
669 //sched_setscheduler(0, SCHED_RR, ¶m);
674 int PluginServer::process_loop(VFrame **buffers, int64_t &write_length)
676 if(!plugin_open) return 1;
677 return client->plugin_process_loop(buffers, write_length);
680 int PluginServer::process_loop(Samples **buffers, int64_t &write_length)
682 if(!plugin_open) return 1;
683 return client->plugin_process_loop(buffers, write_length);
687 int PluginServer::start_loop(int64_t start,
692 if(!plugin_open) return 0;
693 client->plugin_start_loop(start, end, buffer_size, total_buffers);
697 int PluginServer::stop_loop()
699 if(!plugin_open) return 0;
700 return client->plugin_stop_loop();
703 int PluginServer::read_frame(VFrame *buffer,
705 int64_t start_position)
707 ((VModule*)modules->values[channel])->render(buffer,
710 mwindow->edl->session->frame_rate,
716 int PluginServer::read_samples(Samples *buffer,
719 int64_t start_position,
722 // len is now in buffer
723 if(!multichannel) channel = 0;
725 if(nodes->total > channel)
726 return ((VirtualANode*)nodes->values[channel])->read_data(buffer,
731 if(modules->total > channel)
732 return ((AModule*)modules->values[channel])->render(buffer,
740 printf("PluginServer::read_samples no object available for channel=%d\n",
748 int PluginServer::read_samples(Samples *buffer,
750 int64_t start_position,
753 // total_samples is now set in buffer
754 ((AModule*)modules->values[channel])->render(buffer,
758 mwindow->edl->session->sample_rate,
763 int PluginServer::read_frame(VFrame *buffer,
765 int64_t start_position,
769 // Data source depends on whether we're part of a virtual console or a
773 // If we're a VirtualNode, read_data in the virtual plugin node handles
774 // backward propogation and produces the data.
775 // If we're a Module, render in the module produces the data.
778 if(!multichannel) channel = 0;
780 // Push our name on the next effect stack
781 buffer->push_next_effect(title);
782 //printf("PluginServer::read_frame %p\n", buffer);
783 //buffer->dump_stacks();
785 if(nodes->total > channel)
787 //printf("PluginServer::read_frame %d\n", __LINE__);
788 result = ((VirtualVNode*)nodes->values[channel])->read_data(buffer,
794 if(modules->total > channel)
796 //printf("PluginServer::read_frame %d\n", __LINE__);
797 result = ((VModule*)modules->values[channel])->render(buffer,
808 printf("PluginServer::read_frame no object available for channel=%d\n",
812 // Pop our name from the next effect stack
813 buffer->pop_next_effect();
838 int PluginServer::get_gui_status()
841 return plugin->show ? GUI_ON : GUI_OFF;
846 void PluginServer::raise_window()
848 if(!plugin_open) return;
849 client->raise_window();
852 void PluginServer::show_gui()
854 if(!plugin_open) return;
855 if(plugin) client->total_len = plugin->length;
856 if(plugin) client->source_start = plugin->startproject;
859 client->source_position = Units::to_int64(
860 mwindow->edl->local_session->get_selectionstart(1) *
861 mwindow->edl->session->frame_rate);
866 client->source_position = Units::to_int64(
867 mwindow->edl->local_session->get_selectionstart(1) *
868 mwindow->edl->session->sample_rate);
871 client->update_display_title();
875 void PluginServer::hide_gui()
877 if(!plugin_open) return;
878 if(client->defaults) client->save_defaults();
882 void PluginServer::update_gui()
884 if(!plugin_open || !plugin) return;
886 client->total_len = plugin->length;
887 client->source_start = plugin->startproject;
891 client->source_position = Units::to_int64(
892 mwindow->edl->local_session->get_selectionstart(1) *
893 mwindow->edl->session->frame_rate);
898 client->source_position = Units::to_int64(
899 mwindow->edl->local_session->get_selectionstart(1) *
900 mwindow->edl->session->sample_rate);
903 client->plugin_update_gui();
906 void PluginServer::update_title()
908 if(!plugin_open) return;
910 client->update_display_title();
914 int PluginServer::set_string(char *string)
916 if(!plugin_open) return 0;
918 client->set_string_client(string);
922 int PluginServer::gui_open()
924 if(attachmentpoint) return attachmentpoint->gui_open();
928 void PluginServer::set_use_opengl(int value, VideoDevice *vdevice)
930 this->use_opengl = value;
931 this->vdevice = vdevice;
934 int PluginServer::get_use_opengl()
940 void PluginServer::run_opengl(PluginClient *plugin_client)
943 ((VDeviceX11*)vdevice->get_output_base())->run_plugin(plugin_client);
946 // ============================= queries
948 void PluginServer::get_defaults_path(char *path)
950 // Get plugin name from path
951 char *ptr1 = strrchr(get_path(), '/');
952 char *ptr2 = strrchr(get_path(), '.');
953 if(!ptr1) ptr1 = get_path();
954 if(!ptr2) ptr2 = get_path() + strlen(get_path());
955 char string2[BCTEXTLEN];
956 char *ptr3 = string2;
962 sprintf(path, "%s%s.xml", BCASTDIR, string2);
965 void PluginServer::save_defaults()
967 if(client) client->save_defaults();
970 int PluginServer::get_samplerate()
972 if(!plugin_open) return 0;
975 return client->get_samplerate();
979 return mwindow->edl->session->sample_rate;
982 printf("PluginServer::get_samplerate audio and mwindow == NULL\n");
988 double PluginServer::get_framerate()
990 if(!plugin_open) return 0;
993 return client->get_framerate();
997 return mwindow->edl->session->frame_rate;
1000 printf("PluginServer::get_framerate video and mwindow == NULL\n");
1005 int PluginServer::get_project_samplerate()
1008 return mwindow->edl->session->sample_rate;
1011 return edl->session->sample_rate;
1014 printf("PluginServer::get_project_samplerate mwindow and edl are NULL.\n");
1019 double PluginServer::get_project_framerate()
1022 return mwindow->edl->session->frame_rate;
1025 return edl->session->frame_rate;
1028 printf("PluginServer::get_project_framerate mwindow and edl are NULL.\n");
1035 int PluginServer::detach_buffers()
1037 ring_buffers_out.remove_all();
1038 offset_out_render.remove_all();
1039 double_buffer_out_render.remove_all();
1040 realtime_out_size.remove_all();
1042 ring_buffers_in.remove_all();
1043 offset_in_render.remove_all();
1044 double_buffer_in_render.remove_all();
1045 realtime_in_size.remove_all();
1047 out_buffer_size = 0;
1049 total_out_buffers = 0;
1051 total_in_buffers = 0;
1055 int PluginServer::arm_buffer(int buffer_number,
1058 int double_buffer_in,
1059 int double_buffer_out)
1061 offset_in_render.values[buffer_number] = offset_in;
1062 offset_out_render.values[buffer_number] = offset_out;
1063 double_buffer_in_render.values[buffer_number] = double_buffer_in;
1064 double_buffer_out_render.values[buffer_number] = double_buffer_out;
1069 int PluginServer::set_automation(FloatAutos *autos, FloatAuto **start_auto, FloatAuto **end_auto, int reverse)
1071 this->autos = autos;
1072 this->start_auto = start_auto;
1073 this->end_auto = end_auto;
1074 this->reverse = reverse;
1080 void PluginServer::save_data(KeyFrame *keyframe)
1082 if(!plugin_open) return;
1083 client->save_data(keyframe);
1086 KeyFrame* PluginServer::get_prev_keyframe(int64_t position)
1088 KeyFrame *result = 0;
1090 result = plugin->get_prev_keyframe(position, client->direction);
1096 KeyFrame* PluginServer::get_next_keyframe(int64_t position)
1098 KeyFrame *result = 0;
1100 result = plugin->get_next_keyframe(position, client->direction);
1107 KeyFrame* PluginServer::get_keyframe()
1110 // Realtime plugin case
1111 return plugin->get_keyframe();
1113 // Rendered plugin case
1118 void PluginServer::apply_keyframe(KeyFrame *src)
1122 keyframe->copy_data(src);
1127 plugin->keyframes->update_parameter(src);
1135 void PluginServer::get_camera(float *x, float *y, float *z,
1136 int64_t position, int direction)
1138 plugin->track->automation->get_camera(x, y, z, position, direction);
1141 void PluginServer::get_projector(float *x, float *y, float *z,
1142 int64_t position, int direction)
1144 plugin->track->automation->get_projector(x, y, z, position, direction);
1148 int PluginServer::get_interpolation_type()
1150 return plugin->edl->session->interpolation_type;
1153 Theme* PluginServer::new_theme()
1157 return client->new_theme();
1163 Theme* PluginServer::get_theme()
1165 if(mwindow) return mwindow->theme;
1166 printf("PluginServer::get_theme mwindow not set\n");
1171 char *PluginServer::get_plugin_png_path(char *png_path)
1173 char *bp = strrchr(path, '/'), *cp = png_path;
1174 if( !bp ) bp = path; else ++bp;
1175 char *sp = strrchr(bp,'.');
1176 if( !sp || ( strcmp(sp, ".plugin") && strcmp(sp,".so") ) ) return 0;
1177 cp += sprintf(cp,"%s/picons/", mwindow->preferences->plugin_dir);
1178 while( bp < sp ) *cp++ = *bp++;
1183 VFrame *PluginServer::get_plugin_images()
1185 char png_path[BCTEXTLEN];
1186 if( !get_plugin_png_path(png_path) ) return 0;
1188 if( stat(png_path, &st) ) return 0;
1189 if( !S_ISREG(st.st_mode) ) return 0;
1190 if( st.st_size == 0 ) return 0;
1191 unsigned len = st.st_size;
1192 int ret = 0, w = 0, h = 0;
1194 int fd = ::open(png_path, O_RDONLY);
1195 if( fd < 0 ) ret = 1;
1197 bfr = (uint8_t*) ::mmap (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
1198 if( bfr == MAP_FAILED ) ret = 1;
1202 vframe = new VFrame(bfr, st.st_size);
1203 if( (w=vframe->get_w()) <= 0 || (h=vframe->get_h()) <= 0 ||
1204 vframe->get_data() == 0 ) ret = 1;
1206 if( bfr && bfr != MAP_FAILED ) ::munmap(bfr, len);
1207 if( fd >= 0 ) ::close(fd);
1208 if( ret ) { delete vframe; vframe = 0; }
1212 VFrame *PluginServer::get_picon()
1215 picon = get_plugin_images();
1219 // Called when plugin interface is tweeked
1220 void PluginServer::sync_parameters()
1222 if(video) mwindow->restart_brender();
1223 mwindow->sync_parameters();
1224 mwindow->update_keyframe_guis();
1225 if(mwindow->edl->session->auto_conf->plugins)
1227 mwindow->gui->lock_window("PluginServer::sync_parameters");
1228 mwindow->gui->draw_overlays(1);
1229 mwindow->gui->unlock_window();
1235 void PluginServer::dump(FILE *fp)
1237 fprintf(fp," PluginServer %d %p %s %s %d\n",
1238 __LINE__, this, path, title, realtime);