sorta-kinda working latency compensation, latency reporting and capture alignment ... working except that we report the wrong information to JACK and i've noticed a couple of odd circumstances where turning on a latent plugin caused punch recording to fail
git-svn-id: svn://localhost/ardour2/branches/3.0@9121 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
e806084402
commit
d155f32039
|
@ -166,7 +166,7 @@ public:
|
|||
return _data + offset;
|
||||
}
|
||||
|
||||
void prepare () { _written = false; }
|
||||
void prepare () { _written = false; _silent = false; }
|
||||
bool written() const { return _written; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -41,11 +41,11 @@ class AudioPort : public Port
|
|||
|
||||
size_t raw_buffer_size (pframes_t nframes) const;
|
||||
|
||||
Buffer& get_buffer (framecnt_t nframes) {
|
||||
Buffer& get_buffer (pframes_t nframes) {
|
||||
return get_audio_buffer (nframes);
|
||||
}
|
||||
|
||||
AudioBuffer& get_audio_buffer (framecnt_t nframes);
|
||||
AudioBuffer& get_audio_buffer (pframes_t nframes);
|
||||
|
||||
protected:
|
||||
friend class AudioEngine;
|
||||
|
|
|
@ -187,7 +187,6 @@ class AudioEngine : public SessionHandlePtr
|
|||
void get_physical_inputs (DataType type, std::vector<std::string>&);
|
||||
|
||||
void update_total_latencies ();
|
||||
void update_total_latency (const Port&);
|
||||
|
||||
Port *get_port_by_name (const std::string &);
|
||||
|
||||
|
@ -320,10 +319,8 @@ _ the regular process() call to session->process() is not made.
|
|||
|
||||
void set_jack_callbacks ();
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
static void _latency_callback (jack_latency_callback_mode_t, void*);
|
||||
void jack_latency_callback (jack_latency_callback_mode_t);
|
||||
#endif
|
||||
|
||||
int connect_to_jack (std::string client_name, std::string session_uuid);
|
||||
|
||||
|
|
|
@ -75,7 +75,6 @@ public:
|
|||
void flush_buffers (framecnt_t nframes, framepos_t time);
|
||||
void no_outs_cuz_we_no_monitor(bool);
|
||||
void cycle_start (pframes_t);
|
||||
void increment_output_offset (framecnt_t);
|
||||
void transport_stopped (framepos_t frame);
|
||||
|
||||
BufferSet& output_buffers() { return *_output_buffers; }
|
||||
|
@ -105,7 +104,6 @@ public:
|
|||
Role _role;
|
||||
BufferSet* _output_buffers;
|
||||
gain_t _current_gain;
|
||||
framecnt_t _output_offset;
|
||||
bool _no_outs_cuz_we_no_monitor;
|
||||
boost::shared_ptr<MuteMaster> _mute_master;
|
||||
bool no_panner_reset;
|
||||
|
|
|
@ -90,6 +90,7 @@ class IO : public SessionObject, public Latent
|
|||
bool set_name (const std::string& str);
|
||||
|
||||
virtual void silence (framecnt_t);
|
||||
void increment_port_buffer_offset (pframes_t offset);
|
||||
|
||||
int ensure_io (ChanCount cnt, bool clear, void *src);
|
||||
|
||||
|
@ -111,9 +112,6 @@ class IO : public SessionObject, public Latent
|
|||
|
||||
framecnt_t signal_latency () const { return _own_latency; }
|
||||
framecnt_t latency () const;
|
||||
void set_port_latency (framecnt_t);
|
||||
|
||||
void update_port_total_latencies ();
|
||||
|
||||
PortSet& ports() { return _ports; }
|
||||
const PortSet& ports() const { return _ports; }
|
||||
|
|
|
@ -65,6 +65,8 @@ class IOProcessor : public Processor
|
|||
void silence (framecnt_t nframes);
|
||||
void disconnect ();
|
||||
|
||||
void increment_port_buffer_offset (pframes_t);
|
||||
|
||||
virtual bool feeds (boost::shared_ptr<Route> other) const;
|
||||
|
||||
PBD::Signal2<void,IOProcessor*,bool> AutomationPlaybackChanged;
|
||||
|
|
|
@ -46,11 +46,11 @@ class MidiPort : public Port {
|
|||
|
||||
size_t raw_buffer_size (pframes_t nframes) const;
|
||||
|
||||
Buffer& get_buffer (framecnt_t nframes) {
|
||||
Buffer& get_buffer (pframes_t nframes) {
|
||||
return get_midi_buffer (nframes);
|
||||
}
|
||||
|
||||
MidiBuffer& get_midi_buffer (framecnt_t nframes);
|
||||
MidiBuffer& get_midi_buffer (pframes_t nframes);
|
||||
|
||||
protected:
|
||||
friend class AudioEngine;
|
||||
|
|
|
@ -52,8 +52,6 @@ public:
|
|||
return DataType::MIDI;
|
||||
}
|
||||
|
||||
void set_latency_delay (framecnt_t);
|
||||
|
||||
int export_stuff (BufferSet& bufs, framecnt_t nframes, framepos_t end_frame);
|
||||
|
||||
void freeze_me (InterThreadInfo&);
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#ifndef __ardour_port_h__
|
||||
#define __ardour_port_h__
|
||||
|
||||
#include "libardour-config.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -45,9 +47,6 @@ public:
|
|||
|
||||
virtual ~Port ();
|
||||
|
||||
static void set_buffer_size (pframes_t sz) {
|
||||
_buffer_size = sz;
|
||||
}
|
||||
static void set_connecting_blocked( bool yn ) {
|
||||
_connecting_blocked = yn;
|
||||
}
|
||||
|
@ -93,16 +92,22 @@ public:
|
|||
|
||||
void ensure_monitor_input (bool);
|
||||
bool monitoring_input () const;
|
||||
framecnt_t total_latency () const;
|
||||
int reestablish ();
|
||||
int reconnect ();
|
||||
void request_monitor_input (bool);
|
||||
void set_latency (framecnt_t);
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
bool last_monitor() const { return _last_monitor; }
|
||||
void set_last_monitor (bool yn) { _last_monitor = yn; }
|
||||
|
||||
jack_port_t* jack_port() const { return _jack_port; }
|
||||
|
||||
void get_connected_latency_range (jack_latency_range_t& range, bool playback) const;
|
||||
void set_latency_range (jack_latency_range_t& range, bool playback) const;
|
||||
#endif
|
||||
|
||||
void set_private_latency_range (jack_latency_range_t& range, bool playback);
|
||||
const jack_latency_range_t& private_latency_range (bool playback) const;
|
||||
|
||||
void set_public_latency_range (jack_latency_range_t& range, bool playback) const;
|
||||
jack_latency_range_t public_latency_range (bool playback) const;
|
||||
|
||||
virtual void reset ();
|
||||
|
||||
|
@ -110,10 +115,10 @@ public:
|
|||
virtual size_t raw_buffer_size (pframes_t nframes) const = 0;
|
||||
|
||||
virtual DataType type () const = 0;
|
||||
virtual void cycle_start (pframes_t) = 0;
|
||||
virtual void cycle_start (pframes_t);
|
||||
virtual void cycle_end (pframes_t) = 0;
|
||||
virtual void cycle_split () = 0;
|
||||
virtual Buffer& get_buffer (framecnt_t nframes) = 0;
|
||||
virtual Buffer& get_buffer (pframes_t nframes) = 0;
|
||||
virtual void flush_buffers (pframes_t nframes, framepos_t /*time*/) {}
|
||||
virtual void transport_stopped () {}
|
||||
|
||||
|
@ -124,15 +129,18 @@ public:
|
|||
PBD::Signal1<void,bool> MonitorInputChanged;
|
||||
|
||||
|
||||
static framecnt_t port_offset() { return _port_offset; }
|
||||
static void set_cycle_framecnt (pframes_t n) {
|
||||
_cycle_nframes = n;
|
||||
}
|
||||
static framecnt_t port_offset() { return _global_port_buffer_offset; }
|
||||
static void set_global_port_buffer_offset (pframes_t off) {
|
||||
_global_port_buffer_offset = off;
|
||||
}
|
||||
static void increment_global_port_buffer_offset (pframes_t n) {
|
||||
_global_port_buffer_offset += n;
|
||||
}
|
||||
|
||||
static void set_port_offset (framecnt_t off) {
|
||||
_port_offset = off;
|
||||
}
|
||||
|
||||
static void increment_port_offset (framecnt_t n) {
|
||||
_port_offset += n;
|
||||
}
|
||||
virtual void increment_port_buffer_offset (pframes_t n);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -140,25 +148,25 @@ protected:
|
|||
|
||||
jack_port_t* _jack_port; ///< JACK port
|
||||
|
||||
static pframes_t _buffer_size;
|
||||
static bool _connecting_blocked;
|
||||
static framecnt_t _port_offset;
|
||||
static pframes_t _global_port_buffer_offset; /* access only from process() tree */
|
||||
static pframes_t _cycle_nframes; /* access only from process() tree */
|
||||
|
||||
framecnt_t _port_buffer_offset; /* access only from process() tree */
|
||||
|
||||
jack_latency_range_t _private_playback_latency;
|
||||
jack_latency_range_t _private_capture_latency;
|
||||
|
||||
static AudioEngine* _engine; ///< the AudioEngine
|
||||
|
||||
private:
|
||||
friend class AudioEngine;
|
||||
|
||||
void recompute_total_latency () const;
|
||||
|
||||
/* XXX */
|
||||
bool _last_monitor;
|
||||
|
||||
std::string _name; ///< port short name
|
||||
Flags _flags; ///< flags
|
||||
bool _last_monitor;
|
||||
|
||||
/** ports that we are connected to, kept so that we can
|
||||
reconnect to JACK when required */
|
||||
reconnect to JACK when required
|
||||
*/
|
||||
std::set<std::string> _connections;
|
||||
|
||||
};
|
||||
|
|
|
@ -250,11 +250,15 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
|
|||
void all_processors_flip();
|
||||
void all_processors_active (Placement, bool state);
|
||||
|
||||
void set_latency_ranges (bool playback) const;
|
||||
virtual framecnt_t update_total_latency();
|
||||
void set_latency_delay (framecnt_t);
|
||||
framecnt_t set_private_port_latencies (bool playback) const;
|
||||
void set_public_port_latencies (framecnt_t, bool playback) const;
|
||||
|
||||
framecnt_t update_signal_latency();
|
||||
virtual void set_latency_compensation (framecnt_t);
|
||||
|
||||
void set_user_latency (framecnt_t);
|
||||
framecnt_t initial_delay() const { return _initial_delay; }
|
||||
framecnt_t signal_latency() const { return _signal_latency; }
|
||||
|
||||
PBD::Signal0<void> active_changed;
|
||||
PBD::Signal0<void> phase_invert_changed;
|
||||
|
@ -426,6 +430,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
|
|||
boost::shared_ptr<IO> _output;
|
||||
|
||||
bool _active;
|
||||
framecnt_t _signal_latency;
|
||||
framecnt_t _initial_delay;
|
||||
framecnt_t _roll_delay;
|
||||
|
||||
|
@ -517,7 +522,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
|
|||
void set_mute_master_solo ();
|
||||
|
||||
void set_processor_positions ();
|
||||
void update_port_latencies (const PortSet& ports, const PortSet& feeders, bool playback, framecnt_t) const;
|
||||
framecnt_t update_port_latencies (const PortSet& ports, const PortSet& feeders, bool playback, framecnt_t) const;
|
||||
|
||||
void setup_invisible_processors ();
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#ifndef __ardour_session_h__
|
||||
#define __ardour_session_h__
|
||||
|
||||
#include "libardour-config.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
@ -818,7 +820,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
protected:
|
||||
friend class Route;
|
||||
void schedule_curve_reallocation ();
|
||||
void update_latency_compensation (bool, bool);
|
||||
void update_latency_compensation (bool, bool, bool force=false);
|
||||
|
||||
private:
|
||||
int create (const std::string& mix_template, BusProfile*);
|
||||
|
@ -1364,9 +1366,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
void reset_jack_connection (jack_client_t* jack);
|
||||
void process_rtop (SessionEvent*);
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
void update_latency (bool playback);
|
||||
#endif
|
||||
|
||||
XMLNode& state(bool);
|
||||
|
||||
|
|
|
@ -67,8 +67,7 @@ class Track : public Route, public PublicDiskstream
|
|||
virtual void use_new_diskstream () = 0;
|
||||
virtual void set_diskstream (boost::shared_ptr<Diskstream>);
|
||||
|
||||
framecnt_t update_total_latency();
|
||||
void set_latency_delay (framecnt_t);
|
||||
void set_latency_compensation (framecnt_t);
|
||||
|
||||
enum FreezeState {
|
||||
NoFreeze,
|
||||
|
|
|
@ -390,12 +390,12 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
|
|||
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||
|
||||
RingBufferNPT<CaptureTransition>::rw_vector transvec;
|
||||
(*chan)->capture_transition_buf->get_write_vector(&transvec);
|
||||
RingBufferNPT<CaptureTransition>::rw_vector transitions;
|
||||
(*chan)->capture_transition_buf->get_write_vector (&transitions);
|
||||
|
||||
if (transvec.len[0] > 0) {
|
||||
transvec.buf[0]->type = CaptureStart;
|
||||
transvec.buf[0]->capture_val = capture_start_frame;
|
||||
if (transitions.len[0] > 0) {
|
||||
transitions.buf[0]->type = CaptureStart;
|
||||
transitions.buf[0]->capture_val = capture_start_frame;
|
||||
(*chan)->capture_transition_buf->increment_write_ptr(1);
|
||||
} else {
|
||||
// bad!
|
||||
|
@ -1481,7 +1481,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
|
|||
|
||||
RegionFactory::region_name (region_name, whole_file_region_name, false);
|
||||
|
||||
cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
|
||||
// cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
|
||||
|
||||
try {
|
||||
|
||||
|
@ -1548,7 +1548,7 @@ AudioDiskstream::transport_looped (framepos_t transport_frame)
|
|||
capture_captured += _capture_offset;
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
capture_captured += _session.worst_playback_latency();
|
||||
capture_captured += _session.worst_output_latency();
|
||||
} else {
|
||||
capture_captured += _roll_delay;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ AudioPort::cycle_start (pframes_t nframes)
|
|||
{
|
||||
/* caller must hold process lock */
|
||||
|
||||
Port::cycle_start (nframes);
|
||||
|
||||
if (sends_output()) {
|
||||
_buffer->prepare ();
|
||||
}
|
||||
|
@ -67,10 +69,11 @@ AudioPort::cycle_split ()
|
|||
}
|
||||
|
||||
AudioBuffer&
|
||||
AudioPort::get_audio_buffer (framecnt_t nframes)
|
||||
AudioPort::get_audio_buffer (pframes_t nframes)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + _port_offset, nframes);
|
||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
|
||||
_global_port_buffer_offset + _port_buffer_offset, nframes);
|
||||
return *_buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -387,6 +387,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
|
|||
playback distance to zero, thus causing diskstream::commit
|
||||
to do nothing.
|
||||
*/
|
||||
cerr << name() << " Can't operate at " << transport_frame << " since roll delay is only " << _roll_delay << endl;
|
||||
return diskstream->process (transport_frame, 0, can_record, rec_monitors_input, need_butler);
|
||||
}
|
||||
|
||||
|
|
|
@ -190,11 +190,10 @@ AudioEngine::set_jack_callbacks ()
|
|||
if( jack_set_session_callback)
|
||||
jack_set_session_callback (_priv_jack, _session_callback, this);
|
||||
#endif
|
||||
#if HAVE_JACK_NEW_LATENCY
|
||||
|
||||
if (jack_set_latency_callback) {
|
||||
jack_set_latency_callback (_priv_jack, _latency_callback, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
jack_set_error_function (ardour_jack_error);
|
||||
}
|
||||
|
@ -389,13 +388,11 @@ AudioEngine::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* a
|
|||
ae->PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
void
|
||||
AudioEngine::_latency_callback (jack_latency_callback_mode_t mode, void* arg)
|
||||
{
|
||||
return static_cast<AudioEngine *> (arg)->jack_latency_callback (mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
AudioEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn, void* arg)
|
||||
|
@ -413,9 +410,9 @@ AudioEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int co
|
|||
boost::shared_ptr<Ports> pr = ae->ports.reader ();
|
||||
Ports::iterator i = pr->begin ();
|
||||
while (i != pr->end() && (port_a == 0 || port_b == 0)) {
|
||||
if (jack_port_a == (*i)->_jack_port) {
|
||||
if (jack_port_a == (*i)->jack_port()) {
|
||||
port_a = *i;
|
||||
} else if (jack_port_b == (*i)->_jack_port) {
|
||||
} else if (jack_port_b == (*i)->jack_port()) {
|
||||
port_b = *i;
|
||||
}
|
||||
++i;
|
||||
|
@ -429,7 +426,7 @@ AudioEngine::split_cycle (pframes_t offset)
|
|||
{
|
||||
/* caller must hold process lock */
|
||||
|
||||
AudioPort::increment_port_offset (offset);
|
||||
Port::increment_global_port_buffer_offset (offset);
|
||||
|
||||
/* tell all Ports that we're going to start a new (split) cycle */
|
||||
|
||||
|
@ -512,7 +509,8 @@ AudioEngine::process_callback (pframes_t nframes)
|
|||
/* tell all relevant objects that we're starting a new cycle */
|
||||
|
||||
Delivery::CycleStart (nframes);
|
||||
AudioPort::set_port_offset (0);
|
||||
Port::set_global_port_buffer_offset (0);
|
||||
Port::set_cycle_framecnt (nframes);
|
||||
InternalReturn::CycleStart (nframes);
|
||||
|
||||
/* tell all Ports that we're starting a new cycle */
|
||||
|
@ -560,8 +558,8 @@ AudioEngine::process_callback (pframes_t nframes)
|
|||
Port *port = (*i);
|
||||
bool x;
|
||||
|
||||
if (port->_last_monitor != (x = port->monitoring_input ())) {
|
||||
port->_last_monitor = x;
|
||||
if (port->last_monitor() != (x = port->monitoring_input ())) {
|
||||
port->set_last_monitor (x);
|
||||
/* XXX I think this is dangerous, due to
|
||||
a likely mutex in the signal handlers ...
|
||||
*/
|
||||
|
@ -621,7 +619,6 @@ AudioEngine::jack_sample_rate_callback (pframes_t nframes)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
void
|
||||
AudioEngine::jack_latency_callback (jack_latency_callback_mode_t mode)
|
||||
{
|
||||
|
@ -629,7 +626,6 @@ AudioEngine::jack_latency_callback (jack_latency_callback_mode_t mode)
|
|||
_session->update_latency (mode == JackPlaybackLatency);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
AudioEngine::_bufsize_callback (pframes_t nframes, void *arg)
|
||||
|
@ -1188,12 +1184,6 @@ AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
|
|||
get_physical (type, JackPortIsInput, outs);
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::update_total_latency (const Port& port)
|
||||
{
|
||||
port.recompute_total_latency ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::transport_stop ()
|
||||
{
|
||||
|
|
|
@ -59,7 +59,6 @@ Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pann
|
|||
, _role (r)
|
||||
, _output_buffers (new BufferSet())
|
||||
, _current_gain (1.0)
|
||||
, _output_offset (0)
|
||||
, _no_outs_cuz_we_no_monitor (false)
|
||||
, _mute_master (mm)
|
||||
, no_panner_reset (false)
|
||||
|
@ -81,7 +80,6 @@ Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::sha
|
|||
, _role (r)
|
||||
, _output_buffers (new BufferSet())
|
||||
, _current_gain (1.0)
|
||||
, _output_offset (0)
|
||||
, _no_outs_cuz_we_no_monitor (false)
|
||||
, _mute_master (mm)
|
||||
, no_panner_reset (false)
|
||||
|
@ -123,16 +121,9 @@ Delivery::display_name () const
|
|||
void
|
||||
Delivery::cycle_start (pframes_t /*nframes*/)
|
||||
{
|
||||
_output_offset = 0;
|
||||
_no_outs_cuz_we_no_monitor = false;
|
||||
}
|
||||
|
||||
void
|
||||
Delivery::increment_output_offset (framecnt_t n)
|
||||
{
|
||||
_output_offset += n;
|
||||
}
|
||||
|
||||
bool
|
||||
Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
|
||||
{
|
||||
|
|
|
@ -640,6 +640,9 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
|
|||
if (possibly_recording == last_possibly_recording) {
|
||||
return;
|
||||
}
|
||||
|
||||
framecnt_t existing_material_offset = _session.worst_playback_latency();
|
||||
|
||||
if (possibly_recording == fully_rec_enabled) {
|
||||
|
||||
if (last_possibly_recording == fully_rec_enabled) {
|
||||
|
@ -650,52 +653,30 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
|
|||
|
||||
first_recordable_frame = transport_frame + _capture_offset;
|
||||
last_recordable_frame = max_framepos;
|
||||
capture_start_frame = transport_frame;
|
||||
capture_start_frame = _session.transport_frame();
|
||||
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 LRF = %3 CSF = %4 CO = %5, WPL = %6\n",
|
||||
/* in theory, we should be offsetting by _session.worst_playback_latency() when we adjust
|
||||
for ExistingMaterial alignment. But that number includes the worst processor latency
|
||||
across all routes, and each track will already be roll-delay adjusted to handle that.
|
||||
so don't use worst_playback_latency(), just worst_output_latency() which covers
|
||||
only downstream latency from IO ports.
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8\n",
|
||||
name(), first_recordable_frame, last_recordable_frame, capture_start_frame,
|
||||
_capture_offset,
|
||||
_session.worst_playback_latency(),
|
||||
transport_frame));
|
||||
existing_material_offset,
|
||||
transport_frame,
|
||||
_roll_delay));
|
||||
|
||||
|
||||
|
||||
if (change & transport_rolling) {
|
||||
|
||||
/* transport-change (started rolling) */
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
|
||||
/* audio played by ardour will take (up to) _session.worst_playback_latency() ("WOL") to
|
||||
appear at the speakers; audio played at the time when it does appear at
|
||||
the speakers will take _capture_offset to arrive back here. we've
|
||||
already added _capture_offset, so now add WOL.
|
||||
*/
|
||||
|
||||
first_recordable_frame += _session.worst_playback_latency();
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tROLL: shift FRF by delta between WOL %1\n",
|
||||
first_recordable_frame));
|
||||
} else {
|
||||
first_recordable_frame += _roll_delay;
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tROLL: shift FRF by roll delay of %1 to %2\n",
|
||||
_roll_delay, first_recordable_frame));
|
||||
}
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
first_recordable_frame += existing_material_offset;
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n",
|
||||
first_recordable_frame));
|
||||
} else {
|
||||
|
||||
/* punch in */
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
|
||||
/* see comment in ExistingMaterial block above */
|
||||
first_recordable_frame += _session.worst_playback_latency();
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tMANUAL PUNCH: shift FRF by delta between WOL and CO to %1\n",
|
||||
first_recordable_frame));
|
||||
} else {
|
||||
capture_start_frame -= _roll_delay;
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tPUNCH: shift CSF by roll delay of %1 to %2\n",
|
||||
_roll_delay, capture_start_frame));
|
||||
}
|
||||
capture_start_frame += _roll_delay;
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift CFS by roll delay of %1 to %2\n",
|
||||
_roll_delay, capture_start_frame));
|
||||
}
|
||||
|
||||
prepare_record_status (capture_start_frame);
|
||||
|
@ -707,7 +688,11 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
|
|||
/* we were recording last time */
|
||||
|
||||
if (change & transport_rolling) {
|
||||
/* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop() */
|
||||
|
||||
/* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop(). We
|
||||
had to set it there because we likely rolled past the stopping point to declick out,
|
||||
and then backed up.
|
||||
*/
|
||||
|
||||
} else {
|
||||
/* punch out */
|
||||
|
@ -715,7 +700,7 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
|
|||
last_recordable_frame = transport_frame + _capture_offset;
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
last_recordable_frame += _session.worst_input_latency();
|
||||
last_recordable_frame += existing_material_offset;
|
||||
} else {
|
||||
last_recordable_frame += _roll_delay;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,18 @@ IO::~IO ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
IO::increment_port_buffer_offset (pframes_t offset)
|
||||
{
|
||||
/* io_lock, not taken: function must be called from Session::process() calltree */
|
||||
|
||||
if (_direction == Output) {
|
||||
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
|
||||
i->increment_port_buffer_offset (offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IO::silence (framecnt_t nframes)
|
||||
{
|
||||
|
@ -1133,16 +1145,6 @@ IO::set_name (const string& requested_name)
|
|||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
IO::set_port_latency (framecnt_t nframes)
|
||||
{
|
||||
Glib::Mutex::Lock lm (io_lock);
|
||||
|
||||
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
|
||||
i->set_latency (nframes);
|
||||
}
|
||||
}
|
||||
|
||||
framecnt_t
|
||||
IO::latency () const
|
||||
{
|
||||
|
@ -1154,26 +1156,17 @@ IO::latency () const
|
|||
/* io lock not taken - must be protected by other means */
|
||||
|
||||
for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
|
||||
if ((latency = i->total_latency ()) > max_latency) {
|
||||
if ((latency = i->public_latency_range (_direction == Output).max) > max_latency) {
|
||||
max_latency = latency;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: max latency from %2 ports = %3\n",
|
||||
name(), _ports.num_ports(), max_latency));
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: max %4 latency from %2 ports = %3\n",
|
||||
name(), _ports.num_ports(), max_latency,
|
||||
((_direction == Output) ? "PLAYBACK" : "CAPTURE")));
|
||||
return max_latency;
|
||||
}
|
||||
|
||||
void
|
||||
IO::update_port_total_latencies ()
|
||||
{
|
||||
/* io_lock, not taken: function must be called from Session::process() calltree */
|
||||
|
||||
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
|
||||
_session.engine().update_total_latency (*i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
|
||||
{
|
||||
|
|
|
@ -249,6 +249,14 @@ IOProcessor::silence (framecnt_t nframes)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
IOProcessor::increment_port_buffer_offset (pframes_t offset)
|
||||
{
|
||||
if (_own_output && _output) {
|
||||
_output->increment_port_buffer_offset (offset);
|
||||
}
|
||||
}
|
||||
|
||||
ChanCount
|
||||
IOProcessor::natural_output_streams() const
|
||||
{
|
||||
|
|
|
@ -1104,7 +1104,7 @@ MidiDiskstream::transport_looped (framepos_t transport_frame)
|
|||
capture_captured += _capture_offset;
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
capture_captured += _session.worst_playback_latency();
|
||||
capture_captured += _session.worst_output_latency();
|
||||
} else {
|
||||
capture_captured += _roll_delay;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,10 @@ MidiPort::~MidiPort()
|
|||
void
|
||||
MidiPort::cycle_start (pframes_t nframes)
|
||||
{
|
||||
Port::cycle_start (nframes);
|
||||
|
||||
_buffer->clear ();
|
||||
|
||||
assert (_buffer->size () == 0);
|
||||
|
||||
if (sends_output ()) {
|
||||
|
@ -50,7 +53,7 @@ MidiPort::cycle_start (pframes_t nframes)
|
|||
}
|
||||
|
||||
MidiBuffer &
|
||||
MidiPort::get_midi_buffer (framecnt_t nframes)
|
||||
MidiPort::get_midi_buffer (pframes_t nframes)
|
||||
{
|
||||
if (_has_been_mixed_down) {
|
||||
return *_buffer;
|
||||
|
@ -59,7 +62,7 @@ MidiPort::get_midi_buffer (framecnt_t nframes)
|
|||
if (receives_input ()) {
|
||||
|
||||
void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
|
||||
const pframes_t event_count = jack_midi_get_event_count(jack_buffer);
|
||||
const pframes_t event_count = jack_midi_get_event_count (jack_buffer);
|
||||
|
||||
assert (event_count < _buffer->capacity());
|
||||
|
||||
|
@ -78,17 +81,18 @@ MidiPort::get_midi_buffer (framecnt_t nframes)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ev.time >= _port_offset && ev.time < (_port_offset + nframes)) {
|
||||
/* check that the event is in the acceptable time range */
|
||||
|
||||
if ((ev.time >= (_global_port_buffer_offset + _port_buffer_offset)) &&
|
||||
(ev.time < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
|
||||
_buffer->push_back (ev);
|
||||
} else {
|
||||
cerr << "Dropping incoming MIDI at time " << ev.time << "; offset=" << _port_offset << " limit=" << (_port_offset + nframes) << "\n";
|
||||
cerr << "Dropping incoming MIDI at time " << ev.time << "; offset="
|
||||
<< _global_port_buffer_offset << " limit="
|
||||
<< (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (nframes) {
|
||||
_has_been_mixed_down = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
_buffer->silence (nframes);
|
||||
}
|
||||
|
@ -137,14 +141,16 @@ MidiPort::flush_buffers (pframes_t nframes, framepos_t time)
|
|||
|
||||
// event times are in frames, relative to cycle start
|
||||
|
||||
assert (ev.time() < (nframes + _port_offset));
|
||||
assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset));
|
||||
|
||||
if (ev.time() >= _port_offset) {
|
||||
if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) {
|
||||
if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
|
||||
cerr << "write failed, drop flushed note off on the floor, time " << ev.time() << " > " << _port_offset << endl;
|
||||
cerr << "write failed, drop flushed note off on the floor, time "
|
||||
<< ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl;
|
||||
}
|
||||
} else {
|
||||
cerr << "drop flushed event on the floor, time " << ev.time() << " < " << _port_offset << endl;
|
||||
cerr << "drop flushed event on the floor, time " << ev.time()
|
||||
<< " < " << _global_port_buffer_offset + _port_buffer_offset << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,13 +464,6 @@ MidiTrack::export_stuff (BufferSet& /*bufs*/, framecnt_t /*nframes*/, framepos_t
|
|||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
MidiTrack::set_latency_delay (framecnt_t longest_session_latency)
|
||||
{
|
||||
Route::set_latency_delay (longest_session_latency);
|
||||
_diskstream->set_roll_delay (_roll_delay);
|
||||
}
|
||||
|
||||
boost::shared_ptr<Region>
|
||||
MidiTrack::bounce (InterThreadInfo& /*itt*/)
|
||||
{
|
||||
|
|
|
@ -40,15 +40,16 @@ using namespace ARDOUR;
|
|||
using namespace PBD;
|
||||
|
||||
AudioEngine* Port::_engine = 0;
|
||||
pframes_t Port::_buffer_size = 0;
|
||||
bool Port::_connecting_blocked = false;
|
||||
framecnt_t Port::_port_offset = 0;
|
||||
pframes_t Port::_global_port_buffer_offset = 0;
|
||||
pframes_t Port::_cycle_nframes = 0;
|
||||
|
||||
/** @param n Port short name */
|
||||
Port::Port (std::string const & n, DataType t, Flags f)
|
||||
: _last_monitor (false)
|
||||
: _port_buffer_offset (0)
|
||||
, _name (n)
|
||||
, _flags (f)
|
||||
, _last_monitor (false)
|
||||
{
|
||||
|
||||
/* Unfortunately we have to pass the DataType into this constructor so that we can
|
||||
|
@ -217,41 +218,79 @@ void
|
|||
Port::reset ()
|
||||
{
|
||||
_last_monitor = false;
|
||||
|
||||
// XXX
|
||||
// _metering = 0;
|
||||
// reset_meters ();
|
||||
}
|
||||
|
||||
void
|
||||
Port::recompute_total_latency () const
|
||||
Port::cycle_start (pframes_t nframes)
|
||||
{
|
||||
#ifndef HAVE_JACK_NEW_LATENCY
|
||||
#ifdef HAVE_JACK_RECOMPUTE_LATENCY
|
||||
jack_client_t* jack = _engine->jack();
|
||||
|
||||
if (!jack) {
|
||||
return;
|
||||
}
|
||||
|
||||
jack_recompute_total_latency (jack, _jack_port);
|
||||
#endif
|
||||
#endif
|
||||
_port_buffer_offset = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
void
|
||||
Port::set_latency_range (jack_latency_range_t& range, bool playback) const
|
||||
Port::increment_port_buffer_offset (pframes_t nframes)
|
||||
{
|
||||
_port_buffer_offset += nframes;
|
||||
}
|
||||
|
||||
void
|
||||
Port::set_public_latency_range (jack_latency_range_t& range, bool playback) const
|
||||
{
|
||||
/* this sets the visible latency that the rest of JACK sees. because we do latency
|
||||
compensation, all (most) of our visible port latency values are identical.
|
||||
*/
|
||||
|
||||
if (!jack_port_set_latency_range) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1 %4 latency now [%2 - %3]\n", name(),
|
||||
range.min,
|
||||
range.max,
|
||||
(playback ? "PLAYBACK" : "CAPTURE")));;
|
||||
|
||||
jack_port_set_latency_range (_jack_port, (playback ? JackPlaybackLatency : JackCaptureLatency), &range);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
void
|
||||
Port::set_private_latency_range (jack_latency_range_t& range, bool playback)
|
||||
{
|
||||
if (playback) {
|
||||
_private_playback_latency = range;
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1 playback latency now [%2 - %3]\n", name(),
|
||||
_private_playback_latency.min,
|
||||
_private_playback_latency.max));
|
||||
} else {
|
||||
_private_capture_latency = range;
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1 capture latency now [%2 - %3]\n", name(),
|
||||
_private_playback_latency.min,
|
||||
_private_playback_latency.max));
|
||||
}
|
||||
}
|
||||
|
||||
const jack_latency_range_t&
|
||||
Port::private_latency_range (bool playback) const
|
||||
{
|
||||
if (playback) {
|
||||
return _private_playback_latency;
|
||||
} else {
|
||||
return _private_capture_latency;
|
||||
}
|
||||
}
|
||||
|
||||
jack_latency_range_t
|
||||
Port::public_latency_range (bool playback) const
|
||||
{
|
||||
jack_latency_range_t r;
|
||||
|
||||
jack_port_get_latency_range (_jack_port,
|
||||
sends_output() ? JackPlaybackLatency : JackCaptureLatency,
|
||||
&r);
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1: %4 public latency range %2 .. %3\n",
|
||||
name(), r.min, r.max,
|
||||
sends_output() ? "PLAYBACK" : "CAPTURE"));
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) const
|
||||
{
|
||||
|
@ -280,11 +319,9 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c
|
|||
jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str());
|
||||
jack_latency_range_t lr;
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("\t%1 connected to %2\n", name(), *c));
|
||||
|
||||
if (remote_port) {
|
||||
jack_port_get_latency_range (remote_port, (playback ? JackPlaybackLatency : JackCaptureLatency), &lr);
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("\t\tremote has latency range %1 .. %2\n", lr.min, lr.max));
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("\t\%1 has latency range %2 .. %3\n", *c, lr.min, lr.max));
|
||||
range.min = min (range.min, lr.min);
|
||||
range.max = max (range.max, lr.max);
|
||||
}
|
||||
|
@ -296,29 +333,6 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c
|
|||
range.max = 0;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_JACK_NEW_LATENCY */
|
||||
|
||||
framecnt_t
|
||||
Port::total_latency () const
|
||||
{
|
||||
#ifndef HAVE_JACK_NEW_LATENCY
|
||||
jack_client_t* jack = _engine->jack();
|
||||
|
||||
if (!jack) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return jack_port_get_total_latency (jack, _jack_port);
|
||||
#else
|
||||
jack_latency_range_t r;
|
||||
jack_port_get_latency_range (_jack_port,
|
||||
sends_output() ? JackPlaybackLatency : JackCaptureLatency,
|
||||
&r);
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1: latency range %2 .. %3\n",
|
||||
name(), r.min, r.max));
|
||||
return r.max;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
Port::reestablish ()
|
||||
|
@ -329,7 +343,6 @@ Port::reestablish ()
|
|||
return -1;
|
||||
}
|
||||
|
||||
cerr << "RE-REGISTER: " << _name.c_str() << endl;
|
||||
_jack_port = jack_port_register (jack, _name.c_str(), type().to_jack_type(), _flags, 0);
|
||||
|
||||
if (_jack_port == 0) {
|
||||
|
@ -380,14 +393,6 @@ Port::request_monitor_input (bool yn)
|
|||
jack_port_request_monitor (_jack_port, yn);
|
||||
}
|
||||
|
||||
void
|
||||
Port::set_latency (framecnt_t n)
|
||||
{
|
||||
#ifndef HAVE_JACK_NEW_LATENCY
|
||||
jack_port_set_latency (_jack_port, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Port::physically_connected () const
|
||||
{
|
||||
|
|
|
@ -84,6 +84,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
|
|||
, Automatable (sess)
|
||||
, GraphNode( sess.route_graph )
|
||||
, _active (true)
|
||||
, _signal_latency (0)
|
||||
, _initial_delay (0)
|
||||
, _roll_delay (0)
|
||||
, _flags (flg)
|
||||
|
@ -919,7 +920,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
|
|||
processor->activate ();
|
||||
}
|
||||
|
||||
processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
|
||||
processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false, false));
|
||||
|
||||
_output->set_user_latency (0);
|
||||
}
|
||||
|
@ -1056,7 +1057,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
|
|||
}
|
||||
}
|
||||
|
||||
(*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
|
||||
(*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false, false));
|
||||
}
|
||||
|
||||
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
|
@ -2420,6 +2421,9 @@ Route::set_processor_state (const XMLNode& node)
|
|||
}
|
||||
|
||||
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
|
||||
(*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false, false));
|
||||
|
||||
boost::shared_ptr<PluginInsert> pi;
|
||||
|
||||
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
|
||||
|
@ -2837,16 +2841,24 @@ Route::check_initial_delay (framecnt_t nframes, framecnt_t& transport_frame)
|
|||
|
||||
nframes -= _roll_delay;
|
||||
silence_unlocked (_roll_delay);
|
||||
/* we've written _roll_delay of samples into the
|
||||
output ports, so make a note of that for
|
||||
future reference.
|
||||
*/
|
||||
|
||||
_main_outs->increment_output_offset (_roll_delay);
|
||||
transport_frame += _roll_delay;
|
||||
|
||||
/* shuffle all the port buffers for things that lead "out" of this Route
|
||||
to reflect that we just wrote _roll_delay frames of silence.
|
||||
*/
|
||||
|
||||
Glib::RWLock::ReaderLock lm (_processor_lock);
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
|
||||
if (iop) {
|
||||
iop->increment_port_buffer_offset (_roll_delay);
|
||||
}
|
||||
}
|
||||
_output->increment_port_buffer_offset (_roll_delay);
|
||||
|
||||
_roll_delay = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nframes;
|
||||
}
|
||||
|
@ -3040,41 +3052,24 @@ Route::add_export_point()
|
|||
}
|
||||
|
||||
framecnt_t
|
||||
Route::update_total_latency ()
|
||||
Route::update_signal_latency ()
|
||||
{
|
||||
framecnt_t old = _output->effective_latency();
|
||||
framecnt_t own_latency = _output->user_latency();
|
||||
framecnt_t l = _output->user_latency();
|
||||
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if ((*i)->active ()) {
|
||||
own_latency += (*i)->signal_latency ();
|
||||
l += (*i)->signal_latency ();
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: bus: internal redirect latency = %2\n", _name, own_latency));
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: internal signal latency = %2\n", _name, l));
|
||||
|
||||
_output->set_port_latency (own_latency);
|
||||
|
||||
if (_output->user_latency() == 0) {
|
||||
|
||||
/* this (virtual) function is used for pure Routes,
|
||||
not derived classes like AudioTrack. this means
|
||||
that the data processed here comes from an input
|
||||
port, not prerecorded material, and therefore we
|
||||
have to take into account any input latency.
|
||||
*/
|
||||
|
||||
own_latency += _input->signal_latency ();
|
||||
}
|
||||
|
||||
if (old != own_latency) {
|
||||
_output->set_latency_delay (own_latency);
|
||||
if (_signal_latency != l) {
|
||||
_signal_latency = l;
|
||||
signal_latency_changed (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: input latency = %2 total = %3\n", _name, _input->signal_latency(), own_latency));
|
||||
|
||||
return _output->effective_latency ();
|
||||
return _signal_latency;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3085,16 +3080,19 @@ Route::set_user_latency (framecnt_t nframes)
|
|||
}
|
||||
|
||||
void
|
||||
Route::set_latency_delay (framecnt_t longest_session_latency)
|
||||
Route::set_latency_compensation (framecnt_t longest_session_latency)
|
||||
{
|
||||
framecnt_t old = _initial_delay;
|
||||
|
||||
if (_output->effective_latency() < longest_session_latency) {
|
||||
_initial_delay = longest_session_latency - _output->effective_latency();
|
||||
if (_signal_latency < longest_session_latency) {
|
||||
_initial_delay = longest_session_latency - _signal_latency;
|
||||
} else {
|
||||
_initial_delay = 0;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: compensate for maximum latency of %2, given own latency of %3, using initial delay of %4\n",
|
||||
name(), longest_session_latency, _signal_latency, _initial_delay));
|
||||
|
||||
if (_initial_delay != old) {
|
||||
initial_delay_changed (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
@ -3595,33 +3593,10 @@ Route::unknown_processors () const
|
|||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
Route::set_latency_ranges (bool playback) const
|
||||
|
||||
framecnt_t
|
||||
Route::update_port_latencies (const PortSet& from, const PortSet& to, bool playback, framecnt_t our_latency) const
|
||||
{
|
||||
framecnt_t own_latency = 0;
|
||||
|
||||
/* Processor list not protected by lock: MUST BE CALLED FROM PROCESS THREAD OR
|
||||
LATENCY CALLBACK
|
||||
*/
|
||||
|
||||
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if ((*i)->active ()) {
|
||||
own_latency += (*i)->signal_latency ();
|
||||
}
|
||||
}
|
||||
|
||||
if (playback) {
|
||||
update_port_latencies (_input->ports (), _output->ports (), true, own_latency);
|
||||
} else {
|
||||
update_port_latencies (_output->ports (), _input->ports (), false, own_latency);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Route::update_port_latencies (const PortSet& operands, const PortSet& feeders, bool playback, framecnt_t our_latency) const
|
||||
{
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
|
||||
/* we assume that all our input ports feed all our output ports. its not
|
||||
universally true, but the alternative is way too corner-case to worry about.
|
||||
*/
|
||||
|
@ -3631,11 +3606,11 @@ Route::update_port_latencies (const PortSet& operands, const PortSet& feeders, b
|
|||
all_connections.min = ~((jack_nframes_t) 0);
|
||||
all_connections.max = 0;
|
||||
|
||||
/* iterate over all feeder ports and determine their relevant latency, taking
|
||||
the maximum and minimum across all of them.
|
||||
/* iterate over all "from" ports and determine the latency range for all of their
|
||||
connections to the "outside" (outside of this Route).
|
||||
*/
|
||||
|
||||
for (PortSet::const_iterator p = feeders.begin(); p != feeders.end(); ++p) {
|
||||
for (PortSet::const_iterator p = from.begin(); p != from.end(); ++p) {
|
||||
|
||||
jack_latency_range_t range;
|
||||
|
||||
|
@ -3644,24 +3619,81 @@ Route::update_port_latencies (const PortSet& operands, const PortSet& feeders, b
|
|||
all_connections.min = min (all_connections.min, range.min);
|
||||
all_connections.max = max (all_connections.max, range.max);
|
||||
}
|
||||
|
||||
/* set the "from" port latencies to the max/min range of all their connections */
|
||||
|
||||
for (PortSet::const_iterator p = from.begin(); p != from.end(); ++p) {
|
||||
p->set_public_latency_range (all_connections, playback);
|
||||
}
|
||||
|
||||
/* set the ports "in the direction of the flow" to the same value as above plus our own signal latency */
|
||||
|
||||
all_connections.min += our_latency;
|
||||
all_connections.max += our_latency;
|
||||
|
||||
for (PortSet::const_iterator p = operands.begin(); p != operands.end(); ++p) {
|
||||
|
||||
p->set_latency_range (all_connections, playback);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("Port %1 %5 latency range %2 .. %3 (including route latency of %4)\n",
|
||||
p->name(),
|
||||
all_connections.min,
|
||||
all_connections.max,
|
||||
our_latency,
|
||||
(playback ? "PLAYBACK" : "CAPTURE")));
|
||||
|
||||
for (PortSet::const_iterator p = to.begin(); p != to.end(); ++p) {
|
||||
p->set_public_latency_range (all_connections, playback);
|
||||
}
|
||||
#endif
|
||||
|
||||
return all_connections.max;
|
||||
}
|
||||
|
||||
framecnt_t
|
||||
Route::set_private_port_latencies (bool playback) const
|
||||
{
|
||||
framecnt_t own_latency = 0;
|
||||
|
||||
/* Processor list not protected by lock: MUST BE CALLED FROM PROCESS THREAD OR
|
||||
LATENCY CALLBACK.
|
||||
|
||||
This is called (early) from the latency callback. It computes the REAL latency associated
|
||||
with each port and stores the result as the "private" latency of the port. A later
|
||||
call to Route::set_public_port_latencies() sets all ports to the same value to reflect
|
||||
the fact that we do latency compensation and so all signals are delayed by the
|
||||
same amount as they flow through ardour.
|
||||
*/
|
||||
|
||||
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if ((*i)->active ()) {
|
||||
own_latency += (*i)->signal_latency ();
|
||||
}
|
||||
}
|
||||
|
||||
if (playback) {
|
||||
/* playback: propagate latency from "outside the route" to outputs to inputs */
|
||||
return update_port_latencies (_output->ports (), _input->ports (), true, own_latency);
|
||||
} else {
|
||||
/* capture: propagate latency from "outside the route" to inputs to outputs */
|
||||
return update_port_latencies (_input->ports (), _output->ports (), false, own_latency);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Route::set_public_port_latencies (framecnt_t value, bool playback) const
|
||||
{
|
||||
/* this is called to set the JACK-visible port latencies, which take latency compensation
|
||||
into account.
|
||||
*/
|
||||
|
||||
jack_latency_range_t range;
|
||||
|
||||
range.min = value;
|
||||
range.max = value;
|
||||
|
||||
{
|
||||
const PortSet& ports (_input->ports());
|
||||
for (PortSet::const_iterator p = ports.begin(); p != ports.end(); ++p) {
|
||||
p->set_public_latency_range (range, playback);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const PortSet& ports (_output->ports());
|
||||
for (PortSet::const_iterator p = ports.begin(); p != ports.end(); ++p) {
|
||||
p->set_public_latency_range (range, playback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Put the invisible processors in the right place in _processors.
|
||||
* Must be called with a writer lock on _processor_lock held.
|
||||
|
|
|
@ -649,16 +649,14 @@ Session::when_engine_running ()
|
|||
}
|
||||
}
|
||||
|
||||
set_worst_io_latencies ();
|
||||
|
||||
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
|
||||
|
||||
/* hook us up to the engine */
|
||||
|
||||
BootMessage (_("Connect to engine"));
|
||||
|
||||
_engine.set_session (this);
|
||||
_engine.update_total_latencies ();
|
||||
|
||||
update_latency_compensation (false, false, true);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4153,13 +4151,13 @@ Session::unknown_processors () const
|
|||
return p;
|
||||
}
|
||||
|
||||
#ifdef HAVE_JACK_NEW_LATENCY
|
||||
void
|
||||
Session::update_latency (bool playback)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Latency, "JACK latency callback\n");
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("\n\nJACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
|
||||
|
||||
boost::shared_ptr<RouteList> r = routes.reader ();
|
||||
framecnt_t max_latency = 0;
|
||||
|
||||
if (playback) {
|
||||
/* reverse the list so that we work backwards from the last route to run to the first */
|
||||
|
@ -4167,9 +4165,14 @@ Session::update_latency (bool playback)
|
|||
}
|
||||
|
||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("------------- Working on latency for %1\n", (*i)->name()));
|
||||
(*i)->set_latency_ranges (playback);
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("------------- Done working on latency for %1\n\n", (*i)->name()));
|
||||
max_latency = max (max_latency, (*i)->set_private_port_latencies (playback));
|
||||
}
|
||||
|
||||
#if 0
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("Set public port latencies to %1\n", max_latency));
|
||||
|
||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||
(*i)->set_public_port_latencies (max_latency, playback);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -932,7 +932,7 @@ Session::maybe_sync_start (pframes_t & nframes)
|
|||
|
||||
no_roll (sync_offset);
|
||||
nframes -= sync_offset;
|
||||
AudioPort::increment_port_offset (sync_offset);
|
||||
Port::increment_global_port_buffer_offset (sync_offset);
|
||||
waiting_for_sync_offset = false;
|
||||
|
||||
if (nframes == 0) {
|
||||
|
|
|
@ -1466,7 +1466,7 @@ Session::route_processors_changed (RouteProcessorChange c)
|
|||
}
|
||||
|
||||
void
|
||||
Session::update_latency_compensation (bool with_stop, bool abort)
|
||||
Session::update_latency_compensation (bool with_stop, bool abort, bool force_whole_graph)
|
||||
{
|
||||
bool update_jack = false;
|
||||
PostTransportWork ptw;
|
||||
|
@ -1478,7 +1478,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
|
|||
_worst_track_latency = 0;
|
||||
ptw = post_transport_work();
|
||||
|
||||
DEBUG_TRACE(DEBUG::Latency, "---------------------------- update latency\n\n")
|
||||
DEBUG_TRACE(DEBUG::Latency, "---------------------------- update latency compensation\n\n")
|
||||
|
||||
boost::shared_ptr<RouteList> r = routes.reader ();
|
||||
|
||||
|
@ -1488,30 +1488,28 @@ Session::update_latency_compensation (bool with_stop, bool abort)
|
|||
(*i)->nonrealtime_handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
|
||||
}
|
||||
|
||||
framecnt_t old_latency = (*i)->output()->signal_latency ();
|
||||
framecnt_t track_latency = (*i)->update_total_latency ();
|
||||
framecnt_t old_latency = (*i)->signal_latency ();
|
||||
framecnt_t new_latency = (*i)->update_signal_latency ();
|
||||
|
||||
if (old_latency != track_latency) {
|
||||
#ifndef HAVE_JACK_NEW_LATENCY
|
||||
(*i)->input()->update_port_total_latencies ();
|
||||
(*i)->output()->update_port_total_latencies ();
|
||||
#endif
|
||||
if (old_latency != new_latency) {
|
||||
update_jack = true;
|
||||
}
|
||||
|
||||
if (!(*i)->is_hidden() && ((*i)->active())) {
|
||||
_worst_track_latency = max (_worst_track_latency, track_latency);
|
||||
_worst_track_latency = max (_worst_track_latency, new_latency);
|
||||
}
|
||||
}
|
||||
|
||||
if (update_jack) {
|
||||
if (force_whole_graph || update_jack) {
|
||||
/* trigger a full recompute of latency numbers for the graph
|
||||
*/
|
||||
_engine.update_total_latencies ();
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE(DEBUG::Latency, string_compose("worst case route internal latency was %1\n", _worst_track_latency));
|
||||
|
||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||
(*i)->set_latency_delay (_worst_track_latency);
|
||||
(*i)->set_latency_compensation (_worst_track_latency);
|
||||
}
|
||||
|
||||
set_worst_io_latencies ();
|
||||
|
@ -1526,6 +1524,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
|
|||
tr->set_capture_offset ();
|
||||
}
|
||||
}
|
||||
DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n")
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -85,30 +85,6 @@ Track::toggle_monitor_input ()
|
|||
}
|
||||
}
|
||||
|
||||
ARDOUR::framecnt_t
|
||||
Track::update_total_latency ()
|
||||
{
|
||||
framecnt_t old = _output->effective_latency();
|
||||
framecnt_t own_latency = _output->user_latency();
|
||||
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if ((*i)->active ()) {
|
||||
own_latency += (*i)->signal_latency ();
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: track: internal redirect latency = %2\n", _name, own_latency));
|
||||
|
||||
_output->set_port_latency (own_latency);
|
||||
|
||||
if (old != own_latency) {
|
||||
_output->set_latency_delay (own_latency);
|
||||
signal_latency_changed (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
return _output->effective_latency();
|
||||
}
|
||||
|
||||
Track::FreezeRecord::~FreezeRecord ()
|
||||
{
|
||||
for (vector<FreezeRecordProcessorInfo*>::iterator i = processor_info.begin(); i != processor_info.end(); ++i) {
|
||||
|
@ -218,9 +194,9 @@ Track::set_name (const string& str)
|
|||
}
|
||||
|
||||
void
|
||||
Track::set_latency_delay (framecnt_t longest_session_latency)
|
||||
Track::set_latency_compensation (framecnt_t longest_session_latency)
|
||||
{
|
||||
Route::set_latency_delay (longest_session_latency);
|
||||
Route::set_latency_compensation (longest_session_latency);
|
||||
_diskstream->set_roll_delay (_roll_delay);
|
||||
}
|
||||
|
||||
|
|
|
@ -273,9 +273,9 @@ def configure(conf):
|
|||
conf.check_cc(fragment = "#include <jack/jack.h>\nint main(int argc, char **argv) { jack_port_t* p; jack_latency_range_t r; jack_port_set_latency_range (p, JackCaptureLatency, &r); return 0; }\n",
|
||||
linkflags = ['-ljack'],
|
||||
msg = 'Checking for new JACK latency API',
|
||||
define_name = 'HAVE_JACK_NEW_LATENCY',
|
||||
uselib_store = "JACK_NEW_LATENCY",
|
||||
okmsg = 'present')
|
||||
okmsg = 'present',
|
||||
mandatory = True,
|
||||
errmsg = 'missing - a version of JACK that supports jack_port_set_latency_range() is required to compile Ardour3')
|
||||
|
||||
conf.check_cc(fragment = '#include <jack/jack.h>\nint main(int argc, char **argv) { jack_port_type_get_buffer_size ((jack_client_t*)0, ""); }\n',
|
||||
linkflags = ['-ljack'],
|
||||
|
|
Loading…
Reference in New Issue