summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Chappell <jesse@essej.net>2007-06-26 02:15:02 +0000
committerJesse Chappell <jesse@essej.net>2007-06-26 02:15:02 +0000
commit4ecfc19541ed05c5e51c367556e9902c7f83b705 (patch)
tree8b1f73f6aa8154cf30a3b88553262407c7bfa03a
parent4431b678239182a85310d4aba4b4f66c6a7cd06b (diff)
* Added (let's call it revealed) ability to record while the transport is looping.
This works for both Internal (seamless) and JACK sync, new regions are created each cycle around the loop and stacked on top of each other. It is recommended for now that automatic crossfades be turned off when doing this. Punch-In/Out may be used also (this used to be the only way to accomplish recording while looping, but now the GUI represents it without goofiness. * Fixed the stuttering/stuck problem when looping with JACK sync * Fixed gui bug that prevented record-disable when latch record option is on * Fixed issue where it would rec-enable unnecessarily when passing through the punch-out point * Fixed corner case in diskstream record length (that no one would ever notice) git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2034 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/ardour_ui.cc2
-rw-r--r--gtk2_ardour/streamview.cc9
-rw-r--r--gtk2_ardour/streamview.h1
-rw-r--r--libs/ardour/ardour/audio_diskstream.h1
-rw-r--r--libs/ardour/ardour/diskstream.h1
-rw-r--r--libs/ardour/ardour/session.h1
-rw-r--r--libs/ardour/audio_diskstream.cc58
-rw-r--r--libs/ardour/session.cc21
-rw-r--r--libs/ardour/session_process.cc2
-rw-r--r--libs/ardour/session_transport.cc29
10 files changed, 106 insertions, 19 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index ca0506878e..0223e8d027 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -1200,7 +1200,7 @@ ARDOUR_UI::transport_record ()
break;
case Session::Recording:
case Session::Enabled:
- session->disable_record (true);
+ session->disable_record (false, true);
}
}
}
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index 62d8e99254..4a454a32f5 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -72,6 +72,7 @@ StreamView::StreamView (RouteTimeAxisView& tv)
if (_trackview.is_track()) {
_trackview.track()->DiskstreamChanged.connect (mem_fun (*this, &StreamView::diskstream_changed));
_trackview.session().TransportStateChange.connect (mem_fun (*this, &StreamView::transport_changed));
+ _trackview.session().TransportLooped.connect (mem_fun (*this, &StreamView::transport_looped));
_trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &StreamView::rec_enable_changed));
_trackview.session().RecordStateChanged.connect (mem_fun (*this, &StreamView::sess_rec_enable_changed));
}
@@ -312,6 +313,14 @@ StreamView::transport_changed()
}
void
+StreamView::transport_looped()
+{
+ // to force a new rec region
+ rec_active = false;
+ Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
+}
+
+void
StreamView::update_rec_box ()
{
if (rec_active && rec_rects.size() > 0) {
diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h
index ef55ebc4af..4df00d84a5 100644
--- a/gtk2_ardour/streamview.h
+++ b/gtk2_ardour/streamview.h
@@ -101,6 +101,7 @@ protected:
//private: (FIXME?)
void transport_changed();
+ void transport_looped();
void rec_enable_changed();
void sess_rec_enable_changed();
virtual void setup_rec_box () = 0;
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 4846a20cbd..7b7df480d8 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -226,6 +226,7 @@ class AudioDiskstream : public Diskstream
void finish_capture (bool rec_monitors_input, boost::shared_ptr<ChannelList>);
void transport_stopped (struct tm&, time_t, bool abort);
+ void transport_looped (nframes_t transport_frame);
void init (Diskstream::Flag);
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 79fec98d6e..f34cee002d 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -207,6 +207,7 @@ class Diskstream : public PBD::StatefulDestructible
virtual void playlist_deleted (boost::weak_ptr<Playlist>);
virtual void transport_stopped (struct tm&, time_t, bool abort) = 0;
+ virtual void transport_looped (nframes_t transport_frame) = 0;
struct CaptureInfo {
uint32_t start;
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index fb7d24568f..35ebb0d6fe 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -343,6 +343,7 @@ class Session : public PBD::StatefulDestructible
sigc::signal<void,nframes_t> PositionChanged; /* sent after any non-sequential motion */
sigc::signal<void> DurationChanged;
sigc::signal<void> HaltOnXrun;
+ sigc::signal<void> TransportLooped;
sigc::signal<void,RouteList&> RouteAdded;
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 484e4a621a..62f8fb9c36 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -463,7 +463,7 @@ AudioDiskstream::check_record_status (nframes_t transport_frame, nframes_t nfram
}
- if (_flags & Recordable) {
+ if (recordable() && destructive()) {
boost::shared_ptr<ChannelList> c = channels.reader();
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
@@ -592,7 +592,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
/* |--------| recrange
-------------- transrange
*/
- rec_nframes = last_recordable_frame - last_recordable_frame;
+ rec_nframes = last_recordable_frame - first_recordable_frame;
rec_offset = first_recordable_frame - transport_frame;
break;
}
@@ -1663,6 +1663,57 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
}
void
+AudioDiskstream::transport_looped (nframes_t transport_frame)
+{
+ if (was_recording) {
+ // all we need to do is finish this capture, with modified capture length
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ // adjust the capture length knowing that the data will be recorded to disk
+ // only necessary after the first loop where we're recording
+ if (capture_info.size() == 0) {
+ capture_captured += _capture_offset;
+
+ if (_alignment_style == ExistingMaterial) {
+ capture_captured += _session.worst_output_latency();
+ } else {
+ capture_captured += _roll_delay;
+ }
+ }
+
+ finish_capture (true, c);
+
+ // the next region will start recording via the normal mechanism
+ // we'll set the start position to the current transport pos
+ // no latency adjustment or capture offset needs to be made, as that already happened the first time
+ capture_start_frame = transport_frame;
+ first_recordable_frame = transport_frame; // mild lie
+ last_recordable_frame = max_frames;
+ was_recording = true;
+
+ if (recordable() && destructive()) {
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+
+ RingBufferNPT<CaptureTransition>::rw_vector transvec;
+ (*chan)->capture_transition_buf->get_write_vector(&transvec);
+
+ if (transvec.len[0] > 0) {
+ transvec.buf[0]->type = CaptureStart;
+ transvec.buf[0]->capture_val = capture_start_frame;
+ (*chan)->capture_transition_buf->increment_write_ptr(1);
+ }
+ else {
+ // bad!
+ fatal << X_("programming error: capture_transition_buf is full on rec loop! inconceivable!")
+ << endmsg;
+ }
+ }
+ }
+
+ }
+}
+
+void
AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<ChannelList> c)
{
was_recording = false;
@@ -1677,7 +1728,6 @@ AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<Chan
RingBufferNPT<CaptureTransition>::rw_vector transvec;
(*chan)->capture_transition_buf->get_write_vector(&transvec);
-
if (transvec.len[0] > 0) {
transvec.buf[0]->type = CaptureEnd;
transvec.buf[0]->capture_val = capture_captured;
@@ -2370,7 +2420,7 @@ AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_si
playback_buf = new RingBufferNPT<Sample> (bufsize);
capture_buf = new RingBufferNPT<Sample> (bufsize);
- capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
+ capture_transition_buf = new RingBufferNPT<CaptureTransition> (256);
/* touch the ringbuffer buffers, which will cause
them to be mapped into locked physical RAM if
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index c2c21a631d..7c23ae6286 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -1259,7 +1259,7 @@ Session::disable_record (bool rt_context, bool force)
if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
- if (!Config->get_latched_record_enable () || force) {
+ if ((!Config->get_latched_record_enable () && !play_loop) || force) {
g_atomic_int_set (&_record_status, Disabled);
} else {
if (rs == Recording) {
@@ -1290,15 +1290,18 @@ Session::disable_record (bool rt_context, bool force)
void
Session::step_back_from_record ()
{
- g_atomic_int_set (&_record_status, Enabled);
+ /* XXX really atomic compare+swap here */
+ if (g_atomic_int_get (&_record_status) == Recording) {
+ g_atomic_int_set (&_record_status, Enabled);
- if (Config->get_monitoring_model() == HardwareMonitoring) {
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- 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);
+ if (Config->get_monitoring_model() == HardwareMonitoring) {
+ boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
+
+ 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);
+ }
}
}
}
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 055cbcf82d..ba1ac280be 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -469,7 +469,7 @@ Session::follow_slave (nframes_t nframes, nframes_t offset)
cerr << "delta = " << (int) (dir * this_delta)
<< " speed = " << slave_speed
<< " ts = " << _transport_speed
- << " M@"<< slave_transport_frame << " S@" << _transport_frame
+ << " M@ "<< slave_transport_frame << " S@ " << _transport_frame
<< " avgdelta = " << average_slave_delta
<< endl;
#endif
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 22d30fda9d..c5cbae11c9 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -381,7 +381,8 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
_transport_frame = last_stop_frame;
- if (synced_to_jack()) {
+ if (synced_to_jack() && !play_loop) {
+ // cerr << "non-realtimestop: transport locate to " << _transport_frame << endl;
_engine.transport_locate (_transport_frame);
}
}
@@ -420,14 +421,16 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
/* XXX its a little odd that we're doing this here
when realtime_stop(), which has already executed,
will have done this.
+ JLC - so let's not because it seems unnecessary and breaks loop record
*/
-
+#if 0
if (!Config->get_latched_record_enable()) {
g_atomic_int_set (&_record_status, Disabled);
} else {
g_atomic_int_set (&_record_status, Enabled);
}
RecordStateChanged (); /* emit signal */
+#endif
}
if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
@@ -613,7 +616,7 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush,
void
Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop)
{
- if (actively_recording()) {
+ if (actively_recording() && !with_loop) {
return;
}
@@ -704,6 +707,22 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
// cancel looping directly, this is called from event handling context
set_play_loop (false);
}
+ else if (al && _transport_frame == al->start()) {
+ if (with_loop) {
+ // 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
+ (*i)->transport_looped(_transport_frame);
+ }
+ }
+ }
+
+ TransportLooped(); // EMIT SIGNAL
+ }
}
loop_changing = false;
@@ -874,7 +893,9 @@ Session::start_transport ()
break;
case Recording:
- disable_record (false);
+ if (!play_loop) {
+ disable_record (false);
+ }
break;
default: