Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[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  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "bcsignals.h"
24 #include "clip.h"
25 #include "condition.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "localsession.h"
29 #include "playbackengine.h"
30 #include "preferences.h"
31 #include "tracks.h"
32 #include "transportque.h"
33
34
35 TransportCommand::TransportCommand(Preferences *preferences)
36 {
37 // In rendering we want a master EDL so settings don't get clobbered
38 // in the middle of a job.
39         edl = new EDL;
40         edl->create_objects();
41         command = 0;
42         change_type = 0;
43         this->preferences = preferences;
44         reset();
45 }
46
47 TransportCommand::~TransportCommand()
48 {
49         edl->Garbage::remove_user();
50 }
51
52 void TransportCommand::reset()
53 {
54         command = COMMAND_NONE;
55         change_type = 0;
56         playbackstart = 0;
57         start_position = 0;
58         end_position = 0;
59         infinite = 0;
60         realtime = 0;
61         resume = 0;
62         locked = 0;
63         toggle_audio = 0;
64         loop_play = 0;
65         displacement = 0;
66         speed = 0;
67 }
68
69 EDL* TransportCommand::get_edl()
70 {
71         return edl;
72 }
73
74 void TransportCommand::delete_edl()
75 {
76         edl->Garbage::remove_user();
77         edl = 0;
78 }
79
80 void TransportCommand::new_edl()
81 {
82         edl = new EDL;
83         edl->create_objects();
84 }
85
86
87 void TransportCommand::copy_from(TransportCommand *command)
88 {
89         this->command = command->command;
90         this->change_type = command->change_type;
91         this->edl->copy_all(command->edl);
92         this->start_position = command->start_position;
93         this->end_position = command->end_position;
94         this->playbackstart = command->playbackstart;
95         this->realtime = command->realtime;
96         this->resume = command->resume;
97         this->locked = command->locked;
98         this->toggle_audio = command->toggle_audio;
99         this->loop_play = command->loop_play;
100         this->displacement = command->displacement;
101         this->speed = command->speed;
102 }
103
104 TransportCommand& TransportCommand::operator=(TransportCommand &command)
105 {
106         copy_from(&command);
107         return *this;
108 }
109
110 int TransportCommand::single_frame(int command)
111 {
112         return (command == SINGLE_FRAME_FWD || command == SINGLE_FRAME_REWIND ||
113                 command == CURRENT_FRAME || command == LAST_FRAME);
114 }
115
116 int TransportCommand::get_direction(int command)
117 {
118         switch(command) {
119         case SINGLE_FRAME_FWD:
120         case NORMAL_FWD:
121         case FAST_FWD:
122         case SLOW_FWD:
123         case CURRENT_FRAME:
124                 return PLAY_FORWARD;
125
126         case SINGLE_FRAME_REWIND:
127         case NORMAL_REWIND:
128         case FAST_REWIND:
129         case SLOW_REWIND:
130         case LAST_FRAME:
131                 return PLAY_REVERSE;
132
133         default:
134                 break;
135         }
136         return PLAY_FORWARD;
137 }
138
139 float TransportCommand::get_speed(int command, float speed)
140 {
141 // fast = 2.0, slow = 0.5
142 // float my_fast_speed = 2.0;
143 // float my_slow_speed = 0.5;
144 float my_fast_speed = preferences->fast_speed;
145 float my_slow_speed = preferences->slow_speed; 
146
147         switch(command) {
148         case SLOW_FWD:
149         case SLOW_REWIND:
150                 return speed ? speed : my_slow_speed;
151
152         case NORMAL_FWD:
153         case NORMAL_REWIND:
154         case SINGLE_FRAME_FWD:
155         case SINGLE_FRAME_REWIND:
156         case CURRENT_FRAME:
157         case LAST_FRAME:
158                 return 1.;
159
160         case FAST_FWD:
161         case FAST_REWIND:
162                 return speed ? speed : my_fast_speed;
163         }
164
165         return 0.;
166 }
167
168 // Assume starting without pause
169 void TransportCommand::set_playback_range(EDL *edl, int use_inout, int do_displacement)
170 {
171         if( !edl ) edl = this->edl;
172         double length = edl->tracks->total_playable_length();
173         double frame_period = 1.0 / edl->session->frame_rate;
174         displacement = 0;
175
176         start_position = use_inout && edl->local_session->inpoint_valid() ?
177                 edl->local_session->get_inpoint() :
178                 !loop_play ? edl->local_session->get_selectionstart(1) : 0;
179         end_position = use_inout && edl->local_session->outpoint_valid() ?
180                 edl->local_session->get_outpoint() :
181                 !loop_play ? edl->local_session->get_selectionend(1) : length;
182         if( start_position >= length )
183                 length = edl->tracks->total_length();
184
185         if( command == REWIND ) {
186                 start_position = end_position = 0;
187                 command = CURRENT_FRAME;
188         }
189         else if( command == GOTO_END ) {
190                 start_position = end_position = length;
191                 command = LAST_FRAME;
192         }
193         else if( !use_inout && EQUIV(start_position, end_position) ) {
194 // starting play at or past end_position, play to end_position of media (for mixers)
195                 switch( command ) {
196                 case SLOW_FWD:
197                 case FAST_FWD:
198                 case NORMAL_FWD: {
199                         end_position = length;
200 // this prevents a crash if start_position position is after the loop when playing forwards
201                         if( edl->local_session->loop_playback &&
202                             start_position > edl->local_session->loop_end ) {
203                                 start_position = edl->local_session->loop_start;
204                         }
205                         displacement = realtime && do_displacement ? frame_period : 0;
206                         break; }
207
208                 case SLOW_REWIND:
209                 case FAST_REWIND:
210                 case NORMAL_REWIND:
211                         start_position = 0;
212 // this prevents a crash if start_position position is before the loop when playing backwards
213                         if( edl->local_session->loop_playback &&
214                             end_position <= edl->local_session->loop_start ) {
215                                         end_position = edl->local_session->loop_end;
216                         }
217                         break;
218
219                 case SINGLE_FRAME_FWD:
220                         displacement = realtime && do_displacement ? frame_period : 0;
221                 case CURRENT_FRAME:
222                 case LAST_FRAME:
223                         end_position = start_position + frame_period;
224                         break;
225
226                 case SINGLE_FRAME_REWIND:
227                         start_position = end_position - frame_period;
228                         break;
229                 }
230                 start_position += displacement;
231                 end_position += displacement;
232         }
233 //      if( start_position < 0 )
234 //              start_position = 0;
235 //      if( end_position > length )
236 //              end_position = length;
237         if( end_position < start_position )
238                 end_position = start_position;
239
240         playbackstart = get_direction() == PLAY_FORWARD ?
241                 start_position : end_position;
242 }
243
244 void TransportCommand::playback_range_adjust_inout()
245 {
246         if(edl->local_session->inpoint_valid() ||
247                 edl->local_session->outpoint_valid())
248         {
249                 playback_range_inout();
250         }
251 }
252
253 void TransportCommand::playback_range_inout()
254 {
255         if(edl->local_session->inpoint_valid())
256                 start_position = edl->local_session->get_inpoint();
257         else
258                 start_position = 0;
259
260         if(edl->local_session->outpoint_valid())
261                 end_position = edl->local_session->get_outpoint();
262         else {
263                 end_position = edl->tracks->total_playable_length();
264                 if( start_position >= end_position )
265                         end_position = edl->tracks->total_length();
266         }
267 }
268
269 void TransportCommand::playback_range_project()
270 {
271         start_position = 0;
272         end_position = edl->tracks->total_playable_length();
273 }
274
275 void TransportCommand::playback_range_1frame()
276 {
277         start_position = end_position = edl->local_session->get_selectionstart(1);
278         if( edl->session->frame_rate > 0 ) end_position += 1./edl->session->frame_rate;
279 }
280
281