summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2012-06-20 18:46:05 +0000
committerCarl Hetherington <carl@carlh.net>2012-06-20 18:46:05 +0000
commit7a76e8ae96c20b270dd3104328f8bee199c9a770 (patch)
treeb2e81966aa9b87eddb7de53caddd6ba0da4d1697 /libs/ardour
parentd863c200024d1e844f1b1d71471b85acfe671b36 (diff)
Declick before the end of seamless loops, not after the end, so that loops are rendered accurately (#4213, #4593).
git-svn-id: svn://localhost/ardour2/branches/3.0@12801 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/session.h20
-rw-r--r--libs/ardour/ardour/session_event.h3
-rw-r--r--libs/ardour/session.cc19
-rw-r--r--libs/ardour/session_events.cc1
-rw-r--r--libs/ardour/session_process.cc11
-rw-r--r--libs/ardour/session_transport.cc26
6 files changed, 69 insertions, 11 deletions
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index afb1c37d54..e75c7aa206 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -871,10 +871,12 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void destroy ();
enum SubState {
- PendingDeclickIn = 0x1,
- PendingDeclickOut = 0x2,
- StopPendingCapture = 0x4,
- PendingLocate = 0x20,
+ PendingDeclickIn = 0x1, ///< pending de-click fade-in for start
+ PendingDeclickOut = 0x2, ///< pending de-click fade-out for stop
+ StopPendingCapture = 0x4,
+ PendingLoopDeclickIn = 0x8, ///< pending de-click fade-in at the start of a loop
+ PendingLoopDeclickOut = 0x10, ///< pending de-click fade-out at the end of a loop
+ PendingLocate = 0x20,
};
/* stuff used in process() should be close together to
@@ -999,7 +1001,16 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
transport_sub_state &= ~PendingDeclickIn;
return 1;
} else if (transport_sub_state & PendingDeclickOut) {
+ /* XXX: not entirely sure why we don't clear this */
return -1;
+ } else if (transport_sub_state & PendingLoopDeclickOut) {
+ /* Return the declick out first ... */
+ transport_sub_state &= ~PendingLoopDeclickOut;
+ return -1;
+ } else if (transport_sub_state & PendingLoopDeclickIn) {
+ /* ... then the declick in on the next call */
+ transport_sub_state &= ~PendingLoopDeclickIn;
+ return 1;
} else {
return 0;
}
@@ -1089,6 +1100,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
PBD::ScopedConnectionList loop_connections;
void auto_loop_changed (Location *);
+ void auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
void first_stage_init (std::string path, std::string snapshot_name);
int second_stage_init ();
diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h
index 932ddc9176..d5a1b0c255 100644
--- a/libs/ardour/ardour/session_event.h
+++ b/libs/ardour/ardour/session_event.h
@@ -42,7 +42,8 @@ public:
/* only one of each of these events can be queued at any one time */
StopOnce,
- AutoLoop
+ AutoLoop,
+ AutoLoopDeclick,
};
enum Action {
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 72c2a8654f..9eb4c223d0 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -929,10 +929,25 @@ Session::auto_punch_changed (Location* location)
replace_event (SessionEvent::PunchOut, when_to_stop);
}
+/** @param loc A loop location.
+ * @param pos Filled in with the start time of the required fade-out (in session frames).
+ * @param length Filled in with the length of the required fade-out.
+ */
+void
+Session::auto_loop_declick_range (Location* loc, framepos_t & pos, framepos_t & length)
+{
+ pos = max (loc->start(), loc->end() - 64);
+ length = loc->end() - pos;
+}
+
void
Session::auto_loop_changed (Location* location)
{
replace_event (SessionEvent::AutoLoop, location->end(), location->start());
+ framepos_t dcp;
+ framecnt_t dcl;
+ auto_loop_declick_range (location, dcp, dcl);
+ replace_event (SessionEvent::AutoLoopDeclick, dcp, dcl);
if (transport_rolling() && play_loop) {
@@ -1010,6 +1025,10 @@ Session::set_auto_loop_location (Location* location)
loop_connections.drop_connections ();
existing->set_auto_loop (false, this);
remove_event (existing->end(), SessionEvent::AutoLoop);
+ framepos_t dcp;
+ framecnt_t dcl;
+ auto_loop_declick_range (existing, dcp, dcl);
+ remove_event (dcp, SessionEvent::AutoLoopDeclick);
auto_loop_location_changed (0);
}
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index 84b1b75b12..6c828ac6f0 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -173,6 +173,7 @@ SessionEventManager::merge_event (SessionEvent* ev)
switch (ev->type) {
case SessionEvent::AutoLoop:
+ case SessionEvent::AutoLoopDeclick:
case SessionEvent::StopOnce:
_clear_event_type (ev->type);
break;
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index f92ca9f1a7..3936423b14 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -1021,6 +1021,17 @@ Session::process_event (SessionEvent* ev)
del = false;
break;
+ case SessionEvent::AutoLoopDeclick:
+ if (play_loop) {
+ /* Request a declick fade-out and a fade-in; the fade-out will happen
+ at the end of the loop, and the fade-in at the start.
+ */
+ transport_sub_state |= (PendingLoopDeclickOut | PendingLoopDeclickIn);
+ }
+ remove = false;
+ del = false;
+ break;
+
case SessionEvent::Locate:
if (ev->yes_or_no) {
// cerr << "forced locate to " << ev->target_frame << endl;
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 7c23e2aee7..ace5e8e3e1 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -662,7 +662,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".
+ done) before maybe doing something else. this is where we do that "something else".
note: called from the audio thread.
*/
@@ -676,6 +676,10 @@ Session::check_declick_out ()
stop_transport (pending_abort);
transport_sub_state &= ~(PendingDeclickOut|PendingLocate);
}
+
+ } else if (transport_sub_state & PendingLoopDeclickOut) {
+ /* Nothing else to do here; we've declicked, and the loop event will be along shortly */
+ transport_sub_state &= ~PendingLoopDeclickOut;
}
}
@@ -684,6 +688,7 @@ Session::unset_play_loop ()
{
play_loop = false;
clear_events (SessionEvent::AutoLoop);
+ clear_events (SessionEvent::AutoLoopDeclick);
// set all tracks to NOT use internal looping
boost::shared_ptr<RouteList> rl = routes.reader ();
@@ -744,10 +749,16 @@ Session::set_play_loop (bool yn)
}
}
- /* put the loop event into the event list */
+ /* Put the delick and loop events in into the event list. The declick event will
+ cause a de-clicking fade-out just before the end of the loop, and it will also result
+ in a fade-in when the loop restarts. The AutoLoop event will peform the actual loop.
+ */
- SessionEvent* event = new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f);
- merge_event (event);
+ framepos_t dcp;
+ framecnt_t dcl;
+ auto_loop_declick_range (loc, dcp, dcl);
+ merge_event (new SessionEvent (SessionEvent::AutoLoopDeclick, SessionEvent::Replace, dcp, dcl, 0.0f));
+ merge_event (new SessionEvent (SessionEvent::AutoLoop, SessionEvent::Replace, loc->end(), loc->start(), 0.0f));
/* locate to start of loop and roll. If doing seamless loop, force a
locate+buffer refill even if we are positioned there already.
@@ -841,8 +852,11 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
return;
}
- if (_transport_speed) {
- /* schedule a declick. we'll be called again when its done */
+ if (_transport_speed && !with_loop) {
+ /* Schedule a declick. We'll be called again when its done.
+ We only do it this way for ordinary locates, not those
+ due to loops.
+ */
if (!(transport_sub_state & PendingDeclickOut)) {
transport_sub_state |= (PendingDeclickOut|PendingLocate);