shift keypad toggles audio, xtion masks, render+prefs widget placement
[goodguy/history.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 "tracks.h"
29 #include "transportque.h"
30
31 TransportCommand::TransportCommand()
32 {
33 // In rendering we want a master EDL so settings don't get clobbered
34 // in the middle of a job.
35         edl = new EDL;
36         edl->create_objects();
37         command = 0;
38         change_type = 0;
39         reset();
40 }
41
42 TransportCommand::~TransportCommand()
43 {
44         edl->Garbage::remove_user();
45 }
46
47 void TransportCommand::reset()
48 {
49         playbackstart = 0;
50         start_position = 0;
51         end_position = 0;
52         infinite = 0;
53         realtime = 0;
54         resume = 0;
55         audio_toggle = 0;
56 // Don't reset the change type for commands which don't perform the change
57         if(command != STOP) change_type = 0;
58         command = COMMAND_NONE;
59 }
60
61 EDL* TransportCommand::get_edl()
62 {
63         return edl;
64 }
65
66 void TransportCommand::delete_edl()
67 {
68         edl->Garbage::remove_user();
69         edl = 0;
70 }
71
72 void TransportCommand::new_edl()
73 {
74         edl = new EDL;
75         edl->create_objects();
76 }
77
78
79 void TransportCommand::copy_from(TransportCommand *command)
80 {
81         this->command = command->command;
82         this->change_type = command->change_type;
83         this->edl->copy_all(command->edl);
84         this->start_position = command->start_position;
85         this->end_position = command->end_position;
86         this->playbackstart = command->playbackstart;
87         this->realtime = command->realtime;
88         this->resume = command->resume;
89         this->audio_toggle = command->audio_toggle;
90 }
91
92 TransportCommand& TransportCommand::operator=(TransportCommand &command)
93 {
94         copy_from(&command);
95         return *this;
96 }
97
98 int TransportCommand::single_frame()
99 {
100         return (command == SINGLE_FRAME_FWD ||
101                 command == SINGLE_FRAME_REWIND ||
102                 command == CURRENT_FRAME);
103 }
104
105
106 int TransportCommand::get_direction()
107 {
108         switch(command)
109         {
110                 case SINGLE_FRAME_FWD:
111                 case NORMAL_FWD:
112                 case FAST_FWD:
113                 case SLOW_FWD:
114                 case CURRENT_FRAME:
115                         return PLAY_FORWARD;
116
117                 case SINGLE_FRAME_REWIND:
118                 case NORMAL_REWIND:
119                 case FAST_REWIND:
120                 case SLOW_REWIND:
121                         return PLAY_REVERSE;
122
123                 default:
124                         break;
125         }
126         return PLAY_FORWARD;
127 }
128
129 float TransportCommand::get_speed()
130 {
131         switch(command)
132         {
133                 case SLOW_FWD:
134                 case SLOW_REWIND:
135                         return 0.5;
136
137                 case NORMAL_FWD:
138                 case NORMAL_REWIND:
139                 case SINGLE_FRAME_FWD:
140                 case SINGLE_FRAME_REWIND:
141                 case CURRENT_FRAME:
142                         return 1.;
143
144                 case FAST_FWD:
145                 case FAST_REWIND:
146                         return 2.;
147         }
148
149         return 0.;
150 }
151
152 // Assume starting without pause
153 void TransportCommand::set_playback_range(EDL *edl, int use_inout, int toggle_audio)
154 {
155         if(!edl) edl = this->edl;
156
157         switch(command)
158         {
159                 case SLOW_FWD:
160                 case FAST_FWD:
161                 case NORMAL_FWD:
162                         start_position = edl->local_session->get_selectionstart(1);
163                         if(EQUIV(edl->local_session->get_selectionend(1), edl->local_session->get_selectionstart(1)))
164                                 end_position = edl->tracks->total_playable_length();
165                         else
166                                 end_position = edl->local_session->get_selectionend(1);
167 // this prevents a crash if start position is after the loop when playing forwards
168                     if (edl->local_session->loop_playback &&
169                                 start_position > edl->local_session->loop_end)
170                         {
171                                     start_position = edl->local_session->loop_start;
172                         }
173                         break;
174
175                 case SLOW_REWIND:
176                 case FAST_REWIND:
177                 case NORMAL_REWIND:
178                         end_position = edl->local_session->get_selectionend(1);
179                         if(EQUIV(edl->local_session->get_selectionend(1), edl->local_session->get_selectionstart(1)))
180                                 start_position = 0;
181                         else
182                                 start_position = edl->local_session->get_selectionstart(1);
183
184 // this prevents a crash if start position is before the loop when playing backwards
185                         if (edl->local_session->loop_playback &&
186                                 end_position <= edl->local_session->loop_start)
187                         {
188                                         end_position = edl->local_session->loop_end;
189                         }
190                         break;
191
192                 case CURRENT_FRAME:
193                 case SINGLE_FRAME_FWD:
194                         start_position = edl->local_session->get_selectionstart(1);
195                         end_position = start_position +
196                                 1.0 /
197                                 edl->session->frame_rate;
198                         break;
199
200                 case SINGLE_FRAME_REWIND:
201                         start_position = edl->local_session->get_selectionend(1);
202                         end_position = start_position -
203                                 1.0 /
204                                 edl->session->frame_rate;
205                         break;
206         }
207
208
209         if(use_inout)
210         {
211                 if(edl->local_session->inpoint_valid())
212                         start_position = edl->local_session->get_inpoint();
213                 if(edl->local_session->outpoint_valid())
214                         end_position = edl->local_session->get_outpoint();
215         }
216
217         switch(get_direction())
218         {
219                 case PLAY_FORWARD:
220                         playbackstart = start_position;
221                         break;
222
223                 case PLAY_REVERSE:
224                         playbackstart = end_position;
225                         break;
226         }
227
228         audio_toggle = toggle_audio;
229 }
230
231 void TransportCommand::playback_range_adjust_inout()
232 {
233         if(edl->local_session->inpoint_valid() ||
234                 edl->local_session->outpoint_valid())
235         {
236                 playback_range_inout();
237         }
238 }
239
240 void TransportCommand::playback_range_inout()
241 {
242         if(edl->local_session->inpoint_valid())
243                 start_position = edl->local_session->get_inpoint();
244         else
245                 start_position = 0;
246
247         if(edl->local_session->outpoint_valid())
248                 end_position = edl->local_session->get_outpoint();
249         else
250                 end_position = edl->tracks->total_playable_length();
251 }
252
253 void TransportCommand::playback_range_project()
254 {
255         start_position = 0;
256         end_position = edl->tracks->total_playable_length();
257 }
258
259 void TransportCommand::playback_range_1frame()
260 {
261         start_position = end_position = edl->local_session->get_selectionstart(1);
262         if( edl->session->frame_rate > 0 ) end_position += 1./edl->session->frame_rate;
263 }
264
265
266 TransportQue::TransportQue()
267 {
268         input_lock = new Condition(1, "TransportQue::input_lock");
269         output_lock = new Condition(0, "TransportQue::output_lock", 1);
270 }
271
272 TransportQue::~TransportQue()
273 {
274         delete input_lock;
275         delete output_lock;
276 }
277
278 int TransportQue::send_command(int command, int change_type, EDL *new_edl,
279                 int realtime, int resume, int use_inout, int toggle_audio)
280 {
281         input_lock->lock("TransportQue::send_command 1");
282         this->command.command = command;
283 // Mutually exclusive operation
284         this->command.change_type |= change_type;
285         this->command.realtime = realtime;
286         this->command.resume = resume;
287
288         if(new_edl)
289         {
290 // Just change the EDL if the change requires it because renderengine
291 // structures won't point to the new EDL otherwise and because copying the
292 // EDL for every cursor movement is slow.
293                 if(change_type == CHANGE_EDL ||
294                         (uint32_t)change_type == CHANGE_ALL)
295                 {
296 // Copy EDL
297                         this->command.get_edl()->copy_all(new_edl);
298                 }
299                 else
300                 if(change_type == CHANGE_PARAMS)
301                 {
302                         this->command.get_edl()->synchronize_params(new_edl);
303                 }
304
305 // Set playback range
306                 this->command.set_playback_range(new_edl, use_inout, toggle_audio);
307         }
308
309         input_lock->unlock();
310
311         output_lock->unlock();
312         return 0;
313 }
314
315 void TransportQue::update_change_type(int change_type)
316 {
317         input_lock->lock("TransportQue::update_change_type");
318         this->command.change_type |= change_type;
319         input_lock->unlock();
320 }