add libtool prereq, tweak cmake config in 3rdparty, segv dragging silence
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / transportque.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 "bcsignals.h"
23 #include "clip.h"
24 #include "condition.h"
25 #include "edl.h"
26 #include "edlsession.h"
27 #include "localsession.h"
28 #include "playbackengine.h"
29 #include "tracks.h"
30 #include "transportque.h"
31
32 TransportCommand::TransportCommand()
33 {
34 // In rendering we want a master EDL so settings don't get clobbered
35 // in the middle of a job.
36         edl = new EDL;
37         edl->create_objects();
38         command = 0;
39         change_type = 0;
40         reset();
41 }
42
43 TransportCommand::~TransportCommand()
44 {
45         edl->Garbage::remove_user();
46 }
47
48 void TransportCommand::reset()
49 {
50         playbackstart = 0;
51         start_position = 0;
52         end_position = 0;
53         infinite = 0;
54         realtime = 0;
55         resume = 0;
56         toggle_audio = 0;
57         loop_play = 0;
58         speed = 0;
59 // Don't reset the change type for commands which don't perform the change
60         if(command != STOP) change_type = 0;
61         command = COMMAND_NONE;
62 }
63
64 EDL* TransportCommand::get_edl()
65 {
66         return edl;
67 }
68
69 void TransportCommand::delete_edl()
70 {
71         edl->Garbage::remove_user();
72         edl = 0;
73 }
74
75 void TransportCommand::new_edl()
76 {
77         edl = new EDL;
78         edl->create_objects();
79 }
80
81
82 void TransportCommand::copy_from(TransportCommand *command)
83 {
84         this->command = command->command;
85         this->change_type = command->change_type;
86         this->edl->copy_all(command->edl);
87         this->start_position = command->start_position;
88         this->end_position = command->end_position;
89         this->playbackstart = command->playbackstart;
90         this->realtime = command->realtime;
91         this->resume = command->resume;
92         this->toggle_audio = command->toggle_audio;
93         this->loop_play = command->loop_play;
94         this->displacement = command->displacement;
95         this->speed = command->speed;
96 }
97
98 TransportCommand& TransportCommand::operator=(TransportCommand &command)
99 {
100         copy_from(&command);
101         return *this;
102 }
103
104 int TransportCommand::single_frame(int command)
105 {
106         return (command == SINGLE_FRAME_FWD || command == SINGLE_FRAME_REWIND ||
107                 command == CURRENT_FRAME || command == LAST_FRAME);
108 }
109
110 int TransportCommand::get_direction(int command)
111 {
112         switch(command) {
113         case SINGLE_FRAME_FWD:
114         case NORMAL_FWD:
115         case FAST_FWD:
116         case SLOW_FWD:
117         case CURRENT_FRAME:
118                 return PLAY_FORWARD;
119
120         case SINGLE_FRAME_REWIND:
121         case NORMAL_REWIND:
122         case FAST_REWIND:
123         case SLOW_REWIND:
124         case LAST_FRAME:
125                 return PLAY_REVERSE;
126
127         default:
128                 break;
129         }
130         return PLAY_FORWARD;
131 }
132
133 float TransportCommand::get_speed(int command, float speed)
134 {
135         switch(command) {
136         case SLOW_FWD:
137         case SLOW_REWIND:
138                 return speed ? speed : 0.5;
139
140         case NORMAL_FWD:
141         case NORMAL_REWIND:
142         case SINGLE_FRAME_FWD:
143         case SINGLE_FRAME_REWIND:
144         case CURRENT_FRAME:
145         case LAST_FRAME:
146                 return 1.;
147
148         case FAST_FWD:
149         case FAST_REWIND:
150                 return speed ? speed : 2.;
151         }
152
153         return 0.;
154 }
155
156 // Assume starting without pause
157 void TransportCommand::set_playback_range(EDL *edl, int use_inout, int do_displacement)
158 {
159         if( !edl ) edl = this->edl;
160         double length = edl->tracks->total_playable_length();
161         double frame_period = 1.0 / edl->session->frame_rate;
162         displacement = 0;
163
164         start_position = use_inout && edl->local_session->inpoint_valid() ?
165                 edl->local_session->get_inpoint() :
166                 !loop_play ? edl->local_session->get_selectionstart(1) : 0;
167         end_position = use_inout && edl->local_session->outpoint_valid() ?
168                 edl->local_session->get_outpoint() :
169                 !loop_play ? edl->local_session->get_selectionend(1) : length;
170
171         if( !use_inout && EQUIV(start_position, end_position) ) {
172 // starting play at or past end_position, play to end_position of media (for mixers)
173                 if( start_position >= length )
174                         length = edl->tracks->total_length();
175                 switch( command ) {
176                 case SLOW_FWD:
177                 case FAST_FWD:
178                 case NORMAL_FWD: {
179                         end_position = length;
180 // this prevents a crash if start_position position is after the loop when playing forwards
181                         if( edl->local_session->loop_playback &&
182                             start_position > edl->local_session->loop_end ) {
183                                 start_position = edl->local_session->loop_start;
184                         }
185                         break; }
186
187                 case SLOW_REWIND:
188                 case FAST_REWIND:
189                 case NORMAL_REWIND:
190                         start_position = 0;
191 // this prevents a crash if start_position position is before the loop when playing backwards
192                         if( edl->local_session->loop_playback &&
193                             end_position <= edl->local_session->loop_start ) {
194                                         end_position = edl->local_session->loop_end;
195                         }
196                         break;
197
198                 case CURRENT_FRAME:
199                 case LAST_FRAME:
200                 case SINGLE_FRAME_FWD:
201                         end_position = start_position + frame_period;
202                         break;
203
204                 case SINGLE_FRAME_REWIND:
205                         start_position = end_position - frame_period;
206                         break;
207                 }
208
209                 if( realtime && do_displacement ) {
210                         if( (command != CURRENT_FRAME && get_direction() == PLAY_FORWARD ) ||
211                             (command != LAST_FRAME    && get_direction() == PLAY_REVERSE ) ) {
212                                 start_position += frame_period;
213                                 end_position += frame_period;
214                                 displacement = 1;
215                         }
216                 }
217         }
218
219 //      if( start_position < 0 )
220 //              start_position = 0;
221 //      if( end_position > length )
222 //              end_position = length;
223         if( end_position < start_position )
224                 end_position = start_position;
225
226         playbackstart = get_direction() == PLAY_FORWARD ?
227                 start_position : end_position;
228 }
229
230 void TransportCommand::playback_range_adjust_inout()
231 {
232         if(edl->local_session->inpoint_valid() ||
233                 edl->local_session->outpoint_valid())
234         {
235                 playback_range_inout();
236         }
237 }
238
239 void TransportCommand::playback_range_inout()
240 {
241         if(edl->local_session->inpoint_valid())
242                 start_position = edl->local_session->get_inpoint();
243         else
244                 start_position = 0;
245
246         if(edl->local_session->outpoint_valid())
247                 end_position = edl->local_session->get_outpoint();
248         else {
249                 end_position = edl->tracks->total_playable_length();
250                 if( start_position >= end_position )
251                         end_position = edl->tracks->total_length();
252         }
253 }
254
255 void TransportCommand::playback_range_project()
256 {
257         start_position = 0;
258         end_position = edl->tracks->total_playable_length();
259 }
260
261 void TransportCommand::playback_range_1frame()
262 {
263         start_position = end_position = edl->local_session->get_selectionstart(1);
264         if( edl->session->frame_rate > 0 ) end_position += 1./edl->session->frame_rate;
265 }
266
267