alignment/capture/positioning changes ported from 2.X

git-svn-id: svn://localhost/ardour2/branches/3.0@6886 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis
2010-04-12 22:35:06 +00:00
parent ac8c7e427f
commit 981c8906fb
6 changed files with 123 additions and 91 deletions

View File

@@ -233,6 +233,7 @@ class Diskstream : public SessionObject
virtual void set_align_style_from_io() {}
virtual void setup_destructive_playlist () {}
virtual void use_destructive_playlist () {}
virtual void prepare_to_stop (framepos_t pos);
void calculate_record_range(OverlapType ot, sframes_t transport_frame, nframes_t nframes,
nframes_t& rec_nframes, nframes_t& rec_offset);

View File

@@ -428,8 +428,6 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
int ret = -1;
nframes_t rec_offset = 0;
nframes_t rec_nframes = 0;
bool nominally_recording;
bool re = record_enabled ();
bool collect_playback = false;
playback_distance = 0;
@@ -440,8 +438,6 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
check_record_status (transport_frame, nframes, can_record);
nominally_recording = (can_record && re);
if (nframes == 0) {
return 0;
}
@@ -468,27 +464,26 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
frame has left the punch range (which will cause the "can_record" argument to be false).
*/
if (nominally_recording || (re && was_recording && _session.get_record_enabled() && _session.config.get_punch_out())) {
// Safeguard against situations where process() goes haywire when autopunching and last_recordable_frame < first_recordable_frame
if (last_recordable_frame < first_recordable_frame) {
last_recordable_frame = max_frames;
}
OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
if (rec_nframes && !was_recording) {
capture_captured = 0;
was_recording = true;
}
}
// Safeguard against situations where process() goes haywire when autopunching and last_recordable_frame < first_recordable_frame
if (last_recordable_frame < first_recordable_frame) {
last_recordable_frame = max_frames;
}
OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
if (rec_nframes && !was_recording) {
capture_captured = 0;
was_recording = true;
}
if (can_record && !_last_capture_regions.empty()) {
_last_capture_regions.clear ();
}
if (nominally_recording || rec_nframes) {
if (rec_nframes) {
uint32_t limit = _io->n_ports ().n_audio();
@@ -576,7 +571,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
adjust_capture_position = rec_nframes;
} else if (nominally_recording) {
} else if (can_record && record_enabled()) {
/* can't do actual capture yet - waiting for latency effects to finish before we start*/

View File

@@ -525,6 +525,7 @@ Diskstream::check_record_status (nframes_t transport_frame, nframes_t /*nframes*
const int transport_rolling = 0x4;
const int track_rec_enabled = 0x2;
const int global_rec_enabled = 0x1;
const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
/* merge together the 3 factors that affect record status, and compute
what has changed.
@@ -537,88 +538,101 @@ Diskstream::check_record_status (nframes_t transport_frame, nframes_t /*nframes*
if (possibly_recording == last_possibly_recording) {
return;
}
if (possibly_recording == fully_rec_enabled) {
/* change state */
/* if per-track or global rec-enable turned on while the other was already on, we've started recording */
if (((change & track_rec_enabled) && record_enabled() && (!(change & global_rec_enabled) && can_record)) ||
((change & global_rec_enabled) && can_record && (!(change & track_rec_enabled) && record_enabled()))) {
/* starting to record: compute first+last frames */
if (last_possibly_recording == fully_rec_enabled) {
return;
}
/* we transitioned to recording. lets see if its transport based or a punch */
first_recordable_frame = transport_frame + _capture_offset;
last_recordable_frame = max_frames;
capture_start_frame = transport_frame;
if (!(last_possibly_recording & transport_rolling) && (possibly_recording & transport_rolling)) {
/* was stopped, now rolling (and recording) */
if (change & transport_rolling) {
/* transport-change (started rolling) */
if (_alignment_style == ExistingMaterial) {
first_recordable_frame += _session.worst_output_latency();
DEBUG_TRACE (DEBUG::Latency, string_compose ("Offset rec from stop. Capture offset: %1 Worst O/P Latency: %2 Roll Delay: %3 First Recordable Frame: %4 Transport Frame: %5\n",
_capture_offset, _session.worst_output_latency(), _roll_delay, first_recordable_frame, transport_frame));
} else {
/* there are two delays happening:
1) inbound, represented by _capture_offset
2) outbound, represented by _session.worst_output_latency()
the first sample to record occurs when the larger of these
two has elapsed, since they occur in parallel.
since we've already added _capture_offset, just add the
difference if _session.worst_output_latency() is larger.
*/
if (_capture_offset < _session.worst_output_latency()) {
first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
}
} else {
first_recordable_frame += _roll_delay;
}
}
} else {
} else {
/* was rolling, but record state changed */
/* punch in */
if (_alignment_style == ExistingMaterial) {
/* manual punch in happens at the correct transport frame
because the user hit a button. but to get alignment correct
we have to back up the position of the new region to the
appropriate spot given the roll delay.
*/
/* autopunch toggles recording at the precise
/* There are two kinds of punch:
manual punch in happens at the correct transport frame
because the user hit a button. but to get alignment correct
we have to back up the position of the new region to the
appropriate spot given the roll delay.
autopunch toggles recording at the precise
transport frame, and then the DS waits
to start recording for a time that depends
on the output latency.
XXX: BUT THIS CODE DOESN'T DIFFERENTIATE !!!
*/
first_recordable_frame += _session.worst_output_latency();
DEBUG_TRACE (DEBUG::Latency, string_compose ("Punch in manual/auto. Capture offset: %1 Worst O/P Latency: %2 Roll Delay: %3 First Recordable Frame: %4 Transport Frame: %5\n",
_capture_offset, _session.worst_output_latency(), _roll_delay, first_recordable_frame, transport_frame));
if (_capture_offset < _session.worst_output_latency()) {
/* see comment in ExistingMaterial block above */
first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
}
} else {
if (_session.config.get_punch_in()) {
first_recordable_frame += _roll_delay;
} else {
capture_start_frame -= _roll_delay;
}
capture_start_frame -= _roll_delay;
}
}
prepare_record_status (capture_start_frame);
}
} else {
prepare_record_status(capture_start_frame);
if (last_possibly_recording == fully_rec_enabled) {
} else if (!record_enabled() || !can_record) {
/* stop recording */
last_recordable_frame = transport_frame + _capture_offset;
if (_alignment_style == ExistingMaterial) {
last_recordable_frame += _session.worst_output_latency();
} else {
last_recordable_frame += _roll_delay;
}
//first_recordable_frame = max_frames;
DEBUG_TRACE (DEBUG::Latency, string_compose ("Stop record - %6 | %7. Capture offset: %1 Worst O/P Latency: %2 Roll Delay: %3 First Recordable Frame: %4 Transport Frame: %5\n",
_capture_offset, _session.worst_output_latency(), _roll_delay, first_recordable_frame, transport_frame,
can_record, record_enabled()));
}
/* we were recording last time */
if (change & transport_rolling) {
/* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop() */
} else {
/* punch out */
last_recordable_frame = transport_frame + _capture_offset;
if (_alignment_style == ExistingMaterial) {
if (_session.worst_output_latency() > _capture_offset) {
last_recordable_frame += (_session.worst_output_latency() - _capture_offset);
}
} else {
last_recordable_frame += _roll_delay;
}
}
}
}
last_possibly_recording = possibly_recording;
}
@@ -673,3 +687,9 @@ Diskstream::calculate_record_range(OverlapType ot, sframes_t transport_frame, nf
break;
}
}
void
Diskstream::prepare_to_stop (framepos_t pos)
{
last_recordable_frame = pos + _capture_offset;
}

View File

@@ -45,7 +45,7 @@ PortExportChannel::read (Sample * data, nframes_t frames) const
for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
if (*it != 0) {
Sample* port_buffer = (*it)->get_audio_buffer(frames, 0).data();
Sample* port_buffer = (*it)->get_audio_buffer(frames).data();
for (uint32_t i = 0; i < frames; ++i) {
data[i] += (float) port_buffer[i];

View File

@@ -28,11 +28,9 @@
#include <unistd.h>
#include <limits.h>
#include <glibmm/thread.h>
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
#include <glibmm/thread.h>
#include "pbd/error.h"
#include "pbd/boost_debug.h"
@@ -1043,9 +1041,7 @@ Session::disable_record (bool rt_context, bool force)
void
Session::step_back_from_record ()
{
/* XXX really atomic compare+swap here */
if (g_atomic_int_get (&_record_status) == Recording) {
g_atomic_int_set (&_record_status, Enabled);
if (g_atomic_int_compare_and_exchange (&_record_status, Recording, Enabled)) {
if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();

View File

@@ -197,10 +197,17 @@ Session::realtime_stop (bool abort, bool clear_state)
/* move the transport position back to where the
request for a stop was noticed. we rolled
past that point to pick up delayed input.
past that point to pick up delayed input (and/or to delick)
*/
decrement_transport_position (_worst_output_latency);
if (_worst_output_latency > current_block_size) {
/* we rolled past the stop point to pick up data that had
not yet arrived. move back to where the stop occured.
*/
decrement_transport_position (current_block_size + (_worst_output_latency - current_block_size));
} else {
decrement_transport_position (current_block_size);
}
/* the duration change is not guaranteed to have happened, but is likely */
@@ -1011,9 +1018,13 @@ Session::stop_transport (bool abort, bool clear_state)
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) {
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->prepare_to_stop (_transport_frame);
}
/* 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.
@@ -1035,6 +1046,15 @@ Session::stop_transport (bool abort, bool clear_state)
if ((transport_sub_state & PendingDeclickOut) == 0) {
if (!(transport_sub_state & StopPendingCapture)) {
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->prepare_to_stop (_transport_frame);
}
}
transport_sub_state |= PendingDeclickOut;
/* we'll be called again after the declick */
pending_abort = abort;