Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / 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         bzero(prev_head, SPEED_OVERLAP * sizeof(double));
155         bzero(prev_tail, SPEED_OVERLAP * sizeof(double));
156         meter_history = new MeterHistory();
157         nested_allocation = 0;
158         resample = 0;
159         asset = 0;
160         file = 0;
161 }
162
163
164
165
166 AModule::~AModule()
167 {
168         delete transition_temp;
169         delete speed_temp;
170         delete meter_history;
171         for(int i = 0; i < MAX_CHANNELS; i++)
172                 delete nested_output[i];
173         delete resample;
174 }
175
176 AttachmentPoint* AModule::new_attachment(Plugin *plugin)
177 {
178         return new AAttachmentPoint(renderengine, plugin);
179 }
180
181
182 void AModule::create_objects()
183 {
184         Module::create_objects();
185 // Not needed in pluginarray
186         if( commonrender ) {
187                 meter_history->init(1, ((ARender*)commonrender)->total_peaks);
188                 meter_history->reset_channel(0);
189         }
190 }
191
192 int AModule::get_buffer_size()
193 {
194         if(renderengine)
195                 return renderengine->fragment_len;
196         else
197                 return plugin_array->get_bufsize();
198 }
199
200
201 CICache* AModule::get_cache()
202 {
203         if(renderengine)
204                 return renderengine->get_acache();
205         else
206                 return cache;
207 }
208
209
210 int AModule::import_samples(AEdit *edit,
211         int64_t start_project,
212         int64_t edit_startproject,
213         int64_t edit_startsource,
214         int direction,
215         int sample_rate,
216         Samples *buffer,
217         int64_t fragment_len)
218 {
219         int result = 0;
220 // start in EDL samplerate
221         int64_t start_source = start_project -
222                 edit_startproject +
223                 edit_startsource;
224 // fragment size adjusted for speed curve
225         int64_t speed_fragment_len = fragment_len;
226 // boundaries of input fragment required for speed curve
227         double max_position = 0;
228         double min_position = 0;
229
230         double speed_position = edit_startsource;
231 // position in source where speed curve starts reading
232         double speed_position1 = speed_position;
233 // position in source where speed curve finishes
234         double speed_position2 = speed_position;
235
236 // Need speed curve processing
237         int have_speed = 0;
238 // Temporary buffer for rendering speed curve
239         Samples *speed_buffer = buffer;
240         const int debug = 0;
241
242 if(debug) printf("AModule::import_samples %d edit=%p nested_edl=%p\n",
243 __LINE__,
244 edit,
245 nested_edl);
246         if(nested_edl && edit->channel >= nested_edl->session->audio_channels)
247                 return 1;
248 if(debug) printf("AModule::import_samples %d\n", __LINE__);
249
250         this->channel = edit->channel;
251 if(debug) printf("AModule::import_samples %d speed_fragment_len=%jd\n",
252 __LINE__,
253 speed_fragment_len);
254
255
256
257
258 // apply speed curve to source position so the timeline agrees with the playback
259         if(track->has_speed())
260         {
261 // get speed adjusted position from start of edit.
262                 FloatAuto *previous = 0;
263                 FloatAuto *next = 0;
264                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
265                 speed_position += speed_autos->automation_integral(edit_startproject,
266                                 start_project-edit_startproject, PLAY_FORWARD);
267                 speed_position1 = speed_position;
268
269
270 // calculate boundaries of input fragment required for speed curve
271                 max_position = speed_position;
272                 min_position = speed_position;
273                 for(int64_t i = start_project; i < start_project + fragment_len; i++)
274                 {
275                         double speed = speed_autos->get_value(i,
276                                 PLAY_FORWARD,
277                                 previous,
278                                 next);
279                         speed_position += speed;
280                         if(speed_position > max_position) max_position = speed_position;
281                         if(speed_position < min_position) min_position = speed_position;
282                 }
283
284                 speed_position2 = speed_position;
285                 if(speed_position2 < speed_position1)
286                 {
287                         max_position += 1.0;
288 //                      min_position -= 1.0;
289                         speed_fragment_len = (int64_t)(max_position - min_position);
290                 }
291                 else
292                 {
293                         max_position += 1.0;
294                         speed_fragment_len = (int64_t)(max_position - min_position);
295                 }
296
297 //printf("AModule::import_samples %d %f %f %f %f\n",
298 // __LINE__, min_position, max_position, speed_position1, speed_position2);
299
300 // new start of source to read from file
301                 start_source = (int64_t)min_position;
302                 have_speed = 1;
303
304
305
306 // swap in the temp buffer
307                 if(speed_temp && speed_temp->get_allocated() < speed_fragment_len)
308                 {
309                         delete speed_temp;
310                         speed_temp = 0;
311                 }
312
313                 if(!speed_temp)
314                 {
315                         speed_temp = new Samples(speed_fragment_len);
316                 }
317
318                 speed_buffer = speed_temp;
319         }
320
321
322
323         if(speed_fragment_len == 0)
324                 return 1;
325
326
327
328 // Source is a nested EDL
329         if(edit->nested_edl)
330         {
331                 int command;
332                 asset = 0;
333
334                 if(direction == PLAY_REVERSE)
335                         command = NORMAL_REWIND;
336                 else
337                         command = NORMAL_FWD;
338
339 if(debug) printf("AModule::import_samples %d\n", __LINE__);
340                 if(!nested_edl || nested_edl->id != edit->nested_edl->id)
341                 {
342                         nested_edl = edit->nested_edl;
343                         if(nested_renderengine)
344                         {
345                                 delete nested_renderengine;
346                                 nested_renderengine = 0;
347                         }
348
349                         if(!nested_command)
350                         {
351                                 nested_command = new TransportCommand;
352                         }
353
354
355                         if(!nested_renderengine)
356                         {
357                                 nested_command->command = command;
358                                 nested_command->get_edl()->copy_all(nested_edl);
359                                 nested_command->change_type = CHANGE_ALL;
360                                 nested_command->realtime = renderengine->command->realtime;
361                                 nested_renderengine = new RenderEngine(0, get_preferences(), 0, 1);
362                                 nested_renderengine->set_acache(get_cache());
363 // Must use a private cache for the audio
364 //                              if(!cache)
365 //                              {
366 //                                      cache = new CICache(get_preferences());
367 //                                      private_cache = 1;
368 //                              }
369 //                              nested_renderengine->set_acache(cache);
370                                 nested_renderengine->arm_command(nested_command);
371                         }
372                 }
373 if(debug) printf("AModule::import_samples %d speed_fragment_len=%d\n", __LINE__, (int)speed_fragment_len);
374
375 // Allocate output buffers for all channels
376                 for(int i = 0; i < nested_edl->session->audio_channels; i++)
377                 {
378                         if(nested_allocation < speed_fragment_len)
379                         {
380                                 delete nested_output[i];
381                                 nested_output[i] = 0;
382                         }
383
384                         if(!nested_output[i])
385                         {
386                                 nested_output[i] = new Samples(speed_fragment_len);
387                         }
388                 }
389 if(debug) printf("AModule::import_samples %d\n", __LINE__);
390
391                 if(nested_allocation < speed_fragment_len)
392                         nested_allocation = speed_fragment_len;
393
394 // Update direction command
395                 nested_renderengine->command->command = command;
396
397 // Render the segment
398                 if(!nested_renderengine->arender)
399                 {
400                         bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
401                 }
402                 else
403                 if(sample_rate != nested_edl->session->sample_rate)
404                 {
405 // Read through sample rate converter.
406                         if(!resample)
407                         {
408                                 resample = new AModuleResample(this);
409                         }
410
411 if(debug) printf("AModule::import_samples %d %d %d\n",
412 __LINE__,
413 (int)sample_rate,
414 (int)nested_edl->session->sample_rate);
415                         result = resample->resample(speed_buffer,
416                                 speed_fragment_len,
417                                 nested_edl->session->sample_rate,
418                                 sample_rate,
419                                 start_source,
420                                 direction);
421 // Resample reverses to keep it running forward.
422 if(debug) printf("AModule::import_samples %d\n", __LINE__);
423                 }
424                 else
425                 {
426 // Render without resampling
427 if(debug) printf("AModule::import_samples %d\n", __LINE__);
428                         result = nested_renderengine->arender->process_buffer(
429                                 nested_output,
430                                 speed_fragment_len,
431                                 start_source);
432 if(debug) printf("AModule::import_samples %d\n", __LINE__);
433                         memcpy(speed_buffer->get_data(),
434                                 nested_output[edit->channel]->get_data(),
435                                 speed_fragment_len * sizeof(double));
436 if(debug) printf("AModule::import_samples %d\n", __LINE__);
437
438 // Reverse fragment so ::render can apply transitions going forward.
439                         if(direction == PLAY_REVERSE)
440                         {
441                                 Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
442                         }
443                 }
444
445 if(debug) printf("AModule::import_samples %d\n", __LINE__);
446         }
447         else
448 // Source is an asset
449         if(edit->asset)
450         {
451                 nested_edl = 0;
452 if(debug) printf("AModule::import_samples %d\n", __LINE__);
453                 asset = edit->asset;
454
455 if(debug) printf("AModule::import_samples %d\n", __LINE__);
456                 get_cache()->age();
457
458 if(debug) printf("AModule::import_samples %d\n", __LINE__);
459                 if(nested_renderengine)
460                 {
461                         delete nested_renderengine;
462                         nested_renderengine = 0;
463                 }
464
465 if(debug) printf("AModule::import_samples %d\n", __LINE__);
466
467                 if(!(file = get_cache()->check_out(
468                         asset,
469                         get_edl())))
470                 {
471 // couldn't open source file / skip the edit
472                         printf(_("AModule::import_samples Couldn't open %s.\n"), asset->path);
473                         result = 1;
474                 }
475                 else
476                 {
477                         result = 0;
478
479
480                         if(sample_rate != asset->sample_rate)
481                         {
482 // Read through sample rate converter.
483                                 if(!resample)
484                                 {
485                                         resample = new AModuleResample(this);
486                                 }
487
488 if(debug) printf("AModule::import_samples %d %d %d\n",
489 __LINE__,
490 sample_rate,
491 asset->sample_rate);
492                                 result = resample->resample(speed_buffer,
493                                         speed_fragment_len,
494                                         asset->sample_rate,
495                                         sample_rate,
496                                         start_source,
497                                         direction);
498 // Resample reverses to keep it running forward.
499                         }
500                         else
501                         {
502
503 if(debug)
504 printf("AModule::import_samples %d channel=%d start_source=%jd len=%d\n", __LINE__, edit->channel, start_source, (int)speed_fragment_len);
505                                 file->set_audio_position(start_source);
506                                 file->set_channel(edit->channel);
507                                 result = file->read_samples(speed_buffer, speed_fragment_len);
508 // Reverse fragment so ::render can apply transitions going forward.
509 if(debug) printf("AModule::import_samples %d speed_buffer=%p data=%p speed_fragment_len=%d\n",
510 __LINE__,
511 (void*)speed_buffer,
512 (void*)speed_buffer->get_data(),
513 (int)speed_fragment_len);
514                                 if(direction == PLAY_REVERSE)
515                                 {
516                                         Resample::reverse_buffer(speed_buffer->get_data(), speed_fragment_len);
517                                 }
518 if(debug) printf("AModule::import_samples %d\n", __LINE__);
519                         }
520
521 if(debug) printf("AModule::import_samples %d\n", __LINE__);
522                         get_cache()->check_in(asset);
523 if(debug) printf("AModule::import_samples %d\n", __LINE__);
524                         file = 0;
525
526
527
528
529
530                 }
531         }
532         else
533         {
534                 nested_edl = 0;
535                 asset = 0;
536 if(debug) printf("AModule::import_samples %d %p %d\n", __LINE__, speed_buffer->get_data(), (int)speed_fragment_len);
537                 if(speed_fragment_len > 0) bzero(speed_buffer->get_data(), speed_fragment_len * sizeof(double));
538 if(debug) printf("AModule::import_samples %d\n", __LINE__);
539         }
540 if(debug) printf("AModule::import_samples %d\n", __LINE__);
541
542
543
544
545
546
547
548
549
550 // Stretch it to fit the speed curve
551 // Need overlapping buffers to get the interpolation to work, but this
552 // screws up sequential effects.
553         if(have_speed)
554         {
555                 FloatAuto *previous = 0;
556                 FloatAuto *next = 0;
557                 FloatAutos *speed_autos = (FloatAutos*)track->automation->autos[AUTOMATION_SPEED];
558                 double *buffer_samples = buffer->get_data();
559                 double *speed_samples = speed_buffer->get_data();
560
561 //printf("AModule::import_samples %d %lld\n", __LINE__, speed_fragment_len);
562
563                 if(speed_fragment_len == 0)
564                 {
565                         bzero(buffer_samples, fragment_len * sizeof(double));
566                         bzero(prev_tail, SPEED_OVERLAP * sizeof(double));
567                         bzero(prev_head, SPEED_OVERLAP * sizeof(double));
568                 }
569                 else
570                 {
571 // buffer is now reversed
572                         if(direction == PLAY_REVERSE)
573                         {
574                                 int out_offset = 0;
575                                 speed_position = speed_position2;
576         //printf("AModule::import_samples %d %lld %lld\n", __LINE__, start_project, speed_fragment_len);
577                                 for(int64_t i = start_project + fragment_len;
578                                         i != start_project;
579                                         i--)
580                                 {
581         // funky sample reordering, because the source is a reversed buffer
582                                         int in_offset = (int64_t)(speed_fragment_len - 1 - speed_position);
583                                         CLAMP(in_offset, 0, speed_fragment_len - 1);
584                                         buffer_samples[out_offset++] = speed_samples[in_offset];
585                                         double speed = speed_autos->get_value(i,
586                                                 PLAY_REVERSE,
587                                                 previous,
588                                                 next);
589                                         speed_position -= speed;
590                                 }
591         //printf("AModule::import_samples %d %f\n", __LINE__, speed_position);
592                         }
593                         else
594                         {
595                                 int out_offset = 0;
596 // position in buffer to read
597                                 speed_position = speed_position1 - start_source;
598
599 //printf("AModule::import_samples %d %f\n", __LINE__, speed_position);
600                                 for(int64_t i = start_project; i < start_project + fragment_len; i++)
601                                 {
602                                         double speed = speed_autos->get_value(i,
603                                                 PLAY_FORWARD,
604                                                 previous,
605                                                 next);
606                                         double next_speed_position = speed_position + speed;
607
608                                         int in_offset = (int)(speed_position);
609                                         if(fabs(speed) >= 1.0)
610                                         {
611                                                 int total = abs(speed);
612                                                 double accum = 0;
613                                                 for(int j = 0; j < total; j++)
614                                                 {
615                                                         int in_offset2 = in_offset + (speed > 0 ? j : -j);
616
617                                                         CLAMP(in_offset2, 0, speed_fragment_len - 1);
618                                                         accum += speed_samples[in_offset2];
619                                                 }
620
621
622                                                 buffer_samples[out_offset++] = accum / total;
623                                         }
624                                         else
625                                         {
626
627
628 // if(in_offset < 0 || in_offset >= speed_fragment_len)
629 // printf("AModule::import_samples %d %d %d\n",
630 // __LINE__,
631 // in_offset,
632 // speed_fragment_len);
633
634                                                 int in_offset1 = in_offset;
635                                                 int in_offset2 = in_offset;
636
637                                                 if(speed < 0)
638                                                 {
639                                                         in_offset1 += SPEED_OVERLAP;
640                                                         in_offset2 = in_offset1 - 1;
641                                                 }
642                                                 else
643                                                 {
644                                                         in_offset1 -= SPEED_OVERLAP;
645                                                         in_offset2 = in_offset1 + 1;
646                                                 }
647
648                                                 CLAMP(in_offset1, -SPEED_OVERLAP, speed_fragment_len - 1 + SPEED_OVERLAP);
649                                                 CLAMP(in_offset2, -SPEED_OVERLAP, speed_fragment_len - 1 + SPEED_OVERLAP);
650
651                                                 double value1 = 0;
652                                                 if(in_offset1 >= speed_fragment_len)
653                                                 {
654                                                         value1 = prev_head[in_offset1 - speed_fragment_len];
655                                                 }
656                                                 else
657                                                 if(in_offset1 >= 0)
658                                                 {
659                                                         value1 = speed_samples[in_offset1];
660                                                 }
661                                                 else
662                                                 {
663 //printf("AModule::import_samples %d %d\n", __LINE__, in_offset1);
664                                                         value1 = prev_tail[SPEED_OVERLAP + in_offset1];
665                                                 }
666 #if 0
667                                                 double value2 = 0;
668                                                 if(in_offset2 >= speed_fragment_len)
669                                                 {
670                                                         value2 = prev_head[in_offset2 - speed_fragment_len];
671                                                 }
672                                                 else
673                                                 if(in_offset2 >= 0)
674                                                 {
675                                                         value2 = speed_samples()[in_offset2];
676                                                 }
677                                                 else
678                                                 {
679                                                         value2 = prev_tail[SPEED_OVERLAP + in_offset2];
680                                                 }
681
682                                                 double fraction = speed_position - floor(speed_position);
683                                                 buffer_samples[out_offset++] =
684                                                         value1 * (1.0 - fraction) +
685                                                         value2 * fraction;
686 #endif
687                                                 buffer_samples[out_offset++] = value1;
688
689
690                                         }
691
692                                         speed_position = next_speed_position;
693                                 }
694                         }
695
696                         for(int i = 0; i < SPEED_OVERLAP; i++)
697                         {
698                                 int offset = speed_fragment_len -
699                                         SPEED_OVERLAP +
700                                         i;
701                                 CLAMP(offset, 0, speed_fragment_len - 1);
702 //printf("AModule::import_samples %d %d\n", __LINE__, offset, );
703                                 prev_tail[i] = speed_samples[offset];
704                                 offset = i;
705                                 CLAMP(offset, 0, speed_fragment_len - 1);
706                                 prev_head[i] = speed_samples[offset];
707                         }
708                 }
709         }
710
711
712
713
714
715         return result;
716 }
717
718
719
720 int AModule::render(Samples *buffer,
721         int64_t input_len,
722         int64_t start_position,
723         int direction,
724         int sample_rate,
725         int use_nudge)
726 {
727         int64_t edl_rate = get_edl()->session->sample_rate;
728         const int debug = 0;
729
730 if(debug) printf("AModule::render %d\n", __LINE__);
731
732         if(use_nudge)
733                 start_position += track->nudge *
734                         sample_rate /
735                         edl_rate;
736         AEdit *playable_edit;
737         int64_t end_position;
738         if(direction == PLAY_FORWARD)
739                 end_position = start_position + input_len;
740         else
741                 end_position = start_position - input_len;
742         int buffer_offset = 0;
743         int result = 0;
744
745
746 // // Flip range around so the source is always read forward.
747 //      if(direction == PLAY_REVERSE)
748 //      {
749 //              start_project -= input_len;
750 //              end_position -= input_len;
751 //      }
752
753
754 // Clear buffer
755         bzero(buffer->get_data(), input_len * sizeof(double));
756
757 // The EDL is normalized to the requested sample rate because
758 // the requested rate may be the project sample rate and a sample rate
759 // might as well be directly from the source rate to the requested rate.
760 // Get first edit containing the range
761         if(direction == PLAY_FORWARD)
762                 playable_edit = (AEdit*)track->edits->first;
763         else
764                 playable_edit = (AEdit*)track->edits->last;
765 if(debug) printf("AModule::render %d\n", __LINE__);
766
767         while(playable_edit)
768         {
769                 int64_t edit_start = playable_edit->startproject;
770                 int64_t edit_end = playable_edit->startproject + playable_edit->length;
771
772 // Normalize to requested rate
773                 edit_start = edit_start * sample_rate / edl_rate;
774                 edit_end = edit_end * sample_rate / edl_rate;
775
776                 if(direction == PLAY_FORWARD)
777                 {
778                         if(start_position < edit_end && end_position > edit_start)
779                         {
780                                 break;
781                         }
782                         playable_edit = (AEdit*)playable_edit->next;
783                 }
784                 else
785                 {
786                         if(end_position < edit_end && start_position > edit_start)
787                         {
788                                 break;
789                         }
790                         playable_edit = (AEdit*)playable_edit->previous;
791                 }
792         }
793
794
795 if(debug) printf("AModule::render %d\n", __LINE__);
796
797
798
799
800
801 // Fill output one fragment at a time
802         while(start_position != end_position)
803         {
804                 int64_t fragment_len = input_len;
805
806 if(debug) printf("AModule::render %d %jd %jd\n", __LINE__, start_position, end_position);
807 // Clamp fragment to end of input
808                 if(direction == PLAY_FORWARD &&
809                         start_position + fragment_len > end_position)
810                         fragment_len = end_position - start_position;
811                 else
812                 if(direction == PLAY_REVERSE &&
813                         start_position - fragment_len < end_position)
814                         fragment_len = start_position - end_position;
815 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
816
817 // Normalize position here since update_transition is a boolean operation.
818                 update_transition(start_position *
819                                 edl_rate /
820                                 sample_rate,
821                         PLAY_FORWARD);
822
823                 if(playable_edit)
824                 {
825                         AEdit *previous_edit = (AEdit*)playable_edit->previous;
826
827 // Normalize EDL positions to requested rate
828                         int64_t edit_startproject = playable_edit->startproject;
829                         int64_t edit_endproject = playable_edit->startproject + playable_edit->length;
830                         int64_t edit_startsource = playable_edit->startsource;
831 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
832
833                         edit_startproject = edit_startproject * sample_rate / edl_rate;
834                         edit_endproject = edit_endproject * sample_rate / edl_rate;
835                         edit_startsource = edit_startsource * sample_rate / edl_rate;
836 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
837
838
839
840 // Clamp fragment to end of edit
841                         if(direction == PLAY_FORWARD &&
842                                 start_position + fragment_len > edit_endproject)
843                                 fragment_len = edit_endproject - start_position;
844                         else
845                         if(direction == PLAY_REVERSE &&
846                                 start_position - fragment_len < edit_startproject)
847                                 fragment_len = start_position - edit_startproject;
848 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
849
850 // Clamp to end of transition
851                         int64_t transition_len = 0;
852
853                         if(transition &&
854                                 previous_edit)
855                         {
856                                 transition_len = transition->length *
857                                         sample_rate /
858                                         edl_rate;
859                                 if(direction == PLAY_FORWARD &&
860                                         start_position < edit_startproject + transition_len &&
861                                         start_position + fragment_len > edit_startproject + transition_len)
862                                         fragment_len = edit_startproject + transition_len - start_position;
863                                 else
864                                 if(direction == PLAY_REVERSE &&
865                                         start_position > edit_startproject + transition_len &&
866                                         start_position - fragment_len < edit_startproject + transition_len)
867                                         fragment_len = start_position - edit_startproject - transition_len;
868                         }
869 if(debug) printf("AModule::render %d buffer_offset=%d fragment_len=%jd\n",
870 __LINE__,
871 buffer_offset,
872 fragment_len);
873
874                         Samples output(buffer);
875                         output.set_offset(output.get_offset() + buffer_offset);
876                         if(import_samples(playable_edit,
877                                 start_position,
878                                 edit_startproject,
879                                 edit_startsource,
880                                 direction,
881                                 sample_rate,
882                                 &output,
883                                 fragment_len)) result = 1;
884
885 if(debug) printf("AModule::render %d\n", __LINE__);
886
887
888 // Read transition into temp and render
889                         if(transition && previous_edit)
890                         {
891                                 int64_t previous_startproject = previous_edit->startproject *
892                                         sample_rate /
893                                         edl_rate;
894                                 int64_t previous_startsource = previous_edit->startsource *
895                                         sample_rate /
896                                         edl_rate;
897
898 // Allocate transition temp size
899                                 int transition_fragment_len = fragment_len;
900                                 if(direction == PLAY_FORWARD &&
901                                         fragment_len + start_position > edit_startproject + transition_len)
902                                         fragment_len = edit_startproject + transition_len - start_position;
903
904
905 // Read into temp buffers
906 // Temp + master or temp + temp ? temp + master
907                                 if(transition_temp &&
908                                         transition_temp->get_allocated() < fragment_len)
909                                 {
910                                         delete transition_temp;
911                                         transition_temp = 0;
912                                 }
913
914                                 if(!transition_temp)
915                                 {
916                                         transition_temp = new Samples(fragment_len);
917                                 }
918
919 if(debug) printf("AModule::render %d %jd\n", __LINE__, fragment_len);
920
921                                 if(transition_fragment_len > 0)
922                                 {
923 // Previous_edit is always the outgoing segment, regardless of direction
924                                         import_samples(previous_edit,
925                                                 start_position,
926                                                 previous_startproject,
927                                                 previous_startsource,
928                                                 direction,
929                                                 sample_rate,
930                                                 transition_temp,
931                                                 transition_fragment_len);
932                                         int64_t current_position;
933
934 // Reverse buffers here so transitions always render forward.
935                                         if(direction == PLAY_REVERSE)
936                                         {
937                                                 Resample::reverse_buffer(output.get_data(), transition_fragment_len);
938                                                 Resample::reverse_buffer(transition_temp->get_data(), transition_fragment_len);
939                                                 current_position = start_position -
940                                                         transition_fragment_len -
941                                                         edit_startproject;
942                                         }
943                                         else
944                                         {
945                                                 current_position = start_position - edit_startproject;
946                                         }
947
948                                         transition_server->process_transition(
949                                                 transition_temp,
950                                                 &output,
951                                                 current_position,
952                                                 transition_fragment_len,
953                                                 transition->length);
954
955 // Reverse output buffer here so transitions always render forward.
956                                         if(direction == PLAY_REVERSE)
957                                                 Resample::reverse_buffer(output.get_data(),
958                                                         transition_fragment_len);
959                                 }
960                         }
961 if(debug) printf("AModule::render %d start_position=%jd end_position=%jd fragment_len=%jd\n",
962 __LINE__,
963 start_position,
964 end_position,
965 fragment_len);
966
967                         if(direction == PLAY_REVERSE)
968                         {
969                                 if(playable_edit && start_position - fragment_len <= edit_startproject)
970                                         playable_edit = (AEdit*)playable_edit->previous;
971                         }
972                         else
973                         {
974                                 if(playable_edit && start_position + fragment_len >= edit_endproject)
975                                         playable_edit = (AEdit*)playable_edit->next;
976                         }
977                 }
978
979                 if(fragment_len > 0)
980                 {
981                         buffer_offset += fragment_len;
982                         if(direction == PLAY_FORWARD)
983                                 start_position += fragment_len;
984                         else
985                                 start_position -= fragment_len;
986                 }
987         }
988
989 if(debug) printf("AModule::render %d\n", __LINE__);
990
991         return result;
992 }
993
994
995
996
997
998
999
1000
1001