expand vaapi render formats and add shortcut
[goodguy/cinelerra.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                         meter_render_start = i;
285                         meter_render_end = i + meter_render_fragment;
286                         if(meter_render_end > len)
287                                 meter_render_end = len;
288 // Number of samples into the fragment this meter sized fragment is,
289 // normalized to project sample rate.
290                         int64_t meter_render_start_project = meter_render_start *
291                                 project_sample_rate / sample_rate;
292
293 // Scan meter sized fragment
294                         double peak = 0, *output_samples = output_temp->get_data();
295                         while( i < meter_render_end ) {
296                                 double sample = fabs(output_samples[i++]);
297                                 if( sample > peak ) peak = sample;
298                         }
299
300                         MeterHistory *meter_history = ((AModule*)real_module)->meter_history;
301                         int64_t pos = (direction == PLAY_FORWARD) ?
302                                 (start_position_project + meter_render_start_project) :
303                                 (start_position_project - meter_render_start_project) ;
304                         meter_history->set_peak(0, peak, pos);
305                 }
306         }
307 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
308
309 // process pans and copy the output to the output channels
310 // Keep rendering unmuted fragments until finished.
311         int mute_position = 0;
312
313         for(int i = 0; i < len; )
314         {
315                 int mute_constant;
316                 int mute_fragment = len - i;
317                 int mute_fragment_project = mute_fragment *
318                         project_sample_rate /
319                         sample_rate;
320                 start_position_project = start_position +
321                         ((direction == PLAY_FORWARD) ? i : -i);
322                 start_position_project = start_position_project *
323                         project_sample_rate /
324                         sample_rate;
325
326 // How many samples until the next mute?
327                 get_mute_fragment(start_position_project,
328                                 mute_constant,
329                                 mute_fragment_project,
330                                 (Autos*)track->automation->autos[AUTOMATION_MUTE],
331                                 direction,
332                                 0);
333 // Fragment is playable
334                 if(!mute_constant)
335                 {
336                         for(int j = 0;
337                                 j < MAX_CHANNELS;
338                                 j++)
339                         {
340                                 if(audio_out[j])
341                                 {
342                                         double *buffer = audio_out[j]->get_data();
343
344                                         render_pan(output_temp->get_data() + mute_position,
345                                                                 buffer + mute_position,
346                                                                 mute_fragment,
347                                                                 start_position,
348                                                                 sample_rate,
349                                                                 (Autos*)track->automation->autos[AUTOMATION_PAN],
350                                                                 j,
351                                                                 direction,
352                                                                 0);
353 //printf("VirtualANode::render_as_module %d %lld\n", __LINE__, start_position);
354                                 }
355                         }
356                 }
357
358                 len -= mute_fragment;
359                 i += mute_fragment;
360                 mute_position += mute_fragment;
361         }
362 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
363
364         return 0;
365 }
366
367 int VirtualANode::render_fade(double *buffer, int64_t len,
368         int64_t input_position, int64_t sample_rate,
369         Autos *autos, int direction, int use_nudge)
370 {
371         double fade_value;
372         FloatAuto *previous = 0;
373         FloatAuto *next = 0;
374         EDL *edl = vconsole->renderengine->get_edl();
375         const int debug = 0;
376         int64_t project_sample_rate = edl->session->sample_rate;
377         double to_project_rate = (double)project_sample_rate / sample_rate;
378         double to_sample_rate = (double)sample_rate / project_sample_rate;
379
380         if(use_nudge)
381                 input_position += track->nudge * to_sample_rate;
382
383 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
384 // Normalize input position to project sample rate here.
385 // Automation functions are general to video and audio so it
386 // can't normalize itself.
387         int64_t input_pos = input_position * to_project_rate;
388         int64_t len_project = len * to_project_rate;
389
390 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
391         if(((FloatAutos*)autos)->automation_is_constant(
392                 input_pos, len_project, direction, fade_value))
393         {
394 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
395                 double value = fade_value<=INFINITYGAIN ?
396                          0. : DB::fromdb(fade_value);
397                 if( EQUIV(value, 0.) ) {
398                         for(int64_t i = 0; i < len; i++)
399                                 buffer[i] = 0;
400                 }
401                 else if( !EQUIV(value, 1.) ) {
402                         for(int64_t i = 0; i < len; i++)
403                                 buffer[i] *= value;
404                 }
405 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
406         }
407         else
408         {
409 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
410                 for(int64_t i = 0; i < len; i++)
411                 {
412                         input_pos = input_position * to_project_rate;
413
414                         fade_value = ((FloatAutos*)autos)->get_value(
415                                 input_pos, direction, previous, next);
416
417                         double value = fade_value<=INFINITYGAIN ?
418                                  0. : DB::fromdb(fade_value);
419                         if( EQUIV(value,0.) )
420                                 buffer[i] = 0;
421                         else if( !EQUIV(value,1.) ) {
422                                 buffer[i] *= value;
423                         }
424
425                         if(direction == PLAY_FORWARD)
426                                 input_position++;
427                         else
428                                 input_position--;
429                 }
430 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
431         }
432 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
433
434         return 0;
435 }
436
437 int VirtualANode::render_pan(double *input, // start of input fragment
438         double *output,            // start of output fragment
439         int64_t fragment_len,      // fragment length in input scale
440         int64_t input_position,    // starting sample of input buffer in project
441         int64_t sample_rate,       // sample rate of input_position
442         Autos *autos,
443         int channel,
444         int direction,
445         int use_nudge)
446 {
447         double slope = 0.0;
448         double intercept = 1.0;
449         EDL *edl = vconsole->renderengine->get_edl();
450         int64_t project_sample_rate = edl->session->sample_rate;
451         double to_project_rate = (double)project_sample_rate / sample_rate;
452         double to_sample_rate = (double)sample_rate / project_sample_rate;
453         if(use_nudge)
454                 input_position += track->nudge * to_sample_rate;
455
456         for(int i = 0; i < fragment_len; )
457         {
458                 int64_t len = fragment_len - i;
459                 int64_t slope_len = len * to_project_rate;
460                 int64_t input_pos = input_position * to_project_rate;
461
462 // Get slope intercept formula for next fragment
463                 get_pan_automation(slope, intercept, input_pos,
464                         slope_len, autos, channel, direction);
465
466                 slope_len *= to_sample_rate;
467                 slope = slope * to_sample_rate;
468                 slope_len = MIN(slope_len, len);
469
470 //printf("VirtualANode::render_pan 3 %d %jd %f %p %p\n", i, slope_len, slope, output, input);
471                 if(!EQUIV(slope, 0)) {
472                         for(double j = 0; j < slope_len; j++, i++) {
473                                 value = slope * j + intercept;
474                                 output[i] += input[i] * value;
475                         }
476                 }
477                 else if( EQUIV(intercept, 1) ) {
478                         for(int64_t j = 0; j < slope_len; j++, i++)
479                                 output[i] += input[i];
480                 }
481                 else if( !EQUIV(intercept, 0) ) {
482                         for(int64_t j = 0; j < slope_len; j++, i++)
483                                 output[i] += input[i] * intercept;
484                 }
485                 else
486                         i += slope_len;
487
488                 if(direction == PLAY_FORWARD)
489                         input_position += slope_len;
490                 else
491                         input_position -= slope_len;
492
493 //printf("VirtualANode::render_pan 4\n");
494         }
495
496         return 0;
497 }
498
499
500 void VirtualANode::get_pan_automation(double &slope,
501         double &intercept,
502         int64_t input_position,
503         int64_t &slope_len,
504         Autos *autos,
505         int channel,
506         int direction)
507 {
508         intercept = 0;
509         slope = 0;
510
511         Auto *prev_keyframe = 0, *next_keyframe = 0;
512         prev_keyframe = autos->get_prev_auto(input_position, direction, prev_keyframe);
513         next_keyframe = autos->get_next_auto(input_position, direction, next_keyframe);
514         PanAuto *prev_pan_auto = (PanAuto *)prev_keyframe;
515         PanAuto *next_pan_auto = (PanAuto *)next_keyframe;
516
517         if(direction == PLAY_FORWARD)
518         {
519 // Two distinct automation points within range
520                 if(next_pan_auto->position > prev_pan_auto->position)
521                 {
522                         slope = ((double)next_pan_auto->values[channel] - prev_pan_auto->values[channel]) /
523                                 ((double)next_pan_auto->position - prev_pan_auto->position);
524                         intercept = ((double)input_position - prev_pan_auto->position) * slope +
525                                 prev_pan_auto->values[channel];
526
527                         if(next_pan_auto->position < input_position + slope_len)
528                                 slope_len = next_pan_auto->position - input_position;
529                 }
530                 else
531 // One automation point within range
532                 {
533                         slope = 0;
534                         intercept = prev_pan_auto->values[channel];
535                 }
536         }
537         else
538         {
539 // Two distinct automation points within range
540                 if(next_pan_auto->position < prev_pan_auto->position)
541                 {
542                         slope = ((double)next_pan_auto->values[channel] - prev_pan_auto->values[channel]) /
543                                 ((double)next_pan_auto->position - prev_pan_auto->position);
544                         intercept = ((double)input_position - prev_pan_auto->position) * slope +
545                                 prev_pan_auto->values[channel];
546
547                         if(next_pan_auto->position > input_position - slope_len)
548                                 slope_len = input_position - next_pan_auto->position;
549                 }
550                 else
551 // One automation point within range
552                 {
553                         slope = 0;
554                         intercept = next_pan_auto->values[channel];
555                 }
556         }
557 }