X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_transport.cc;h=ff36e30743e7750453b48f4ab64d2c85e2262b0b;hb=33da74c8e353ac56194956cae8e2b7d74ec1a1b0;hp=c122989b68ee6875cfc18792e249b08b18ed44f9;hpb=24ccaac67e9d416b3f3c564a441934313f3e9a21;p=ardour.git diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index c122989b68..ff36e30743 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2003 Paul Davis + Copyright (C) 1999-2003 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 @@ -24,22 +24,23 @@ #include #include -#include -#include +#include "pbd/undo.h" +#include "pbd/error.h" #include -#include -#include +#include "pbd/pthread_utils.h" +#include "pbd/memento_command.h" +#include "pbd/stacktrace.h" -#include -#include +#include "midi++/mmc.h" +#include "midi++/port.h" -#include -#include -#include -#include -#include -#include -#include +#include "ardour/ardour.h" +#include "ardour/audioengine.h" +#include "ardour/session.h" +#include "ardour/audio_diskstream.h" +#include "ardour/auditioner.h" +#include "ardour/slave.h" +#include "ardour/location.h" #include "i18n.h" @@ -73,14 +74,14 @@ Session::request_slave_source (SlaveSource src) } void -Session::request_transport_speed (float speed) +Session::request_transport_speed (double speed) { Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed); queue_event (ev); } void -Session::request_diskstream_speed (Diskstream& ds, float speed) +Session::request_diskstream_speed (Diskstream& ds, double speed) { Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed); ev->set_ptr (&ds); @@ -111,7 +112,7 @@ Session::force_locate (nframes_t target_frame, bool with_roll) void Session::request_play_loop (bool yn) { - Event* ev; + Event* ev; Location *location = _locations.auto_loop_location(); if (location == 0 && yn) { @@ -134,10 +135,10 @@ void Session::realtime_stop (bool abort) { /* assume that when we start, we'll be moving forwards */ - + // FIXME: where should this really be? [DR] //send_full_time_code(); - deliver_mmc (MIDI::MachineControl::cmdStop, _transport_frame); + deliver_mmc (MIDI::MachineControl::cmdStop, 0); deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); if (_transport_speed < 0.0f) { @@ -173,14 +174,15 @@ Session::realtime_stop (bool abort) disable_record (true); reset_slave_state (); - + _transport_speed = 0; + _target_transport_speed = 0; - if (Config->get_use_video_sync()) { + if (config.get_use_video_sync()) { waiting_for_sync_offset = true; } - transport_sub_state = ((Config->get_slave_source() == None && Config->get_auto_return()) ? AutoReturning : 0); + transport_sub_state = ((Config->get_slave_source() == None && config.get_auto_return()) ? AutoReturning : 0); } void @@ -212,7 +214,6 @@ Session::butler_transport_work () if (post_transport_work & PostTransportReverse) { - clear_clicks(); cumulative_rf_motion = 0; reset_rf_scale (0); @@ -220,15 +221,10 @@ Session::butler_transport_work () /* don't seek if locate will take care of that in non_realtime_stop() */ if (!(post_transport_work & PostTransportLocate)) { - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if (!(*i)->hidden()) { - if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { - (*i)->seek ((nframes_t) (_transport_frame * (double) (*i)->speed())); - } - else { - (*i)->seek (_transport_frame); - } + (*i)->non_realtime_locate (_transport_frame); } if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) { /* new request, stop seeking, and start again */ @@ -239,7 +235,11 @@ Session::butler_transport_work () } } - if (post_transport_work & (PostTransportStop|PostTransportLocate)) { + if (post_transport_work & PostTransportLocate) { + non_realtime_locate (); + } + + if (post_transport_work & PostTransportStop) { non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished); if (!finished) { g_atomic_int_dec_and_test (&butler_should_do_transport_work); @@ -258,7 +258,7 @@ Session::butler_transport_work () if (post_transport_work & PostTransportAudition) { non_realtime_set_audition (); } - + g_atomic_int_dec_and_test (&butler_should_do_transport_work); } @@ -288,6 +288,18 @@ Session::non_realtime_overwrite (int on_entry, bool& finished) } } + +void +Session::non_realtime_locate () +{ + boost::shared_ptr dsl = diskstreams.reader(); + + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { + (*i)->non_realtime_locate (_transport_frame); + } +} + + void Session::non_realtime_stop (bool abort, int on_entry, bool& finished) { @@ -300,7 +312,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) saved = false; boost::shared_ptr dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->get_captured_frames () != 0) { did_record = true; @@ -309,7 +321,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } /* stop and locate are merged here because they share a lot of common stuff */ - + time (&xnow); now = localtime (&xnow); @@ -323,28 +335,28 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (did_record) { begin_reversible_command ("capture"); - + Location* loc = _locations.end_location(); bool change_end = false; - + if (_transport_frame < loc->end()) { /* stopped recording before current end */ - if (_end_location_is_free) { + if (config.get_end_marker_is_free()) { /* first capture for this session, move end back to where we are */ change_end = true; - } + } } else if (_transport_frame > loc->end()) { - + /* stopped recording after the current end, extend it */ change_end = true; } - + if (change_end) { XMLNode &before = loc->get_state(); loc->set_end(_transport_frame); @@ -352,14 +364,14 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) add_command (new MementoCommand(*loc, &before, &after)); } - _end_location_is_free = false; + config.set_end_marker_is_free (false); _have_captured = true; } for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->transport_stopped (*now, xnow, abort); } - + boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { @@ -367,30 +379,49 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) (*i)->set_pending_declick (0); } } - + if (did_record) { commit_reversible_command (); - } - + } + if (_engine.running()) { update_latency_compensation (true, abort); } - if ((Config->get_slave_source() == None && Config->get_auto_return()) || (post_transport_work & PostTransportLocate) || synced_to_jack()) { - + bool const auto_return_enabled = + (Config->get_slave_source() == None && config.get_auto_return()); + + if (auto_return_enabled || + (post_transport_work & PostTransportLocate) || + (_requested_return_frame >= 0) || + synced_to_jack()) { + if (pending_locate_flush) { flush_all_inserts (); } - - if (((Config->get_slave_source() == None && Config->get_auto_return()) || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) { - _transport_frame = last_stop_frame; + if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) && + !(post_transport_work & PostTransportLocate)) { + + bool do_locate = false; + + if (_requested_return_frame >= 0) { + _transport_frame = _requested_return_frame; + _requested_return_frame = -1; + do_locate = true; + } else { + _transport_frame = _last_roll_location; + } if (synced_to_jack() && !play_loop) { + do_locate = true; + } + + if (do_locate) { // cerr << "non-realtimestop: transport locate to " << _transport_frame << endl; _engine.transport_locate (_transport_frame); } - } + } #ifndef LEAVE_TRANSPORT_UNADJUSTED } @@ -398,12 +429,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if (!(*i)->hidden()) { - if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { - (*i)->seek ((nframes_t) (_transport_frame * (double) (*i)->speed())); - } - else { - (*i)->seek (_transport_frame); - } + (*i)->non_realtime_locate (_transport_frame); } if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) { finished = false; @@ -416,7 +442,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } #endif - last_stop_frame = _transport_frame; + have_looped = false; + + send_full_time_code (0); + deliver_mmc (MIDI::MachineControl::cmdStop, 0); + deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); if (did_record) { @@ -434,7 +464,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) RecordStateChanged (); /* emit signal */ #endif } - + if ((post_transport_work & PostTransportLocate) && get_record_enabled()) { /* capture start has been changed, so save pending state */ save_state ("", true); @@ -444,7 +474,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) /* always try to get rid of this */ remove_pending_capture_state (); - + /* save the current state of things if appropriate */ if (did_record && !saved) { @@ -455,14 +485,16 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) DurationChanged (); /* EMIT SIGNAL */ } - if (post_transport_work & PostTransportStop) { + if (post_transport_work & PostTransportStop) { _play_range = false; /* do not turn off autoloop on stop */ - + } - PositionChanged (_transport_frame); /* EMIT SIGNAL */ + nframes_t tf = _transport_frame; + + PositionChanged (tf); /* EMIT SIGNAL */ TransportStateChange (); /* EMIT SIGNAL */ /* and start it up again if relevant */ @@ -481,7 +513,7 @@ Session::check_declick_out () /* this is called after a process() iteration. if PendingDeclickOut was set, it means that we were waiting to declick the output (which has just been done) before doing something else. this is where we do that "something else". - + note: called from the audio thread. */ @@ -501,11 +533,11 @@ void Session::set_play_loop (bool yn) { /* Called from event-handling context */ - + if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) { return; } - + set_dirty(); if (yn && Config->get_seamless_loop() && synced_to_jack()) { @@ -515,12 +547,12 @@ Session::set_play_loop (bool yn) return; } - + if ((play_loop = yn)) { Location *loc; - + if ((loc = _locations.auto_loop_location()) != 0) { if (Config->get_seamless_loop()) { @@ -541,9 +573,9 @@ Session::set_play_loop (bool yn) } } } - + /* stick in the loop event */ - + Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f); merge_event (event); @@ -571,7 +603,7 @@ Session::set_play_loop (bool yn) (*i)->set_loop (0); } } - + } } @@ -590,7 +622,7 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush, { if (synced_to_jack()) { - float sp; + double sp; nframes_t pos; _slave->speed_and_position (sp, pos); @@ -610,11 +642,29 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush, } } else { - locate (target_frame, with_roll, with_flush, with_loop); } } +int +Session::micro_locate (nframes_t distance) +{ + boost::shared_ptr dsl = diskstreams.reader(); + + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { + if (!(*i)->can_internal_playback_seek (distance)) { + return -1; + } + } + + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { + (*i)->internal_playback_seek (distance); + } + + _transport_frame += distance; + return 0; +} + void Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop) { @@ -646,17 +696,17 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w pending_locate_roll = with_roll; pending_locate_flush = with_flush; return; - } + } } - if (transport_rolling() && (!auto_play_legal || !Config->get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) { + if (transport_rolling() && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) { realtime_stop (false); - } + } if ( !with_loop || loop_changing) { post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate); - + if (with_roll) { post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll); } @@ -668,13 +718,13 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w /* this is functionally what clear_clicks() does but with a tentative lock */ Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK); - + if (clickm.locked()) { - + for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) { delete *i; } - + clicks.clear (); } } @@ -688,7 +738,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (!Config->get_auto_input()); + (*i)->monitor_input (!config.get_auto_input()); } } } @@ -709,7 +759,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w /* cancel looped playback if transport pos outside of loop range */ if (play_loop) { Location* al = _locations.auto_loop_location(); - + if (al && (_transport_frame < al->start() || _transport_frame > al->end())) { // cancel looping directly, this is called from event handling context set_play_loop (false); @@ -719,7 +769,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w // this is only necessary for seamless looping boost::shared_ptr dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { // tell it we've looped, so it can deal with the record state @@ -727,14 +777,16 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w } } } - + have_looped = true; TransportLooped(); // EMIT SIGNAL } } - + loop_changing = false; _send_smpte_update = true; + + Located (); /* EMIT SIGNAL */ } /** Set the transport speed. @@ -742,16 +794,22 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w * @param abort */ void -Session::set_transport_speed (float speed, bool abort) +Session::set_transport_speed (double speed, bool abort) { if (_transport_speed == speed) { return; } + _target_transport_speed = fabs(speed); + + /* 8.0 max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability + and user needs. We really need CD-style "skip" playback for ffwd and rewind. + */ + if (speed > 0) { - speed = min (8.0f, speed); + speed = min (8.0, speed); } else if (speed < 0) { - speed = max (-8.0f, speed); + speed = max (-8.0, speed); } if (transport_rolling() && speed == 0.0) { @@ -765,7 +823,7 @@ Session::set_transport_speed (float speed, bool abort) for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (true); + (*i)->monitor_input (true); } } } @@ -775,7 +833,7 @@ Session::set_transport_speed (float speed, bool abort) } else { stop_transport (abort); } - + } else if (transport_stopped() && speed == 1.0) { /* we are stopped and we want to start rolling at speed 1 */ @@ -789,9 +847,9 @@ Session::set_transport_speed (float speed, bool abort) boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { - if (Config->get_auto_input() && (*i)->record_enabled ()) { + if (config.get_auto_input() && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (false); + (*i)->monitor_input (false); } } } @@ -818,34 +876,34 @@ Session::set_transport_speed (float speed, bool abort) return; } - if (speed > 0.0f && _transport_frame == current_end_frame()) { + if (speed > 0.0 && _transport_frame == current_end_frame()) { return; } - if (speed < 0.0f && _transport_frame == 0) { + if (speed < 0.0 && _transport_frame == 0) { return; } - + clear_clicks (); /* if we are reversing relative to the current speed, or relative to the speed before the last stop, then we have to do extra work. */ - if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_last_transport_speed == 0.0f && speed < 0.0f)) { + if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0f && speed < 0.0f)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse); } - + _last_transport_speed = _transport_speed; _transport_speed = speed; - + boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); } } - + if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) { schedule_butler_transport_work (); } @@ -860,11 +918,11 @@ Session::stop_transport (bool abort) if (_transport_speed == 0.0f) { return; } - - if (actively_recording() && !(transport_sub_state & StopPendingCapture) && - _worst_output_latency > current_block_size) + + if (actively_recording() && !(transport_sub_state & StopPendingCapture) && + _worst_output_latency > current_block_size) { - + /* we need to capture the audio that has still not yet been received by the system at the time the stop is requested, so we have to roll past that time. @@ -872,16 +930,16 @@ Session::stop_transport (bool abort) block before the actual end. we'll declick in the subsequent block, and then we'll really be stopped. */ - - Event *ev = new Event (Event::StopOnce, Event::Replace, + + Event *ev = new Event (Event::StopOnce, Event::Replace, _transport_frame + _worst_output_latency - current_block_size, 0, 0, abort); - + merge_event (ev); transport_sub_state |= StopPendingCapture; pending_abort = abort; return; - } + } if ((transport_sub_state & PendingDeclickOut) == 0) { @@ -899,14 +957,15 @@ void Session::start_transport () { _last_roll_location = _transport_frame; + have_looped = false; /* if record status is Enabled, move it to Recording. if its - already Recording, move it to Disabled. + already Recording, move it to Disabled. */ switch (record_status()) { case Enabled: - if (!Config->get_punch_in()) { + if (!config.get_punch_in()) { enable_record (); } break; @@ -921,21 +980,11 @@ Session::start_transport () break; } - if (!synced_to_jack() || _exporting) { - actually_start_transport (); - } else { - waiting_to_start = true; - } -} - -void -Session::actually_start_transport () -{ - waiting_to_start = false; - transport_sub_state |= PendingDeclickIn; + _transport_speed = 1.0; - + _target_transport_speed = 1.0; + boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->realtime_set_speed ((*i)->speed(), true); @@ -967,9 +1016,9 @@ Session::post_transport () if (post_transport_work & PostTransportLocate) { - if (((Config->get_slave_source() == None && (auto_play_legal && Config->get_auto_play())) && !_exporting) || (post_transport_work & PostTransportRoll)) { + if (((Config->get_slave_source() == None && (auto_play_legal && config.get_auto_play())) && !_exporting) || (post_transport_work & PostTransportRoll)) { start_transport (); - + } else { transport_sub_state = 0; } @@ -1011,14 +1060,12 @@ Session::set_slave_source (SlaveSource src) return; } -// if (src == JACK && Config->get_jack_time_master()) { -// return; -// } - - if (_slave) { - delete _slave; - _slave = 0; - } +// if (src == JACK && Config->get_jack_time_master()) { +// return; +// } + + delete _slave; + _slave = 0; if (_transport_speed < 0.0) { reverse = true; @@ -1028,7 +1075,7 @@ Session::set_slave_source (SlaveSource src) case None: stop_transport (); break; - + case MTC: if (_mtc_port) { try { @@ -1043,17 +1090,32 @@ Session::set_slave_source (SlaveSource src) error << _("No MTC port defined: MTC slaving is impossible.") << endmsg; return; } - _desired_transport_speed = _transport_speed; break; - + + case MIDIClock: + if (_midi_clock_port) { + try { + _slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24); + } + + catch (failed_constructor& err) { + return; + } + + } else { + error << _("No MIDI Clock port defined: MIDI Clock slaving is impossible.") << endmsg; + return; + } + break; + case JACK: _slave = new JACK_Slave (_engine.jack()); - _desired_transport_speed = _transport_speed; break; + }; Config->set_slave_source (src); - + boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if (!(*i)->hidden()) { @@ -1084,7 +1146,7 @@ Session::reverse_diskstream_buffers () } void -Session::set_diskstream_speed (Diskstream* stream, float speed) +Session::set_diskstream_speed (Diskstream* stream, double speed) { if (stream->realtime_set_speed (speed, false)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); @@ -1131,7 +1193,7 @@ Session::setup_auto_play () /* Called from event-processing context */ Event* ev; - + _clear_event_type (Event::RangeStop); _clear_event_type (Event::RangeLocate); @@ -1140,57 +1202,65 @@ Session::setup_auto_play () } list::size_type sz = current_audio_range.size(); - + if (sz > 1) { - - list::iterator i = current_audio_range.begin(); + + list::iterator i = current_audio_range.begin(); list::iterator next; - + while (i != current_audio_range.end()) { - + next = i; ++next; - + /* locating/stopping is subject to delays for declicking. */ - + nframes_t requested_frame = (*i).end; - + if (requested_frame > current_block_size) { requested_frame -= current_block_size; } else { requested_frame = 0; } - + if (next == current_audio_range.end()) { ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f); } else { ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f); } - + merge_event (ev); - + i = next; } - + } else if (sz == 1) { - + ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f); merge_event (ev); - - } + + } /* now start rolling at the right place */ - + ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false); merge_event (ev); } +void +Session::request_roll_at_and_return (nframes_t start, nframes_t return_to) +{ + Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0); + ev->target2_frame = start; + queue_event (ev); +} + void Session::request_bounded_roll (nframes_t start, nframes_t end) { request_stop (); - Event *ev = new Event (Event::StopOnce, Event::Replace, end, Event::Immediate, 0.0); + Event *ev = new Event (Event::StopOnce, Event::Replace, end, Event::Immediate, 0.0); queue_event (ev); request_locate (start, true); } @@ -1203,14 +1273,14 @@ Session::engine_halted () /* there will be no more calls to process(), so we'd better clean up for ourselves, right now. - but first, make sure the butler is out of + but first, make sure the butler is out of the picture. */ g_atomic_int_set (&butler_should_do_transport_work, 0); post_transport_work = PostTransportWork (0); stop_butler (); - + realtime_stop (false); non_realtime_stop (false, 0, ignored); transport_sub_state = 0; @@ -1222,16 +1292,16 @@ Session::engine_halted () void Session::xrun_recovery () { - if (Config->get_stop_recording_on_xrun() && actively_recording()) { + Xrun (transport_frame()); //EMIT SIGNAL - HaltOnXrun (); /* EMIT SIGNAL */ + if (Config->get_stop_recording_on_xrun() && actively_recording()) { /* it didn't actually halt, but we need to handle things in the same way. */ engine_halted(); - } + } } void @@ -1245,32 +1315,42 @@ Session::update_latency_compensation (bool with_stop, bool abort) _worst_track_latency = 0; +#undef DEBUG_LATENCY +#ifdef DEBUG_LATENCY + cerr << "\n---------------------------------\nUPDATE LATENCY\n"; +#endif + boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - + if (with_stop) { - (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), + (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), (!(post_transport_work & PostTransportLocate) || pending_locate_flush)); } - - nframes_t old_latency = (*i)->signal_latency (); + + nframes_t old_latency = (*i)->output()->signal_latency (); nframes_t track_latency = (*i)->update_total_latency (); - + if (old_latency != track_latency) { - (*i)->update_port_total_latencies (); + (*i)->input()->update_port_total_latencies (); + (*i)->output()->update_port_total_latencies (); update_jack = true; } - if (!(*i)->is_hidden() && ((*i)->active())) { + if (!(*i)->is_hidden() && ((*i)->active())) { _worst_track_latency = max (_worst_track_latency, track_latency); } - } + } if (update_jack) { _engine.update_total_latencies (); } +#ifdef DEBUG_LATENCY + cerr << "\tworst was " << _worst_track_latency << endl; +#endif + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_latency_delay (_worst_track_latency); } @@ -1279,7 +1359,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) /* reflect any changes in latencies into capture offsets */ - + boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {