summaryrefslogtreecommitdiff
path: root/libs/ardour/session_transport.cc
diff options
context:
space:
mode:
authorHans Baier <hansfbaier@googlemail.com>2008-08-04 22:37:24 +0000
committerHans Baier <hansfbaier@googlemail.com>2008-08-04 22:37:24 +0000
commited990de6040215412baf8f448b1876d78bd9cc19 (patch)
tree196c6552040b0ad1c9c402cba2b4543ae39536ef /libs/ardour/session_transport.cc
parent44fd104ada0fbd8b76d34150e941d85d6de6f81b (diff)
* first implementation of MIDI Clock Slave support
git-svn-id: svn://localhost/ardour2/branches/3.0@3652 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/session_transport.cc')
-rw-r--r--libs/ardour/session_transport.cc210
1 files changed, 114 insertions, 96 deletions
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index c86a868e56..61a741d0fb 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
@@ -55,7 +55,7 @@ Session::request_input_change_handling ()
if (!(_state_of_the_state & (InitialConnecting|Deletion))) {
Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
queue_event (ev);
- }
+ }
}
void
@@ -112,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) {
@@ -135,7 +135,7 @@ 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);
@@ -174,7 +174,7 @@ Session::realtime_stop (bool abort)
disable_record (true);
reset_slave_state ();
-
+
_transport_speed = 0;
if (Config->get_use_video_sync()) {
@@ -221,7 +221,7 @@ 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) {
@@ -239,7 +239,7 @@ Session::butler_transport_work ()
}
}
}
-
+
if (post_transport_work & PostTransportLocate) {
non_realtime_locate ();
}
@@ -263,7 +263,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);
}
@@ -293,7 +293,7 @@ Session::non_realtime_overwrite (int on_entry, bool& finished)
}
}
-
+
void
Session::non_realtime_locate ()
{
@@ -317,7 +317,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
saved = false;
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->get_captured_frames () != 0) {
did_record = true;
@@ -326,7 +326,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);
@@ -340,10 +340,10 @@ 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 */
@@ -353,15 +353,15 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
/* 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);
@@ -376,7 +376,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->transport_stopped (*now, xnow, abort);
}
-
+
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
@@ -384,25 +384,25 @@ 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) ||
+ if ((Config->get_slave_source() == None && Config->get_auto_return()) ||
+ (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()) ||
+
+ if (((Config->get_slave_source() == None && Config->get_auto_return()) ||
synced_to_jack() ||
_requested_return_frame >= 0) &&
!(post_transport_work & PostTransportLocate)) {
@@ -421,12 +421,12 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
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
}
@@ -475,7 +475,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);
@@ -485,7 +485,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) {
@@ -496,11 +496,11 @@ 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 */
-
+
}
nframes_t tf = _transport_frame;
@@ -524,7 +524,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.
*/
@@ -544,11 +544,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()) {
@@ -558,12 +558,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()) {
@@ -584,9 +584,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);
@@ -614,7 +614,7 @@ Session::set_play_loop (bool yn)
(*i)->set_loop (0);
}
}
-
+
}
}
@@ -689,17 +689,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)) {
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);
}
@@ -711,13 +711,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 ();
}
}
@@ -752,7 +752,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);
@@ -762,7 +762,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<DiskstreamList> 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
@@ -774,7 +774,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
TransportLooped(); // EMIT SIGNAL
}
}
-
+
loop_changing = false;
_send_smpte_update = true;
@@ -808,7 +808,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);
}
}
}
@@ -818,7 +818,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 */
@@ -834,7 +834,7 @@ Session::set_transport_speed (float speed, bool abort)
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if (Config->get_auto_input() && (*i)->record_enabled ()) {
//cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (false);
+ (*i)->monitor_input (false);
}
}
}
@@ -868,7 +868,7 @@ Session::set_transport_speed (float speed, bool abort)
if (speed < 0.0f && _transport_frame == 0) {
return;
}
-
+
clear_clicks ();
/* if we are reversing relative to the current speed, or relative to the speed
@@ -878,17 +878,17 @@ Session::set_transport_speed (float speed, bool abort)
if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_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<DiskstreamList> 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 ();
}
@@ -903,11 +903,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.
@@ -915,16 +915,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) {
@@ -944,7 +944,7 @@ Session::start_transport ()
_last_roll_location = _transport_frame;
/* 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()) {
@@ -978,7 +978,7 @@ Session::actually_start_transport ()
transport_sub_state |= PendingDeclickIn;
_transport_speed = 1.0;
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->realtime_set_speed ((*i)->speed(), true);
@@ -1012,7 +1012,7 @@ Session::post_transport ()
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;
}
@@ -1057,7 +1057,7 @@ Session::set_slave_source (SlaveSource src)
// if (src == JACK && Config->get_jack_time_master()) {
// return;
// }
-
+
if (_slave) {
delete _slave;
_slave = 0;
@@ -1071,7 +1071,7 @@ Session::set_slave_source (SlaveSource src)
case None:
stop_transport ();
break;
-
+
case MTC:
if (_mtc_port) {
try {
@@ -1088,15 +1088,33 @@ Session::set_slave_source (SlaveSource src)
}
_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;
+ }
+ _desired_transport_speed = _transport_speed;
+ break;
+
case JACK:
_slave = new JACK_Slave (_engine.jack());
_desired_transport_speed = _transport_speed;
break;
+
};
Config->set_slave_source (src);
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if (!(*i)->hidden()) {
@@ -1174,7 +1192,7 @@ Session::setup_auto_play ()
/* Called from event-processing context */
Event* ev;
-
+
_clear_event_type (Event::RangeStop);
_clear_event_type (Event::RangeLocate);
@@ -1183,48 +1201,48 @@ Session::setup_auto_play ()
}
list<AudioRange>::size_type sz = current_audio_range.size();
-
+
if (sz > 1) {
-
- list<AudioRange>::iterator i = current_audio_range.begin();
+
+ list<AudioRange>::iterator i = current_audio_range.begin();
list<AudioRange>::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);
}
@@ -1254,14 +1272,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;
@@ -1282,7 +1300,7 @@ Session::xrun_recovery ()
*/
engine_halted();
- }
+ }
}
void
@@ -1299,15 +1317,15 @@ Session::update_latency_compensation (bool with_stop, bool abort)
boost::shared_ptr<RouteList> 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 track_latency = (*i)->update_total_latency ();
-
+
if (old_latency != track_latency) {
(*i)->update_port_total_latencies ();
update_jack = true;
@@ -1316,7 +1334,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
if (!(*i)->is_hidden() && ((*i)->active())) {
_worst_track_latency = max (_worst_track_latency, track_latency);
}
- }
+ }
if (update_jack) {
_engine.update_total_latencies ();
@@ -1330,7 +1348,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
/* reflect any changes in latencies into capture offsets
*/
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {