r793: Small API addon, so plugins can 'see' camera and projector automation
[cinelerra_cv/mob.git] / cinelerra / virtualanode.C
blob521239db104d28cda3aad48d7d1b685b95e0d1a1
1 #include "aattachmentpoint.h"
2 #include "amodule.h"
3 #include "arender.h"
4 #include "atrack.h"
5 #include "automation.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "clip.h"
9 #include "floatautos.h"
10 #include "mwindow.h"
11 #include "module.h"
12 #include "panauto.h"
13 #include "plugin.h"
14 #include "renderengine.h"
15 #include "track.h"
16 #include "transition.h"
17 #include "transportque.h"
18 #include "virtualaconsole.h"
19 #include "virtualanode.h"
22 #include <string.h>
24 VirtualANode::VirtualANode(RenderEngine *renderengine, 
25                 VirtualConsole *vconsole, 
26                 Module *real_module, 
27                 Plugin *real_plugin,
28                 Track *track, 
29                 VirtualNode *parent_module)
30  : VirtualNode(renderengine, 
31                 vconsole, 
32                 real_module, 
33                 real_plugin,
34                 track, 
35                 parent_module)
37         for(int i = 0; i < MAXCHANNELS; i++)
38         {
39                 pan_before[i] = pan_after[i] = 0;
40         }
43 VirtualANode::~VirtualANode()
51 VirtualNode* VirtualANode::create_module(Plugin *real_plugin, 
52                                                         Module *real_module, 
53                                                         Track *track)
55         return new VirtualANode(renderengine, 
56                 vconsole, 
57                 real_module,
58                 0,
59                 track,
60                 this);
64 VirtualNode* VirtualANode::create_plugin(Plugin *real_plugin)
66         return new VirtualANode(renderengine, 
67                 vconsole, 
68                 0,
69                 real_plugin,
70                 track,
71                 this);
76 int VirtualANode::read_data(double *output_temp,
77         int64_t start_position,
78         int64_t len,
79         int64_t sample_rate)
81         VirtualNode *previous_plugin = 0;
83 // This is a plugin on parent module with a preceeding effect.
84 // Get data from preceeding effect on parent module.
85         if(parent_node && 
86                 (previous_plugin = parent_node->get_previous_plugin(this)))
87         {
88                 ((VirtualANode*)previous_plugin)->render(output_temp,
89                         start_position,
90                         len,
91                         sample_rate);
92         }
93         else
94 // First plugin on parent module.
95 // Read data from parent module
96         if(parent_node)
97         {
98                 ((VirtualANode*)parent_node)->read_data(output_temp,
99                         start_position,
100                         len,
101                         sample_rate);
102         }
103         else
104 // This is the first node in the tree
105         {
106                 ((AModule*)real_module)->render(output_temp,
107                         start_position,
108                         len,
109                         renderengine->command->get_direction(),
110                         sample_rate,
111                         0);
112         }
113         return 0;
116 int VirtualANode::render(double *output_temp,
117         int64_t start_position,
118         int64_t len,
119         int64_t sample_rate)
121         ARender *arender = ((VirtualAConsole*)vconsole)->arender;
122         if(real_module)
123         {
124                 render_as_module(arender->audio_out, 
125                         output_temp,
126                         start_position, 
127                         len,
128                         sample_rate);
129         }
130         else
131         if(real_plugin)
132         {
133                 render_as_plugin(output_temp,
134                         start_position,
135                         len,
136                         sample_rate);
137         }
138         return 0;
141 void VirtualANode::render_as_plugin(double *output_temp,
142         int64_t start_position, 
143         int64_t len,
144         int64_t sample_rate)
146         if(!attachment ||
147                 !real_plugin ||
148                 !real_plugin->on) return;
150 // If we're the first plugin in the parent module, data needs to be read from 
151 // what comes before the parent module.  Otherwise, data needs to come from the
152 // previous plugin.
153         ((AAttachmentPoint*)attachment)->render(
154                 output_temp, 
155                 plugin_buffer_number,
156                 start_position,
157                 len, 
158                 sample_rate);
161 int VirtualANode::render_as_module(double **audio_out, 
162                                 double *output_temp,
163                                 int64_t start_position,
164                                 int64_t len, 
165                                 int64_t sample_rate)
167         int in_output = 0;
168         int direction = renderengine->command->get_direction();
169         EDL *edl = vconsole->renderengine->edl;
172 // Process last subnode.  This calls read_data, propogates up the chain 
173 // of subnodes, and finishes the chain.
174         if(subnodes.total)
175         {
176                 VirtualANode *node = (VirtualANode*)subnodes.values[subnodes.total - 1];
177                 node->render(output_temp,
178                         start_position,
179                         len,
180                         sample_rate);
181         }
182         else
183 // Read data from previous entity
184         {
185                 read_data(output_temp,
186                         start_position,
187                         len,
188                         sample_rate);
189         }
192         render_fade(output_temp,
193                                 len,
194                                 start_position,
195                                 sample_rate,
196                                 track->automation->autos[AUTOMATION_FADE],
197                                 direction,
198                                 0);
200 // Get the peak but don't limit
201 // Calculate position relative to project for meters
202         int64_t project_sample_rate = edl->session->sample_rate;
203         int64_t start_position_project = start_position * 
204                 project_sample_rate /
205                 sample_rate;
206         if(real_module && renderengine->command->realtime)
207         {
208                 ARender *arender = ((VirtualAConsole*)vconsole)->arender;
209 // Starting sample of meter block
210                 int64_t meter_render_start;
211 // Ending sample of meter block
212                 int64_t meter_render_end;
213 // Number of samples in each meter fragment normalized to requested rate
214                 int meter_render_fragment = arender->meter_render_fragment * 
215                         sample_rate /
216                         project_sample_rate;
219 // Scan fragment in meter sized fragments
220                 for(int i = 0; i < len; )
221                 {
222                         int current_level = ((AModule*)real_module)->current_level;
223                         double peak = 0;
224                         meter_render_start = i;
225                         meter_render_end = i + meter_render_fragment;
226                         if(meter_render_end > len) 
227                                 meter_render_end = len;
228 // Number of samples into the fragment this meter sized fragment is,
229 // normalized to project sample rate.
230                         int64_t meter_render_start_project = meter_render_start *
231                                 project_sample_rate /
232                                 sample_rate;
234 // Scan meter sized fragment
235                         for( ; i < meter_render_end; i++)
236                         {
237                                 double sample = fabs(output_temp[i]);
238                                 if(sample > peak) peak = sample;
239                         }
241                         ((AModule*)real_module)->level_history[current_level] = 
242                                 peak;
243                         ((AModule*)real_module)->level_samples[current_level] = 
244                                 (direction == PLAY_FORWARD) ?
245                                 (start_position_project + meter_render_start_project) :
246                                 (start_position_project - meter_render_start_project);
247                         ((AModule*)real_module)->current_level = 
248                                 arender->get_next_peak(current_level);
249                 }
250         }
252 // process pans and copy the output to the output channels
253 // Keep rendering unmuted fragments until finished.
254         int mute_position = 0;
256         for(int i = 0; i < len; )
257         {
258                 int mute_constant;
259                 int mute_fragment = len - i;
260                 int mute_fragment_project = mute_fragment *
261                         project_sample_rate /
262                         sample_rate;
263                 start_position_project = start_position + 
264                         ((direction == PLAY_FORWARD) ? i : -i);
265                 start_position_project = start_position_project *
266                         project_sample_rate / 
267                         sample_rate;
269 // How many samples until the next mute?
270                 get_mute_fragment(start_position_project,
271                                 mute_constant, 
272                                 mute_fragment_project,
273                                 (Autos*)track->automation->autos[AUTOMATION_MUTE],
274                                 direction,
275                                 0);
276 // Fragment is playable
277                 if(!mute_constant)
278                 {
279                         for(int j = 0; 
280                                 j < MAX_CHANNELS; 
281                                 j++)
282                         {
283                                 if(audio_out[j])
284                                 {
285                                         double *buffer = audio_out[j];
287                                         render_pan(output_temp + mute_position, 
288                                                                 buffer + mute_position,
289                                                                 mute_fragment,
290                                                                 start_position,
291                                                                 sample_rate,
292                                                                 (Autos*)track->automation->autos[AUTOMATION_PAN],
293                                                                 j,
294                                                                 direction,
295                                                                 0);
296                                 }
297                         }
298                 }
300                 len -= mute_fragment;
301                 i += mute_fragment;
302                 mute_position += mute_fragment;
303         }
305         return 0;
308 int VirtualANode::render_fade(double *buffer,
309                                 int64_t len,
310                                 int64_t input_position,
311                                 int64_t sample_rate,
312                                 Autos *autos,
313                                 int direction,
314                                 int use_nudge)
316         double value, fade_value;
317         FloatAuto *previous = 0;
318         FloatAuto *next = 0;
319         EDL *edl = vconsole->renderengine->edl;
320         int64_t project_sample_rate = edl->session->sample_rate;
321         if(use_nudge) input_position += track->nudge * 
322                 sample_rate / 
323                 project_sample_rate;
325 // Normalize input position to project sample rate here.
326 // Automation functions are general to video and audio so it 
327 // can't normalize itself.
328         int64_t input_position_project = input_position * 
329                 project_sample_rate / 
330                 sample_rate;
331         int64_t len_project = len * 
332                 project_sample_rate / 
333                 sample_rate;
335         if(((FloatAutos*)autos)->automation_is_constant(input_position_project, 
336                 len_project,
337                 direction,
338                 fade_value))
339         {
340                 if(fade_value <= INFINITYGAIN)
341                         value = 0;
342                 else
343                         value = DB::fromdb(fade_value);
344                 for(int64_t i = 0; i < len; i++)
345                 {
346                         buffer[i] *= value;
347                 }
348         }
349         else
350         {
351                 for(int64_t i = 0; i < len; i++)
352                 {
353                         int64_t slope_len = len - i;
354                         input_position_project = input_position * 
355                                 project_sample_rate / 
356                                 sample_rate;
358                         fade_value = ((FloatAutos*)autos)->get_value(input_position_project, 
359                                 direction,
360                                 previous,
361                                 next);
363                         if(fade_value <= INFINITYGAIN)
364                                 value = 0;
365                         else
366                                 value = DB::fromdb(fade_value);
368                         buffer[i] *= value;
370                         if(direction == PLAY_FORWARD)
371                                 input_position++;
372                         else
373                                 input_position--;
374                 }
375         }
377         return 0;
380 int VirtualANode::render_pan(double *input, // start of input fragment
381         double *output,            // start of output fragment
382         int64_t fragment_len,      // fragment length in input scale
383         int64_t input_position,    // starting sample of input buffer in project
384         int64_t sample_rate,       // sample rate of input_position
385         Autos *autos,
386         int channel,
387         int direction,
388         int use_nudge)
390         double slope = 0.0;
391         double intercept = 1.0;
392         EDL *edl = vconsole->renderengine->edl;
393         int64_t project_sample_rate = edl->session->sample_rate;
394         if(use_nudge) input_position += track->nudge * 
395                 sample_rate / 
396                 project_sample_rate;
398         for(int i = 0; i < fragment_len; )
399         {
400                 int64_t slope_len = (fragment_len - i)  *
401                                                         project_sample_rate /
402                                                         sample_rate;
404 // Get slope intercept formula for next fragment
405                 get_pan_automation(slope, 
406                                                 intercept, 
407                                                 input_position * 
408                                                         project_sample_rate / 
409                                                         sample_rate,
410                                                 slope_len,
411                                                 autos,
412                                                 channel,
413                                                 direction);
415                 slope_len = slope_len * sample_rate / project_sample_rate;
416                 slope = slope * sample_rate / project_sample_rate;
417                 slope_len = MIN(slope_len, fragment_len - i);
419 //printf("VirtualANode::render_pan 3 %d %lld %f %p %p\n", i, slope_len, slope, output, input);
420                 if(!EQUIV(slope, 0))
421                 {
422                         for(double j = 0; j < slope_len; j++, i++)
423                         {
424                                 value = slope * j + intercept;
425                                 output[i] += input[i] * value;
426                         }
427                 }
428                 else
429                 {
430                         for(int j = 0; j < slope_len; j++, i++)
431                         {
432                                 output[i] += input[i] * intercept;
433                         }
434                 }
437                 if(direction == PLAY_FORWARD)
438                         input_position += slope_len;
439                 else
440                         input_position -= slope_len;
442 //printf("VirtualANode::render_pan 4\n");
443         }
445         return 0;
449 void VirtualANode::get_pan_automation(double &slope,
450         double &intercept,
451         int64_t input_position,
452         int64_t &slope_len,
453         Autos *autos,
454         int channel,
455         int direction)
457         intercept = 0;
458         slope = 0;
460         PanAuto *prev_keyframe = 0;
461         PanAuto *next_keyframe = 0;
462         prev_keyframe = (PanAuto*)autos->get_prev_auto(input_position, 
463                 direction, 
464                 (Auto* &)prev_keyframe);
465         next_keyframe = (PanAuto*)autos->get_next_auto(input_position, 
466                 direction, 
467                 (Auto* &)next_keyframe);
468         
469         if(direction == PLAY_FORWARD)
470         {
471 // Two distinct automation points within range
472                 if(next_keyframe->position > prev_keyframe->position)
473                 {
474                         slope = ((double)next_keyframe->values[channel] - prev_keyframe->values[channel]) / 
475                                 ((double)next_keyframe->position - prev_keyframe->position);
476                         intercept = ((double)input_position - prev_keyframe->position) * slope + 
477                                 prev_keyframe->values[channel];
479                         if(next_keyframe->position < input_position + slope_len)
480                                 slope_len = next_keyframe->position - input_position;
481                 }
482                 else
483 // One automation point within range
484                 {
485                         slope = 0;
486                         intercept = prev_keyframe->values[channel];
487                 }
488         }
489         else
490         {
491 // Two distinct automation points within range
492                 if(next_keyframe->position < prev_keyframe->position)
493                 {
494                         slope = ((double)next_keyframe->values[channel] - prev_keyframe->values[channel]) / 
495                                 ((double)next_keyframe->position - prev_keyframe->position);
496                         intercept = ((double)input_position - prev_keyframe->position) * slope + 
497                                 prev_keyframe->values[channel];
499                         if(next_keyframe->position > input_position - slope_len)
500                                 slope_len = input_position - next_keyframe->position;
501                 }
502                 else
503 // One automation point within range
504                 {
505                         slope = 0;
506                         intercept = next_keyframe->values[channel];
507                 }
508         }