summaryrefslogtreecommitdiff
path: root/libs/ardour/session_events.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-06-02 21:41:35 +0000
commit449aab3c465bbbf66d221fac3d7ea559f1720357 (patch)
tree6843cc40c88250a132acac701271f1504cd2df04 /libs/ardour/session_events.cc
parent9c0d7d72d70082a54f823cd44c0ccda5da64bb6f (diff)
rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/session_events.cc')
-rw-r--r--libs/ardour/session_events.cc453
1 files changed, 453 insertions, 0 deletions
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
new file mode 100644
index 0000000000..5fc8cd7535
--- /dev/null
+++ b/libs/ardour/session_events.cc
@@ -0,0 +1,453 @@
+/*
+ Copyright (C) 1999-2004 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <cmath>
+#include <unistd.h>
+
+#include <ardour/timestamps.h>
+
+#include <pbd/error.h>
+#include <glibmm/thread.h>
+
+#include <ardour/ardour.h>
+#include <ardour/session.h>
+#include <ardour/audio_diskstream.h>
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+
+MultiAllocSingleReleasePool Session::Event::pool ("event", sizeof (Session::Event), 512);
+
+static const char* event_names[] = {
+ "SetTransportSpeed",
+ "SetDiskstreamSpeed",
+ "Locate",
+ "LocateRoll",
+ "LocateRollLocate",
+ "SetLoop",
+ "PunchIn",
+ "PunchOut",
+ "RangeStop",
+ "RangeLocate",
+ "Overwrite",
+ "SetSlaveSource",
+ "Audition",
+ "InputConfigurationChange",
+ "SetAudioRange",
+ "SetMusicRange",
+ "SetPlayRange",
+ "StopOnce",
+ "AutoLoop"
+};
+
+void
+Session::add_event (nframes_t frame, Event::Type type, nframes_t target_frame)
+{
+ Event* ev = new Event (type, Event::Add, frame, target_frame, 0);
+ queue_event (ev);
+}
+
+void
+Session::remove_event (nframes_t frame, Event::Type type)
+{
+ Event* ev = new Event (type, Event::Remove, frame, 0, 0);
+ queue_event (ev);
+}
+
+void
+Session::replace_event (Event::Type type, nframes_t frame, nframes_t target)
+{
+ Event* ev = new Event (type, Event::Replace, frame, target, 0);
+ queue_event (ev);
+}
+
+void
+Session::clear_events (Event::Type type)
+{
+ Event* ev = new Event (type, Event::Clear, 0, 0, 0);
+ queue_event (ev);
+}
+
+
+void
+Session::dump_events () const
+{
+ cerr << "EVENT DUMP" << endl;
+ for (Events::const_iterator i = events.begin(); i != events.end(); ++i) {
+ cerr << "\tat " << (*i)->action_frame << ' ' << (*i)->type << " target = " << (*i)->target_frame << endl;
+ }
+ cerr << "Next event: ";
+
+ if ((Events::const_iterator) next_event == events.end()) {
+ cerr << "none" << endl;
+ } else {
+ cerr << "at " << (*next_event)->action_frame << ' '
+ << (*next_event)->type << " target = "
+ << (*next_event)->target_frame << endl;
+ }
+ cerr << "Immediate events pending:\n";
+ for (Events::const_iterator i = immediate_events.begin(); i != immediate_events.end(); ++i) {
+ cerr << "\tat " << (*i)->action_frame << ' ' << (*i)->type << " target = " << (*i)->target_frame << endl;
+ }
+ cerr << "END EVENT_DUMP" << endl;
+}
+
+void
+Session::queue_event (Event* ev)
+{
+ if (_state_of_the_state & Loading) {
+ merge_event (ev);
+ } else {
+ pending_events.write (&ev, 1);
+ }
+}
+
+void
+Session::merge_event (Event* ev)
+{
+ switch (ev->action) {
+ case Event::Remove:
+ _remove_event (ev);
+ delete ev;
+ return;
+
+ case Event::Replace:
+ _replace_event (ev);
+ return;
+
+ case Event::Clear:
+ _clear_event_type (ev->type);
+ delete ev;
+ return;
+
+ case Event::Add:
+ break;
+ }
+
+ /* try to handle immediate events right here */
+
+ if (ev->action_frame == 0) {
+ process_event (ev);
+ return;
+ }
+
+ switch (ev->type) {
+ case Event::AutoLoop:
+ case Event::StopOnce:
+ _clear_event_type (ev->type);
+ break;
+
+ default:
+ for (Events::iterator i = events.begin(); i != events.end(); ++i) {
+ if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
+ error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."),
+ event_names[ev->type], ev->action_frame) << endmsg;
+ return;
+ }
+ }
+ }
+
+ events.insert (events.begin(), ev);
+ events.sort (Event::compare);
+ next_event = events.begin();
+ set_next_event ();
+}
+
+/** @return true when @a ev is deleted. */
+bool
+Session::_replace_event (Event* ev)
+{
+ bool ret = false;
+ Events::iterator i;
+
+ /* private, used only for events that can only exist once in the queue */
+
+ for (i = events.begin(); i != events.end(); ++i) {
+ if ((*i)->type == ev->type) {
+ (*i)->action_frame = ev->action_frame;
+ (*i)->target_frame = ev->target_frame;
+ if ((*i) == ev) {
+ ret = true;
+ }
+ delete ev;
+ break;
+ }
+ }
+
+ if (i == events.end()) {
+ events.insert (events.begin(), ev);
+ }
+
+ events.sort (Event::compare);
+ next_event = events.end();
+ set_next_event ();
+
+ return ret;
+}
+
+/** @return true when @a ev is deleted. */
+bool
+Session::_remove_event (Session::Event* ev)
+{
+ bool ret = false;
+ Events::iterator i;
+
+ for (i = events.begin(); i != events.end(); ++i) {
+ if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) {
+ if ((*i) == ev) {
+ ret = true;
+ }
+
+ delete *i;
+ if (i == next_event) {
+ ++next_event;
+ }
+ events.erase (i);
+ break;
+ }
+ }
+
+ if (i != events.end()) {
+ set_next_event ();
+ }
+
+ return ret;
+}
+
+void
+Session::_clear_event_type (Event::Type type)
+{
+ Events::iterator i, tmp;
+
+ for (i = events.begin(); i != events.end(); ) {
+
+ tmp = i;
+ ++tmp;
+
+ if ((*i)->type == type) {
+ delete *i;
+ if (i == next_event) {
+ ++next_event;
+ }
+ events.erase (i);
+ }
+
+ i = tmp;
+ }
+
+ for (i = immediate_events.begin(); i != immediate_events.end(); ) {
+
+ tmp = i;
+ ++tmp;
+
+ if ((*i)->type == type) {
+ delete *i;
+ immediate_events.erase (i);
+ }
+
+ i = tmp;
+ }
+
+ set_next_event ();
+}
+
+void
+Session::set_next_event ()
+{
+ if (events.empty()) {
+ next_event = events.end();
+ return;
+ }
+
+ if (next_event == events.end()) {
+ next_event = events.begin();
+ }
+
+ if ((*next_event)->action_frame > _transport_frame) {
+ next_event = events.begin();
+ }
+
+ for (; next_event != events.end(); ++next_event) {
+ if ((*next_event)->action_frame >= _transport_frame) {
+ break;
+ }
+ }
+}
+
+void
+Session::process_event (Event* ev)
+{
+ bool remove = true;
+ bool del = true;
+
+ /* if we're in the middle of a state change (i.e. waiting
+ for the butler thread to complete the non-realtime
+ part of the change), we'll just have to queue this
+ event for a time when the change is complete.
+ */
+
+ if (non_realtime_work_pending()) {
+
+ /* except locates, which we have the capability to handle */
+
+ if (ev->type != Event::Locate) {
+ immediate_events.insert (immediate_events.end(), ev);
+ _remove_event (ev);
+ return;
+ }
+ }
+
+ //printf("Processing event: %s\n", event_names[ev->type]);
+
+ switch (ev->type) {
+ case Event::SetLoop:
+ set_play_loop (ev->yes_or_no);
+ break;
+
+ case Event::AutoLoop:
+ if (play_loop) {
+ start_locate (ev->target_frame, true, false, Config->get_seamless_loop());
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case Event::Locate:
+ if (ev->yes_or_no) {
+ // cerr << "forced locate to " << ev->target_frame << endl;
+ locate (ev->target_frame, false, true, false);
+ } else {
+ // cerr << "soft locate to " << ev->target_frame << endl;
+ start_locate (ev->target_frame, false, true, false);
+ }
+ _send_smpte_update = true;
+ break;
+
+ case Event::LocateRoll:
+ if (ev->yes_or_no) {
+ // cerr << "forced locate to+roll " << ev->target_frame << endl;
+ locate (ev->target_frame, true, true, false);
+ } else {
+ // cerr << "soft locate to+roll " << ev->target_frame << endl;
+ start_locate (ev->target_frame, true, true, false);
+ }
+ _send_smpte_update = true;
+ break;
+
+ case Event::LocateRollLocate:
+ // locate is handled by ::request_roll_at_and_return()
+ _requested_return_frame = ev->target_frame;
+ cerr << "Set RRF " << ev->target_frame << endl;
+ request_locate (ev->target2_frame, true);
+ break;
+
+
+ case Event::SetTransportSpeed:
+ set_transport_speed (ev->speed, ev->yes_or_no);
+ break;
+
+ case Event::PunchIn:
+ // cerr << "PunchIN at " << transport_frame() << endl;
+ if (Config->get_punch_in() && record_status() == Enabled) {
+ enable_record ();
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case Event::PunchOut:
+ // cerr << "PunchOUT at " << transport_frame() << endl;
+ if (Config->get_punch_out()) {
+ step_back_from_record ();
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case Event::StopOnce:
+ if (!non_realtime_work_pending()) {
+ stop_transport (ev->yes_or_no);
+ _clear_event_type (Event::StopOnce);
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case Event::RangeStop:
+ if (!non_realtime_work_pending()) {
+ stop_transport (ev->yes_or_no);
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case Event::RangeLocate:
+ start_locate (ev->target_frame, true, true, false);
+ remove = false;
+ del = false;
+ break;
+
+ case Event::Overwrite:
+ overwrite_some_buffers (static_cast<Diskstream*>(ev->ptr));
+ break;
+
+ case Event::SetDiskstreamSpeed:
+ set_diskstream_speed (static_cast<Diskstream*> (ev->ptr), ev->speed);
+ break;
+
+ case Event::SetSlaveSource:
+ set_slave_source (ev->slave);
+ break;
+
+ case Event::Audition:
+ set_audition (ev->region);
+ // drop reference to region
+ ev->region.reset ();
+ break;
+
+ case Event::InputConfigurationChange:
+ post_transport_work = PostTransportWork (post_transport_work | PostTransportInputChange);
+ schedule_butler_transport_work ();
+ break;
+
+ case Event::SetAudioRange:
+ current_audio_range = ev->audio_range;
+ setup_auto_play ();
+ break;
+
+ case Event::SetPlayRange:
+ set_play_range (ev->yes_or_no);
+ break;
+
+ default:
+ fatal << string_compose(_("Programming error: illegal event type in process_event (%1)"), ev->type) << endmsg;
+ /*NOTREACHED*/
+ break;
+ };
+
+ if (remove) {
+ del = del && !_remove_event (ev);
+ }
+
+ if (del) {
+ delete ev;
+ }
+}