1 #include "aattachmentpoint.h"
6 #include "automation.h"
9 #include "edlsession.h"
11 #include "floatautos.h"
16 #include "renderengine.h"
18 #include "transition.h"
19 #include "transportque.h"
20 #include "virtualaconsole.h"
21 #include "virtualanode.h"
26 VirtualANode::VirtualANode(RenderEngine *renderengine,
27 VirtualConsole *vconsole,
31 VirtualNode *parent_module)
32 : VirtualNode(renderengine,
39 for(int i = 0; i < MAXCHANNELS; i++)
41 pan_before[i] = pan_after[i] = 0;
45 VirtualANode::~VirtualANode()
53 VirtualNode* VirtualANode::create_module(Plugin *real_plugin,
57 return new VirtualANode(renderengine,
66 VirtualNode* VirtualANode::create_plugin(Plugin *real_plugin)
68 return new VirtualANode(renderengine,
78 int VirtualANode::read_data(double *output_temp,
79 int64_t start_position,
83 VirtualNode *previous_plugin = 0;
85 // Current edit in parent track
86 AEdit *parent_edit = 0;
87 if(parent_node && parent_node->track && renderengine)
89 int64_t edl_rate = renderengine->edl->session->sample_rate;
90 int64_t start_position_project = (int64_t)(start_position *
94 parent_edit = (AEdit*)parent_node->track->edits->editof(start_position_project,
95 renderengine->command->get_direction(),
100 if(vconsole->debug_tree)
101 printf(" VirtualANode::read_data position=%lld rate=%lld title=%s parent_node=%p parent_edit=%p\n",
109 // This is a plugin on parent module with a preceeding effect.
110 // Get data from preceeding effect on parent module.
112 (previous_plugin = parent_node->get_previous_plugin(this)))
114 ((VirtualANode*)previous_plugin)->render(output_temp,
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))
126 ((VirtualANode*)parent_node)->read_data(output_temp,
133 // This is the first node in the tree
135 ((AModule*)real_module)->render(output_temp,
138 renderengine->command->get_direction(),
145 int VirtualANode::render(double *output_temp,
146 int64_t start_position,
150 ARender *arender = ((VirtualAConsole*)vconsole)->arender;
153 render_as_module(arender->audio_out,
162 render_as_plugin(output_temp,
170 void VirtualANode::render_as_plugin(double *output_temp,
171 int64_t start_position,
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
182 ((AAttachmentPoint*)attachment)->render(
184 plugin_buffer_number,
190 int VirtualANode::render_as_module(double **audio_out,
192 int64_t start_position,
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.
205 VirtualANode *node = (VirtualANode*)subnodes.values[subnodes.total - 1];
206 node->render(output_temp,
212 // Read data from previous entity
214 read_data(output_temp,
221 render_fade(output_temp,
225 track->automation->autos[AUTOMATION_FADE],
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 /
235 if(real_module && renderengine->command->realtime)
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 *
248 // Scan fragment in meter sized fragments
249 for(int i = 0; i < len; )
251 int current_level = ((AModule*)real_module)->current_level;
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 /
263 // Scan meter sized fragment
264 for( ; i < meter_render_end; i++)
266 double sample = fabs(output_temp[i]);
267 if(sample > peak) peak = sample;
270 ((AModule*)real_module)->level_history[current_level] =
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);
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; )
288 int mute_fragment = len - i;
289 int mute_fragment_project = mute_fragment *
290 project_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 /
298 // How many samples until the next mute?
299 get_mute_fragment(start_position_project,
301 mute_fragment_project,
302 (Autos*)track->automation->autos[AUTOMATION_MUTE],
305 // Fragment is playable
314 double *buffer = audio_out[j];
316 render_pan(output_temp + mute_position,
317 buffer + mute_position,
321 (Autos*)track->automation->autos[AUTOMATION_PAN],
329 len -= mute_fragment;
331 mute_position += mute_fragment;
337 int VirtualANode::render_fade(double *buffer,
339 int64_t input_position,
345 double value, fade_value;
346 FloatAuto *previous = 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 *
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 /
360 int64_t len_project = len *
361 project_sample_rate /
364 if(((FloatAutos*)autos)->automation_is_constant(input_position_project,
369 if(fade_value <= INFINITYGAIN)
372 value = DB::fromdb(fade_value);
373 for(int64_t i = 0; i < len; i++)
380 for(int64_t i = 0; i < len; i++)
382 int64_t slope_len = len - i;
383 input_position_project = input_position *
384 project_sample_rate /
387 fade_value = ((FloatAutos*)autos)->get_value(input_position_project,
392 if(fade_value <= INFINITYGAIN)
395 value = DB::fromdb(fade_value);
399 if(direction == PLAY_FORWARD)
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
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 *
427 for(int i = 0; i < fragment_len; )
429 int64_t slope_len = (fragment_len - i) *
430 project_sample_rate /
433 // Get slope intercept formula for next fragment
434 get_pan_automation(slope,
437 project_sample_rate /
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);
451 for(double j = 0; j < slope_len; j++, i++)
453 value = slope * j + intercept;
454 output[i] += input[i] * value;
459 for(int j = 0; j < slope_len; j++, i++)
461 output[i] += input[i] * intercept;
466 if(direction == PLAY_FORWARD)
467 input_position += slope_len;
469 input_position -= slope_len;
471 //printf("VirtualANode::render_pan 4\n");
478 void VirtualANode::get_pan_automation(double &slope,
480 int64_t input_position,
489 PanAuto *prev_keyframe = 0;
490 PanAuto *next_keyframe = 0;
491 prev_keyframe = (PanAuto*)autos->get_prev_auto(input_position,
493 (Auto* &)prev_keyframe);
494 next_keyframe = (PanAuto*)autos->get_next_auto(input_position,
496 (Auto* &)next_keyframe);
498 if(direction == PLAY_FORWARD)
500 // Two distinct automation points within range
501 if(next_keyframe->position > prev_keyframe->position)
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;
512 // One automation point within range
515 intercept = prev_keyframe->values[channel];
520 // Two distinct automation points within range
521 if(next_keyframe->position < prev_keyframe->position)
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;
532 // One automation point within range
535 intercept = next_keyframe->values[channel];
542 // c-file-style: "linux"