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