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