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
22 #include "bcsignals.h"
24 #include "condition.h"
26 #include "edlsession.h"
27 #include "localsession.h"
29 #include "transportque.h"
31 TransportCommand::TransportCommand()
33 // In rendering we want a master EDL so settings don't get clobbered
34 // in the middle of a job.
36 edl->create_objects();
42 TransportCommand::~TransportCommand()
44 edl->Garbage::remove_user();
47 void TransportCommand::reset()
58 // Don't reset the change type for commands which don't perform the change
59 if(command != STOP) change_type = 0;
60 command = COMMAND_NONE;
63 EDL* TransportCommand::get_edl()
68 void TransportCommand::delete_edl()
70 edl->Garbage::remove_user();
74 void TransportCommand::new_edl()
77 edl->create_objects();
81 void TransportCommand::copy_from(TransportCommand *command)
83 this->command = command->command;
84 this->change_type = command->change_type;
85 this->edl->copy_all(command->edl);
86 this->start_position = command->start_position;
87 this->end_position = command->end_position;
88 this->playbackstart = command->playbackstart;
89 this->realtime = command->realtime;
90 this->resume = command->resume;
91 this->audio_toggle = command->audio_toggle;
92 this->play_loop = command->play_loop;
93 this->displacement = command->displacement;
96 TransportCommand& TransportCommand::operator=(TransportCommand &command)
102 int TransportCommand::single_frame(int command)
104 return (command == SINGLE_FRAME_FWD || command == SINGLE_FRAME_REWIND ||
105 command == CURRENT_FRAME || command == LAST_FRAME);
107 int TransportCommand::single_frame()
109 return single_frame(command);
113 int TransportCommand::get_direction(int command)
116 case SINGLE_FRAME_FWD:
123 case SINGLE_FRAME_REWIND:
135 int TransportCommand::get_direction()
137 return get_direction(command);
140 float TransportCommand::get_speed(int command)
149 case SINGLE_FRAME_FWD:
150 case SINGLE_FRAME_REWIND:
162 float TransportCommand::get_speed()
164 return get_speed(command);
167 // Assume starting without pause
168 void TransportCommand::set_playback_range(EDL *edl,
169 int use_inout, int toggle_audio, int loop_play, int use_displacement)
171 if(!edl) edl = this->edl;
172 double length = edl->tracks->total_playable_length();
173 double frame_period = 1.0 / edl->session->frame_rate;
176 audio_toggle = toggle_audio;
177 play_loop = loop_play;
179 start_position = use_inout && edl->local_session->inpoint_valid() ?
180 edl->local_session->get_inpoint() :
181 !loop_play ? edl->local_session->get_selectionstart(1) : 0;
182 end_position = use_inout && edl->local_session->outpoint_valid() ?
183 edl->local_session->get_outpoint() :
184 !loop_play ? edl->local_session->get_selectionend(1) : length;
186 if( !use_inout && EQUIV(start_position, end_position) ) {
187 // starting play at or past end_position, play to end_position of media (for mixers)
188 if( start_position >= length )
189 length = edl->tracks->total_length();
194 end_position = length;
195 // this prevents a crash if start_position position is after the loop when playing forwards
196 if( edl->local_session->loop_playback &&
197 start_position > edl->local_session->loop_end ) {
198 start_position = edl->local_session->loop_start;
206 // this prevents a crash if start_position position is before the loop when playing backwards
207 if( edl->local_session->loop_playback &&
208 end_position <= edl->local_session->loop_start ) {
209 end_position = edl->local_session->loop_end;
215 case SINGLE_FRAME_FWD:
216 end_position = start_position + frame_period;
219 case SINGLE_FRAME_REWIND:
220 start_position = end_position - frame_period;
224 if( use_displacement && (
225 (command != CURRENT_FRAME && get_direction() == PLAY_FORWARD ) ||
226 (command != LAST_FRAME && get_direction() == PLAY_REVERSE ) ) ) {
227 start_position += frame_period;
228 end_position += frame_period;
233 if( end_position < start_position )
234 end_position = start_position;
236 playbackstart = get_direction() == PLAY_FORWARD ?
237 start_position : end_position;
240 void TransportCommand::playback_range_adjust_inout()
242 if(edl->local_session->inpoint_valid() ||
243 edl->local_session->outpoint_valid())
245 playback_range_inout();
249 void TransportCommand::playback_range_inout()
251 if(edl->local_session->inpoint_valid())
252 start_position = edl->local_session->get_inpoint();
256 if(edl->local_session->outpoint_valid())
257 end_position = edl->local_session->get_outpoint();
259 end_position = edl->tracks->total_playable_length();
260 if( start_position >= end_position )
261 end_position = edl->tracks->total_length();
265 void TransportCommand::playback_range_project()
268 end_position = edl->tracks->total_playable_length();
271 void TransportCommand::playback_range_1frame()
273 start_position = end_position = edl->local_session->get_selectionstart(1);
274 if( edl->session->frame_rate > 0 ) end_position += 1./edl->session->frame_rate;
278 TransportQue::TransportQue()
280 input_lock = new Condition(1, "TransportQue::input_lock");
281 output_lock = new Condition(0, "TransportQue::output_lock", 1);
284 TransportQue::~TransportQue()
290 int TransportQue::send_command(int command, int change_type,
291 EDL *new_edl, int realtime, int resume, int use_inout,
292 int toggle_audio, int loop_play, int use_displacement)
294 input_lock->lock("TransportQue::send_command 1");
295 this->command.command = command;
296 // Mutually exclusive operation
297 this->command.change_type |= change_type;
298 this->command.realtime = realtime;
299 this->command.resume = resume;
303 // Just change the EDL if the change requires it because renderengine
304 // structures won't point to the new EDL otherwise and because copying the
305 // EDL for every cursor movement is slow.
306 if(change_type == CHANGE_EDL ||
307 (uint32_t)change_type == CHANGE_ALL)
310 this->command.get_edl()->copy_all(new_edl);
313 if(change_type == CHANGE_PARAMS)
315 this->command.get_edl()->synchronize_params(new_edl);
318 // Set playback range
319 this->command.set_playback_range(new_edl, use_inout,
320 toggle_audio, loop_play, use_displacement);
323 input_lock->unlock();
325 output_lock->unlock();
329 void TransportQue::update_change_type(int change_type)
331 input_lock->lock("TransportQue::update_change_type");
332 this->command.change_type |= change_type;
333 input_lock->unlock();