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"
62 AModuleResample::AModuleResample(AModule *module)
65 this->module = module;
66 bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
67 nested_allocation = 0;
70 AModuleResample::~AModuleResample()
72 for(int i = 0; i < MAX_CHANNELS; i++)
73 delete nested_output[i];
76 int AModuleResample::read_samples(Samples *buffer,
77 int64_t start, int64_t len, int direction)
79 return module->read_samples(buffer, start, len, direction);
82 AModule::AModule(RenderEngine *renderengine,
83 CommonRender *commonrender,
84 PluginArray *plugin_array,
86 : Module(renderengine, commonrender, plugin_array, track)
88 data_type = TRACK_AUDIO;
92 bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
93 meter_history = new MeterHistory();
94 nested_allocation = 0;
105 delete transition_temp;
107 delete meter_history;
108 for(int i = 0; i < MAX_CHANNELS; i++)
109 delete nested_output[i];
113 int AModule::read_samples(Samples *buffer, int64_t start, int64_t len, int direction)
115 if( len < 0 ) return 1;
116 double *buffer_data = buffer->get_data();
117 // if start < 0, zero fill prefix. if error, zero fill buffer
121 // Files only read going forward.
122 if( direction == PLAY_REVERSE ) start -= len;
123 int64_t sz = start >= 0 ? len : len + start;
124 if( start < 0 ) start = 0;
126 file->set_audio_position(start);
127 file->set_channel(channel);
128 result = file->read_samples(buffer, sz);
129 if( !result && (zeros-=sz) > 0 ) {
130 double *top_data = buffer_data + zeros;
131 memmove(top_data, buffer_data, sz*sizeof(*buffer_data));
134 if( !result && direction == PLAY_REVERSE )
135 Resample::reverse_buffer(buffer_data, len);
137 else if( nested_edl ) {
138 if( nested_allocation < len ) {
139 nested_allocation = len;
140 for( int i=0; i<nested_edl->session->audio_channels; ++i ) {
141 delete nested_output[i];
142 nested_output[i] = new Samples(nested_allocation);
145 result = nested_renderengine->arender->
146 process_buffer(nested_output, len, start);
148 double *sample_data = nested_output[channel]->get_data();
149 int buffer_size = len * sizeof(*buffer_data);
150 memcpy(buffer_data, sample_data, buffer_size);
155 memset(buffer_data, 0, zeros*sizeof(*buffer_data));
159 AttachmentPoint* AModule::new_attachment(Plugin *plugin)
161 return new AAttachmentPoint(renderengine, plugin);
165 void AModule::create_objects()
167 Module::create_objects();
168 // Not needed in pluginarray
170 meter_history->init(1, ((ARender*)commonrender)->total_peaks);
171 meter_history->reset_channel(0);
175 int AModule::get_buffer_size()
178 return renderengine->fragment_len;
180 return plugin_array->get_bufsize();
184 CICache* AModule::get_cache()
187 return renderengine->get_acache();
193 int AModule::import_samples(AEdit *edit,
194 int64_t start_project, int64_t edit_startproject, int64_t edit_startsource,
195 int direction, int sample_rate, Samples *buffer, int64_t fragment_len)
198 if( fragment_len <= 0 )
200 if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
202 double *buffer_data = buffer->get_data();
203 // buffer fragment adjusted for speed curve
204 Samples *speed_buffer = buffer;
205 double *speed_data = speed_buffer->get_data();
206 int64_t speed_fragment_len = fragment_len;
207 int dir = direction == PLAY_FORWARD ? 1 : -1;
208 // normal speed source boundaries in EDL samplerate
209 int64_t start_source = start_project - edit_startproject + edit_startsource;
210 double end_source = start_source + dir*speed_fragment_len;
211 double start_position = start_source;
212 // double end_position = end_source;
213 // normal speed playback boundaries
214 double min_source = bmin(start_source, end_source);
215 double max_source = bmax(start_source, end_source);
217 this->channel = edit->channel;
218 int have_speed = track->has_speed();
220 // apply speed curve to source position so the timeline agrees with the playback
221 if( !result && have_speed ) {
222 // get speed adjusted start position from start of edit.
223 FloatAuto *previous = 0, *next = 0;
224 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
225 double source_position = edit_startsource +
226 speed_autos->automation_integral(edit_startproject,
227 start_project-edit_startproject, PLAY_FORWARD);
228 min_source = source_position;
229 max_source = source_position;
230 // calculate boundaries of input fragment required for speed curve
231 int64_t pos = start_project;
232 start_position = source_position;
233 for( int64_t i=fragment_len; --i>=0; pos+=dir ) {
234 double speed = speed_autos->get_value(pos, direction, previous, next);
235 source_position += dir*speed;
236 if( source_position > max_source ) max_source = source_position;
237 if( source_position < min_source ) min_source = source_position;
239 // end_position = source_position;
240 speed_fragment_len = (int64_t)(max_source - min_source);
241 start_source = direction == PLAY_FORWARD ? min_source : max_source;
242 if( speed_fragment_len > 0 ) {
243 // swap in the temp buffer
244 if( speed_temp && speed_temp->get_allocated() < speed_fragment_len ) {
245 delete speed_temp; speed_temp = 0;
248 speed_temp = new Samples(speed_fragment_len);
249 speed_buffer = speed_temp;
250 speed_data = speed_buffer->get_data();
254 int edit_sample_rate = 0;
255 if( speed_fragment_len <= 0 )
258 if( !result && edit->asset ) {
260 if( nested_renderengine ) {
261 delete nested_renderengine; nested_renderengine = 0;
263 // Source is an asset
265 edit_sample_rate = asset->sample_rate;
267 file = get_cache()->check_out(asset, get_edl());
269 printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
273 else if( !result && edit->nested_edl ) {
275 // Source is a nested EDL
276 if( !nested_edl || nested_edl->id != edit->nested_edl->id ) {
277 nested_edl = edit->nested_edl;
278 delete nested_renderengine;
279 nested_renderengine = 0;
281 edit_sample_rate = nested_edl->session->sample_rate;
282 int command = direction == PLAY_REVERSE ?
283 NORMAL_REWIND : NORMAL_FWD;
284 if( !nested_command ) {
285 nested_command = new TransportCommand;
286 nested_command->command = command;
287 nested_command->get_edl()->copy_all(nested_edl);
288 nested_command->change_type = CHANGE_ALL;
289 nested_command->realtime = renderengine->command->realtime;
291 if( !nested_renderengine ) {
292 nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
293 nested_renderengine->set_acache(get_cache());
294 nested_renderengine->arm_command(nested_command);
296 nested_renderengine->command->command = command;
299 if( edit_sample_rate <= 0 )
303 // speed_buffer is (have_speed ? speed_temp : buffer)
304 if( sample_rate != edit_sample_rate ) {
306 resample = new AModuleResample(this);
307 result = resample->resample(speed_buffer,
308 speed_fragment_len, edit_sample_rate,
309 sample_rate, start_source, direction);
312 result = read_samples(speed_buffer,
313 start_source, speed_fragment_len, direction);
316 if( asset && file ) {
318 get_cache()->check_in(asset);
320 // Stretch it to fit the speed curve
321 // Need overlapping buffers to get the interpolation to work, but this
322 // screws up sequential effects.
323 if( !result && have_speed ) {
324 FloatAuto *previous = 0, *next = 0;
325 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
326 int len1 = speed_fragment_len-1;
327 double speed_position = start_position;
328 double pos = start_project;
329 // speed gnuplot> plot "/tmp/x.dat" using($1) with lines
330 // speed_position gnuplot> plot "/tmp/x.dat" using($2) with lines
332 //if( !channel ) { fp = fopen("/tmp/x.dat", "a"); fprintf(fp," %f %f\n",0.,0.); }
333 for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
334 int64_t speed_pos = speed_position;
335 double speed = speed_autos->get_value(pos,
336 direction, previous, next);
337 //if(fp) fprintf(fp," %f %f\n", speed, speed_position);
338 double next_position = speed_position + dir*speed;
339 int64_t next_pos = next_position;
340 int total = abs(next_pos - speed_pos);
341 int k = speed_pos - min_source;
342 if( dir < 0 ) k = len1 - k; // if buffer reversed
343 double sample = speed_data[bclip(k, 0,len1)];
345 int d = next_pos >= speed_pos ? 1 : -1;
346 for( int j=total; --j>0; ) {
348 sample += speed_data[bclip(k, 0,len1)];
353 else if( total < 1 ) {
354 int d = next_pos >= speed_pos ? 1 : -1;
356 double next_sample = speed_data[bclip(k, 0,len1)];
357 double v = speed_position - speed_pos;
358 sample = (1.-v) * sample + v * next_sample;
361 buffer_data[i] = sample;
362 speed_position = next_position;
368 bzero(buffer_data, fragment_len*sizeof(*buffer_data));
373 int AModule::render(Samples *buffer,
375 int64_t start_position,
380 int64_t edl_rate = get_edl()->session->sample_rate;
383 if(debug) printf("AModule::render %d\n", __LINE__);
386 start_position += track->nudge *
389 AEdit *playable_edit;
390 int64_t end_position;
391 if(direction == PLAY_FORWARD)
392 end_position = start_position + input_len;
394 end_position = start_position - input_len;
395 int buffer_offset = 0;
399 // // Flip range around so the source is always read forward.
400 // if(direction == PLAY_REVERSE)
402 // start_project -= input_len;
403 // end_position -= input_len;
408 bzero(buffer->get_data(), input_len * sizeof(double));
410 // The EDL is normalized to the requested sample rate because
411 // the requested rate may be the project sample rate and a sample rate
412 // might as well be directly from the source rate to the requested rate.
413 // Get first edit containing the range
414 if(direction == PLAY_FORWARD)
415 playable_edit = (AEdit*)track->edits->first;
417 playable_edit = (AEdit*)track->edits->last;
418 if(debug) printf("AModule::render %d\n", __LINE__);
422 int64_t edit_start = playable_edit->startproject;
423 int64_t edit_end = playable_edit->startproject + playable_edit->length;
425 // Normalize to requested rate
426 edit_start = edit_start * sample_rate / edl_rate;
427 edit_end = edit_end * sample_rate / edl_rate;
429 if(direction == PLAY_FORWARD)
431 if(start_position < edit_end && end_position > edit_start)
435 playable_edit = (AEdit*)playable_edit->next;
439 if(end_position < edit_end && start_position > edit_start)
443 playable_edit = (AEdit*)playable_edit->previous;
448 if(debug) printf("AModule::render %d\n", __LINE__);
454 // Fill output one fragment at a time
455 while(start_position != end_position)
457 int64_t fragment_len = input_len;
459 if(debug) printf("AModule::render %d %jd %jd\n", __LINE__, start_position, end_position);
460 // Clamp fragment to end of input
461 if(direction == PLAY_FORWARD &&
462 start_position + fragment_len > end_position)
463 fragment_len = end_position - start_position;
465 if(direction == PLAY_REVERSE &&
466 start_position - fragment_len < end_position)
467 fragment_len = start_position - end_position;
468 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
470 // Normalize position here since update_transition is a boolean operation.
471 update_transition(start_position *
478 AEdit *previous_edit = (AEdit*)playable_edit->previous;
480 // Normalize EDL positions to requested rate
481 int64_t edit_startproject = playable_edit->startproject;
482 int64_t edit_endproject = playable_edit->startproject + playable_edit->length;
483 int64_t edit_startsource = playable_edit->startsource;
484 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
486 edit_startproject = edit_startproject * sample_rate / edl_rate;
487 edit_endproject = edit_endproject * sample_rate / edl_rate;
488 edit_startsource = edit_startsource * sample_rate / edl_rate;
489 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
493 // Clamp fragment to end of edit
494 if(direction == PLAY_FORWARD &&
495 start_position + fragment_len > edit_endproject)
496 fragment_len = edit_endproject - start_position;
498 if(direction == PLAY_REVERSE &&
499 start_position - fragment_len < edit_startproject)
500 fragment_len = start_position - edit_startproject;
501 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
503 // Clamp to end of transition
504 int64_t transition_len = 0;
505 Plugin *transition = get_edl()->tracks->plugin_exists(transition_id);
506 if( transition && previous_edit ) {
507 transition_len = transition->length * sample_rate / edl_rate;
508 if(direction == PLAY_FORWARD &&
509 start_position < edit_startproject + transition_len &&
510 start_position + fragment_len > edit_startproject + transition_len)
511 fragment_len = edit_startproject + transition_len - start_position;
513 if(direction == PLAY_REVERSE &&
514 start_position > edit_startproject + transition_len &&
515 start_position - fragment_len < edit_startproject + transition_len)
516 fragment_len = start_position - edit_startproject - transition_len;
518 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
523 Samples output(buffer);
524 output.set_offset(output.get_offset() + buffer_offset);
525 if(import_samples(playable_edit,
532 fragment_len)) result = 1;
534 if(debug) printf("AModule::render %d\n", __LINE__);
537 // Read transition into temp and render
538 if(transition && previous_edit)
540 int64_t previous_startproject = previous_edit->startproject *
543 int64_t previous_startsource = previous_edit->startsource *
547 // Allocate transition temp size
548 int transition_fragment_len = fragment_len;
549 if(direction == PLAY_FORWARD &&
550 fragment_len + start_position > edit_startproject + transition_len)
551 fragment_len = edit_startproject + transition_len - start_position;
554 // Read into temp buffers
555 // Temp + master or temp + temp ? temp + master
556 if(transition_temp &&
557 transition_temp->get_allocated() < fragment_len)
559 delete transition_temp;
565 transition_temp = new Samples(fragment_len);
568 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
570 if(transition_fragment_len > 0)
572 // Previous_edit is always the outgoing segment, regardless of direction
573 import_samples(previous_edit,
575 previous_startproject,
576 previous_startsource,
580 transition_fragment_len);
581 int64_t current_position;
583 // Reverse buffers here so transitions always render forward.
584 if(direction == PLAY_REVERSE)
586 Resample::reverse_buffer(output.get_data(), transition_fragment_len);
587 Resample::reverse_buffer(transition_temp->get_data(), transition_fragment_len);
588 current_position = start_position -
589 transition_fragment_len -
594 current_position = start_position - edit_startproject;
597 transition_server->process_transition(
601 transition_fragment_len,
604 // Reverse output buffer here so transitions always render forward.
605 if(direction == PLAY_REVERSE)
606 Resample::reverse_buffer(output.get_data(),
607 transition_fragment_len);
610 if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
611 __LINE__, start_position, end_position, fragment_len);
613 if(direction == PLAY_REVERSE)
615 if(playable_edit && start_position - fragment_len <= edit_startproject)
616 playable_edit = (AEdit*)playable_edit->previous;
620 if(playable_edit && start_position + fragment_len >= edit_endproject)
621 playable_edit = (AEdit*)playable_edit->next;
627 buffer_offset += fragment_len;
628 if(direction == PLAY_FORWARD)
629 start_position += fragment_len;
631 start_position -= fragment_len;
635 if(debug) printf("AModule::render %d\n", __LINE__);