4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "aattachmentpoint.h"
27 #include "automation.h"
31 #include "edlsession.h"
32 #include "floatautos.h"
37 #include "renderengine.h"
40 #include "transition.h"
41 #include "transportque.h"
42 #include "virtualaconsole.h"
43 #include "virtualanode.h"
48 VirtualANode::VirtualANode(RenderEngine *renderengine,
49 VirtualConsole *vconsole,
53 VirtualNode *parent_module)
54 : VirtualNode(renderengine,
61 for(int i = 0; i < MAXCHANNELS; i++)
63 pan_before[i] = pan_after[i] = 0;
67 VirtualANode::~VirtualANode()
75 VirtualNode* VirtualANode::create_module(Plugin *real_plugin,
79 return new VirtualANode(renderengine,
88 VirtualNode* VirtualANode::create_plugin(Plugin *real_plugin)
90 return new VirtualANode(renderengine,
100 int VirtualANode::read_data(Samples *output_temp,
102 int64_t start_position,
105 VirtualNode *previous_plugin = 0;
107 // Current edit in parent track
108 AEdit *parent_edit = 0;
109 if(parent_node && parent_node->track && renderengine)
111 int64_t edl_rate = renderengine->get_edl()->session->sample_rate;
112 int64_t start_position_project = (int64_t)(start_position *
116 parent_edit = (AEdit*)parent_node->track->edits->editof(start_position_project,
117 renderengine->command->get_direction(),
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);
129 // This is a plugin on parent module with a preceeding effect.
130 // Get data from preceeding effect on parent module.
132 (previous_plugin = parent_node->get_previous_plugin(this)))
134 ((VirtualANode*)previous_plugin)->render(output_temp,
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))
146 ((VirtualANode*)parent_node)->read_data(output_temp,
153 // This is the first node in the tree
155 ((AModule*)real_module)->render(output_temp,
158 renderengine->command->get_direction(),
165 int VirtualANode::render(Samples *output_temp,
167 int64_t start_position,
171 if(debug) printf("VirtualANode::render %d this=%p\n", __LINE__, this);
172 ARender *arender = ((VirtualAConsole*)vconsole)->arender;
175 if(debug) printf("VirtualANode::render %d this=%p\n", __LINE__, this);
176 render_as_module(arender->audio_out,
181 if(debug) printf("VirtualANode::render %d this=%p\n", __LINE__, this);
186 if(debug) printf("VirtualANode::render %d this=%p\n", __LINE__, this);
187 render_as_plugin(output_temp,
191 if(debug) printf("VirtualANode::render %d this=%p\n", __LINE__, this);
193 if(debug) printf("VirtualANode::render %d this=%p\n", __LINE__, this);
197 void VirtualANode::render_as_plugin(Samples *output_temp,
199 int64_t start_position,
204 !real_plugin->on) return;
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
209 ((AAttachmentPoint*)attachment)->render(
211 plugin_buffer_number,
217 int VirtualANode::render_as_module(Samples **audio_out,
218 Samples *output_temp,
220 int64_t start_position,
223 int direction = renderengine->command->get_direction();
224 EDL *edl = vconsole->renderengine->get_edl();
227 // Process last subnode. This calls read_data, propogates up the chain
228 // of subnodes, and finishes the chain.
231 VirtualANode *node = (VirtualANode*)subnodes.values[subnodes.total - 1];
232 node->render(output_temp,
238 // Read data from previous entity
240 read_data(output_temp,
246 // for(int k = 0; k < len; k++)
248 // output_temp->get_data()[k] = (k / 10) % 2;
251 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
252 render_fade(output_temp->get_data(),
256 track->automation->autos[AUTOMATION_FADE],
259 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
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 /
267 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
268 if(real_module && renderengine->command->realtime)
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 *
281 // Scan fragment in meter sized fragments
282 for(int i = 0; i < len; )
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;
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;
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);
307 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
309 // process pans and copy the output to the output channels
310 // Keep rendering unmuted fragments until finished.
311 int mute_position = 0;
313 for(int i = 0; i < len; )
316 int mute_fragment = len - i;
317 int mute_fragment_project = mute_fragment *
318 project_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 /
326 // How many samples until the next mute?
327 get_mute_fragment(start_position_project,
329 mute_fragment_project,
330 (Autos*)track->automation->autos[AUTOMATION_MUTE],
333 // Fragment is playable
342 double *buffer = audio_out[j]->get_data();
344 render_pan(output_temp->get_data() + mute_position,
345 buffer + mute_position,
349 (Autos*)track->automation->autos[AUTOMATION_PAN],
353 //printf("VirtualANode::render_as_module %d %lld\n", __LINE__, start_position);
358 len -= mute_fragment;
360 mute_position += mute_fragment;
362 if(debug) printf("VirtualANode::render_as_module %d\n", __LINE__);
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)
372 FloatAuto *previous = 0;
374 EDL *edl = vconsole->renderengine->get_edl();
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;
381 input_position += track->nudge * to_sample_rate;
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;
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))
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++)
401 else if( !EQUIV(value, 1.) ) {
402 for(int64_t i = 0; i < len; i++)
405 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
409 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
410 for(int64_t i = 0; i < len; i++)
412 input_pos = input_position * to_project_rate;
414 fade_value = ((FloatAutos*)autos)->get_value(
415 input_pos, direction, previous, next);
417 double value = fade_value<=INFINITYGAIN ?
418 0. : DB::fromdb(fade_value);
419 if( EQUIV(value,0.) )
421 else if( !EQUIV(value,1.) ) {
425 if(direction == PLAY_FORWARD)
430 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
432 if(debug) printf("VirtualANode::render_fade %d\n", __LINE__);
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
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;
454 input_position += track->nudge * to_sample_rate;
456 for(int i = 0; i < fragment_len; )
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;
462 // Get slope intercept formula for next fragment
463 get_pan_automation(slope, intercept, input_pos,
464 slope_len, autos, channel, direction);
466 slope_len *= to_sample_rate;
467 slope = slope * to_sample_rate;
468 slope_len = MIN(slope_len, len);
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;
477 else if( EQUIV(intercept, 1) ) {
478 for(int64_t j = 0; j < slope_len; j++, i++)
479 output[i] += input[i];
481 else if( !EQUIV(intercept, 0) ) {
482 for(int64_t j = 0; j < slope_len; j++, i++)
483 output[i] += input[i] * intercept;
488 if(direction == PLAY_FORWARD)
489 input_position += slope_len;
491 input_position -= slope_len;
493 //printf("VirtualANode::render_pan 4\n");
500 void VirtualANode::get_pan_automation(double &slope,
502 int64_t input_position,
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;
517 if(direction == PLAY_FORWARD)
519 // Two distinct automation points within range
520 if(next_pan_auto->position > prev_pan_auto->position)
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];
527 if(next_pan_auto->position < input_position + slope_len)
528 slope_len = next_pan_auto->position - input_position;
531 // One automation point within range
534 intercept = prev_pan_auto->values[channel];
539 // Two distinct automation points within range
540 if(next_pan_auto->position < prev_pan_auto->position)
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];
547 if(next_pan_auto->position > input_position - slope_len)
548 slope_len = input_position - next_pan_auto->position;
551 // One automation point within range
554 intercept = next_pan_auto->values[channel];