4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
25 #include "edlsession.h"
26 #include "floatauto.h"
27 #include "localsession.h"
30 #include "transportque.inc"
33 Autos::Autos(EDL *edl, Track *track)
47 while(last) delete last;
51 void Autos::create_objects()
54 default_auto = new_auto();
55 default_auto->is_default = 1;
63 Auto* Autos::append_auto()
65 return append(new_auto());
69 Auto* Autos::new_auto()
71 return new Auto(edl, this);
74 void Autos::resample(double old_rate, double new_rate)
76 for(Auto *current = first; current; current = NEXT)
78 current->position = (int64_t)((double)current->position *
85 void Autos::equivalent_output(Autos *autos, int64_t startproject, int64_t *result)
87 // Default keyframe differs
88 if(!total() && !(*default_auto == *autos->default_auto))
90 if(*result < 0 || *result > startproject) *result = startproject;
93 // Search for difference
95 for(Auto *current = first, *that_current = autos->first;
96 current || that_current;
98 that_current = that_current->next)
101 if(current && !that_current)
103 int64_t position1 = (autos->last ? autos->last->position : startproject);
104 int64_t position2 = current->position;
105 if(*result < 0 || *result > MIN(position1, position2))
106 *result = MIN(position1, position2);
110 if(!current && that_current)
112 int64_t position1 = (last ? last->position : startproject);
113 int64_t position2 = that_current->position;
114 if(*result < 0 || *result > MIN(position1, position2))
115 *result = MIN(position1, position2);
120 if(!(*current == *that_current) ||
121 current->position != that_current->position)
123 int64_t position1 = (current->previous ?
124 current->previous->position :
126 int64_t position2 = (that_current->previous ?
127 that_current->previous->position :
129 if(*result < 0 || *result > MIN(position1, position2))
130 *result = MIN(position1, position2);
137 void Autos::copy_from(Autos *autos)
139 Auto *current = autos->first, *this_current = first;
141 default_auto->copy_from(autos->default_auto);
143 // Detect common memory leak bug
144 if(autos->first && !autos->last)
146 printf("Autos::copy_from inconsistent pointers\n");
150 for(current = autos->first; current; current = NEXT)
152 //printf("Autos::copy_from 1 %p\n", current);
156 append(this_current = new_auto());
158 this_current->copy_from(current);
159 this_current = this_current->next;
162 for( ; this_current; )
164 Auto *next_current = this_current->next;
166 this_current = next_current;
171 // We don't replace it in pasting but
172 // when inserting the first EDL of a load operation we need to replace
173 // the default keyframe.
174 void Autos::insert_track(Autos *automation,
176 int64_t length_units,
180 insert(start_unit, start_unit + length_units);
182 if(replace_default) default_auto->copy_from(automation->default_auto);
183 for(Auto *current = automation->first; current; current = NEXT)
185 // fill new auto with values from current (template), interpolate values if possible
186 Auto *new_auto = insert_auto(start_unit + current->position, current);
187 // Override copy_from
188 new_auto->position = current->position + start_unit;
192 Auto* Autos::get_prev_auto(int64_t position,
197 // Get on or before position
198 if(direction == PLAY_FORWARD)
200 // Try existing result
203 while(current && current->position < position) current = NEXT;
204 while(current && current->position > position) current = PREVIOUS;
207 if(!current && first && first->position <= position)
210 current && current->position > position;
211 current = PREVIOUS) ;
213 if(!current && use_default) current = (first ? first : default_auto);
216 // Get on or after position
217 if(direction == PLAY_REVERSE)
221 while(current && current->position > position) current = PREVIOUS;
222 while(current && current->position < position) current = NEXT;
225 if(!current && last && last->position >= position)
228 current && current->position < position;
232 if(!current && use_default) current = (last ? last : default_auto);
238 Auto* Autos::get_prev_auto(int direction, Auto* ¤t)
240 double position_double = edl->local_session->get_selectionstart(1);
241 position_double = edl->align_to_frame(position_double, 0);
242 int64_t position = track->to_units(position_double, 0);
244 return get_prev_auto(position, direction, current);
247 int Autos::auto_exists_for_editing(double position)
251 if(edl->session->auto_keyframes)
253 double unit_position = position;
254 unit_position = edl->align_to_frame(unit_position, 0);
255 if (get_auto_at_position(unit_position))
266 Auto* Autos::get_auto_at_position(double position)
269 for( Auto *current=first; current; current=NEXT ) {
270 double pos = track->from_units(current->position);
271 if( edl->equivalent(position, pos) )
277 Auto* Autos::get_auto(int id)
279 Auto *current = first;
280 while( current && current->orig_id != id ) current = NEXT;
284 Auto* Autos::get_auto_for_editing(double position, int create)
287 position = edl->local_session->get_selectionstart(1);
291 get_prev_auto(track->to_units(position, 0), PLAY_FORWARD, result);
292 if( create > 0 ) create = edl->session->auto_keyframes;
293 if( create && (!result || result->is_default ||
294 !EQUIV(track->from_units(result->position), position)) ) {
295 //printf("Autos::get_auto_for_editing %p %p %p\n", default_auto, first, result);
296 position = edl->align_to_frame(position, 0);
297 result = insert_auto(track->to_units(position, 0));
299 //printf("Autos::get_auto_for_editing %p %p\n", first, default_auto);
305 Auto* Autos::get_next_auto(int64_t position, int direction, Auto* ¤t, int use_default)
307 if(direction == PLAY_FORWARD)
311 while(current && current->position > position) current = PREVIOUS;
312 while(current && current->position < position) current = NEXT;
315 if(!current && last && last->position > position)
318 current && current->position <= position;
323 if(!current && use_default) current = (last ? last : default_auto);
326 if(direction == PLAY_REVERSE)
330 while(current && current->position < position) current = NEXT;
331 while(current && current->position > position) current = PREVIOUS;
334 if(!current && first && first->position <= position)
337 current && current->position > position;
342 if(!current && use_default) current = (first ? first : default_auto);
347 Auto* Autos::insert_auto(int64_t position, Auto *templ)
349 Auto *current, *result;
351 // Test for existence
353 current && !edl->equivalent(current->position, position);
362 // Get first one on or before as a template
364 current && current->position > position;
372 insert_after(current, result = new_auto());
377 if(!current) current = default_auto;
379 insert_before(first, result = new_auto());
382 // interpolate if possible, else copy from template
383 result->interpolate_from(0, 0, position, templ);
385 if( !templ && result->is_floatauto() ) {
386 FloatAuto *floatauto = (FloatAuto *)result;
387 FloatAuto::t_mode new_mode =
388 edl->local_session->playback_start >= 0 &&
389 edl->local_session->playback_end < 0 ? FloatAuto::SMOOTH :
390 (FloatAuto::t_mode) edl->local_session->floatauto_type;
391 floatauto->change_curve_mode(new_mode, 0);
402 void Autos::clear_all()
404 while( last ) delete last;
409 int Autos::insert(int64_t start, int64_t end)
412 Auto *current = first;
414 for( ; current && current->position < start; current = NEXT)
417 length = end - start;
419 for(; current; current = NEXT)
421 current->position += length;
426 void Autos::paste(int64_t start,
436 //printf("Autos::paste %d start=%jd\n", __LINE__, start);
438 result = file->read_tag();
440 if(!result && !file->tag.title_is("/AUTO"))
443 if(file->tag.get_title()[0] == '/')
448 if(!strcmp(file->tag.get_title(), "AUTO"))
452 // Paste first auto into default
453 if(default_only && total == 0)
455 current = default_auto;
458 // Paste default auto into default
461 int64_t position = Units::to_int64(
462 (double)file->tag.get_property("POSITION", 0) *
465 // Paste active auto into track
466 current = insert_auto(position);
480 int Autos::paste_silence(int64_t start, int64_t end)
486 int Autos::copy(int64_t start,
492 // First auto always loaded with default
493 //printf("Autos::copy %d %d %d\n", __LINE__, default_only, active_only);
494 if(default_only || (!active_only && !default_only))
496 default_auto->copy(0, 0, file, default_only);
499 //printf("Autos::copy 10 %d %d %p\n", default_only, start, autoof(start));
500 if(active_only || (!default_only && !active_only))
502 Auto *current = autoof(start);
504 while( current && current->position <= end ) {
505 // Want to copy single keyframes by putting the cursor on them
506 if( current->position >= start && current->position <= end ) {
507 current->copy(start, end, file, default_only);
512 // Copy default auto again to make it the active auto on the clipboard
515 // Need to force position to 0 for the case of plugins
516 // and default status to 0.
517 // default_auto->copy(0, 0, file, default_only);
519 //printf("Autos::copy 20\n");
524 // Remove 3 consecutive autos with the same value
525 // Remove autos which are out of order
526 void Autos::optimize()
531 // Default auto should always be at 0
532 default_auto->position = 0;
539 for(Auto *current = first; current; current = NEXT)
541 // Get 3rd consecutive auto of equal value
544 if(*current == *PREVIOUS)
556 if(done && current->position <= PREVIOUS->position)
567 void Autos::remove_nonsequential(Auto *keyframe)
569 if((keyframe->next && keyframe->next->position <= keyframe->position) ||
570 (keyframe->previous && keyframe->previous->position >= keyframe->position))
577 void Autos::set_automation_mode(int64_t start, int64_t end, int mode)
581 void Autos::clear(int64_t start,
586 Auto *next, *current;
587 length = end - start;
590 current = autoof(start);
592 // If a range is selected don't delete the ending keyframe but do delete
593 // the beginning keyframe because shifting end handle forward shouldn't
594 // delete the first keyframe of the next edit.
597 ((end != start && current->position < end) ||
598 (end == start && current->position <= end)))
605 while(current && shift_autos)
607 current->position -= length;
612 int Autos::clear_auto(int64_t position)
615 current = autoof(position);
616 return current->position==position ? (remove(current), 1) : 0;
620 int Autos::load(FileXML *file)
623 remove(last); // remove any existing autos
625 int result = 0, first_auto = 1;
629 result = file->read_tag();
631 if(!result && !file->tag.title_is("/AUTO"))
633 // First tag with leading / is taken as end of autos
634 if(/* strstr(file->tag.get_title(), "AUTOS") && */
636 file->tag.get_title()[0] == '/')
641 if(!strcmp(file->tag.get_title(), "AUTO"))
645 default_auto->load(file);
646 default_auto->position = 0;
651 current = append(new_auto());
652 current->position = file->tag.get_property("POSITION", (int64_t)0);
666 int Autos::slope_adjustment(int64_t ax, double slope)
668 return (int)(ax * slope);
672 int Autos::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
676 for(current = first; current && scale_autos; current = NEXT)
678 // if(current->position >= start && current->position <= end)
680 current->position = (int64_t)((current->position - start) * rate_scale + start + 0.5);
686 Auto* Autos::autoof(int64_t position)
691 current && current->position < position;
696 return current; // return 0 on failure
699 Auto* Autos::nearest_before(int64_t position)
702 for(current = last; current && current->position >= position; current = PREVIOUS);
703 return current; // return 0 on failure
706 Auto* Autos::nearest_after(int64_t position)
709 for(current = first; current && current->position <= position; current = NEXT);
710 return current; // return 0 on failure
713 int Autos::get_neighbors(int64_t start, int64_t end, Auto **before, Auto **after)
715 if(*before == 0) *before = first;
716 if(*after == 0) *after = last;
718 while(*before && (*before)->next && (*before)->next->position <= start)
719 *before = (*before)->next;
721 while(*after && (*after)->previous && (*after)->previous->position >= end)
722 *after = (*after)->previous;
724 while(*before && (*before)->position > start) *before = (*before)->previous;
726 while(*after && (*after)->position < end) *after = (*after)->next;
730 int Autos::automation_is_constant(int64_t start, int64_t end)
735 double Autos::get_automation_constant(int64_t start, int64_t end)
741 int Autos::init_automation(int64_t &buffer_position,
742 int64_t &input_start,
746 int64_t input_position,
754 // set start and end boundaries for automation info
755 input_start = reverse ? input_position - buffer_len : input_position;
756 input_end = reverse ? input_position : input_position + buffer_len;
758 // test automation for constant value
759 // and set up *before and *after
762 if(automation_is_constant(input_start, input_end))
764 constant += get_automation_constant(input_start, input_end);
772 int Autos::init_slope(Auto **current_auto,
775 double &slope_position,
776 int64_t &input_start,
783 *current_auto = reverse ? *after : *before;
784 // no auto before start so use first auto in range
785 // already know there is an auto since automation isn't constant
788 *current_auto = reverse ? last : first;
789 // slope_value = (*current_auto)->value;
790 slope_start = input_start;
795 // otherwise get the first slope point and advance auto
796 // slope_value = (*current_auto)->value;
797 slope_start = (*current_auto)->position;
798 slope_position = reverse ? slope_start - input_end : input_start - slope_start;
799 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
805 int Autos::get_slope(Auto **current_auto,
811 int64_t buffer_position,
817 slope_end = reverse ? slope_start - (*current_auto)->position : (*current_auto)->position - slope_start;
819 // slope = ((*current_auto)->value - slope_value) / slope_end;
826 slope_end = buffer_len - buffer_position;
831 int Autos::advance_slope(Auto **current_auto,
834 double &slope_position,
839 slope_start = (*current_auto)->position;
840 // slope_value = (*current_auto)->value;
841 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
847 int64_t Autos::get_length()
850 return last->position + 1;
855 void Autos::get_extents(float *min,
857 int *coords_undefined,
865 void Autos::dump(FILE *fp)