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