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