add formatting trailer for emacs
[cinelerra_cv/ct.git] / cinelerra / virtualanode.C
blob4653dc4a665541dfcac306e3b4d55c19dd409b8f
1 #include "aattachmentpoint.h"
2 #include "aedit.h"
3 #include "amodule.h"
4 #include "arender.h"
5 #include "atrack.h"
6 #include "automation.h"
7 #include "edits.h"
8 #include "edl.h"
9 #include "edlsession.h"
10 #include "clip.h"
11 #include "floatautos.h"
12 #include "mwindow.h"
13 #include "module.h"
14 #include "panauto.h"
15 #include "plugin.h"
16 #include "renderengine.h"
17 #include "track.h"
18 #include "transition.h"
19 #include "transportque.h"
20 #include "virtualaconsole.h"
21 #include "virtualanode.h"
24 #include <string.h>
26 VirtualANode::VirtualANode(RenderEngine *renderengine, 
27                 VirtualConsole *vconsole, 
28                 Module *real_module, 
29                 Plugin *real_plugin,
30                 Track *track, 
31                 VirtualNode *parent_module)
32  : VirtualNode(renderengine, 
33                 vconsole, 
34                 real_module, 
35                 real_plugin,
36                 track, 
37                 parent_module)
39         for(int i = 0; i < MAXCHANNELS; i++)
40         {
41                 pan_before[i] = pan_after[i] = 0;
42         }
45 VirtualANode::~VirtualANode()
53 VirtualNode* VirtualANode::create_module(Plugin *real_plugin, 
54                                                         Module *real_module, 
55                                                         Track *track)
57         return new VirtualANode(renderengine, 
58                 vconsole, 
59                 real_module,
60                 0,
61                 track,
62                 this);
66 VirtualNode* VirtualANode::create_plugin(Plugin *real_plugin)
68         return new VirtualANode(renderengine, 
69                 vconsole, 
70                 0,
71                 real_plugin,
72                 track,
73                 this);
78 int VirtualANode::read_data(double *output_temp,
79         int64_t start_position,
80         int64_t len,
81         int64_t sample_rate)
83         VirtualNode *previous_plugin = 0;
85 // Current edit in parent track
86         AEdit *parent_edit = 0;
87         if(parent_node && parent_node->track && renderengine)
88         {
89                 int64_t edl_rate = renderengine->edl->session->sample_rate;
90                 int64_t start_position_project = (int64_t)(start_position *
91                         edl_rate /
92                         sample_rate + 
93                         0.5);
94                 parent_edit = (AEdit*)parent_node->track->edits->editof(start_position_project, 
95                         renderengine->command->get_direction(),
96                         0);
97         }
100         if(vconsole->debug_tree) 
101                 printf("  VirtualANode::read_data position=%lld rate=%lld title=%s parent_node=%p parent_edit=%p\n", 
102                                 start_position,
103                                 sample_rate,
104                                 track->title,
105                                 parent_node,
106                                 parent_edit);
109 // This is a plugin on parent module with a preceeding effect.
110 // Get data from preceeding effect on parent module.
111         if(parent_node && 
112                 (previous_plugin = parent_node->get_previous_plugin(this)))
113         {
114                 ((VirtualANode*)previous_plugin)->render(output_temp,
115                         start_position,
116                         len,
117                         sample_rate);
118         }
119         else
120 // The current node is the first plugin on parent module.
121 // The parent module has an edit to read from or the current node
122 // has no source to read from.
123 // Read data from parent module
124         if(parent_node && (parent_edit || !real_module))
125         {
126                 ((VirtualANode*)parent_node)->read_data(output_temp,
127                         start_position,
128                         len,
129                         sample_rate);
130         }
131         else
132         if(real_module)
133 // This is the first node in the tree
134         {
135                 ((AModule*)real_module)->render(output_temp,
136                         start_position,
137                         len,
138                         renderengine->command->get_direction(),
139                         sample_rate,
140                         0);
141         }
142         return 0;
145 int VirtualANode::render(double *output_temp,
146         int64_t start_position,
147         int64_t len,
148         int64_t sample_rate)
150         ARender *arender = ((VirtualAConsole*)vconsole)->arender;
151         if(real_module)
152         {
153                 render_as_module(arender->audio_out, 
154                         output_temp,
155                         start_position, 
156                         len,
157                         sample_rate);
158         }
159         else
160         if(real_plugin)
161         {
162                 render_as_plugin(output_temp,
163                         start_position,
164                         len,
165                         sample_rate);
166         }
167         return 0;
170 void VirtualANode::render_as_plugin(double *output_temp,
171         int64_t start_position, 
172         int64_t len,
173         int64_t sample_rate)
175         if(!attachment ||
176                 !real_plugin ||
177                 !real_plugin->on) return;
179 // If we're the first plugin in the parent module, data needs to be read from 
180 // what comes before the parent module.  Otherwise, data needs to come from the
181 // previous plugin.
182         ((AAttachmentPoint*)attachment)->render(
183                 output_temp, 
184                 plugin_buffer_number,
185                 start_position,
186                 len, 
187                 sample_rate);
190 int VirtualANode::render_as_module(double **audio_out, 
191                                 double *output_temp,
192                                 int64_t start_position,
193                                 int64_t len, 
194                                 int64_t sample_rate)
196         int in_output = 0;
197         int direction = renderengine->command->get_direction();
198         EDL *edl = vconsole->renderengine->edl;
201 // Process last subnode.  This calls read_data, propogates up the chain 
202 // of subnodes, and finishes the chain.
203         if(subnodes.total)
204         {
205                 VirtualANode *node = (VirtualANode*)subnodes.values[subnodes.total - 1];
206                 node->render(output_temp,
207                         start_position,
208                         len,
209                         sample_rate);
210         }
211         else
212 // Read data from previous entity
213         {
214                 read_data(output_temp,
215                         start_position,
216                         len,
217                         sample_rate);
218         }
221         render_fade(output_temp,
222                                 len,
223                                 start_position,
224                                 sample_rate,
225                                 track->automation->autos[AUTOMATION_FADE],
226                                 direction,
227                                 0);
229 // Get the peak but don't limit
230 // Calculate position relative to project for meters
231         int64_t project_sample_rate = edl->session->sample_rate;
232         int64_t start_position_project = start_position * 
233                 project_sample_rate /
234                 sample_rate;
235         if(real_module && renderengine->command->realtime)
236         {
237                 ARender *arender = ((VirtualAConsole*)vconsole)->arender;
238 // Starting sample of meter block
239                 int64_t meter_render_start;
240 // Ending sample of meter block
241                 int64_t meter_render_end;
242 // Number of samples in each meter fragment normalized to requested rate
243                 int meter_render_fragment = arender->meter_render_fragment * 
244                         sample_rate /
245                         project_sample_rate;
248 // Scan fragment in meter sized fragments
249                 for(int i = 0; i < len; )
250                 {
251                         int current_level = ((AModule*)real_module)->current_level;
252                         double peak = 0;
253                         meter_render_start = i;
254                         meter_render_end = i + meter_render_fragment;
255                         if(meter_render_end > len) 
256                                 meter_render_end = len;
257 // Number of samples into the fragment this meter sized fragment is,
258 // normalized to project sample rate.
259                         int64_t meter_render_start_project = meter_render_start *
260                                 project_sample_rate /
261                                 sample_rate;
263 // Scan meter sized fragment
264                         for( ; i < meter_render_end; i++)
265                         {
266                                 double sample = fabs(output_temp[i]);
267                                 if(sample > peak) peak = sample;
268                         }
270                         ((AModule*)real_module)->level_history[current_level] = 
271                                 peak;
272                         ((AModule*)real_module)->level_samples[current_level] = 
273                                 (direction == PLAY_FORWARD) ?
274                                 (start_position_project + meter_render_start_project) :
275                                 (start_position_project - meter_render_start_project);
276                         ((AModule*)real_module)->current_level = 
277                                 arender->get_next_peak(current_level);
278                 }
279         }
281 // process pans and copy the output to the output channels
282 // Keep rendering unmuted fragments until finished.
283         int mute_position = 0;
285         for(int i = 0; i < len; )
286         {
287                 int mute_constant;
288                 int mute_fragment = len - i;
289                 int mute_fragment_project = mute_fragment *
290                         project_sample_rate /
291                         sample_rate;
292                 start_position_project = start_position + 
293                         ((direction == PLAY_FORWARD) ? i : -i);
294                 start_position_project = start_position_project *
295                         project_sample_rate / 
296                         sample_rate;
298 // How many samples until the next mute?
299                 get_mute_fragment(start_position_project,
300                                 mute_constant, 
301                                 mute_fragment_project,
302                                 (Autos*)track->automation->autos[AUTOMATION_MUTE],
303                                 direction,
304                                 0);
305 // Fragment is playable
306                 if(!mute_constant)
307                 {
308                         for(int j = 0; 
309                                 j < MAX_CHANNELS; 
310                                 j++)
311                         {
312                                 if(audio_out[j])
313                                 {
314                                         double *buffer = audio_out[j];
316                                         render_pan(output_temp + mute_position, 
317                                                                 buffer + mute_position,
318                                                                 mute_fragment,
319                                                                 start_position,
320                                                                 sample_rate,
321                                                                 (Autos*)track->automation->autos[AUTOMATION_PAN],
322                                                                 j,
323                                                                 direction,
324                                                                 0);
325                                 }
326                         }
327                 }
329                 len -= mute_fragment;
330                 i += mute_fragment;
331                 mute_position += mute_fragment;
332         }
334         return 0;
337 int VirtualANode::render_fade(double *buffer,
338                                 int64_t len,
339                                 int64_t input_position,
340                                 int64_t sample_rate,
341                                 Autos *autos,
342                                 int direction,
343                                 int use_nudge)
345         double value, fade_value;
346         FloatAuto *previous = 0;
347         FloatAuto *next = 0;
348         EDL *edl = vconsole->renderengine->edl;
349         int64_t project_sample_rate = edl->session->sample_rate;
350         if(use_nudge) input_position += track->nudge * 
351                 sample_rate / 
352                 project_sample_rate;
354 // Normalize input position to project sample rate here.
355 // Automation functions are general to video and audio so it 
356 // can't normalize itself.
357         int64_t input_position_project = input_position * 
358                 project_sample_rate / 
359                 sample_rate;
360         int64_t len_project = len * 
361                 project_sample_rate / 
362                 sample_rate;
364         if(((FloatAutos*)autos)->automation_is_constant(input_position_project, 
365                 len_project,
366                 direction,
367                 fade_value))
368         {
369                 if(fade_value <= INFINITYGAIN)
370                         value = 0;
371                 else
372                         value = DB::fromdb(fade_value);
373                 for(int64_t i = 0; i < len; i++)
374                 {
375                         buffer[i] *= value;
376                 }
377         }
378         else
379         {
380                 for(int64_t i = 0; i < len; i++)
381                 {
382                         int64_t slope_len = len - i;
383                         input_position_project = input_position * 
384                                 project_sample_rate / 
385                                 sample_rate;
387                         fade_value = ((FloatAutos*)autos)->get_value(input_position_project, 
388                                 direction,
389                                 previous,
390                                 next);
392                         if(fade_value <= INFINITYGAIN)
393                                 value = 0;
394                         else
395                                 value = DB::fromdb(fade_value);
397                         buffer[i] *= value;
399                         if(direction == PLAY_FORWARD)
400                                 input_position++;
401                         else
402                                 input_position--;
403                 }
404         }
406         return 0;
409 int VirtualANode::render_pan(double *input, // start of input fragment
410         double *output,            // start of output fragment
411         int64_t fragment_len,      // fragment length in input scale
412         int64_t input_position,    // starting sample of input buffer in project
413         int64_t sample_rate,       // sample rate of input_position
414         Autos *autos,
415         int channel,
416         int direction,
417         int use_nudge)
419         double slope = 0.0;
420         double intercept = 1.0;
421         EDL *edl = vconsole->renderengine->edl;
422         int64_t project_sample_rate = edl->session->sample_rate;
423         if(use_nudge) input_position += track->nudge * 
424                 sample_rate / 
425                 project_sample_rate;
427         for(int i = 0; i < fragment_len; )
428         {
429                 int64_t slope_len = (fragment_len - i)  *
430                                                         project_sample_rate /
431                                                         sample_rate;
433 // Get slope intercept formula for next fragment
434                 get_pan_automation(slope, 
435                                                 intercept, 
436                                                 input_position * 
437                                                         project_sample_rate / 
438                                                         sample_rate,
439                                                 slope_len,
440                                                 autos,
441                                                 channel,
442                                                 direction);
444                 slope_len = slope_len * sample_rate / project_sample_rate;
445                 slope = slope * sample_rate / project_sample_rate;
446                 slope_len = MIN(slope_len, fragment_len - i);
448 //printf("VirtualANode::render_pan 3 %d %lld %f %p %p\n", i, slope_len, slope, output, input);
449                 if(!EQUIV(slope, 0))
450                 {
451                         for(double j = 0; j < slope_len; j++, i++)
452                         {
453                                 value = slope * j + intercept;
454                                 output[i] += input[i] * value;
455                         }
456                 }
457                 else
458                 {
459                         for(int j = 0; j < slope_len; j++, i++)
460                         {
461                                 output[i] += input[i] * intercept;
462                         }
463                 }
466                 if(direction == PLAY_FORWARD)
467                         input_position += slope_len;
468                 else
469                         input_position -= slope_len;
471 //printf("VirtualANode::render_pan 4\n");
472         }
474         return 0;
478 void VirtualANode::get_pan_automation(double &slope,
479         double &intercept,
480         int64_t input_position,
481         int64_t &slope_len,
482         Autos *autos,
483         int channel,
484         int direction)
486         intercept = 0;
487         slope = 0;
489         PanAuto *prev_keyframe = 0;
490         PanAuto *next_keyframe = 0;
491         prev_keyframe = (PanAuto*)autos->get_prev_auto(input_position, 
492                 direction, 
493                 (Auto* &)prev_keyframe);
494         next_keyframe = (PanAuto*)autos->get_next_auto(input_position, 
495                 direction, 
496                 (Auto* &)next_keyframe);
497         
498         if(direction == PLAY_FORWARD)
499         {
500 // Two distinct automation points within range
501                 if(next_keyframe->position > prev_keyframe->position)
502                 {
503                         slope = ((double)next_keyframe->values[channel] - prev_keyframe->values[channel]) / 
504                                 ((double)next_keyframe->position - prev_keyframe->position);
505                         intercept = ((double)input_position - prev_keyframe->position) * slope + 
506                                 prev_keyframe->values[channel];
508                         if(next_keyframe->position < input_position + slope_len)
509                                 slope_len = next_keyframe->position - input_position;
510                 }
511                 else
512 // One automation point within range
513                 {
514                         slope = 0;
515                         intercept = prev_keyframe->values[channel];
516                 }
517         }
518         else
519         {
520 // Two distinct automation points within range
521                 if(next_keyframe->position < prev_keyframe->position)
522                 {
523                         slope = ((double)next_keyframe->values[channel] - prev_keyframe->values[channel]) / 
524                                 ((double)next_keyframe->position - prev_keyframe->position);
525                         intercept = ((double)input_position - prev_keyframe->position) * slope + 
526                                 prev_keyframe->values[channel];
528                         if(next_keyframe->position > input_position - slope_len)
529                                 slope_len = input_position - next_keyframe->position;
530                 }
531                 else
532 // One automation point within range
533                 {
534                         slope = 0;
535                         intercept = next_keyframe->values[channel];
536                 }
537         }
540 //      Local Variables:
541 //      mode: C++
542 //      c-file-style: "linux"
543 //      End: