diff options
author | Jesse Chappell <jesse@essej.net> | 2007-06-26 02:15:02 +0000 |
---|---|---|
committer | Jesse Chappell <jesse@essej.net> | 2007-06-26 02:15:02 +0000 |
commit | 4ecfc19541ed05c5e51c367556e9902c7f83b705 (patch) | |
tree | 8b1f73f6aa8154cf30a3b88553262407c7bfa03a /libs | |
parent | 4431b678239182a85310d4aba4b4f66c6a7cd06b (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
Diffstat (limited to 'libs')
-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 |
7 files changed, 95 insertions, 18 deletions
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: |