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