r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / cinelerra / virtualanode.C
blobd22bcf213d3c0e7c00bb5345136694a6d902878e
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 //printf("VirtualANode::read_data 1 %p\n", this);
84 // This is a plugin on parent module with a preceeding effect.
85 // Get data from preceeding effect on parent module.
86         if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this)))
87         {
88 //printf("VirtualANode::read_data 2\n");
89                 ((VirtualANode*)previous_plugin)->render(output_temp,
90                         start_position,
91                         len,
92                         sample_rate);
93 //printf("VirtualANode::read_data 3\n");
94         }
95         else
96 // First plugin on parent module.
97 // Read data from parent module
98         if(parent_node)
99         {
100                 ((VirtualANode*)parent_node)->read_data(output_temp,
101                         start_position,
102                         len,
103                         sample_rate);
104         }
105         else
106 // This is the first node in the tree
107         {
108 //printf("VirtualANode::read_data 8\n");
109                 ((AModule*)real_module)->render(output_temp,
110                         start_position,
111                         len,
112                         renderengine->command->get_direction(),
113                         sample_rate,
114                         0);
115 //printf("VirtualANode::read_data 9\n");
116         }
117 //printf("VirtualANode::read_data 100 %p\n", this);
118         return 0;
121 int VirtualANode::render(double *output_temp,
122         int64_t start_position,
123         int64_t len,
124         int64_t sample_rate)
126         ARender *arender = ((VirtualAConsole*)vconsole)->arender;
127         if(real_module)
128         {
129 //printf("VirtualANode::render 1\n");
130                 render_as_module(arender->audio_out, 
131                         output_temp,
132                         start_position, 
133                         len,
134                         sample_rate);
135 //printf("VirtualANode::render 2\n");
136         }
137         else
138         if(real_plugin)
139         {
140 //printf("VirtualANode::render 3\n");
141                 render_as_plugin(output_temp,
142                         start_position,
143                         len,
144                         sample_rate);
145 //printf("VirtualANode::render 4\n");
146         }
147         return 0;
150 void VirtualANode::render_as_plugin(double *output_temp,
151         int64_t start_position, 
152         int64_t len,
153         int64_t sample_rate)
155 //printf("VirtualANode::render_as_plugin 1 %p\n", this);
156         if(!attachment ||
157                 !real_plugin ||
158                 !real_plugin->on) return;
160 //printf("VirtualANode::render_as_plugin 2 %p\n", output_temp);
161 // If we're the first plugin in the parent module, data needs to be read from 
162 // what comes before the parent module.  Otherwise, data needs to come from the
163 // previous plugin.
164         ((AAttachmentPoint*)attachment)->render(
165                 output_temp, 
166                 plugin_buffer_number,
167                 start_position,
168                 len, 
169                 sample_rate);
170 //printf("VirtualANode::render_as_plugin 100 %p\n", this);
173 int VirtualANode::render_as_module(double **audio_out, 
174                                 double *output_temp,
175                                 int64_t start_position,
176                                 int64_t len, 
177                                 int64_t sample_rate)
179         int in_output = 0;
180         int direction = renderengine->command->get_direction();
181         EDL *edl = vconsole->renderengine->edl;
184 // Process last subnode.  This calls read_data, propogates up the chain 
185 // of subnodes, and finishes the chain.
186         if(subnodes.total)
187         {
188                 VirtualANode *node = (VirtualANode*)subnodes.values[subnodes.total - 1];
189                 node->render(output_temp,
190                         start_position,
191                         len,
192                         sample_rate);
193         }
194         else
195 // Read data from previous entity
196         {
197                 read_data(output_temp,
198                         start_position,
199                         len,
200                         sample_rate);
201         }
204         render_fade(output_temp,
205                                 len,
206                                 start_position,
207                                 sample_rate,
208                                 track->automation->fade_autos,
209                                 direction,
210                                 0);
212 // Get the peak but don't limit
213 // Calculate position relative to project for meters
214         int64_t project_sample_rate = edl->session->sample_rate;
215         int64_t start_position_project = start_position * 
216                 project_sample_rate /
217                 sample_rate;
218         if(real_module && renderengine->command->realtime)
219         {
220                 ARender *arender = ((VirtualAConsole*)vconsole)->arender;
221 // Starting sample of meter block
222                 int64_t meter_render_start;
223 // Ending sample of meter block
224                 int64_t meter_render_end;
225 // Number of samples in each meter fragment normalized to requested rate
226                 int meter_render_fragment = arender->meter_render_fragment * 
227                         sample_rate /
228                         project_sample_rate;
231 // Scan fragment in meter sized fragments
232                 for(int i = 0; i < len; )
233                 {
234                         int current_level = ((AModule*)real_module)->current_level;
235                         double peak = 0;
236                         meter_render_start = i;
237                         meter_render_end = i + meter_render_fragment;
238                         if(meter_render_end > len) 
239                                 meter_render_end = len;
240 // Number of samples into the fragment this meter sized fragment is,
241 // normalized to project sample rate.
242                         int64_t meter_render_start_project = meter_render_start *
243                                 project_sample_rate /
244                                 sample_rate;
246 // Scan meter sized fragment
247                         for( ; i < meter_render_end; i++)
248                         {
249                                 double sample = fabs(output_temp[i]);
250                                 if(sample > peak) peak = sample;
251                         }
253                         ((AModule*)real_module)->level_history[current_level] = 
254                                 peak;
255                         ((AModule*)real_module)->level_samples[current_level] = 
256                                 (direction == PLAY_FORWARD) ?
257                                 (start_position_project + meter_render_start_project) :
258                                 (start_position_project - meter_render_start_project);
259                         ((AModule*)real_module)->current_level = 
260                                 arender->get_next_peak(current_level);
261                 }
262         }
264 // process pans and copy the output to the output channels
265 // Keep rendering unmuted fragments until finished.
266         int mute_position = 0;
268         for(int i = 0; i < len; )
269         {
270                 int mute_constant;
271                 int mute_fragment = len - i;
272                 int mute_fragment_project = mute_fragment *
273                         project_sample_rate /
274                         sample_rate;
275                 start_position_project = start_position + 
276                         ((direction == PLAY_FORWARD) ? i : -i);
277                 start_position_project = start_position_project *
278                         project_sample_rate / 
279                         sample_rate;
281 // How many samples until the next mute?
282                 get_mute_fragment(start_position_project,
283                                 mute_constant, 
284                                 mute_fragment_project,
285                                 (Autos*)track->automation->mute_autos,
286                                 direction,
287                                 0);
288 // Fragment is playable
289                 if(!mute_constant)
290                 {
291                         for(int j = 0; 
292                                 j < MAX_CHANNELS; 
293                                 j++)
294                         {
295                                 if(audio_out[j])
296                                 {
297                                         double *buffer = audio_out[j];
299                                         render_pan(output_temp + mute_position, 
300                                                                 buffer + mute_position,
301                                                                 mute_fragment,
302                                                                 start_position,
303                                                                 sample_rate,
304                                                                 (Autos*)track->automation->pan_autos,
305                                                                 j,
306                                                                 direction,
307                                                                 0);
308                                 }
309                         }
310                 }
312                 len -= mute_fragment;
313                 i += mute_fragment;
314                 mute_position += mute_fragment;
315         }
317         return 0;
320 int VirtualANode::render_fade(double *buffer,
321                                 int64_t len,
322                                 int64_t input_position,
323                                 int64_t sample_rate,
324                                 Autos *autos,
325                                 int direction,
326                                 int use_nudge)
328         double value, fade_value;
329         FloatAuto *previous = 0;
330         FloatAuto *next = 0;
331         EDL *edl = vconsole->renderengine->edl;
332         int64_t project_sample_rate = edl->session->sample_rate;
333         if(use_nudge) input_position += track->nudge * 
334                 sample_rate / 
335                 project_sample_rate;
337 // Normalize input position to project sample rate here.
338 // Automation functions are general to video and audio so it 
339 // can't normalize itself.
340         int64_t input_position_project = input_position * 
341                 project_sample_rate / 
342                 sample_rate;
343         int64_t len_project = len * 
344                 project_sample_rate / 
345                 sample_rate;
347         if(((FloatAutos*)autos)->automation_is_constant(input_position_project, 
348                 len_project,
349                 direction,
350                 fade_value))
351         {
352                 if(fade_value <= INFINITYGAIN)
353                         value = 0;
354                 else
355                         value = DB::fromdb(fade_value);
356                 for(int64_t i = 0; i < len; i++)
357                 {
358                         buffer[i] *= value;
359                 }
360         }
361         else
362         {
363                 for(int64_t i = 0; i < len; i++)
364                 {
365                         int64_t slope_len = len - i;
366                         input_position_project = input_position * 
367                                 project_sample_rate / 
368                                 sample_rate;
370                         fade_value = ((FloatAutos*)autos)->get_value(input_position_project, 
371                                 direction,
372                                 previous,
373                                 next);
375                         if(fade_value <= INFINITYGAIN)
376                                 value = 0;
377                         else
378                                 value = DB::fromdb(fade_value);
380                         buffer[i] *= value;
382                         if(direction == PLAY_FORWARD)
383                                 input_position++;
384                         else
385                                 input_position--;
386                 }
387         }
389         return 0;
392 int VirtualANode::render_pan(double *input, // start of input fragment
393         double *output,            // start of output fragment
394         int64_t fragment_len,      // fragment length in input scale
395         int64_t input_position,    // starting sample of input buffer in project
396         int64_t sample_rate,       // sample rate of input_position
397         Autos *autos,
398         int channel,
399         int direction,
400         int use_nudge)
402         double slope = 0.0;
403         double intercept = 1.0;
404         EDL *edl = vconsole->renderengine->edl;
405         int64_t project_sample_rate = edl->session->sample_rate;
406         if(use_nudge) input_position += track->nudge * 
407                 sample_rate / 
408                 project_sample_rate;
410         for(int i = 0; i < fragment_len; )
411         {
412                 int64_t slope_len = (fragment_len - i)  *
413                                                         project_sample_rate /
414                                                         sample_rate;
416 // Get slope intercept formula for next fragment
417                 get_pan_automation(slope, 
418                                                 intercept, 
419                                                 input_position * 
420                                                         project_sample_rate / 
421                                                         sample_rate,
422                                                 slope_len,
423                                                 autos,
424                                                 channel,
425                                                 direction);
427                 slope_len = slope_len * sample_rate / project_sample_rate;
428                 slope = slope * sample_rate / project_sample_rate;
429                 slope_len = MIN(slope_len, fragment_len - i);
431 //printf("VirtualANode::render_pan 3 %d %lld %f %p %p\n", i, slope_len, slope, output, input);
432                 if(!EQUIV(slope, 0))
433                 {
434                         for(double j = 0; j < slope_len; j++, i++)
435                         {
436                                 value = slope * j + intercept;
437                                 output[i] += input[i] * value;
438                         }
439                 }
440                 else
441                 {
442                         for(int j = 0; j < slope_len; j++, i++)
443                         {
444                                 output[i] += input[i] * intercept;
445                         }
446                 }
449                 if(direction == PLAY_FORWARD)
450                         input_position += slope_len;
451                 else
452                         input_position -= slope_len;
454 //printf("VirtualANode::render_pan 4\n");
455         }
457         return 0;
461 void VirtualANode::get_pan_automation(double &slope,
462         double &intercept,
463         int64_t input_position,
464         int64_t &slope_len,
465         Autos *autos,
466         int channel,
467         int direction)
469         intercept = 0;
470         slope = 0;
472         PanAuto *prev_keyframe = 0;
473         PanAuto *next_keyframe = 0;
474         prev_keyframe = (PanAuto*)autos->get_prev_auto(input_position, direction, (Auto*)prev_keyframe);
475         next_keyframe = (PanAuto*)autos->get_next_auto(input_position, direction, (Auto*)next_keyframe);
476         
477         if(direction == PLAY_FORWARD)
478         {
479 // Two distinct automation points within range
480                 if(next_keyframe->position > prev_keyframe->position)
481                 {
482                         slope = ((double)next_keyframe->values[channel] - prev_keyframe->values[channel]) / 
483                                 ((double)next_keyframe->position - prev_keyframe->position);
484                         intercept = ((double)input_position - prev_keyframe->position) * slope + 
485                                 prev_keyframe->values[channel];
487                         if(next_keyframe->position < input_position + slope_len)
488                                 slope_len = next_keyframe->position - input_position;
489                 }
490                 else
491 // One automation point within range
492                 {
493                         slope = 0;
494                         intercept = prev_keyframe->values[channel];
495                 }
496         }
497         else
498         {
499 // Two distinct automation points within range
500                 if(next_keyframe->position < prev_keyframe->position)
501                 {
502                         slope = ((double)next_keyframe->values[channel] - prev_keyframe->values[channel]) / 
503                                 ((double)next_keyframe->position - prev_keyframe->position);
504                         intercept = ((double)input_position - prev_keyframe->position) * slope + 
505                                 prev_keyframe->values[channel];
507                         if(next_keyframe->position > input_position - slope_len)
508                                 slope_len = input_position - next_keyframe->position;
509                 }
510                 else
511 // One automation point within range
512                 {
513                         slope = 0;
514                         intercept = next_keyframe->values[channel];
515                 }
516         }