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