Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / transportque.C
diff --git a/cinelerra-5.1/cinelerra/transportque.C b/cinelerra-5.1/cinelerra/transportque.C
new file mode 100644 (file)
index 0000000..5b7fba9
--- /dev/null
@@ -0,0 +1,334 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "bcsignals.h"
+#include "clip.h"
+#include "condition.h"
+#include "edl.h"
+#include "edlsession.h"
+#include "localsession.h"
+#include "tracks.h"
+#include "transportque.h"
+
+TransportCommand::TransportCommand()
+{
+// In rendering we want a master EDL so settings don't get clobbered
+// in the middle of a job.
+       edl = new EDL;
+       edl->create_objects();
+       command = 0;
+       change_type = 0;
+       reset();
+}
+
+TransportCommand::~TransportCommand()
+{
+       edl->Garbage::remove_user();
+}
+
+void TransportCommand::reset()
+{
+       playbackstart = 0;
+       start_position = 0;
+       end_position = 0;
+       infinite = 0;
+       realtime = 0;
+       resume = 0;
+// Don't reset the change type for commands which don't perform the change
+       if(command != STOP) change_type = 0;
+       command = COMMAND_NONE;
+}
+
+EDL* TransportCommand::get_edl()
+{
+       return edl;
+}
+
+void TransportCommand::delete_edl()
+{
+       edl->Garbage::remove_user();
+       edl = 0;
+}
+
+void TransportCommand::new_edl()
+{
+       edl = new EDL;
+       edl->create_objects();
+}
+
+
+void TransportCommand::copy_from(TransportCommand *command)
+{
+       this->command = command->command;
+       this->change_type = command->change_type;
+       this->edl->copy_all(command->edl);
+       this->start_position = command->start_position;
+       this->end_position = command->end_position;
+       this->playbackstart = command->playbackstart;
+       this->realtime = command->realtime;
+       this->resume = command->resume;
+}
+
+TransportCommand& TransportCommand::operator=(TransportCommand &command)
+{
+       copy_from(&command);
+       return *this;
+}
+
+int TransportCommand::single_frame()
+{
+       return (command == SINGLE_FRAME_FWD ||
+               command == SINGLE_FRAME_REWIND ||
+               command == CURRENT_FRAME);
+}
+
+
+int TransportCommand::get_direction()
+{
+       switch(command)
+       {
+               case SINGLE_FRAME_FWD:
+               case NORMAL_FWD:
+               case FAST_FWD:
+               case SLOW_FWD:
+               case CURRENT_FRAME:
+                       return PLAY_FORWARD;
+                       break;
+
+               case SINGLE_FRAME_REWIND:
+               case NORMAL_REWIND:
+               case FAST_REWIND:
+               case SLOW_REWIND:
+                       return PLAY_REVERSE;
+                       break;
+
+               default:
+                       return PLAY_FORWARD;
+                       break;
+       }
+}
+
+float TransportCommand::get_speed()
+{
+       switch(command)
+       {
+               case SLOW_FWD:
+               case SLOW_REWIND:
+                       return 0.5;
+
+               case NORMAL_FWD:
+               case NORMAL_REWIND:
+               case SINGLE_FRAME_FWD:
+               case SINGLE_FRAME_REWIND:
+               case CURRENT_FRAME:
+                       return 1.;
+
+               case FAST_FWD:
+               case FAST_REWIND:
+                       return 2.;
+       }
+
+       return 0.;
+}
+
+// Assume starting without pause
+void TransportCommand::set_playback_range(EDL *edl, int use_inout)
+{
+       if(!edl) edl = this->edl;
+
+
+
+
+       switch(command)
+       {
+               case SLOW_FWD:
+               case FAST_FWD:
+               case NORMAL_FWD:
+                       start_position = edl->local_session->get_selectionstart(1);
+                       if(EQUIV(edl->local_session->get_selectionend(1), edl->local_session->get_selectionstart(1)))
+                               end_position = edl->tracks->total_playable_length();
+                       else
+                               end_position = edl->local_session->get_selectionend(1);
+// this prevents a crash if start position is after the loop when playing forwards
+                   if (edl->local_session->loop_playback &&
+                               start_position > edl->local_session->loop_end)
+                       {
+                                   start_position = edl->local_session->loop_start;
+                       }
+                       break;
+
+               case SLOW_REWIND:
+               case FAST_REWIND:
+               case NORMAL_REWIND:
+                       end_position = edl->local_session->get_selectionend(1);
+                       if(EQUIV(edl->local_session->get_selectionend(1), edl->local_session->get_selectionstart(1)))
+                               start_position = 0;
+                       else
+                               start_position = edl->local_session->get_selectionstart(1);
+
+// this prevents a crash if start position is before the loop when playing backwards
+                       if (edl->local_session->loop_playback &&
+                               end_position <= edl->local_session->loop_start)
+                       {
+                                       end_position = edl->local_session->loop_end;
+                       }
+                       break;
+
+               case CURRENT_FRAME:
+               case SINGLE_FRAME_FWD:
+                       start_position = edl->local_session->get_selectionstart(1);
+                       end_position = start_position +
+                               1.0 /
+                               edl->session->frame_rate;
+                       break;
+
+               case SINGLE_FRAME_REWIND:
+                       start_position = edl->local_session->get_selectionend(1);
+                       end_position = start_position -
+                               1.0 /
+                               edl->session->frame_rate;
+                       break;
+       }
+
+
+       if(use_inout)
+       {
+               if(edl->local_session->inpoint_valid())
+                       start_position = edl->local_session->get_inpoint();
+               if(edl->local_session->outpoint_valid())
+                       end_position = edl->local_session->get_outpoint();
+       }
+
+       switch(get_direction())
+       {
+               case PLAY_FORWARD:
+                       playbackstart = start_position;
+                       break;
+
+               case PLAY_REVERSE:
+                       playbackstart = end_position;
+                       break;
+       }
+
+}
+
+void TransportCommand::playback_range_adjust_inout()
+{
+       if(edl->local_session->inpoint_valid() ||
+               edl->local_session->outpoint_valid())
+       {
+               playback_range_inout();
+       }
+}
+
+void TransportCommand::playback_range_inout()
+{
+       if(edl->local_session->inpoint_valid())
+               start_position = edl->local_session->get_inpoint();
+       else
+               start_position = 0;
+
+       if(edl->local_session->outpoint_valid())
+               end_position = edl->local_session->get_outpoint();
+       else
+               end_position = edl->tracks->total_playable_length();
+}
+
+void TransportCommand::playback_range_project()
+{
+       start_position = 0;
+       end_position = edl->tracks->total_playable_length();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+TransportQue::TransportQue()
+{
+       input_lock = new Condition(1, "TransportQue::input_lock");
+       output_lock = new Condition(0, "TransportQue::output_lock", 1);
+}
+
+TransportQue::~TransportQue()
+{
+       delete input_lock;
+       delete output_lock;
+}
+
+int TransportQue::send_command(int command,
+               int change_type,
+               EDL *new_edl,
+               int realtime,
+               int resume,
+               int use_inout)
+{
+       input_lock->lock("TransportQue::send_command 1");
+       this->command.command = command;
+// Mutually exclusive operation
+       this->command.change_type |= change_type;
+       this->command.realtime = realtime;
+       this->command.resume = resume;
+
+       if(new_edl)
+       {
+// Just change the EDL if the change requires it because renderengine
+// structures won't point to the new EDL otherwise and because copying the
+// EDL for every cursor movement is slow.
+               if(change_type == CHANGE_EDL ||
+                       (uint32_t)change_type == CHANGE_ALL)
+               {
+// Copy EDL
+                       this->command.get_edl()->copy_all(new_edl);
+               }
+               else
+               if(change_type == CHANGE_PARAMS)
+               {
+                       this->command.get_edl()->synchronize_params(new_edl);
+               }
+
+// Set playback range
+               this->command.set_playback_range(new_edl, use_inout);
+       }
+
+       input_lock->unlock();
+
+       output_lock->unlock();
+       return 0;
+}
+
+void TransportQue::update_change_type(int change_type)
+{
+       input_lock->lock("TransportQue::update_change_type");
+       this->command.change_type |= change_type;
+       input_lock->unlock();
+}