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