diff options
author | Jesse Chappell <jesse@essej.net> | 2007-06-26 02:16:54 +0000 |
---|---|---|
committer | Jesse Chappell <jesse@essej.net> | 2007-06-26 02:16:54 +0000 |
commit | e9b1b7110ba49103af8e99547c3a165526a80b14 (patch) | |
tree | f6eac5ae42f48605df6167bdc9a12421bdbe103b | |
parent | cdccec62fe0ec32c8f4ae1efd3d2ab70dae19dfc (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/trunk@2035 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | gtk2_ardour/ardour_ui.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/streamview.cc | 9 | ||||
-rw-r--r-- | gtk2_ardour/streamview.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/audio_diskstream.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/diskstream.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 1 | ||||
-rw-r--r-- | libs/ardour/audio_diskstream.cc | 58 | ||||
-rw-r--r-- | libs/ardour/session.cc | 21 | ||||
-rw-r--r-- | libs/ardour/session_process.cc | 2 | ||||
-rw-r--r-- | libs/ardour/session_transport.cc | 29 |
10 files changed, 106 insertions, 19 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 10f6a2fe7a..bde4ca2947 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1244,7 +1244,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 305b5c3240..b18e5efb42 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -76,6 +76,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)); } @@ -315,6 +316,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 7011801560..15e354bdab 100644 --- a/gtk2_ardour/streamview.h +++ b/gtk2_ardour/streamview.h @@ -102,6 +102,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 1bf94a4494..aaf5461361 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -227,6 +227,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 3dd6555011..85fc3d3371 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -205,6 +205,7 @@ class Diskstream : public SessionObject 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 1fea324406..f0a175c624 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -351,6 +351,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 7e583afeb7..d0e2b24263 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -465,7 +465,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) { @@ -594,7 +594,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; } @@ -1640,6 +1640,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; @@ -1654,7 +1705,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; @@ -2348,7 +2398,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 10860b0c88..6df71611ce 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1120,7 +1120,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) { @@ -1155,15 +1155,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 44ca7f1235..dc71a40ca2 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -489,7 +489,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 60cc8b91ae..7deb40c161 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -386,7 +386,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); } } @@ -422,14 +423,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()) { @@ -615,7 +618,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; } @@ -711,6 +714,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; @@ -893,7 +912,9 @@ Session::start_transport () break; case Recording: - disable_record (false); + if (!play_loop) { + disable_record (false); + } break; default: |