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