+void
+Session::queue_event (SessionEvent* ev)
+{
+ if (_state_of_the_state & Deletion) {
+ return;
+ } else if (_state_of_the_state & Loading) {
+ merge_event (ev);
+ } else {
+ pending_events.write (&ev, 1);
+ }
+}
+
+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 (SessionEvent* 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 != SessionEvent::Locate) {
+ immediate_events.insert (immediate_events.end(), ev);
+ _remove_event (ev);
+ return;
+ }
+ }
+
+ DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("Processing event: %1 @ %2\n", enum_2_string (ev->type), _transport_frame));
+
+ switch (ev->type) {
+ case SessionEvent::SetLoop:
+ set_play_loop (ev->yes_or_no);
+ break;
+
+ case SessionEvent::AutoLoop:
+ if (play_loop) {
+ start_locate (ev->target_frame, true, false, Config->get_seamless_loop());
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case SessionEvent::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_timecode_update = true;
+ break;
+
+ case SessionEvent::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_timecode_update = true;
+ break;
+
+ case SessionEvent::LocateRollLocate:
+ // locate is handled by ::request_roll_at_and_return()
+ _requested_return_frame = ev->target_frame;
+ request_locate (ev->target2_frame, true);
+ break;
+
+
+ case SessionEvent::SetTransportSpeed:
+ set_transport_speed (ev->speed, ev->yes_or_no, ev->second_yes_or_no);
+ break;
+
+ case SessionEvent::PunchIn:
+ // cerr << "PunchIN at " << transport_frame() << endl;
+ if (config.get_punch_in() && record_status() == Enabled) {
+ enable_record ();
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case SessionEvent::PunchOut:
+ // cerr << "PunchOUT at " << transport_frame() << endl;
+ if (config.get_punch_out()) {
+ step_back_from_record ();
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case SessionEvent::StopOnce:
+ if (!non_realtime_work_pending()) {
+ stop_transport (ev->yes_or_no);
+ _clear_event_type (SessionEvent::StopOnce);
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case SessionEvent::RangeStop:
+ if (!non_realtime_work_pending()) {
+ stop_transport (ev->yes_or_no);
+ }
+ remove = false;
+ del = false;
+ break;
+
+ case SessionEvent::RangeLocate:
+ start_locate (ev->target_frame, true, true, false);
+ remove = false;
+ del = false;
+ break;
+
+ case SessionEvent::Overwrite:
+ overwrite_some_buffers (static_cast<Diskstream*>(ev->ptr));
+ break;
+
+ case SessionEvent::SetDiskstreamSpeed:
+ set_diskstream_speed (static_cast<Diskstream*> (ev->ptr), ev->speed);
+ break;
+
+ case SessionEvent::SetSyncSource:
+ use_sync_source (ev->slave);
+ break;
+
+ case SessionEvent::Audition:
+ set_audition (ev->region);
+ // drop reference to region
+ ev->region.reset ();
+ break;
+
+ case SessionEvent::InputConfigurationChange:
+ add_post_transport_work (PostTransportInputChange);
+ _butler->schedule_transport_work ();
+ break;
+
+ case SessionEvent::SetPlayAudioRange:
+ set_play_range (ev->audio_range, (ev->speed == 1.0f));
+ break;
+
+ case SessionEvent::RealTimeOperation:
+ process_rtop (ev);
+ del = false; // other side of RT request needs to clean up
+ 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;
+ }
+}
+