summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/meter.h1
-rw-r--r--libs/ardour/ardour/route.h13
-rw-r--r--libs/ardour/ardour/session.h15
-rw-r--r--libs/ardour/meter.cc7
-rw-r--r--libs/ardour/route.cc51
-rw-r--r--libs/ardour/session.cc12
-rw-r--r--libs/ardour/session_process.cc89
7 files changed, 174 insertions, 14 deletions
diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h
index 8ed1ade50d..d34d5b3710 100644
--- a/libs/ardour/ardour/meter.h
+++ b/libs/ardour/ardour/meter.h
@@ -72,6 +72,7 @@ public:
*/
void reflect_inputs (const ChanCount& in);
+ void emit_configuration_changed ();
/** Compute peaks */
void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool);
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 5fdc047ef8..ba0acbc38f 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -182,7 +182,8 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou
bool denormal_protection() const;
void set_meter_point (MeterPoint, bool force = false);
- void apply_processor_changes_rt ();
+ bool apply_processor_changes_rt ();
+ void emit_pending_signals ();
MeterPoint meter_point() const { return _pending_meter_point; }
void meter ();
@@ -522,8 +523,16 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou
boost::shared_ptr<MonitorProcessor> _monitor_control;
boost::shared_ptr<Pannable> _pannable;
+ enum {
+ EmitNone = 0x00,
+ EmitMeterChanged = 0x01,
+ EmitMeterVisibilityChange = 0x02,
+ EmitRtProcessorChange = 0x04
+ };
+
ProcessorList _pending_processor_order;
gint _pending_process_reorder; // atomic
+ gint _pending_signals; // atomic
Flag _flags;
int _pending_declick;
@@ -604,7 +613,7 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou
bool _initial_io_setup;
int configure_processors_unlocked (ProcessorStreams*);
- void set_meter_point_unlocked ();
+ bool set_meter_point_unlocked ();
void apply_processor_order (const ProcessorList& new_order);
std::list<std::pair<ChanCount, ChanCount> > try_configure_processors (ChanCount, ProcessorStreams *);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 3da040af0d..9d97bce69f 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -1267,6 +1267,21 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void *do_work();
+ /* Signal Forwarding */
+ void emit_route_signals () const;
+ void emit_thread_run ();
+ static void *emit_thread (void *);
+ void emit_thread_start ();
+ void emit_thread_terminate ();
+
+ pthread_t _rt_emit_thread;
+ bool _rt_thread_active;
+
+ pthread_mutex_t _rt_emit_mutex;
+ pthread_cond_t _rt_emit_cond;
+ bool _rt_emit_pending;
+
+
/* SessionEventManager interface */
void process_event (SessionEvent*);
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index e5fabfc291..dffefd4a58 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -209,7 +209,12 @@ PeakMeter::reflect_inputs (const ChanCount& in)
current_meters = in;
reset_max();
- ConfigurationChanged (in, in); /* EMIT SIGNAL */
+ // ConfigurationChanged() postponed
+}
+
+void
+PeakMeter::emit_configuration_changed () {
+ ConfigurationChanged (current_meters, current_meters); /* EMIT SIGNAL */
}
void
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 3c03d7c1a4..6409fb5bf0 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -3382,15 +3382,21 @@ Route::flush_processors ()
#ifdef __clang__
__attribute__((annotate("realtime")))
#endif
-void
+bool
Route::apply_processor_changes_rt ()
{
+ int emissions = EmitNone;
+
if (_pending_meter_point != _meter_point) {
Glib::Threads::RWLock::WriterLock pwl (_processor_lock, Glib::Threads::TRY_LOCK);
if (pwl.locked()) {
/* meters always have buffers for 'processor_max_streams'
* they can be re-positioned without re-allocation */
- set_meter_point_unlocked();
+ if (set_meter_point_unlocked()) {
+ emissions |= EmitMeterChanged | EmitMeterVisibilityChange;;
+ } else {
+ emissions |= EmitMeterChanged;
+ }
}
}
@@ -3401,15 +3407,38 @@ Route::apply_processor_changes_rt ()
if (pwl.locked()) {
apply_processor_order (_pending_processor_order);
setup_invisible_processors ();
-
changed = true;
g_atomic_int_set (&_pending_process_reorder, 0);
+ emissions |= EmitRtProcessorChange;
}
}
if (changed) {
- processors_changed (RouteProcessorChange (RouteProcessorChange::RealTimeChange)); /* EMIT SIGNAL */
set_processor_positions ();
}
+ if (emissions != 0) {
+ g_atomic_int_set (&_pending_signals, emissions);
+ return true;
+ }
+ return false;
+}
+
+void
+Route::emit_pending_signals ()
+{
+
+ int sig = g_atomic_int_and (&_pending_signals, 0);
+ if (sig & EmitMeterChanged) {
+ _meter->emit_configuration_changed();
+ meter_change (); /* EMIT SIGNAL */
+ if (sig & EmitMeterVisibilityChange) {
+ processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, true)); /* EMIT SIGNAL */
+ } else {
+ processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, false)); /* EMIT SIGNAL */
+ }
+ }
+ if (sig & EmitRtProcessorChange) {
+ processors_changed (RouteProcessorChange (RouteProcessorChange::RealTimeChange)); /* EMIT SIGNAL */
+ }
}
void
@@ -3423,7 +3452,13 @@ Route::set_meter_point (MeterPoint p, bool force)
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
Glib::Threads::RWLock::WriterLock lm (_processor_lock);
_pending_meter_point = p;
- set_meter_point_unlocked();
+ _meter->emit_configuration_changed();
+ meter_change (); /* EMIT SIGNAL */
+ if (set_meter_point_unlocked()) {
+ processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, true)); /* EMIT SIGNAL */
+ } else {
+ processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, false)); /* EMIT SIGNAL */
+ }
} else {
_pending_meter_point = p;
}
@@ -3433,7 +3468,7 @@ Route::set_meter_point (MeterPoint p, bool force)
#ifdef __clang__
__attribute__((annotate("realtime")))
#endif
-void
+bool
Route::set_meter_point_unlocked ()
{
#ifndef NDEBUG
@@ -3502,9 +3537,7 @@ Route::set_meter_point_unlocked ()
* but all those signals are subscribed to with gui_thread()
* so we're safe.
*/
- meter_change (); /* EMIT SIGNAL */
- bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
- processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */
+ return (_meter->display_to_user() != meter_was_visible_to_user);
}
void
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 100c124d72..ff366e5ceb 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -212,6 +212,8 @@ Session::Session (AudioEngine &eng,
, rf_scale (1.0)
, _locations (new Locations (*this))
, _ignore_skips_updates (false)
+ , _rt_thread_active (false)
+ , _rt_emit_pending (false)
, step_speed (0)
, outbound_mtc_timecode_frame (0)
, next_quarter_frame_to_send (-1)
@@ -275,6 +277,9 @@ Session::Session (AudioEngine &eng,
{
uint32_t sr = 0;
+ pthread_mutex_init (&_rt_emit_mutex, 0);
+ pthread_cond_init (&_rt_emit_cond, 0);
+
pre_engine_init (fullpath);
if (_is_new) {
@@ -353,6 +358,8 @@ Session::Session (AudioEngine &eng,
_is_new = false;
+ emit_thread_start ();
+
/* hook us up to the engine since we are now completely constructed */
BootMessage (_("Connect to engine"));
@@ -570,6 +577,11 @@ Session::destroy ()
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists.reset ();
+ emit_thread_terminate ();
+
+ pthread_cond_destroy (&_rt_emit_cond);
+ pthread_mutex_destroy (&_rt_emit_mutex);
+
delete _scene_changer; _scene_changer = 0;
delete midi_control_ui; midi_control_ui = 0;
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index d65fe3d56d..6366abde71 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -75,7 +75,7 @@ Session::process (pframes_t nframes)
(this->*process_function) (nframes);
- /* realtime-safe meter-position changes
+ /* realtime-safe meter-position and processor-order changes
*
* ideally this would be done in
* Route::process_output_buffers() but various functions
@@ -83,7 +83,19 @@ Session::process (pframes_t nframes)
*/
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
- (*i)->apply_processor_changes_rt();
+ if ((*i)->apply_processor_changes_rt()) {
+ _rt_emit_pending = true;
+ }
+ }
+ if (_rt_emit_pending) {
+ if (!_rt_thread_active) {
+ emit_route_signals ();
+ }
+ if (pthread_mutex_trylock (&_rt_emit_mutex) == 0) {
+ pthread_cond_signal (&_rt_emit_cond);
+ pthread_mutex_unlock (&_rt_emit_mutex);
+ _rt_emit_pending = false;
+ }
}
_engine.main_thread()->drop_buffers ();
@@ -1226,3 +1238,76 @@ Session::compute_stop_limit () const
return current_end_frame ();
}
+
+
+
+/* dedicated thread for signal emission.
+ *
+ * while sending cross-thread signals from the process thread
+ * is fine in general, PBD::Signal's use of boost::function and
+ * boost:bind can produce a vast overhead which is not
+ * acceptable for low latency.
+ *
+ * This works around the issue by moving the boost overhead
+ * out of the RT thread. The overall load is probably higher but
+ * the realtime thread remains unaffected.
+ */
+
+void
+Session::emit_route_signals () const
+{
+ boost::shared_ptr<RouteList> r = routes.reader ();
+ for (RouteList::const_iterator ci = r->begin(); ci != r->end(); ++ci) {
+ (*ci)->emit_pending_signals ();
+ }
+}
+
+void
+Session::emit_thread_start ()
+{
+ if (_rt_thread_active) {
+ return;
+ }
+ _rt_thread_active = true;
+
+ if (pthread_create (&_rt_emit_thread, NULL, emit_thread, this)) {
+ _rt_thread_active = false;
+ }
+}
+
+void
+Session::emit_thread_terminate ()
+{
+ if (!_rt_thread_active) {
+ return;
+ }
+ _rt_thread_active = false;
+
+ if (pthread_mutex_lock (&_rt_emit_mutex) == 0) {
+ pthread_cond_signal (&_rt_emit_cond);
+ pthread_mutex_unlock (&_rt_emit_mutex);
+ }
+
+ void *status;
+ pthread_join (_rt_emit_thread, &status);
+}
+
+void *
+Session::emit_thread (void *arg)
+{
+ Session *s = static_cast<Session *>(arg);
+ s->emit_thread_run ();
+ pthread_exit (0);
+ return 0;
+}
+
+void
+Session::emit_thread_run ()
+{
+ pthread_mutex_lock (&_rt_emit_mutex);
+ while (_rt_thread_active) {
+ emit_route_signals();
+ pthread_cond_wait (&_rt_emit_cond, &_rt_emit_mutex);
+ }
+ pthread_mutex_unlock (&_rt_emit_mutex);
+}