rework playback speed and speed auto sampling, change conver to transcode, change...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / amodule.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009-2013 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "aattachmentpoint.h"
23 #include "aedit.h"
24 #include "amodule.h"
25 #include "aplugin.h"
26 #include "arender.h"
27 #include "asset.h"
28 #include "atrack.h"
29 #include "automation.h"
30 #include "bcsignals.h"
31 #include "cache.h"
32 #include "clip.h"
33 #include "edits.h"
34 #include "edl.h"
35 #include "edlsession.h"
36 #include "file.h"
37 #include "filexml.h"
38 #include "floatautos.h"
39 #include "language.h"
40 #include "module.h"
41 #include "patch.h"
42 #include "plugin.h"
43 #include "pluginarray.h"
44 #include "preferences.h"
45 #include "renderengine.h"
46 #include "mainsession.h"
47 #include "samples.h"
48 #include "sharedlocation.h"
49 #include "theme.h"
50 #include "transition.h"
51 #include "transportque.h"
52 #include <string.h>
53
54
55
56
57
58
59
60
61 AModuleResample::AModuleResample(AModule *module)
62  : Resample()
63 {
64         this->module = module;
65         bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
66         nested_allocation = 0;
67 }
68
69 AModuleResample::~AModuleResample()
70 {
71         for(int i = 0; i < MAX_CHANNELS; i++)
72                 delete nested_output[i];
73 }
74
75 int AModuleResample::read_samples(Samples *buffer, int64_t start, int64_t len)
76 {
77         int result = 0;
78
79
80         if(module->asset)
81         {
82 // Files only read going forward.
83                 if(get_direction() == PLAY_REVERSE)
84                 {
85                         start -= len;
86                 }
87
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);
92
93 // Reverse buffer so resampling filter renders forward.
94                 if(get_direction() == PLAY_REVERSE)
95                         Resample::reverse_buffer(buffer->get_data(), len);
96         }
97         else
98         if(module->nested_edl)
99         {
100
101
102 // Nested EDL generates reversed buffer.
103                 for(int i = 0; i < module->nested_edl->session->audio_channels; i++)
104                 {
105                         if(nested_allocation < len)
106                         {
107                                 delete nested_output[i];
108                                 nested_output[i] = 0;
109                         }
110
111                         if(!nested_output[i])
112                         {
113                                 nested_output[i] = new Samples(len);
114                         }
115                 }
116
117
118                 result = module->nested_renderengine->arender->process_buffer(
119                         nested_output,
120                         len,
121                         start);
122 // printf("AModuleResample::read_samples buffer=%p module=%p len=%d\n",
123 // buffer,
124 // module,
125 // len);
126                 memcpy(buffer->get_data(),
127                         nested_output[module->channel]->get_data(),
128                         len * sizeof(double));
129
130         }
131         return result;
132 }
133
134
135
136
137
138
139
140
141
142
143
144 AModule::AModule(RenderEngine *renderengine,
145         CommonRender *commonrender,
146         PluginArray *plugin_array,
147         Track *track)
148  : Module(renderengine, commonrender, plugin_array, track)
149 {
150         data_type = TRACK_AUDIO;
151         transition_temp = 0;
152         speed_temp = 0;
153         bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
154         meter_history = new MeterHistory();
155         nested_allocation = 0;
156         resample = 0;
157         asset = 0;
158         file = 0;
159 }
160
161
162
163
164 AModule::~AModule()
165 {
166         delete transition_temp;
167         delete speed_temp;
168         delete meter_history;
169         for(int i = 0; i < MAX_CHANNELS; i++)
170                 delete nested_output[i];
171         delete resample;
172 }
173
174 AttachmentPoint* AModule::new_attachment(Plugin *plugin)
175 {
176         return new AAttachmentPoint(renderengine, plugin);
177 }
178
179
180 void AModule::create_objects()
181 {
182         Module::create_objects();
183 // Not needed in pluginarray
184         if( commonrender ) {
185                 meter_history->init(1, ((ARender*)commonrender)->total_peaks);
186                 meter_history->reset_channel(0);
187         }
188 }
189
190 int AModule::get_buffer_size()
191 {
192         if(renderengine)
193                 return renderengine->fragment_len;
194         else
195                 return plugin_array->get_bufsize();
196 }
197
198
199 CICache* AModule::get_cache()
200 {
201         if(renderengine)
202                 return renderengine->get_acache();
203         else
204                 return cache;
205 }
206
207
208 int AModule::import_samples(AEdit *edit,
209         int64_t start_project,
210         int64_t edit_startproject,
211         int64_t edit_startsource,
212         int direction,
213         int sample_rate,
214         Samples *buffer,
215         int64_t fragment_len)
216 {
217         const int debug = 0;
218         int result = 0;
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;
226
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
233         int have_speed = 0;
234 // Temporary buffer for rendering speed curve
235         Samples *speed_buffer = buffer;
236
237         if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
238                 return 1;
239         this->channel = edit->channel;
240         int dir = direction == PLAY_FORWARD ? 1 : -1;
241
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;
250
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;
260                 }
261
262                 speed_position2 = speed_position;
263                 if(speed_position2 < speed_position1)
264                 {
265                         max_position += 1.0;
266 //                      min_position -= 1.0;
267                         speed_fragment_len = (int64_t)(max_position - min_position);
268                 }
269                 else
270                 {
271                         max_position += 1.0;
272                         speed_fragment_len = (int64_t)(max_position - min_position);
273                 }
274
275 //printf("AModule::import_samples %d %f %f %f %f\n",
276 // __LINE__, min_position, max_position, speed_position1, speed_position2);
277
278 // new start of source to read from file
279                 start_source = (int64_t)min_position;
280                 have_speed = 1;
281
282 // swap in the temp buffer
283                 if(speed_temp && speed_temp->get_allocated() < speed_fragment_len) {
284                         delete speed_temp;  speed_temp = 0;
285                 }
286                 if(!speed_temp)
287                         speed_temp = new Samples(speed_fragment_len);
288                 speed_buffer = speed_temp;
289         }
290
291         if( speed_fragment_len == 0 )
292                 return 1;
293
294 // Source is a nested EDL
295         if( edit->nested_edl ) {
296                 int command = direction == PLAY_REVERSE ?
297                         NORMAL_REWIND : NORMAL_FWD;
298                 asset = 0;
299
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;
304                         }
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
315 //                              if(!cache)
316 //                              {
317 //                                      cache = new CICache(get_preferences());
318 //                                      private_cache = 1;
319 //                              }
320 //                              nested_renderengine->set_acache(cache);
321                                 nested_renderengine->arm_command(nested_command);
322                         }
323                 }
324 if(debug) printf("AModule::import_samples %d speed_fragment_len=%d\n", __LINE__, (int)speed_fragment_len);
325
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;
330                         }
331                         if(!nested_output[i])
332                                 nested_output[i] = new Samples(speed_fragment_len);
333                 }
334
335                 if( nested_allocation < speed_fragment_len )
336                         nested_allocation = speed_fragment_len;
337
338 // Update direction command
339                 nested_renderengine->command->command = command;
340
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) {
345                         if( !resample )
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.
351                 }
352                 else {
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));
359
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);
363                         }
364                 }
365         }
366         else if( edit->asset ) {
367 // Source is an asset
368                 nested_edl = 0;
369                 asset = edit->asset;
370                 get_cache()->age();
371
372                 if( nested_renderengine ) {
373                         delete nested_renderengine;  nested_renderengine = 0;
374                 }
375
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);
379                         result = 1;
380                 }
381                 else {
382                         result = 0;
383
384                         if( sample_rate != asset->sample_rate ) {
385 // Read through sample rate converter.
386                                 if( !resample )
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.
392                         }
393                         else {
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);
400                         }
401
402                         get_cache()->check_in(asset);
403                         file = 0;
404                 }
405         }
406         else {
407                 nested_edl = 0;
408                 asset = 0;
409                 if( speed_fragment_len > 0 )
410                         bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
411         }
412
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.
416         if( have_speed ) {
417                 double *buffer_samples = buffer->get_data();
418                 if( speed_fragment_len > 0 ) {
419                         FloatAuto *previous = 0;
420                         FloatAuto *next = 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;
427
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);
438                                 if( total > 1 ) {
439                                         for( int j=total; --j>0; ) {
440                                                 k += d;
441                                                 sample += speed_samples[bclip(k, 0,len1)];
442                                         }
443                                         sample /= total;
444                                 }
445 #if 0
446                                 else if( total < 1 ) {
447                                         k += d;
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;
451                                 }
452 #endif
453                                 buffer_samples[out_offset] = sample;
454                                 out_offset += dir;
455                                 speed_position = next_position;
456                                 speed_pos = next_pos;
457                         }
458                 }
459         }
460
461         return result;
462 }
463
464
465 int AModule::render(Samples *buffer,
466         int64_t input_len,
467         int64_t start_position,
468         int direction,
469         int sample_rate,
470         int use_nudge)
471 {
472         int64_t edl_rate = get_edl()->session->sample_rate;
473         const int debug = 0;
474
475 if(debug) printf("AModule::render %d\n", __LINE__);
476
477         if(use_nudge)
478                 start_position += track->nudge *
479                         sample_rate /
480                         edl_rate;
481         AEdit *playable_edit;
482         int64_t end_position;
483         if(direction == PLAY_FORWARD)
484                 end_position = start_position + input_len;
485         else
486                 end_position = start_position - input_len;
487         int buffer_offset = 0;
488         int result = 0;
489
490
491 // // Flip range around so the source is always read forward.
492 //      if(direction == PLAY_REVERSE)
493 //      {
494 //              start_project -= input_len;
495 //              end_position -= input_len;
496 //      }
497
498
499 // Clear buffer
500         bzero(buffer->get_data(), input_len * sizeof(double));
501
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;
508         else
509                 playable_edit = (AEdit*)track->edits->last;
510 if(debug) printf("AModule::render %d\n", __LINE__);
511
512         while(playable_edit)
513         {
514                 int64_t edit_start = playable_edit->startproject;
515                 int64_t edit_end = playable_edit->startproject + playable_edit->length;
516
517 // Normalize to requested rate
518                 edit_start = edit_start * sample_rate / edl_rate;
519                 edit_end = edit_end * sample_rate / edl_rate;
520
521                 if(direction == PLAY_FORWARD)
522                 {
523                         if(start_position < edit_end && end_position > edit_start)
524                         {
525                                 break;
526                         }
527                         playable_edit = (AEdit*)playable_edit->next;
528                 }
529                 else
530                 {
531                         if(end_position < edit_end && start_position > edit_start)
532                         {
533                                 break;
534                         }
535                         playable_edit = (AEdit*)playable_edit->previous;
536                 }
537         }
538
539
540 if(debug) printf("AModule::render %d\n", __LINE__);
541
542
543
544
545
546 // Fill output one fragment at a time
547         while(start_position != end_position)
548         {
549                 int64_t fragment_len = input_len;
550
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;
556                 else
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);
561
562 // Normalize position here since update_transition is a boolean operation.
563                 update_transition(start_position *
564                                 edl_rate /
565                                 sample_rate,
566                         PLAY_FORWARD);
567
568                 if(playable_edit)
569                 {
570                         AEdit *previous_edit = (AEdit*)playable_edit->previous;
571
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);
577
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);
582
583
584
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;
589                         else
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);
594
595 // Clamp to end of transition
596                         int64_t transition_len = 0;
597
598                         if(transition &&
599                                 previous_edit)
600                         {
601                                 transition_len = transition->length *
602                                         sample_rate /
603                                         edl_rate;
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;
608                                 else
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;
613                         }
614 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
615 __LINE__,
616 buffer_offset,
617 fragment_len);
618
619                         Samples output(buffer);
620                         output.set_offset(output.get_offset() + buffer_offset);
621                         if(import_samples(playable_edit,
622                                 start_position,
623                                 edit_startproject,
624                                 edit_startsource,
625                                 direction,
626                                 sample_rate,
627                                 &output,
628                                 fragment_len)) result = 1;
629
630 if(debug) printf("AModule::render %d\n", __LINE__);
631
632
633 // Read transition into temp and render
634                         if(transition && previous_edit)
635                         {
636                                 int64_t previous_startproject = previous_edit->startproject *
637                                         sample_rate /
638                                         edl_rate;
639                                 int64_t previous_startsource = previous_edit->startsource *
640                                         sample_rate /
641                                         edl_rate;
642
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;
648
649
650 // Read into temp buffers
651 // Temp + master or temp + temp ? temp + master
652                                 if(transition_temp &&
653                                         transition_temp->get_allocated() < fragment_len)
654                                 {
655                                         delete transition_temp;
656                                         transition_temp = 0;
657                                 }
658
659                                 if(!transition_temp)
660                                 {
661                                         transition_temp = new Samples(fragment_len);
662                                 }
663
664 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
665
666                                 if(transition_fragment_len > 0)
667                                 {
668 // Previous_edit is always the outgoing segment, regardless of direction
669                                         import_samples(previous_edit,
670                                                 start_position,
671                                                 previous_startproject,
672                                                 previous_startsource,
673                                                 direction,
674                                                 sample_rate,
675                                                 transition_temp,
676                                                 transition_fragment_len);
677                                         int64_t current_position;
678
679 // Reverse buffers here so transitions always render forward.
680                                         if(direction == PLAY_REVERSE)
681                                         {
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 -
686                                                         edit_startproject;
687                                         }
688                                         else
689                                         {
690                                                 current_position = start_position - edit_startproject;
691                                         }
692
693                                         transition_server->process_transition(
694                                                 transition_temp,
695                                                 &output,
696                                                 current_position,
697                                                 transition_fragment_len,
698                                                 transition->length);
699
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);
704                                 }
705                         }
706 if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
707 __LINE__,
708 start_position,
709 end_position,
710 fragment_len);
711
712                         if(direction == PLAY_REVERSE)
713                         {
714                                 if(playable_edit && start_position - fragment_len <= edit_startproject)
715                                         playable_edit = (AEdit*)playable_edit->previous;
716                         }
717                         else
718                         {
719                                 if(playable_edit && start_position + fragment_len >= edit_endproject)
720                                         playable_edit = (AEdit*)playable_edit->next;
721                         }
722                 }
723
724                 if(fragment_len > 0)
725                 {
726                         buffer_offset += fragment_len;
727                         if(direction == PLAY_FORWARD)
728                                 start_position += fragment_len;
729                         else
730                                 start_position -= fragment_len;
731                 }
732         }
733
734 if(debug) printf("AModule::render %d\n", __LINE__);
735
736         return result;
737 }
738
739
740
741
742
743
744
745
746