r105: This commit was manufactured by cvs2svn to create tag
[cinelerra_cv/mob.git] / hvirtual / cinelerra / playbackengine.C
blob3af58ab69e0b488e59cf653ac1db4cb19c419fa5
1 #include "cache.h"
2 #include "defaults.h"
3 #include "edl.h"
4 #include "edlsession.h"
5 #include "localsession.h"
6 #include "mbuttons.h"
7 #include "mwindow.h"
8 #include "mwindowgui.h"
9 #include "patchbay.h"
10 #include "tracking.h"
11 #include "playbackengine.h"
12 #include "playtransport.h"
13 #include "preferences.h"
14 #include "renderengine.h"
15 #include "mainsession.h"
16 #include "trackcanvas.h"
17 #include "transportque.h"
18 #include "videodevice.h"
19 #include "vrender.h"
22 PlaybackEngine::PlaybackEngine(MWindow *mwindow, Canvas *output)
23  : Thread()
25         this->mwindow = mwindow;
26         this->output = output;
27         is_playing_back = 0;
28         tracking_position = 0;
29         tracking_active = 0;
30         audio_cache = 0;
31         video_cache = 0;
32         last_command = STOP;
33         Thread::set_synchronous(1);
36 PlaybackEngine::~PlaybackEngine()
38 //printf("PlaybackEngine::~PlaybackEngine 1\n");
39         done = 1;
40         que->send_command(STOP,
41                 CHANGE_NONE, 
42                 0,
43                 0);
44         interrupt_playback();
45 //printf("PlaybackEngine::~PlaybackEngine 1\n");
46         Thread::join();
47 //printf("PlaybackEngine::~PlaybackEngine 1\n");
48         delete preferences;
49 //printf("PlaybackEngine::~PlaybackEngine 1\n");
50         delete command;
51 //printf("PlaybackEngine::~PlaybackEngine 1\n");
52         delete que;
53 //printf("PlaybackEngine::~PlaybackEngine 1\n");
54         delete_render_engines();
55 //printf("PlaybackEngine::~PlaybackEngine 1\n");
56         if(audio_cache) delete audio_cache;
57 //printf("PlaybackEngine::~PlaybackEngine 1\n");
58         if(video_cache) delete video_cache;
59 //printf("PlaybackEngine::~PlaybackEngine 2\n");
62 int PlaybackEngine::create_objects()
64         int result = 0;
65         preferences = new Preferences;
66         command = new TransportCommand;
67         que = new TransportQue;
68 // Set the first change to maximum
69         que->command.change_type = CHANGE_ALL;
71         *preferences = *mwindow->preferences;
73         done = 0;
74         start_lock.lock();
75 //printf("PlaybackEngine::create_objects 1\n");
76         Thread::start();
77 //printf("PlaybackEngine::create_objects 1\n");
78         start_lock.lock();
79 //printf("PlaybackEngine::create_objects 1\n");
80         start_lock.unlock();
81 //printf("PlaybackEngine::create_objects 1\n");
82         return result;
86 int PlaybackEngine::create_render_engines()
88 //printf("PlaybackEngine::create_render_engines 1 %d\n", command->edl->session->playback_strategy);
89 // Fix playback configurations
90         int playback_strategy = command->get_edl()->session->playback_strategy;
91         int current_vchannel = 0;
92         int current_achannel = 0;
94         delete_render_engines();
97 //printf("PlaybackEngine::create_render_engines %d\n", command->get_edl()->session->playback_config[playback_strategy].total);
98         for(int i = 0; 
99                 i < command->get_edl()->session->playback_config[playback_strategy].total; 
100                 i++)
101         {
102                 RenderEngine *engine = new RenderEngine(this,
103                         preferences, 
104                         command, 
105                         output,
106                         mwindow->plugindb,
107                         &mwindow->channeldb_buz,
108                         i);  
109                 render_engines.append(engine);
110         }
111         return 0;
114 void PlaybackEngine::delete_render_engines()
116         render_engines.remove_all_objects();
119 void PlaybackEngine::arm_render_engines()
121         int current_achannel = 0, current_vchannel = 0;
122         for(int i = 0; i < render_engines.total; i++)
123         {
124 //printf("PlaybackEngine::arm_render_engines %ld\n", command->playbackstart);
125                 render_engines.values[i]->arm_command(command,
126                         current_achannel,
127                         current_vchannel);
128         }
131 void PlaybackEngine::start_render_engines()
133 //printf("PlaybackEngine::start_render_engines 1 %d\n", render_engines.total);
134         for(int i = 0; i < render_engines.total; i++)
135         {
136                 render_engines.values[i]->start_command();
137         }
140 void PlaybackEngine::wait_render_engines()
142 //printf("PlaybackEngine::wait_render_engines 1 %d %d\n", command->command, command->realtime);
143         if(command->realtime)
144         {
145                 for(int i = 0; i < render_engines.total; i++)
146                 {
147 //printf("PlaybackEngine::wait_render_engines 2 %p %d\n", render_engines.values[i], render_engines.values[i]->get_tid());
148                         render_engines.values[i]->join();
149                 }
150 //printf("PlaybackEngine::wait_render_engines 3 %d\n", render_engines.total);
151         }
154 void PlaybackEngine::create_cache()
156         if(audio_cache) delete audio_cache;
157         audio_cache = 0;
158         if(video_cache) delete video_cache;
159         video_cache = 0;
160         if(!audio_cache) 
161                 audio_cache = new CICache(command->get_edl(), preferences, mwindow->plugindb);
162         else
163                 audio_cache->set_edl(command->get_edl());
165         if(!video_cache) 
166                 video_cache = new CICache(command->get_edl(), preferences, mwindow->plugindb);
167         else
168                 video_cache->set_edl(command->get_edl());
172 void PlaybackEngine::perform_change()
174 //printf("PlaybackEngine::perform_change 1 %x\n", command->change_type);
175         switch(command->change_type)
176         {
177                 case CHANGE_ALL:
178                         create_cache();
179                 case CHANGE_EDL:
180                         audio_cache->set_edl(command->get_edl());
181                         video_cache->set_edl(command->get_edl());
182 //printf("PlaybackEngine::perform_change 1\n");
183                         create_render_engines();
184                 case CHANGE_PARAMS:
185 //printf("PlaybackEngine::perform_change 1\n");
186                         if(command->change_type != CHANGE_EDL &&
187                                 command->change_type != CHANGE_ALL)
188                                 for(int i = 0; i < render_engines.total; i++)
189                                         render_engines.values[i]->edl->synchronize_params(command->get_edl());
190                 case CHANGE_NONE:
191 //printf("PlaybackEngine::perform_change 2\n");
192                         break;
193         }
196 void PlaybackEngine::sync_parameters(EDL *edl)
198 // TODO: lock out render engine from keyframe deletions
199         for(int i = 0; i < render_engines.total; i++)
200                 render_engines.values[i]->edl->synchronize_params(edl);
204 void PlaybackEngine::interrupt_playback(int wait_tracking)
206 //printf("PlaybackEngine::interrupt_playback 1\n");
207         for(int i = 0; i < render_engines.total; i++)
208                 render_engines.values[i]->interrupt_playback();
210 // Stop pausing
211         pause_lock.unlock();
213 // Wait for tracking to finish if it is running
214 //printf("PlaybackEngine::interrupt_playback 2\n");
215         if(wait_tracking)
216         {
217                 tracking_done.lock();
218                 tracking_done.unlock();
219         }
220 //printf("PlaybackEngine::interrupt_playback 3\n");
224 // Return 1 if levels exist
225 int PlaybackEngine::get_output_levels(double *levels, long position)
227         int result = 0;
228         for(int j = 0; j < render_engines.total; j++)
229         {
230                 if(render_engines.values[j]->do_audio)
231                 {
232                         result = 1;
233                         render_engines.values[j]->get_output_levels(levels, position);
234                 }
235         }
236         return result;
240 int PlaybackEngine::get_module_levels(ArrayList<double> *module_levels, long position)
242         int result = 0;
243         for(int j = 0; j < render_engines.total; j++)
244         {
245                 if(render_engines.values[j]->do_audio)
246                 {
247                         result = 1;
248                         render_engines.values[j]->get_module_levels(module_levels, position);
249                         break;
250                 }
251         }
252         return result;
255 int PlaybackEngine::brender_available(long position)
257         return 0;
260 void PlaybackEngine::init_cursor()
264 void PlaybackEngine::stop_cursor()
269 void PlaybackEngine::init_tracking()
271         if(!command->single_frame()) 
272                 tracking_active = 1;
273         else
274                 tracking_active = 0;
276         tracking_position = command->playbackstart;
277         tracking_done.lock();
278         init_cursor();
279 //printf("PlaybackEngine::init_tracking %ld\n", tracking_position);
282 void PlaybackEngine::stop_tracking()
284 // Set the tracking position to right now before stopping it.
285 //      tracking_position = get_tracking_position();
286 //printf("PlaybackEngine::stop_tracking %ld\n", tracking_position);
287         tracking_active = 0;
288         stop_cursor();
289 //printf("PlaybackEngine::stop_tracking 1\n");
290         tracking_done.unlock();
293 void PlaybackEngine::update_tracking(double position)
295         tracking_lock.lock();
297         tracking_position = position;
299 // Signal that the timer is accurate.
300         if(tracking_active) tracking_active = 2;
301         tracking_timer.update();
302         tracking_lock.unlock();
305 double PlaybackEngine::get_tracking_position()
307         double result = 0;
309         tracking_lock.lock();
312 // Adjust for elapsed time since last update_tracking.
313 // But tracking timer isn't accurate until the first update_tracking
314 // so wait.
315         if(tracking_active == 2)
316         {
317 //printf("PlaybackEngine::get_tracking_position %d %d %d\n", command->get_direction(), tracking_position, tracking_timer.get_scaled_difference(command->get_edl()->session->sample_rate));
320 // Don't interpolate when every frame is played.
321                 if(command->get_edl()->session->video_every_frame &&
322                         render_engines.total &&
323                         render_engines.values[0]->do_video)
324                 {
325                         result = tracking_position;
326                 }
327                 else
328 // Interpolate
329                 {
330                         double loop_start = command->get_edl()->local_session->loop_start;
331                         double loop_end = command->get_edl()->local_session->loop_end;
332                         double loop_size = loop_end - loop_start;
334                         if(command->get_direction() == PLAY_FORWARD)
335                         {
336 // Interpolate
337                                 result = tracking_position + 
338                                         command->get_speed() * 
339                                         tracking_timer.get_difference() /
340                                         1000.0;
342 // Compensate for loop
343 //printf("PlaybackEngine::get_tracking_position 1 %d\n", command->get_edl()->local_session->loop_playback);
344                                 if(command->get_edl()->local_session->loop_playback)
345                                 {
346                                         while(result > loop_end) result -= loop_size;
347                                 }
348                         }
349                         else
350                         {
351 // Interpolate
352                                 result = tracking_position - 
353                                         command->get_speed() * 
354                                         tracking_timer.get_difference() /
355                                         1000.0;
357 // Compensate for loop
358                                 if(command->get_edl()->local_session->loop_playback)
359                                 {
360                                         while(result < loop_start) result += loop_size;
361                                 }
362                         }
364                 }
365         }
366         else
367                 result = tracking_position;
369         tracking_lock.unlock();
370 //printf("PlaybackEngine::get_tracking_position %f %f %d\n", result, tracking_position, tracking_active);
372 // Adjust for loop
374         return result;
377 void PlaybackEngine::update_transport(int command, int paused)
379 //      mwindow->gui->lock_window();
380 //      mwindow->gui->mbuttons->transport->update_gui_state(command, paused);
381 //      mwindow->gui->unlock_window();
384 void PlaybackEngine::run()
386         start_lock.unlock();
387         do
388         {
389 // Wait for current command to finish
390 //printf("PlaybackEngine::run 1\n");
391                 que->output_lock.lock();
392 //printf("PlaybackEngine::run 2\n");
394                 wait_render_engines();
396 //printf("PlaybackEngine::run 3 %d\n", que->command.command);
398 // Read the new command
399                 que->input_lock.lock();
400                 if(done) return;
402 //printf("PlaybackEngine::run 3\n");
403                 *command = que->command;
404 //printf("PlaybackEngine::run 3 %f %f\n", command->playbackstart, que->command.playbackstart);
405                 que->command.reset();
406 //printf("PlaybackEngine::run 3 %p\n", this);
407                 que->input_lock.unlock();
409 // printf("PlaybackEngine::run 4 %d %x %x\n", 
410 //      this->command->command, 
411 //      this->command->change_type, 
412 //      que->command.change_type);
415                 switch(command->command)
416                 {
417 // Parameter change only
418                         case COMMAND_NONE:
419 //                              command->command = last_command;
420                                 perform_change();
421                                 break;
423                         case PAUSE:
424                                 pause_lock.lock();
425                                 init_cursor();
426                                 pause_lock.lock();
427                                 pause_lock.unlock();
428                                 stop_cursor();
429                                 break;
431                         case STOP:
432 // No changing
433                                 break;
435                         case CURRENT_FRAME:
436 //printf("PlaybackEngine::run 5\n");
437                                 last_command = command->command;
438 //printf("PlaybackEngine::run 5.1\n");
439                                 perform_change();
440 //printf("PlaybackEngine::run 7\n");
441                                 arm_render_engines();
442 // Dispatch the command
443                                 start_render_engines();
444 //printf("PlaybackEngine::run 8\n");
445                                 break;
447                         default:
448 //printf("PlaybackEngine::run 5\n");
449                                 last_command = command->command;
450                                 is_playing_back = 1;
451 //printf("PlaybackEngine::run 6 %f %f\n", command->playbackstart, get_tracking_position());
452                                 if(command->command == SINGLE_FRAME_FWD ||
453                                         command->command == SINGLE_FRAME_REWIND)
454                                 {
455                                         command->playbackstart = get_tracking_position();
456                                 }
458                                 perform_change();
459 //printf("PlaybackEngine::run 9 %f\n", command->playbackstart);
460                                 arm_render_engines();
462 // Start tracking after arming so the tracking position doesn't change.
463 // The tracking for a single frame command occurs during PAUSE
464 //printf("PlaybackEngine::run 9 %d\n", command->playbackstart);
465                                 init_tracking();
467 // Dispatch the command
468 //printf("PlaybackEngine::run 10\n");
469                                 start_render_engines();
470 //printf("PlaybackEngine::run 11\n");
471                                 break;
472                 }
474 //printf("PlaybackEngine::run 12\n");
475         }while(!done);
499 int PlaybackEngine::reset_parameters()
501 // called before every playback
502         is_playing_back = 0;
503         follow_loop = 0;
504         speed = 1;
505         reverse = 0;
506         cursor = 0;
507         last_position = 0;
508         playback_start = playback_end = 0;
509         infinite = 0;
510         use_buttons = 0;
511         audio = 0;
512         video = 0;
513         shared_audio = 0;
514         return 0;
517 int PlaybackEngine::init_parameters()
519 //      is_playing_back = 1;
520         update_button = 1;
521         correction_factor = 0;
523 // correct playback buffer sizes
524         input_length = 
525                 playback_buffer = 
526                 output_length = 
527                 audio_module_fragment = 
528                 command->get_edl()->session->audio_module_fragment;
530 // get maximum actual buffer size written to device plus padding
531         if(speed != 1) output_length = (long)(output_length / speed) + 16;   
532         if(output_length < playback_buffer) output_length = playback_buffer;
534 // samples to read at a time is a multiple of the playback buffer greater than read_length
535         while(input_length < command->get_edl()->session->audio_read_length)
536                 input_length += playback_buffer;
537         return 0;
540 int PlaybackEngine::init_audio_device()
542         return 0;
545 int PlaybackEngine::init_video_device()
547         return 0;
552 int PlaybackEngine::start_reconfigure()
554         reconfigure_status = is_playing_back;
555 //      if(is_playing_back) stop_playback(0);
556         return 0;
559 int PlaybackEngine::stop_reconfigure()
561         return 0;
564 int PlaybackEngine::reset_buttons()
566         return 0;
570 long PlaybackEngine::absolute_position(int sync_time)
572         return 0;
575 long PlaybackEngine::get_position(int sync_time)
577         long result;
579         switch(is_playing_back)
580         {
581                 case 2:
582 // playing back
583                         result = absolute_position(sync_time);
584 // adjust for speed
585                         result = (long)(result * speed);
587 // adjust direction and initial position
588                         if(reverse)
589                         {
590                                 result = playback_end - result;
591                                 result += loop_adjustment;
593 // adjust for looping
594 //                              while(mwindow->session->loop_playback && follow_loop && 
595 //                                      result < mwindow->session->loop_start)
596 //                              {
597 //                                      result += mwindow->session->loop_end - mwindow->session->loop_start;
598 //                                      loop_adjustment += mwindow->session->loop_end - mwindow->session->loop_start;
599 //                              }
600                         }
601                         else
602                         {
603                                 result += playback_start;
604                                 result -= loop_adjustment;
605                                 
606 //                              while(mwindow->session->loop_playback && follow_loop && 
607 //                                      result > mwindow->session->loop_end)
608 //                              {
609 //                                      result -= mwindow->session->loop_end - mwindow->session->loop_start;
610 //                                      loop_adjustment += mwindow->session->loop_end - mwindow->session->loop_start;
611 //                              }
612                         }
613                         break;
615                 case 1:
616 // paused
617                         result = last_position;
618                         break;
620                 default:
621 // no value
622                         result = -1;
623                         break;
624         }
626         return result;
630 int PlaybackEngine::move_right(long distance) 
632         mwindow->move_right(distance); 
633         return 0;
637 int PlaybackEngine::cleanup()
639         return 0;
642 int PlaybackEngine::wait_for_startup()
644         return 0;
647 int PlaybackEngine::wait_for_completion()
649 // must use mutex not join since playback engine also terminates itself
650         complete.lock();
651         complete.unlock();
652         return 0;