4 * Copyright (C) 2009-2013 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"
29 #include "automation.h"
30 #include "bcsignals.h"
35 #include "edlsession.h"
38 #include "floatautos.h"
43 #include "pluginarray.h"
44 #include "preferences.h"
45 #include "renderengine.h"
46 #include "mainsession.h"
48 #include "sharedlocation.h"
50 #include "transition.h"
51 #include "transportque.h"
61 AModuleResample::AModuleResample(AModule *module)
64 this->module = module;
65 bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
66 nested_allocation = 0;
69 AModuleResample::~AModuleResample()
71 for(int i = 0; i < MAX_CHANNELS; i++)
72 delete nested_output[i];
75 int AModuleResample::read_samples(Samples *buffer, int64_t start, int64_t len)
82 // Files only read going forward.
83 if(get_direction() == PLAY_REVERSE)
88 //printf("AModuleResample::read_samples start=%jd len=%jd\n", start, len);
89 module->file->set_audio_position(start);
90 module->file->set_channel(module->channel);
91 result = module->file->read_samples(buffer, len);
93 // Reverse buffer so resampling filter renders forward.
94 if(get_direction() == PLAY_REVERSE)
95 Resample::reverse_buffer(buffer->get_data(), len);
98 if(module->nested_edl)
102 // Nested EDL generates reversed buffer.
103 for(int i = 0; i < module->nested_edl->session->audio_channels; i++)
105 if(nested_allocation < len)
107 delete nested_output[i];
108 nested_output[i] = 0;
111 if(!nested_output[i])
113 nested_output[i] = new Samples(len);
118 result = module->nested_renderengine->arender->process_buffer(
122 // printf("AModuleResample::read_samples buffer=%p module=%p len=%d\n",
126 memcpy(buffer->get_data(),
127 nested_output[module->channel]->get_data(),
128 len * sizeof(double));
144 AModule::AModule(RenderEngine *renderengine,
145 CommonRender *commonrender,
146 PluginArray *plugin_array,
148 : Module(renderengine, commonrender, plugin_array, track)
150 data_type = TRACK_AUDIO;
153 bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
154 meter_history = new MeterHistory();
155 nested_allocation = 0;
166 delete transition_temp;
168 delete meter_history;
169 for(int i = 0; i < MAX_CHANNELS; i++)
170 delete nested_output[i];
174 AttachmentPoint* AModule::new_attachment(Plugin *plugin)
176 return new AAttachmentPoint(renderengine, plugin);
180 void AModule::create_objects()
182 Module::create_objects();
183 // Not needed in pluginarray
185 meter_history->init(1, ((ARender*)commonrender)->total_peaks);
186 meter_history->reset_channel(0);
190 int AModule::get_buffer_size()
193 return renderengine->fragment_len;
195 return plugin_array->get_bufsize();
199 CICache* AModule::get_cache()
202 return renderengine->get_acache();
208 int AModule::import_samples(AEdit *edit,
209 int64_t start_project,
210 int64_t edit_startproject,
211 int64_t edit_startsource,
215 int64_t fragment_len)
219 // start in EDL samplerate
220 int64_t start_source = start_project - edit_startproject + edit_startsource;
221 // fragment size adjusted for speed curve
222 int64_t speed_fragment_len = fragment_len;
223 // boundaries of input fragment required for speed curve
224 double max_position = 0;
225 double min_position = 0;
227 double speed_position = edit_startsource;
228 // position in source where speed curve starts reading
229 double speed_position1 = speed_position;
230 // position in source where speed curve finishes
231 double speed_position2 = speed_position;
232 // Need speed curve processing
234 // Temporary buffer for rendering speed curve
235 Samples *speed_buffer = buffer;
237 if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
239 this->channel = edit->channel;
240 int dir = direction == PLAY_FORWARD ? 1 : -1;
242 // apply speed curve to source position so the timeline agrees with the playback
243 if( track->has_speed() ) {
244 // get speed adjusted position from start of edit.
245 FloatAuto *previous = 0, *next = 0;
246 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
247 speed_position += speed_autos->automation_integral(edit_startproject,
248 start_project-edit_startproject, PLAY_FORWARD);
249 speed_position1 = speed_position;
251 // calculate boundaries of input fragment required for speed curve
252 max_position = speed_position;
253 min_position = speed_position;
254 int64_t pos = start_project;
255 for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
256 double speed = speed_autos->get_value(pos, direction, previous, next);
257 speed_position += dir*speed;
258 if(speed_position > max_position) max_position = speed_position;
259 if(speed_position < min_position) min_position = speed_position;
262 speed_position2 = speed_position;
263 if(speed_position2 < speed_position1)
266 // min_position -= 1.0;
267 speed_fragment_len = (int64_t)(max_position - min_position);
272 speed_fragment_len = (int64_t)(max_position - min_position);
275 //printf("AModule::import_samples %d %f %f %f %f\n",
276 // __LINE__, min_position, max_position, speed_position1, speed_position2);
278 // new start of source to read from file
279 start_source = (int64_t)min_position;
282 // swap in the temp buffer
283 if(speed_temp && speed_temp->get_allocated() < speed_fragment_len) {
284 delete speed_temp; speed_temp = 0;
287 speed_temp = new Samples(speed_fragment_len);
288 speed_buffer = speed_temp;
291 if( speed_fragment_len == 0 )
294 // Source is a nested EDL
295 if( edit->nested_edl ) {
296 int command = direction == PLAY_REVERSE ?
297 NORMAL_REWIND : NORMAL_FWD;
300 if( !nested_edl || nested_edl->id != edit->nested_edl->id ) {
301 nested_edl = edit->nested_edl;
302 if( nested_renderengine ) {
303 delete nested_renderengine; nested_renderengine = 0;
305 if( !nested_command )
306 nested_command = new TransportCommand;
307 if( !nested_renderengine ) {
308 nested_command->command = command;
309 nested_command->get_edl()->copy_all(nested_edl);
310 nested_command->change_type = CHANGE_ALL;
311 nested_command->realtime = renderengine->command->realtime;
312 nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
313 nested_renderengine->set_acache(get_cache());
314 // Must use a private cache for the audio
317 // cache = new CICache(get_preferences());
318 // private_cache = 1;
320 // nested_renderengine->set_acache(cache);
321 nested_renderengine->arm_command(nested_command);
324 if(debug) printf("AModule::import_samples %d speed_fragment_len=%d\n", __LINE__, (int)speed_fragment_len);
326 // Allocate output buffers for all channels
327 for( int i=0; i<nested_edl->session->audio_channels; ++i ) {
328 if( nested_allocation < speed_fragment_len ) {
329 delete nested_output[i]; nested_output[i] = 0;
331 if(!nested_output[i])
332 nested_output[i] = new Samples(speed_fragment_len);
335 if( nested_allocation < speed_fragment_len )
336 nested_allocation = speed_fragment_len;
338 // Update direction command
339 nested_renderengine->command->command = command;
341 // Render the segment
342 if( !nested_renderengine->arender )
343 bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
344 else if(sample_rate != nested_edl->session->sample_rate) {
346 resample = new AModuleResample(this);
347 result = resample->resample(speed_buffer,
348 speed_fragment_len, nested_edl->session->sample_rate,
349 sample_rate, start_source, direction);
350 // Resample reverses to keep it running forward.
353 // Render without resampling
354 result = nested_renderengine->arender->process_buffer(
355 nested_output, speed_fragment_len, start_source);
356 memcpy(speed_buffer->get_data(),
357 nested_output[edit->channel]->get_data(),
358 speed_fragment_len * sizeof(double));
360 // Reverse fragment so ::render can apply transitions going forward.
361 if( direction == PLAY_REVERSE ) {
362 Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
366 else if( edit->asset ) {
367 // Source is an asset
372 if( nested_renderengine ) {
373 delete nested_renderengine; nested_renderengine = 0;
376 if( !(file = get_cache()->check_out( asset, get_edl())) ) {
377 // couldn't open source file / skip the edit
378 printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
384 if( sample_rate != asset->sample_rate ) {
385 // Read through sample rate converter.
387 resample = new AModuleResample(this);
388 result = resample->resample(speed_buffer,
389 speed_fragment_len, asset->sample_rate,
390 sample_rate, start_source, direction);
391 // Resample reverses to keep it running forward.
394 file->set_audio_position(start_source);
395 file->set_channel(edit->channel);
396 result = file->read_samples(speed_buffer, speed_fragment_len);
397 // Reverse fragment so ::render can apply transitions going forward.
398 if(direction == PLAY_REVERSE)
399 Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
402 get_cache()->check_in(asset);
409 if( speed_fragment_len > 0 )
410 bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
413 // Stretch it to fit the speed curve
414 // Need overlapping buffers to get the interpolation to work, but this
415 // screws up sequential effects.
417 double *buffer_samples = buffer->get_data();
418 if( speed_fragment_len > 0 ) {
419 FloatAuto *previous = 0;
421 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
422 double *speed_samples = speed_buffer->get_data();
423 int len1 = speed_fragment_len-1;
424 int out_offset = dir>0 ? 0 : fragment_len-1;
425 speed_position = speed_position1;
426 int64_t speed_pos = speed_position;
428 int64_t pos = start_project;
429 for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
430 double speed = speed_autos->get_value(pos,
431 direction, previous, next);
432 double next_position = speed_position + dir*speed;
433 int64_t next_pos = next_position;
434 int d = next_pos >= speed_pos ? 1 : -1;
435 int k = speed_pos - start_source;
436 double sample = speed_samples[bclip(k, 0,len1)];
437 int total = abs(next_pos - speed_pos);
439 for( int j=total; --j>0; ) {
441 sample += speed_samples[bclip(k, 0,len1)];
446 else if( total < 1 ) {
448 double next_sample = speed_samples[bclip(k, 0,len1)];
449 double v = speed_position - speed_pos;
450 sample = (1.-v) * sample + v * next_sample;
453 buffer_samples[out_offset] = sample;
455 speed_position = next_position;
456 speed_pos = next_pos;
465 int AModule::render(Samples *buffer,
467 int64_t start_position,
472 int64_t edl_rate = get_edl()->session->sample_rate;
475 if(debug) printf("AModule::render %d\n", __LINE__);
478 start_position += track->nudge *
481 AEdit *playable_edit;
482 int64_t end_position;
483 if(direction == PLAY_FORWARD)
484 end_position = start_position + input_len;
486 end_position = start_position - input_len;
487 int buffer_offset = 0;
491 // // Flip range around so the source is always read forward.
492 // if(direction == PLAY_REVERSE)
494 // start_project -= input_len;
495 // end_position -= input_len;
500 bzero(buffer->get_data(), input_len * sizeof(double));
502 // The EDL is normalized to the requested sample rate because
503 // the requested rate may be the project sample rate and a sample rate
504 // might as well be directly from the source rate to the requested rate.
505 // Get first edit containing the range
506 if(direction == PLAY_FORWARD)
507 playable_edit = (AEdit*)track->edits->first;
509 playable_edit = (AEdit*)track->edits->last;
510 if(debug) printf("AModule::render %d\n", __LINE__);
514 int64_t edit_start = playable_edit->startproject;
515 int64_t edit_end = playable_edit->startproject + playable_edit->length;
517 // Normalize to requested rate
518 edit_start = edit_start * sample_rate / edl_rate;
519 edit_end = edit_end * sample_rate / edl_rate;
521 if(direction == PLAY_FORWARD)
523 if(start_position < edit_end && end_position > edit_start)
527 playable_edit = (AEdit*)playable_edit->next;
531 if(end_position < edit_end && start_position > edit_start)
535 playable_edit = (AEdit*)playable_edit->previous;
540 if(debug) printf("AModule::render %d\n", __LINE__);
546 // Fill output one fragment at a time
547 while(start_position != end_position)
549 int64_t fragment_len = input_len;
551 if(debug) printf("AModule::render %d %jd %jd\n", __LINE__, start_position, end_position);
552 // Clamp fragment to end of input
553 if(direction == PLAY_FORWARD &&
554 start_position + fragment_len > end_position)
555 fragment_len = end_position - start_position;
557 if(direction == PLAY_REVERSE &&
558 start_position - fragment_len < end_position)
559 fragment_len = start_position - end_position;
560 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
562 // Normalize position here since update_transition is a boolean operation.
563 update_transition(start_position *
570 AEdit *previous_edit = (AEdit*)playable_edit->previous;
572 // Normalize EDL positions to requested rate
573 int64_t edit_startproject = playable_edit->startproject;
574 int64_t edit_endproject = playable_edit->startproject + playable_edit->length;
575 int64_t edit_startsource = playable_edit->startsource;
576 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
578 edit_startproject = edit_startproject * sample_rate / edl_rate;
579 edit_endproject = edit_endproject * sample_rate / edl_rate;
580 edit_startsource = edit_startsource * sample_rate / edl_rate;
581 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
585 // Clamp fragment to end of edit
586 if(direction == PLAY_FORWARD &&
587 start_position + fragment_len > edit_endproject)
588 fragment_len = edit_endproject - start_position;
590 if(direction == PLAY_REVERSE &&
591 start_position - fragment_len < edit_startproject)
592 fragment_len = start_position - edit_startproject;
593 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
595 // Clamp to end of transition
596 int64_t transition_len = 0;
601 transition_len = transition->length *
604 if(direction == PLAY_FORWARD &&
605 start_position < edit_startproject + transition_len &&
606 start_position + fragment_len > edit_startproject + transition_len)
607 fragment_len = edit_startproject + transition_len - start_position;
609 if(direction == PLAY_REVERSE &&
610 start_position > edit_startproject + transition_len &&
611 start_position - fragment_len < edit_startproject + transition_len)
612 fragment_len = start_position - edit_startproject - transition_len;
614 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
619 Samples output(buffer);
620 output.set_offset(output.get_offset() + buffer_offset);
621 if(import_samples(playable_edit,
628 fragment_len)) result = 1;
630 if(debug) printf("AModule::render %d\n", __LINE__);
633 // Read transition into temp and render
634 if(transition && previous_edit)
636 int64_t previous_startproject = previous_edit->startproject *
639 int64_t previous_startsource = previous_edit->startsource *
643 // Allocate transition temp size
644 int transition_fragment_len = fragment_len;
645 if(direction == PLAY_FORWARD &&
646 fragment_len + start_position > edit_startproject + transition_len)
647 fragment_len = edit_startproject + transition_len - start_position;
650 // Read into temp buffers
651 // Temp + master or temp + temp ? temp + master
652 if(transition_temp &&
653 transition_temp->get_allocated() < fragment_len)
655 delete transition_temp;
661 transition_temp = new Samples(fragment_len);
664 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
666 if(transition_fragment_len > 0)
668 // Previous_edit is always the outgoing segment, regardless of direction
669 import_samples(previous_edit,
671 previous_startproject,
672 previous_startsource,
676 transition_fragment_len);
677 int64_t current_position;
679 // Reverse buffers here so transitions always render forward.
680 if(direction == PLAY_REVERSE)
682 Resample::reverse_buffer(output.get_data(), transition_fragment_len);
683 Resample::reverse_buffer(transition_temp->get_data(), transition_fragment_len);
684 current_position = start_position -
685 transition_fragment_len -
690 current_position = start_position - edit_startproject;
693 transition_server->process_transition(
697 transition_fragment_len,
700 // Reverse output buffer here so transitions always render forward.
701 if(direction == PLAY_REVERSE)
702 Resample::reverse_buffer(output.get_data(),
703 transition_fragment_len);
706 if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
712 if(direction == PLAY_REVERSE)
714 if(playable_edit && start_position - fragment_len <= edit_startproject)
715 playable_edit = (AEdit*)playable_edit->previous;
719 if(playable_edit && start_position + fragment_len >= edit_endproject)
720 playable_edit = (AEdit*)playable_edit->next;
726 buffer_offset += fragment_len;
727 if(direction == PLAY_FORWARD)
728 start_position += fragment_len;
730 start_position -= fragment_len;
734 if(debug) printf("AModule::render %d\n", __LINE__);