Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / keyframes.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "bchash.h"
23 #include "clip.h"
24 #include "edl.h"
25 #include "edlsession.h"
26 #include "filexml.h"
27 #include "keyframe.h"
28 #include "keyframes.h"
29 #include "localsession.h"
30 #include "track.h"
31 #include "transportque.inc"
32
33 KeyFrames::KeyFrames(EDL *edl, Track *track)
34  : Autos(edl, track)
35 {
36         type = Autos::AUTOMATION_TYPE_PLUGIN;
37 }
38
39 KeyFrames::~KeyFrames()
40 {
41 }
42
43
44 KeyFrame* KeyFrames::get_prev_keyframe(int64_t position,
45         int direction)
46 {
47         KeyFrame *current = 0;
48
49 // This doesn't work because edl->selectionstart doesn't change during
50 // playback at the same rate as PluginClient::source_position.
51         if(position < 0)
52         {
53                 position = track->to_units(edl->local_session->get_selectionstart(1), 0);
54         }
55
56 // Get keyframe on or before current position
57         for(current = (KeyFrame*)last;
58                 current;
59                 current = (KeyFrame*)PREVIOUS)
60         {
61                 if(direction == PLAY_FORWARD && current->position <= position) break;
62                 else
63                 if(direction == PLAY_REVERSE && current->position < position) break;
64         }
65
66 // Nothing before current position
67         if(!current && first)
68         {
69                 current = (KeyFrame*)first;
70         }
71         else
72 // No keyframes
73         if(!current)
74         {
75                 current = (KeyFrame*)default_auto;
76         }
77
78         return current;
79 }
80
81 KeyFrame* KeyFrames::get_keyframe()
82 {
83         int64_t pos = track->to_units(edl->local_session->get_selectionstart(1), 0);
84 // Search for keyframe on or before selection
85         KeyFrame *result = get_prev_keyframe(pos, PLAY_FORWARD);
86         if( edl->session->auto_keyframes ) {
87                 if( !result || result->position != pos ||
88                     result == (KeyFrame*)default_auto )
89 // generate keyframes while tweeking, and no keyframe found at pos
90                         result = (KeyFrame*)insert_auto(pos);
91         }
92         return result;
93 }
94
95
96 void KeyFrames::update_parameter(KeyFrame *src)
97 {
98 // Create new keyframe if auto keyframes or replace entire keyframe.
99         double selection_start = edl->local_session->get_selectionstart(0);
100         double selection_end = edl->local_session->get_selectionend(0);
101         selection_start = edl->align_to_frame(selection_start, 0);
102         selection_end = edl->align_to_frame(selection_end, 0);
103
104         if( EQUIV(selection_start, selection_end) ) {
105 // Search for keyframe to write
106                 KeyFrame *dst = get_keyframe();
107                 dst->copy_data(src);
108         }
109         else {
110 // Replace changed parameter in all selected keyframes.
111                 BC_Hash *params = 0;
112                 char *text = 0, *extra = 0;
113 // Search all keyframes in selection but don't create a new one.
114                 int64_t start = track->to_units(selection_start, 0);
115                 int64_t end = track->to_units(selection_end, 0);
116                 KeyFrame *current = get_prev_keyframe(start, PLAY_FORWARD);
117 // The first one determines the changed parameters since it is the one displayed
118                 current->get_diff(src, &params, &text, &extra);
119 // Always update the first one
120                 current->update_parameter(params, text, extra);
121
122                 for( current = (KeyFrame*)NEXT; current;  current = (KeyFrame*)NEXT ) {
123                         if( current->position >= end ) break;
124                         current->update_parameter(params, text, extra);
125                 }
126                 delete params;
127                 delete [] text,
128                 delete [] extra;
129         }
130 }
131
132 Auto* KeyFrames::new_auto()
133 {
134         return new KeyFrame(edl, this);
135 }
136
137
138 void KeyFrames::dump(FILE *fp)
139 {
140         fprintf(fp,"    DEFAULT_KEYFRAME\n");
141         ((KeyFrame*)default_auto)->dump(fp);
142         fprintf(fp,"    KEYFRAMES total=%d\n", total());
143         for(KeyFrame *current = (KeyFrame*)first;
144                 current;
145                 current = (KeyFrame*)NEXT)
146         {
147                 current->dump(fp);
148         }
149 }
150