detect missing transitions, dont draw transitions if show off, obey audio transition...
[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 "mainerror.h"
41 #include "module.h"
42 #include "patch.h"
43 #include "plugin.h"
44 #include "pluginarray.h"
45 #include "preferences.h"
46 #include "renderengine.h"
47 #include "mainsession.h"
48 #include "samples.h"
49 #include "sharedlocation.h"
50 #include "theme.h"
51 #include "transition.h"
52 #include "transportque.h"
53 #include "tracks.h"
54 #include <string.h>
55
56
57
58
59
60
61
62
63 AModuleResample::AModuleResample(AModule *module)
64  : Resample()
65 {
66         this->module = module;
67         bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
68         nested_allocation = 0;
69 }
70
71 AModuleResample::~AModuleResample()
72 {
73         for(int i = 0; i < MAX_CHANNELS; i++)
74                 delete nested_output[i];
75 }
76
77 int AModuleResample::read_samples(Samples *buffer,
78                 int64_t start, int64_t len, int direction)
79 {
80         return module->read_samples(buffer, start, len, direction);
81 }
82
83 AModule::AModule(RenderEngine *renderengine,
84         CommonRender *commonrender,
85         PluginArray *plugin_array,
86         Track *track)
87  : Module(renderengine, commonrender, plugin_array, track)
88 {
89         data_type = TRACK_AUDIO;
90         channel = 0;
91         transition_temp = 0;
92         speed_temp = 0;
93         bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
94         meter_history = new MeterHistory();
95         nested_allocation = 0;
96         resample = 0;
97         asset = 0;
98         file = 0;
99 }
100
101
102
103
104 AModule::~AModule()
105 {
106         delete transition_temp;
107         delete speed_temp;
108         delete meter_history;
109         for(int i = 0; i < MAX_CHANNELS; i++)
110                 delete nested_output[i];
111         delete resample;
112 }
113
114 int AModule::read_samples(Samples *buffer, int64_t start, int64_t len, int direction)
115 {
116         if( len < 0 ) return 1;
117         double *buffer_data = buffer->get_data();
118 // if start < 0, zero fill prefix.  if error, zero fill buffer
119         int64_t zeros = len;
120         int result = 0;
121         if( asset ) {
122 // Files only read going forward.
123                 if( direction == PLAY_REVERSE ) start -= len;
124                 int64_t sz = start >= 0 ? len : len + start;
125                 if( start < 0 ) start = 0;
126                 if( sz > 0 ) {
127                         file->set_audio_position(start);
128                         file->set_channel(channel);
129                         result = file->read_samples(buffer, sz);
130                         if( !result && (zeros-=sz) > 0 ) {
131                                 double *top_data = buffer_data + zeros;
132                                 memmove(top_data, buffer_data, sz*sizeof(*buffer_data));
133                         }
134                 }
135                 if( !result && direction == PLAY_REVERSE )
136                         Resample::reverse_buffer(buffer_data, len);
137         }
138         else if( nested_edl ) {
139                 if( nested_allocation < len ) {
140                         nested_allocation = len;
141                         for( int i=0; i<nested_edl->session->audio_channels; ++i ) {
142                                 delete nested_output[i];
143                                 nested_output[i] = new Samples(nested_allocation);
144                         }
145                 }
146                 result = nested_renderengine->arender->
147                         process_buffer(nested_output, len, start);
148                 if( !result ) {
149                         double *sample_data = nested_output[channel]->get_data();
150                         int buffer_size = len * sizeof(*buffer_data);
151                         memcpy(buffer_data, sample_data, buffer_size);
152                         zeros = 0;
153                 }
154         }
155         if( zeros > 0 )
156                 memset(buffer_data, 0, zeros*sizeof(*buffer_data));
157         return result;
158 }
159
160 AttachmentPoint* AModule::new_attachment(Plugin *plugin)
161 {
162         return new AAttachmentPoint(renderengine, plugin);
163 }
164
165
166 void AModule::create_objects()
167 {
168         Module::create_objects();
169 // Not needed in pluginarray
170         if( commonrender ) {
171                 meter_history->init(1, ((ARender*)commonrender)->total_peaks);
172                 meter_history->reset_channel(0);
173         }
174 }
175
176 int AModule::get_buffer_size()
177 {
178         if(renderengine)
179                 return renderengine->fragment_len;
180         else
181                 return plugin_array->get_bufsize();
182 }
183
184
185 CICache* AModule::get_cache()
186 {
187         if(renderengine)
188                 return renderengine->get_acache();
189         else
190                 return cache;
191 }
192
193
194 int AModule::import_samples(AEdit *edit,
195         int64_t start_project, int64_t edit_startproject, int64_t edit_startsource,
196         int direction, int sample_rate, Samples *buffer, int64_t fragment_len)
197 {
198         int result = 0;
199         if( fragment_len <= 0 )
200                 result = 1;
201         if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
202                 result = 1;
203         double *buffer_data = buffer->get_data();
204 // buffer fragment adjusted for speed curve
205         Samples *speed_buffer = buffer;
206         double *speed_data = speed_buffer->get_data();
207         int64_t speed_fragment_len = fragment_len;
208         int dir = direction == PLAY_FORWARD ? 1 : -1;
209 // normal speed source boundaries in EDL samplerate
210         int64_t start_source = start_project - edit_startproject + edit_startsource;
211         double end_source = start_source + dir*speed_fragment_len;
212         double start_position = start_source;
213 //      double end_position = end_source;
214 // normal speed playback boundaries
215         double min_source = bmin(start_source, end_source);
216         double max_source = bmax(start_source, end_source);
217
218         this->channel = edit->channel;
219         int have_speed = track->has_speed();
220
221 // apply speed curve to source position so the timeline agrees with the playback
222         if( !result && have_speed ) {
223 // get speed adjusted start position from start of edit.
224                 FloatAuto *previous = 0, *next = 0;
225                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
226                 double source_position = edit_startsource +
227                         speed_autos->automation_integral(edit_startproject,
228                                 start_project-edit_startproject, PLAY_FORWARD);
229                 min_source = source_position;
230                 max_source = source_position;
231 // calculate boundaries of input fragment required for speed curve
232                 int64_t pos = start_project;
233                 start_position = source_position;
234                 for( int64_t i=fragment_len; --i>=0; pos+=dir ) {
235                         double speed = speed_autos->get_value(pos, direction, previous, next);
236                         source_position += dir*speed;
237                         if( source_position > max_source ) max_source = source_position;
238                         if( source_position < min_source ) min_source = source_position;
239                 }
240 //              end_position = source_position;
241                 speed_fragment_len = (int64_t)(max_source - min_source);
242                 start_source = direction == PLAY_FORWARD ? min_source : max_source;
243                 if( speed_fragment_len > 0 ) {
244 // swap in the temp buffer
245                         if( speed_temp && speed_temp->get_allocated() < speed_fragment_len ) {
246                                 delete speed_temp;  speed_temp = 0;
247                         }
248                         if( !speed_temp )
249                                 speed_temp = new Samples(speed_fragment_len);
250                         speed_buffer = speed_temp;
251                         speed_data = speed_buffer->get_data();
252                 }
253         }
254
255         int edit_sample_rate = 0;
256         if( speed_fragment_len <= 0 )
257                 result = 1;
258
259         if( !result && edit->asset ) {
260                 nested_edl = 0;
261                 if( nested_renderengine ) {
262                         delete nested_renderengine;  nested_renderengine = 0;
263                 }
264 // Source is an asset
265                 asset = edit->asset;
266                 edit_sample_rate = asset->sample_rate;
267                 get_cache()->age();
268                 file = get_cache()->check_out(asset, get_edl());
269                 if( !file ) {
270                         printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
271                         result = 1;
272                 }
273         }
274         else if( !result && edit->nested_edl ) {
275                 asset = 0;
276 // Source is a nested EDL
277                 if( !nested_edl || nested_edl->id != edit->nested_edl->id ) {
278                         nested_edl = edit->nested_edl;
279                         delete nested_renderengine;
280                         nested_renderengine = 0;
281                 }
282                 edit_sample_rate = nested_edl->session->sample_rate;
283                 int command = direction == PLAY_REVERSE ?
284                         NORMAL_REWIND : NORMAL_FWD;
285                 if( !nested_command )
286                         nested_command = new TransportCommand;
287                 nested_command->command = command;
288                 nested_command->get_edl()->copy_all(nested_edl);
289                 nested_command->change_type = CHANGE_ALL;
290                 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);
295                 }
296                 nested_renderengine->command->command = command;
297                 result = 0;
298         }
299         if( edit_sample_rate <= 0 )
300                 result = 1;
301
302         if( !result ) {
303 // speed_buffer is (have_speed ? speed_temp : buffer)
304                 if( sample_rate != edit_sample_rate ) {
305                         if( !resample )
306                                 resample = new AModuleResample(this);
307                         result = resample->resample(speed_buffer,
308                                 speed_fragment_len, edit_sample_rate,
309                                 sample_rate, start_source, direction);
310                 }
311                 else {
312                         result = read_samples(speed_buffer,
313                                 start_source, speed_fragment_len, direction);
314                 }
315         }
316         if( asset && file ) {
317                 file = 0;
318                 get_cache()->check_in(asset);
319         }
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
331 //FILE *fp = 0;
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)];
344                         if( total > 1 ) {
345                                 int d = next_pos >= speed_pos ? 1 : -1;
346                                 for( int j=total; --j>0; ) {
347                                         k += d;
348                                         sample += speed_data[bclip(k, 0,len1)];
349                                 }
350                                 sample /= total;
351                         }
352 #if 0
353                         else if( total < 1 ) {
354                                 int d = next_pos >= speed_pos ? 1 : -1;
355                                 k += d;
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;
359                         }
360 #endif
361                         buffer_data[i] = sample;
362                         speed_position = next_position;
363                 }
364 //if(fp) fclose(fp);
365         }
366
367         if( result )
368                 bzero(buffer_data, fragment_len*sizeof(*buffer_data));
369         return result;
370 }
371
372
373 int AModule::render(Samples *buffer,
374         int64_t input_len,
375         int64_t start_position,
376         int direction,
377         int sample_rate,
378         int use_nudge)
379 {
380         int64_t edl_rate = get_edl()->session->sample_rate;
381         const int debug = 0;
382
383 if(debug) printf("AModule::render %d\n", __LINE__);
384
385         if(use_nudge)
386                 start_position += track->nudge *
387                         sample_rate /
388                         edl_rate;
389         AEdit *playable_edit;
390         int64_t end_position;
391         if(direction == PLAY_FORWARD)
392                 end_position = start_position + input_len;
393         else
394                 end_position = start_position - input_len;
395         int buffer_offset = 0;
396         int result = 0;
397
398
399 // // Flip range around so the source is always read forward.
400 //      if(direction == PLAY_REVERSE)
401 //      {
402 //              start_project -= input_len;
403 //              end_position -= input_len;
404 //      }
405
406
407 // Clear buffer
408         bzero(buffer->get_data(), input_len * sizeof(double));
409
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;
416         else
417                 playable_edit = (AEdit*)track->edits->last;
418 if(debug) printf("AModule::render %d\n", __LINE__);
419
420         while(playable_edit)
421         {
422                 int64_t edit_start = playable_edit->startproject;
423                 int64_t edit_end = playable_edit->startproject + playable_edit->length;
424
425 // Normalize to requested rate
426                 edit_start = edit_start * sample_rate / edl_rate;
427                 edit_end = edit_end * sample_rate / edl_rate;
428
429                 if(direction == PLAY_FORWARD)
430                 {
431                         if(start_position < edit_end && end_position > edit_start)
432                         {
433                                 break;
434                         }
435                         playable_edit = (AEdit*)playable_edit->next;
436                 }
437                 else
438                 {
439                         if(end_position < edit_end && start_position > edit_start)
440                         {
441                                 break;
442                         }
443                         playable_edit = (AEdit*)playable_edit->previous;
444                 }
445         }
446
447
448 if(debug) printf("AModule::render %d\n", __LINE__);
449
450
451
452
453
454 // Fill output one fragment at a time
455         while(start_position != end_position)
456         {
457                 int64_t fragment_len = input_len;
458
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;
464                 else
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);
469
470 // Normalize position here since update_transition is a boolean operation.
471                 update_transition(start_position *
472                                 edl_rate /
473                                 sample_rate,
474                         PLAY_FORWARD);
475
476                 if(playable_edit)
477                 {
478                         AEdit *previous_edit = (AEdit*)playable_edit->previous;
479
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);
485
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);
490
491
492
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;
497                         else
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);
502
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 && transition->on && 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;
512                                 else
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;
517                         }
518 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
519 __LINE__,
520 buffer_offset,
521 fragment_len);
522
523                         Samples output(buffer);
524                         output.set_offset(output.get_offset() + buffer_offset);
525                         if(import_samples(playable_edit,
526                                 start_position,
527                                 edit_startproject,
528                                 edit_startsource,
529                                 direction,
530                                 sample_rate,
531                                 &output,
532                                 fragment_len)) result = 1;
533
534 if(debug) printf("AModule::render %d\n", __LINE__);
535
536
537 // Read transition into temp and render
538                         if(transition && transition->on && previous_edit)
539                         {
540                                 int64_t previous_startproject = previous_edit->startproject *
541                                         sample_rate /
542                                         edl_rate;
543                                 int64_t previous_startsource = previous_edit->startsource *
544                                         sample_rate /
545                                         edl_rate;
546
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;
552
553
554 // Read into temp buffers
555 // Temp + master or temp + temp ? temp + master
556                                 if(transition_temp &&
557                                         transition_temp->get_allocated() < fragment_len)
558                                 {
559                                         delete transition_temp;
560                                         transition_temp = 0;
561                                 }
562
563                                 if(!transition_temp)
564                                 {
565                                         transition_temp = new Samples(fragment_len);
566                                 }
567
568 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
569
570                                 if(transition_fragment_len > 0)
571                                 {
572 // Previous_edit is always the outgoing segment, regardless of direction
573                                         import_samples(previous_edit,
574                                                 start_position,
575                                                 previous_startproject,
576                                                 previous_startsource,
577                                                 direction,
578                                                 sample_rate,
579                                                 transition_temp,
580                                                 transition_fragment_len);
581                                         int64_t current_position;
582
583 // Reverse buffers here so transitions always render forward.
584                                         if(direction == PLAY_REVERSE)
585                                         {
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 -
590                                                         edit_startproject;
591                                         }
592                                         else
593                                         {
594                                                 current_position = start_position - edit_startproject;
595                                         }
596                                         if( transition_server ) {
597                                                 transition_server->process_transition(
598                                                         transition_temp, &output, current_position,
599                                                         transition_fragment_len, transition->length);
600                                         }
601                                         else
602                                                 eprintf("missing transition plugin: %s\n", transition->title);
603
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);
608                                 }
609                         }
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);
612
613                         if(direction == PLAY_REVERSE)
614                         {
615                                 if(playable_edit && start_position - fragment_len <= edit_startproject)
616                                         playable_edit = (AEdit*)playable_edit->previous;
617                         }
618                         else
619                         {
620                                 if(playable_edit && start_position + fragment_len >= edit_endproject)
621                                         playable_edit = (AEdit*)playable_edit->next;
622                         }
623                 }
624
625                 if(fragment_len > 0)
626                 {
627                         buffer_offset += fragment_len;
628                         if(direction == PLAY_FORWARD)
629                                 start_position += fragment_len;
630                         else
631                                 start_position -= fragment_len;
632                 }
633         }
634
635 if(debug) printf("AModule::render %d\n", __LINE__);
636
637         return result;
638 }
639
640
641
642
643
644
645
646
647