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:
@@ -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);
|
||||
|
||||
@@ -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*/
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user