Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / virtualnode.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "attachmentpoint.h"
24 #include "auto.h"
25 #include "automation.h"
26 #include "autos.h"
27 #include "bcsignals.h"
28 #include "floatauto.h"
29 #include "floatautos.h"
30 #include "intauto.h"
31 #include "intautos.h"
32 #include "mainerror.h"
33 #include "mwindow.h"
34 #include "module.h"
35 #include "panauto.h"
36 #include "panautos.h"
37 #include "patchbay.h"
38 #include "plugin.h"
39 #include "pluginserver.h"
40 #include "renderengine.h"
41 #include "tracks.h"
42 #include "transition.h"
43 #include "transportque.h"
44 #include "virtualconsole.h"
45 #include "virtualnode.h"
46
47 VirtualNode::VirtualNode(RenderEngine *renderengine,
48                 VirtualConsole *vconsole,
49                 Module *real_module,
50                 Plugin *real_plugin,
51                 Track *track,
52                 VirtualNode *parent_node)
53 {
54         this->renderengine = renderengine;
55         this->vconsole = vconsole;
56         this->real_module = real_module;
57         this->real_plugin = real_plugin;
58         this->track = track;
59         this->parent_node = parent_node;
60
61
62         render_count = 0;
63         plugin_type = 0;
64         waiting_real_plugin = 0;
65         plugin_buffer_number = 0;
66         plugin_autos = 0;
67         plugin_auto_before = plugin_auto_after = 0;
68         attachment = 0;
69         is_exit = 0;
70 //printf("VirtualNode::VirtualNode 1\n");
71 }
72
73 VirtualNode::~VirtualNode()
74 {
75         subnodes.remove_all_objects();
76 //printf("VirtualNode::VirtualNode 2\n");
77 }
78
79 #define PRINT_INDENT for(int j = 0; j < indent; j++) printf(" ");
80
81 void VirtualNode::dump(int indent)
82 {
83         PRINT_INDENT
84         printf("VirtualNode %p title=%s real_module=%p %s\n",
85                 this,
86                 track->title,
87                 real_module,
88                 is_exit ? "*" : " ");
89         if(real_module)
90         {
91                 PRINT_INDENT
92                 printf(" Plugins total=%d\n", subnodes.total);
93                 for(int i = 0; i < subnodes.total; i++)
94                 {
95                         subnodes.values[i]->dump(indent + 2);
96                 }
97         }
98         else
99         if(real_plugin)
100         {
101                 printf("    Plugin %s\n", real_plugin->title);
102         }
103 }
104
105 int VirtualNode::expand(int persistent_plugins, int64_t current_position)
106 {
107         const int debug = 0;
108
109
110
111 // TODO: need to use speed curve to determine chain for current position
112
113
114 // module needs to know where the input data for the next process is
115 if(debug) printf("VirtualNode::expand %d real_module=%p real_plugin=%p\n",
116 __LINE__,
117 real_module,
118 real_plugin);
119         if(real_module)
120         {
121 if(debug) printf("VirtualNode::expand %d\n", __LINE__);
122                 expand_as_module(persistent_plugins, current_position);
123         }
124         else
125         if(real_plugin)
126         {
127 // attach to a real plugin for a plugin
128 // plugin always takes data from input to output
129 if(debug) printf("VirtualNode::expand %d\n", __LINE__);
130                 expand_as_plugin(persistent_plugins);
131         }
132
133         return 0;
134 }
135
136 int VirtualNode::expand_as_module(int duplicate, int64_t current_position)
137 {
138 // create the plugins for this module
139         for(int i = 0; i < track->plugin_set.total; i++)
140         {
141                 Plugin *plugin = track->get_current_plugin(current_position,
142                         i,
143                         renderengine->command->get_direction(),
144                         0,
145                         1);
146
147 //printf("VirtualNode::expand_as_module %d plugin=%p\n", __LINE__, plugin);
148                 int circular_reference = 0;
149 // Switch off if circular reference.  This happens if a plugin set or a track is deleted.
150                 if(plugin == real_plugin) circular_reference = 1;
151
152 // Switch off consecutive references to the same plugin
153                 if(plugin &&
154                         (plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
155                         plugin->plugin_type == PLUGIN_SHAREDMODULE))
156                 {
157                         int real_module_number = plugin->shared_location.module;
158                         int real_plugin_number = plugin->shared_location.plugin;
159
160                         for(int j = i - 1; j >= 0; j--)
161                         {
162                                 Plugin *prev_plugin = track->get_current_plugin(current_position,
163                                         j,
164                                         renderengine->command->get_direction(),
165                                         0,
166                                         1);
167                                 if(prev_plugin &&
168                                         prev_plugin->plugin_type == PLUGIN_SHAREDPLUGIN &&
169                                         plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
170                                 {
171                                         int prev_module_number = prev_plugin->shared_location.module;
172                                         int prev_plugin_number = prev_plugin->shared_location.plugin;
173                                         if(real_module_number == prev_module_number &&
174                                                 real_plugin_number == prev_plugin_number)
175                                         {
176                                                 circular_reference = 1;
177                                                 break;
178                                         }
179                                 }
180                                 else
181                                 if(prev_plugin &&
182                                         prev_plugin->plugin_type == PLUGIN_SHAREDMODULE &&
183                                         plugin->plugin_type == PLUGIN_SHAREDMODULE)
184                                 {
185                                         int prev_module_number = prev_plugin->shared_location.module;
186                                         if(real_module_number == prev_module_number)
187                                         {
188                                                 circular_reference = 1;
189                                                 break;
190                                         }
191                                 }
192                         }
193                 }
194
195                 if(circular_reference) continue;
196
197                 if(plugin && plugin->on)
198                 {
199                         int plugin_type = plugin->plugin_type;
200                         if(plugin_type == PLUGIN_SHAREDMODULE)
201                         {
202 // plugin is a module
203                                 attach_virtual_module(plugin,
204                                         i,
205                                         duplicate,
206                                         current_position);
207                         }
208                         else
209                         if(plugin_type == PLUGIN_SHAREDPLUGIN ||
210                                 plugin_type == PLUGIN_STANDALONE)
211                         {
212 // plugin is a plugin
213                                 attach_virtual_plugin(plugin,
214                                         i,
215                                         duplicate,
216                                         current_position);
217                         }
218                 }
219         }
220
221
222         if(!parent_node) vconsole->append_exit_node(this);
223 //printf("VirtualNode::expand_as_module %d parent_node=%p\n", __LINE__, parent_node);
224
225         return 0;
226 }
227
228 int VirtualNode::expand_as_plugin(int duplicate)
229 {
230         plugin_type = real_plugin->plugin_type;
231
232         if(plugin_type == PLUGIN_SHAREDPLUGIN)
233         {
234 // Attached to a shared plugin.
235 // Get the real real plugin it's attached to.
236
237 // Redirect the real_plugin to the shared plugin.
238                 int real_module_number = real_plugin->shared_location.module;
239                 int real_plugin_number = real_plugin->shared_location.plugin;
240                 Module *real_module = vconsole->module_number(real_module_number);
241                 real_plugin = 0;
242 // module references are absolute so may get the wrong data type track.
243                 if(real_module)
244                 {
245                         attachment = real_module->get_attachment(real_plugin_number);
246 // Attachment is NULL if off
247                         if(attachment)
248                         {
249                                 real_plugin = attachment->plugin;
250
251 // Real plugin not on then null it.
252                                 if(!real_plugin || !real_plugin->on) real_plugin = 0;
253                         }
254                 }
255         }
256
257
258
259
260
261
262         if(plugin_type == PLUGIN_STANDALONE)
263         {
264 // Get plugin server
265                 Module *module = vconsole->module_of(track);
266
267                 attachment = module->attachment_of(real_plugin);
268         }
269
270
271
272
273
274 // Add to real plugin's list of virtual plugins for configuration updates
275 // and plugin_server initializations.
276 // Input and output are taken care of when the parent module creates this plugin.
277 // Get number for passing to render.
278 // real_plugin may become NULL after shared plugin test.
279         if(real_plugin && attachment)
280         {
281                 if(attachment)
282                         plugin_buffer_number = attachment->attach_virtual_plugin(this);
283         }
284
285
286
287
288         return 0;
289 }
290
291 int VirtualNode::check_circular(Track *track)
292 {
293         if( real_module && real_module->track == track ) return 1;
294         return !parent_node ? 0 : parent_node->check_circular(track);
295 }
296
297 int VirtualNode::attach_virtual_module(Plugin *plugin, int plugin_set_no,
298                 int duplicate, int64_t current_position)
299 {
300         if( plugin->on ) {
301                 int shared_track_no = plugin->shared_location.module;
302                 Module *real_module = vconsole->module_number(shared_track_no);
303 // If a track is deleted real_module is not found
304                 if( !real_module ) return 1;
305                 Track *real_track = real_module->track;
306 // Switch off if circular reference.  This happens if a track is deleted.
307                 if( check_circular(real_track) ) {
308                         int plugin_track_no = plugin->track->get_item_number();
309                         eprintf("circular references, track %d, plugin_set %d, plugin %d\n",
310                                 plugin_track_no, plugin_set_no, plugin->get_item_number());
311                         return 1;
312                 }
313                 VirtualNode *virtual_module = create_module(plugin, real_module, real_track);
314
315                 subnodes.append(virtual_module);
316                 virtual_module->expand(duplicate, current_position);
317         }
318
319         return 0;
320 }
321
322 int VirtualNode::attach_virtual_plugin(Plugin *plugin,
323         int plugin_number,
324         int duplicate,
325         int64_t current_position)
326 {
327 // Get real plugin and test if it is on.
328         int is_on = 1;
329         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
330         {
331                 int real_module_number = plugin->shared_location.module;
332                 int real_plugin_number = plugin->shared_location.plugin;
333                 Module *real_module = vconsole->module_number(real_module_number);
334                 if(real_module)
335                 {
336                         AttachmentPoint *attachment = real_module->get_attachment(real_plugin_number);
337                         if(attachment)
338                         {
339                                 Plugin *real_plugin = attachment->plugin;
340                                 if(!real_plugin || !real_plugin->on)
341                                         is_on = 0;
342                         }
343                         else
344                                 is_on = 0;
345                 }
346                 else
347                         is_on = 0;
348         }
349
350         if(is_on)
351         {
352                 VirtualNode *virtual_plugin = create_plugin(plugin);
353                 subnodes.append(virtual_plugin);
354                 virtual_plugin->expand(duplicate, current_position);
355         }
356         return 0;
357 }
358
359 VirtualNode* VirtualNode::get_previous_plugin(VirtualNode *current_node)
360 {
361         for(int i = 0; i < subnodes.total; i++)
362         {
363 // Assume plugin is on
364                 if(subnodes.values[i] == current_node)
365                 {
366                         if(i > 0)
367                                 return subnodes.values[i - 1];
368                         else
369                                 return 0;
370                 }
371         }
372         return 0;
373 }
374
375
376
377 void VirtualNode::get_mute_fragment(int64_t input_position,
378                                 int &mute_constant,
379                                 int &fragment_len,
380                                 Autos *autos,
381                                 int direction,
382                                 int use_nudge)
383 {
384         if(use_nudge) input_position += track->nudge;
385
386         Auto *prev_keyframe = 0;
387         Auto *next_keyframe = 0;
388         prev_keyframe = autos->get_prev_auto(input_position,
389                 direction, prev_keyframe);
390         next_keyframe = autos->get_next_auto(input_position,
391                 direction, next_keyframe);
392         IntAuto *prev_int_auto = (IntAuto *)prev_keyframe;
393         IntAuto *next_int_auto = (IntAuto *)next_keyframe;
394
395         if(direction == PLAY_FORWARD)
396         {
397 // Two distinct keyframes within range
398                 if(next_int_auto->position > prev_int_auto->position)
399                 {
400                         mute_constant = prev_int_auto->value;
401
402                         if(next_int_auto->position < input_position + fragment_len)
403                                 fragment_len = next_int_auto->position - input_position;
404                 }
405                 else
406 // One keyframe within range
407                 {
408                         mute_constant = prev_int_auto->value;
409                 }
410         }
411         else
412         {
413 // Two distinct keyframes within range
414                 if(next_int_auto->position < prev_int_auto->position)
415                 {
416                         mute_constant = next_int_auto->value;
417
418                         if(next_int_auto->position > input_position - fragment_len)
419                                 fragment_len = input_position - next_int_auto->position;
420                 }
421                 else
422 // One keyframe within range
423                 {
424                         mute_constant = next_int_auto->value;
425                 }
426         }
427 }
428
429
430
431
432
433