tweak zoom/fullscr to remember cwdw scale after fullscr
[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,
76                 int64_t start, int64_t len, int direction)
77 {
78         return module->read_samples(buffer, start, len, direction);
79 }
80
81 AModule::AModule(RenderEngine *renderengine,
82         CommonRender *commonrender,
83         PluginArray *plugin_array,
84         Track *track)
85  : Module(renderengine, commonrender, plugin_array, track)
86 {
87         data_type = TRACK_AUDIO;
88         channel = 0;
89         transition_temp = 0;
90         speed_temp = 0;
91         bzero(nested_output, sizeof(Samples*) * MAX_CHANNELS);
92         meter_history = new MeterHistory();
93         nested_allocation = 0;
94         resample = 0;
95         asset = 0;
96         file = 0;
97 }
98
99
100
101
102 AModule::~AModule()
103 {
104         delete transition_temp;
105         delete speed_temp;
106         delete meter_history;
107         for(int i = 0; i < MAX_CHANNELS; i++)
108                 delete nested_output[i];
109         delete resample;
110 }
111
112 int AModule::read_samples(Samples *buffer, int64_t start, int64_t len, int direction)
113 {
114         if( len < 0 ) return 1;
115         double *buffer_data = buffer->get_data();
116 // if start < 0, zero fill prefix.  if error, zero fill buffer
117         int64_t zeros = len;
118         int result = 0;
119         if( asset ) {
120 // Files only read going forward.
121                 if( direction == PLAY_REVERSE ) start -= len;
122                 int64_t sz = start >= 0 ? len : len + start;
123                 if( start < 0 ) start = 0;
124                 if( sz > 0 ) {
125                         file->set_audio_position(start);
126                         file->set_channel(channel);
127                         result = file->read_samples(buffer, sz);
128                         if( !result && (zeros-=sz) > 0 ) {
129                                 double *top_data = buffer_data + zeros;
130                                 memmove(top_data, buffer_data, sz*sizeof(*buffer_data));
131                         }
132                 }
133                 if( !result && direction == PLAY_REVERSE )
134                         Resample::reverse_buffer(buffer_data, len);
135         }
136         else if( nested_edl ) {
137                 if( nested_allocation < len ) {
138                         nested_allocation = len;
139                         for( int i=0; i<nested_edl->session->audio_channels; ++i ) {
140                                 delete nested_output[i];
141                                 nested_output[i] = new Samples(nested_allocation);
142                         }
143                 }
144                 result = nested_renderengine->arender->
145                         process_buffer(nested_output, len, start);
146                 if( !result ) {
147                         double *sample_data = nested_output[channel]->get_data();
148                         int buffer_size = len * sizeof(*buffer_data);
149                         memcpy(buffer_data, sample_data, buffer_size);
150                         zeros = 0;
151                 }
152         }
153         if( zeros > 0 )
154                 memset(buffer_data, 0, zeros*sizeof(*buffer_data));
155         return result;
156 }
157
158 AttachmentPoint* AModule::new_attachment(Plugin *plugin)
159 {
160         return new AAttachmentPoint(renderengine, plugin);
161 }
162
163
164 void AModule::create_objects()
165 {
166         Module::create_objects();
167 // Not needed in pluginarray
168         if( commonrender ) {
169                 meter_history->init(1, ((ARender*)commonrender)->total_peaks);
170                 meter_history->reset_channel(0);
171         }
172 }
173
174 int AModule::get_buffer_size()
175 {
176         if(renderengine)
177                 return renderengine->fragment_len;
178         else
179                 return plugin_array->get_bufsize();
180 }
181
182
183 CICache* AModule::get_cache()
184 {
185         if(renderengine)
186                 return renderengine->get_acache();
187         else
188                 return cache;
189 }
190
191
192 int AModule::import_samples(AEdit *edit,
193         int64_t start_project, int64_t edit_startproject, int64_t edit_startsource,
194         int direction, int sample_rate, Samples *buffer, int64_t fragment_len)
195 {
196         int result = 0;
197         if( fragment_len <= 0 )
198                 result = 1;
199         if( nested_edl && edit->channel >= nested_edl->session->audio_channels )
200                 result = 1;
201         double *buffer_data = buffer->get_data();
202 // buffer fragment adjusted for speed curve
203         Samples *speed_buffer = buffer;
204         double *speed_data = speed_buffer->get_data();
205         int64_t speed_fragment_len = fragment_len;
206         int dir = direction == PLAY_FORWARD ? 1 : -1;
207 // normal speed source boundaries in EDL samplerate
208         int64_t start_source = start_project - edit_startproject + edit_startsource;
209         double end_source = start_source + dir*speed_fragment_len;
210         double start_position = start_source;
211 //      double end_position = end_source;
212 // normal speed playback boundaries
213         double min_source = bmin(start_source, end_source);
214         double max_source = bmax(start_source, end_source);
215
216         this->channel = edit->channel;
217         int have_speed = track->has_speed();
218
219 // apply speed curve to source position so the timeline agrees with the playback
220         if( !result && have_speed ) {
221 // get speed adjusted start position from start of edit.
222                 FloatAuto *previous = 0, *next = 0;
223                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
224                 double source_position = edit_startsource +
225                         speed_autos->automation_integral(edit_startproject,
226                                 start_project-edit_startproject, PLAY_FORWARD);
227                 min_source = source_position;
228                 max_source = source_position;
229 // calculate boundaries of input fragment required for speed curve
230                 int64_t pos = start_project;
231                 start_position = source_position;
232                 for( int64_t i=fragment_len; --i>=0; pos+=dir ) {
233                         double speed = speed_autos->get_value(pos, direction, previous, next);
234                         source_position += dir*speed;
235                         if( source_position > max_source ) max_source = source_position;
236                         if( source_position < min_source ) min_source = source_position;
237                 }
238 //              end_position = source_position;
239                 speed_fragment_len = (int64_t)(max_source - min_source);
240                 start_source = direction == PLAY_FORWARD ? min_source : max_source;
241                 if( speed_fragment_len > 0 ) {
242 // swap in the temp buffer
243                         if( speed_temp && speed_temp->get_allocated() < speed_fragment_len ) {
244                                 delete speed_temp;  speed_temp = 0;
245                         }
246                         if( !speed_temp )
247                                 speed_temp = new Samples(speed_fragment_len);
248                         speed_buffer = speed_temp;
249                         speed_data = speed_buffer->get_data();
250                 }
251         }
252
253         int edit_sample_rate = 0;
254         if( speed_fragment_len <= 0 )
255                 result = 1;
256
257         if( !result && edit->asset ) {
258                 nested_edl = 0;
259                 if( nested_renderengine ) {
260                         delete nested_renderengine;  nested_renderengine = 0;
261                 }
262 // Source is an asset
263                 asset = edit->asset;
264                 edit_sample_rate = asset->sample_rate;
265                 get_cache()->age();
266                 file = get_cache()->check_out(asset, get_edl());
267                 if( !file ) {
268                         printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
269                         result = 1;
270                 }
271         }
272         else if( !result && edit->nested_edl ) {
273                 asset = 0;
274 // Source is a nested EDL
275                 if( !nested_edl || nested_edl->id != edit->nested_edl->id ) {
276                         nested_edl = edit->nested_edl;
277                         delete nested_renderengine;
278                         nested_renderengine = 0;
279                 }
280                 edit_sample_rate = nested_edl->session->sample_rate;
281                 int command = direction == PLAY_REVERSE ?
282                         NORMAL_REWIND : NORMAL_FWD;
283                 if( !nested_command ) {
284                         nested_command = new TransportCommand;
285                         nested_command->command = command;
286                         nested_command->get_edl()->copy_all(nested_edl);
287                         nested_command->change_type = CHANGE_ALL;
288                         nested_command->realtime = renderengine->command->realtime;
289                 }
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);
294                 }
295                 nested_renderengine->command->command = command;
296                 result = 0;
297         }
298
299         if( !result ) {
300 // speed_buffer is (have_speed ? speed_temp : buffer)
301                 if( sample_rate != edit_sample_rate ) {
302                         if( !resample )
303                                 resample = new AModuleResample(this);
304                         result = resample->resample(speed_buffer,
305                                 speed_fragment_len, edit_sample_rate,
306                                 sample_rate, start_source, direction);
307                 }
308                 else {
309                         result = read_samples(speed_buffer,
310                                 start_source, speed_fragment_len, direction);
311                 }
312         }
313         if( asset && file ) {
314                 file = 0;
315                 get_cache()->check_in(asset);
316         }
317 // Stretch it to fit the speed curve
318 // Need overlapping buffers to get the interpolation to work, but this
319 // screws up sequential effects.
320         if( !result && have_speed ) {
321                 FloatAuto *previous = 0, *next = 0;
322                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
323                 int len1 = speed_fragment_len-1;
324                 double speed_position = start_position;
325                 double pos = start_project;
326 // speed                gnuplot> plot "/tmp/x.dat" using($1) with lines
327 // speed_position       gnuplot> plot "/tmp/x.dat" using($2) with lines
328 //FILE *fp = 0;
329 //if( !channel ) { fp = fopen("/tmp/x.dat", "a"); fprintf(fp," %f %f\n",0.,0.); }
330                 for( int64_t i=0; i<fragment_len; ++i,pos+=dir ) {
331                         int64_t speed_pos = speed_position;
332                         double speed = speed_autos->get_value(pos,
333                                 direction, previous, next);
334 //if(fp) fprintf(fp," %f %f\n", speed, speed_position);
335                         double next_position = speed_position + dir*speed;
336                         int64_t next_pos = next_position;
337                         int total = abs(next_pos - speed_pos);
338                         int k = speed_pos - min_source;
339                         if( dir < 0 ) k = len1 - k; // if buffer reversed
340                         double sample = speed_data[bclip(k, 0,len1)];
341                         if( total > 1 ) {
342                                 int d = next_pos >= speed_pos ? 1 : -1;
343                                 for( int j=total; --j>0; ) {
344                                         k += d;
345                                         sample += speed_data[bclip(k, 0,len1)];
346                                 }
347                                 sample /= total;
348                         }
349 #if 0
350                         else if( total < 1 ) {
351                                 int d = next_pos >= speed_pos ? 1 : -1;
352                                 k += d;
353                                 double next_sample = speed_data[bclip(k, 0,len1)];
354                                 double v = speed_position - speed_pos;
355                                 sample = (1.-v) * sample + v * next_sample;
356                         }
357 #endif
358                         buffer_data[i] = sample;
359                         speed_position = next_position;
360                 }
361 //if(fp) fclose(fp);
362         }
363
364         if( result )
365                 bzero(buffer_data, fragment_len*sizeof(*buffer_data));
366         return result;
367 }
368
369
370 int AModule::render(Samples *buffer,
371         int64_t input_len,
372         int64_t start_position,
373         int direction,
374         int sample_rate,
375         int use_nudge)
376 {
377         int64_t edl_rate = get_edl()->session->sample_rate;
378         const int debug = 0;
379
380 if(debug) printf("AModule::render %d\n", __LINE__);
381
382         if(use_nudge)
383                 start_position += track->nudge *
384                         sample_rate /
385                         edl_rate;
386         AEdit *playable_edit;
387         int64_t end_position;
388         if(direction == PLAY_FORWARD)
389                 end_position = start_position + input_len;
390         else
391                 end_position = start_position - input_len;
392         int buffer_offset = 0;
393         int result = 0;
394
395
396 // // Flip range around so the source is always read forward.
397 //      if(direction == PLAY_REVERSE)
398 //      {
399 //              start_project -= input_len;
400 //              end_position -= input_len;
401 //      }
402
403
404 // Clear buffer
405         bzero(buffer->get_data(), input_len * sizeof(double));
406
407 // The EDL is normalized to the requested sample rate because
408 // the requested rate may be the project sample rate and a sample rate
409 // might as well be directly from the source rate to the requested rate.
410 // Get first edit containing the range
411         if(direction == PLAY_FORWARD)
412                 playable_edit = (AEdit*)track->edits->first;
413         else
414                 playable_edit = (AEdit*)track->edits->last;
415 if(debug) printf("AModule::render %d\n", __LINE__);
416
417         while(playable_edit)
418         {
419                 int64_t edit_start = playable_edit->startproject;
420                 int64_t edit_end = playable_edit->startproject + playable_edit->length;
421
422 // Normalize to requested rate
423                 edit_start = edit_start * sample_rate / edl_rate;
424                 edit_end = edit_end * sample_rate / edl_rate;
425
426                 if(direction == PLAY_FORWARD)
427                 {
428                         if(start_position < edit_end && end_position > edit_start)
429                         {
430                                 break;
431                         }
432                         playable_edit = (AEdit*)playable_edit->next;
433                 }
434                 else
435                 {
436                         if(end_position < edit_end && start_position > edit_start)
437                         {
438                                 break;
439                         }
440                         playable_edit = (AEdit*)playable_edit->previous;
441                 }
442         }
443
444
445 if(debug) printf("AModule::render %d\n", __LINE__);
446
447
448
449
450
451 // Fill output one fragment at a time
452         while(start_position != end_position)
453         {
454                 int64_t fragment_len = input_len;
455
456 if(debug) printf("AModule::render %d %jd %jd\n", __LINE__, start_position, end_position);
457 // Clamp fragment to end of input
458                 if(direction == PLAY_FORWARD &&
459                         start_position + fragment_len > end_position)
460                         fragment_len = end_position - start_position;
461                 else
462                 if(direction == PLAY_REVERSE &&
463                         start_position - fragment_len < end_position)
464                         fragment_len = start_position - end_position;
465 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
466
467 // Normalize position here since update_transition is a boolean operation.
468                 update_transition(start_position *
469                                 edl_rate /
470                                 sample_rate,
471                         PLAY_FORWARD);
472
473                 if(playable_edit)
474                 {
475                         AEdit *previous_edit = (AEdit*)playable_edit->previous;
476
477 // Normalize EDL positions to requested rate
478                         int64_t edit_startproject = playable_edit->startproject;
479                         int64_t edit_endproject = playable_edit->startproject + playable_edit->length;
480                         int64_t edit_startsource = playable_edit->startsource;
481 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
482
483                         edit_startproject = edit_startproject * sample_rate / edl_rate;
484                         edit_endproject = edit_endproject * sample_rate / edl_rate;
485                         edit_startsource = edit_startsource * sample_rate / edl_rate;
486 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
487
488
489
490 // Clamp fragment to end of edit
491                         if(direction == PLAY_FORWARD &&
492                                 start_position + fragment_len > edit_endproject)
493                                 fragment_len = edit_endproject - start_position;
494                         else
495                         if(direction == PLAY_REVERSE &&
496                                 start_position - fragment_len < edit_startproject)
497                                 fragment_len = start_position - edit_startproject;
498 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
499
500 // Clamp to end of transition
501                         int64_t transition_len = 0;
502
503                         if(transition &&
504                                 previous_edit)
505                         {
506                                 transition_len = transition->length *
507                                         sample_rate /
508                                         edl_rate;
509                                 if(direction == PLAY_FORWARD &&
510                                         start_position < edit_startproject + transition_len &&
511                                         start_position + fragment_len > edit_startproject + transition_len)
512                                         fragment_len = edit_startproject + transition_len - start_position;
513                                 else
514                                 if(direction == PLAY_REVERSE &&
515                                         start_position > edit_startproject + transition_len &&
516                                         start_position - fragment_len < edit_startproject + transition_len)
517                                         fragment_len = start_position - edit_startproject - transition_len;
518                         }
519 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
520 __LINE__,
521 buffer_offset,
522 fragment_len);
523
524                         Samples output(buffer);
525                         output.set_offset(output.get_offset() + buffer_offset);
526                         if(import_samples(playable_edit,
527                                 start_position,
528                                 edit_startproject,
529                                 edit_startsource,
530                                 direction,
531                                 sample_rate,
532                                 &output,
533                                 fragment_len)) result = 1;
534
535 if(debug) printf("AModule::render %d\n", __LINE__);
536
537
538 // Read transition into temp and render
539                         if(transition && previous_edit)
540                         {
541                                 int64_t previous_startproject = previous_edit->startproject *
542                                         sample_rate /
543                                         edl_rate;
544                                 int64_t previous_startsource = previous_edit->startsource *
545                                         sample_rate /
546                                         edl_rate;
547
548 // Allocate transition temp size
549                                 int transition_fragment_len = fragment_len;
550                                 if(direction == PLAY_FORWARD &&
551                                         fragment_len + start_position > edit_startproject + transition_len)
552                                         fragment_len = edit_startproject + transition_len - start_position;
553
554
555 // Read into temp buffers
556 // Temp + master or temp + temp ? temp + master
557                                 if(transition_temp &&
558                                         transition_temp->get_allocated() < fragment_len)
559                                 {
560                                         delete transition_temp;
561                                         transition_temp = 0;
562                                 }
563
564                                 if(!transition_temp)
565                                 {
566                                         transition_temp = new Samples(fragment_len);
567                                 }
568
569 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
570
571                                 if(transition_fragment_len > 0)
572                                 {
573 // Previous_edit is always the outgoing segment, regardless of direction
574                                         import_samples(previous_edit,
575                                                 start_position,
576                                                 previous_startproject,
577                                                 previous_startsource,
578                                                 direction,
579                                                 sample_rate,
580                                                 transition_temp,
581                                                 transition_fragment_len);
582                                         int64_t current_position;
583
584 // Reverse buffers here so transitions always render forward.
585                                         if(direction == PLAY_REVERSE)
586                                         {
587                                                 Resample::reverse_buffer(output.get_data(), transition_fragment_len);
588                                                 Resample::reverse_buffer(transition_temp->get_data(), transition_fragment_len);
589                                                 current_position = start_position -
590                                                         transition_fragment_len -
591                                                         edit_startproject;
592                                         }
593                                         else
594                                         {
595                                                 current_position = start_position - edit_startproject;
596                                         }
597
598                                         transition_server->process_transition(
599                                                 transition_temp,
600                                                 &output,
601                                                 current_position,
602                                                 transition_fragment_len,
603                                                 transition->length);
604
605 // Reverse output buffer here so transitions always render forward.
606                                         if(direction == PLAY_REVERSE)
607                                                 Resample::reverse_buffer(output.get_data(),
608                                                         transition_fragment_len);
609                                 }
610                         }
611 if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
612  __LINE__, start_position, end_position, fragment_len);
613
614                         if(direction == PLAY_REVERSE)
615                         {
616                                 if(playable_edit && start_position - fragment_len <= edit_startproject)
617                                         playable_edit = (AEdit*)playable_edit->previous;
618                         }
619                         else
620                         {
621                                 if(playable_edit && start_position + fragment_len >= edit_endproject)
622                                         playable_edit = (AEdit*)playable_edit->next;
623                         }
624                 }
625
626                 if(fragment_len > 0)
627                 {
628                         buffer_offset += fragment_len;
629                         if(direction == PLAY_FORWARD)
630                                 start_position += fragment_len;
631                         else
632                                 start_position -= fragment_len;
633                 }
634         }
635
636 if(debug) printf("AModule::render %d\n", __LINE__);
637
638         return result;
639 }
640
641
642
643
644
645
646
647
648