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;
290 if( !nested_renderengine ) {
291 nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
292 nested_renderengine->set_acache(get_cache());
293 nested_renderengine->arm_command(nested_command);
295 nested_renderengine->command->command = command;
298 if( edit_sample_rate <= 0 )
302 // speed_buffer is (have_speed ? speed_temp : buffer)
303 if( sample_rate != edit_sample_rate ) {
305 resample = new AModuleResample(this);
306 result = resample->resample(speed_buffer,
307 speed_fragment_len, edit_sample_rate,
308 sample_rate, start_source, direction);
311 result = read_samples(speed_buffer,
312 start_source, speed_fragment_len, direction);
315 if( asset && file ) {
317 get_cache()->check_in(asset);
319 // Stretch it to fit the speed curve
320 // Need overlapping buffers to get the interpolation to work, but this
321 // screws up sequential effects.
322 if( !result && have_speed ) {
323 FloatAuto *previous = 0, *next = 0;
324 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
325 int len1 = speed_fragment_len-1;
326 double speed_position = start_position;
327 double pos = start_project;
328 // speed gnuplot> plot "/tmp/x.dat" using($1) with lines
329 // speed_position gnuplot> plot "/tmp/x.dat" using($2) with lines
331 //if( !channel ) { fp = fopen("/tmp/x.dat", "a"); fprintf(fp," %f %f\n",0.,0.); }
332 for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
333 int64_t speed_pos = speed_position;
334 double speed = speed_autos->get_value(pos,
335 direction, previous, next);
336 //if(fp) fprintf(fp," %f %f\n", speed, speed_position);
337 double next_position = speed_position + dir*speed;
338 int64_t next_pos = next_position;
339 int total = abs(next_pos - speed_pos);
340 int k = speed_pos - min_source;
341 if( dir < 0 ) k = len1 - k; // if buffer reversed
342 double sample = speed_data[bclip(k, 0,len1)];
344 int d = next_pos >= speed_pos ? 1 : -1;
345 for( int j=total; --j>0; ) {
347 sample += speed_data[bclip(k, 0,len1)];
352 else if( total < 1 ) {
353 int d = next_pos >= speed_pos ? 1 : -1;
355 double next_sample = speed_data[bclip(k, 0,len1)];
356 double v = speed_position - speed_pos;
357 sample = (1.-v) * sample + v * next_sample;
360 buffer_data[i] = sample;
361 speed_position = next_position;
367 bzero(buffer_data, fragment_len*sizeof(*buffer_data));
372 int AModule::render(Samples *buffer,
374 int64_t start_position,
379 int64_t edl_rate = get_edl()->session->sample_rate;
382 if(debug) printf("AModule::render %d\n", __LINE__);
385 start_position += track->nudge *
388 AEdit *playable_edit;
389 int64_t end_position;
390 if(direction == PLAY_FORWARD)
391 end_position = start_position + input_len;
393 end_position = start_position - input_len;
394 int buffer_offset = 0;
398 // // Flip range around so the source is always read forward.
399 // if(direction == PLAY_REVERSE)
401 // start_project -= input_len;
402 // end_position -= input_len;
407 bzero(buffer->get_data(), input_len * sizeof(double));
409 // The EDL is normalized to the requested sample rate because
410 // the requested rate may be the project sample rate and a sample rate
411 // might as well be directly from the source rate to the requested rate.
412 // Get first edit containing the range
413 if(direction == PLAY_FORWARD)
414 playable_edit = (AEdit*)track->edits->first;
416 playable_edit = (AEdit*)track->edits->last;
417 if(debug) printf("AModule::render %d\n", __LINE__);
421 int64_t edit_start = playable_edit->startproject;
422 int64_t edit_end = playable_edit->startproject + playable_edit->length;
424 // Normalize to requested rate
425 edit_start = edit_start * sample_rate / edl_rate;
426 edit_end = edit_end * sample_rate / edl_rate;
428 if(direction == PLAY_FORWARD)
430 if(start_position < edit_end && end_position > edit_start)
434 playable_edit = (AEdit*)playable_edit->next;
438 if(end_position < edit_end && start_position > edit_start)
442 playable_edit = (AEdit*)playable_edit->previous;
447 if(debug) printf("AModule::render %d\n", __LINE__);
453 // Fill output one fragment at a time
454 while(start_position != end_position)
456 int64_t fragment_len = input_len;
458 if(debug) printf("AModule::render %d %jd %jd\n", __LINE__, start_position, end_position);
459 // Clamp fragment to end of input
460 if(direction == PLAY_FORWARD &&
461 start_position + fragment_len > end_position)
462 fragment_len = end_position - start_position;
464 if(direction == PLAY_REVERSE &&
465 start_position - fragment_len < end_position)
466 fragment_len = start_position - end_position;
467 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
469 // Normalize position here since update_transition is a boolean operation.
470 update_transition(start_position *
477 AEdit *previous_edit = (AEdit*)playable_edit->previous;
479 // Normalize EDL positions to requested rate
480 int64_t edit_startproject = playable_edit->startproject;
481 int64_t edit_endproject = playable_edit->startproject + playable_edit->length;
482 int64_t edit_startsource = playable_edit->startsource;
483 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
485 edit_startproject = edit_startproject * sample_rate / edl_rate;
486 edit_endproject = edit_endproject * sample_rate / edl_rate;
487 edit_startsource = edit_startsource * sample_rate / edl_rate;
488 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
492 // Clamp fragment to end of edit
493 if(direction == PLAY_FORWARD &&
494 start_position + fragment_len > edit_endproject)
495 fragment_len = edit_endproject - start_position;
497 if(direction == PLAY_REVERSE &&
498 start_position - fragment_len < edit_startproject)
499 fragment_len = start_position - edit_startproject;
500 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
502 // Clamp to end of transition
503 int64_t transition_len = 0;
504 Plugin *transition = get_edl()->tracks->plugin_exists(transition_id);
505 if( transition && previous_edit ) {
506 transition_len = transition->length * sample_rate / edl_rate;
507 if(direction == PLAY_FORWARD &&
508 start_position < edit_startproject + transition_len &&
509 start_position + fragment_len > edit_startproject + transition_len)
510 fragment_len = edit_startproject + transition_len - start_position;
512 if(direction == PLAY_REVERSE &&
513 start_position > edit_startproject + transition_len &&
514 start_position - fragment_len < edit_startproject + transition_len)
515 fragment_len = start_position - edit_startproject - transition_len;
517 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
522 Samples output(buffer);
523 output.set_offset(output.get_offset() + buffer_offset);
524 if(import_samples(playable_edit,
531 fragment_len)) result = 1;
533 if(debug) printf("AModule::render %d\n", __LINE__);
536 // Read transition into temp and render
537 if(transition && previous_edit)
539 int64_t previous_startproject = previous_edit->startproject *
542 int64_t previous_startsource = previous_edit->startsource *
546 // Allocate transition temp size
547 int transition_fragment_len = fragment_len;
548 if(direction == PLAY_FORWARD &&
549 fragment_len + start_position > edit_startproject + transition_len)
550 fragment_len = edit_startproject + transition_len - start_position;
553 // Read into temp buffers
554 // Temp + master or temp + temp ? temp + master
555 if(transition_temp &&
556 transition_temp->get_allocated() < fragment_len)
558 delete transition_temp;
564 transition_temp = new Samples(fragment_len);
567 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
569 if(transition_fragment_len > 0)
571 // Previous_edit is always the outgoing segment, regardless of direction
572 import_samples(previous_edit,
574 previous_startproject,
575 previous_startsource,
579 transition_fragment_len);
580 int64_t current_position;
582 // Reverse buffers here so transitions always render forward.
583 if(direction == PLAY_REVERSE)
585 Resample::reverse_buffer(output.get_data(), transition_fragment_len);
586 Resample::reverse_buffer(transition_temp->get_data(), transition_fragment_len);
587 current_position = start_position -
588 transition_fragment_len -
593 current_position = start_position - edit_startproject;
596 transition_server->process_transition(
600 transition_fragment_len,
603 // Reverse output buffer here so transitions always render forward.
604 if(direction == PLAY_REVERSE)
605 Resample::reverse_buffer(output.get_data(),
606 transition_fragment_len);
609 if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
610 __LINE__, start_position, end_position, fragment_len);
612 if(direction == PLAY_REVERSE)
614 if(playable_edit && start_position - fragment_len <= edit_startproject)
615 playable_edit = (AEdit*)playable_edit->previous;
619 if(playable_edit && start_position + fragment_len >= edit_endproject)
620 playable_edit = (AEdit*)playable_edit->next;
626 buffer_offset += fragment_len;
627 if(direction == PLAY_FORWARD)
628 start_position += fragment_len;
630 start_position -= fragment_len;
634 if(debug) printf("AModule::render %d\n", __LINE__);