tweaks to NO_PLUGIN_STATE logic
[ardour.git] / libs / ardour / route.cc
index 1a90553be2f80ebd4089597968beb515b595bf6b..9d7dc8792b17ee7b5e9e4ad9614206eb2919b94f 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "ardour/amp.h"
 #include "ardour/audio_buffer.h"
+#include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
 #include "ardour/buffer_set.h"
@@ -46,6 +47,8 @@
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
 #include "ardour/meter.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/midi_port.h"
 #include "ardour/monitor_processor.h"
 #include "ardour/pannable.h"
 #include "ardour/panner_shell.h"
@@ -80,6 +83,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _flags (flg)
        , _pending_declick (true)
        , _meter_point (MeterPostFader)
+       , _meter_type (MeterPeak)
        , _self_solo (false)
        , _soloed_by_others_upstream (0)
        , _soloed_by_others_downstream (0)
@@ -139,7 +143,7 @@ Route::init ()
           they will be added to _processors by setup_invisible_processors ()
        */
 
-       _meter.reset (new PeakMeter (_session));
+       _meter.reset (new PeakMeter (_session, _name));
        _meter->set_display_to_user (false);
        _meter->activate ();
 
@@ -158,7 +162,7 @@ Route::init ()
                _monitor_control->activate ();
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -305,7 +309,7 @@ Route::sync_order_keys (RouteSortOrderKey base)
 void
 Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid)
 {
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                /* hard-coded remote IDs, or no remote ID */
                return;
        }
@@ -454,8 +458,8 @@ Route::process_output_buffers (BufferSet& bufs,
           on a transition between monitoring states we get a de-clicking gain
           change in the _main_outs delivery.
        */
-       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
+       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
@@ -561,39 +565,26 @@ Route::n_process_buffers ()
 }
 
 void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
 {
-       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+       assert (is_monitor());
+       BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+       passthru (bufs, start_frame, end_frame, nframes, declick);
+}
 
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
        _silent = false;
 
-       assert (bufs.available() >= input_streams());
-
-       if (_input->n_ports() == ChanCount::ZERO) {
-               silence_unlocked (nframes);
-       }
-
-       bufs.set_count (input_streams());
-
        if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
 
                /* control/monitor bus ignores input ports when something is
                   feeding the listen "stream". data will "arrive" into the
                   route from the intreturn processor element.
                */
-               bufs.silence (nframes, 0);
-
-       } else {
-
-               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
-                       BufferSet::iterator o = bufs.begin(*t);
-                       PortSet& ports (_input->ports());
 
-                       for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
-                               o->read_from (i->get_buffer(nframes), nframes);
-                       }
-               }
+               bufs.silence (nframes, 0);
        }
 
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
@@ -789,7 +780,7 @@ Route::set_mute_master_solo ()
 void
 Route::set_solo_isolated (bool yn, void *src)
 {
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                return;
        }
 
@@ -803,7 +794,7 @@ Route::set_solo_isolated (bool yn, void *src)
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
 
-               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
+               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
                        continue;
                }
 
@@ -1888,6 +1879,8 @@ Route::state(bool full_state)
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
+       node->add_property("meter-type", enum_2_string (_meter_type));
+
        if (_route_group) {
                node->add_property("route-group", _route_group->name());
        }
@@ -2006,7 +1999,7 @@ Route::set_state (const XMLNode& node, int version)
                _flags = Flag (0);
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -2062,6 +2055,10 @@ Route::set_state (const XMLNode& node, int version)
                }
        }
 
+       if ((prop = node.property (X_("meter-type"))) != 0) {
+               _meter_type = MeterType (string_2_enum (prop->value (), _meter_type));
+       }
+
        set_processor_state (processor_state);
 
        // this looks up the internal instrument in processors
@@ -2222,7 +2219,7 @@ Route::set_state_2X (const XMLNode& node, int version)
                _flags = Flag (0);
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -2561,9 +2558,24 @@ Route::set_processor_state (const XMLNode& node)
                                        continue;
                                }
 
-                               if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
-                                       /* This processor could not be configured.  Turn it into a UnknownProcessor */
-                                       processor.reset (new UnknownProcessor (_session, **niter));
+                               if (boost::dynamic_pointer_cast<PluginInsert>(processor)) {     
+#ifndef NO_PLUGIN_STATE
+                                       if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+                                               /* This processor could not be configured.  Turn it into a UnknownProcessor */
+                                               processor.reset (new UnknownProcessor (_session, **niter));
+                                       }
+#else
+                                       /* plugin, with NO_PLUGIN_STATE defined
+                                        * =>::set_state() not allowed. Do not
+                                        * display a message here - things will
+                                        * get too verbose.
+                                        */
+#endif
+                               } else {
+                                       if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+                                               /* This processor could not be configured.  Turn it into a UnknownProcessor */
+                                               processor.reset (new UnknownProcessor (_session, **niter));
+                                       }
                                }
 
                                /* we have to note the monitor send here, otherwise a new one will be created
@@ -2948,6 +2960,8 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                   contains ConfigurationChanged 
                */
                need_to_queue_solo_change = false;
+               configure_processors (0);
+               io_changed (); /* EMIT SIGNAL */
        }
 
        if (!_output->connected() && _soloed_by_others_downstream) {
@@ -2985,6 +2999,7 @@ int
 Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
        if (!lm.locked()) {
                return 0;
        }
@@ -2997,6 +3012,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                silence_unlocked (nframes);
                return 0;
        }
+
        if (session_state_changing) {
                if (_session.transport_speed() != 0.0f) {
                        /* we're rolling but some state is changing (e.g. our diskstream contents)
@@ -3012,8 +3028,16 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                */
        }
 
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
        _amp->apply_gain_automation (false);
-       passthru (start_frame, end_frame, nframes, 0);
+       passthru (bufs, start_frame, end_frame, nframes, 0);
 
        return 0;
 }
@@ -3043,7 +3067,15 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
 
        _silent = false;
 
-       passthru (start_frame, end_frame, nframes, declick);
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
+       passthru (bufs, start_frame, end_frame, nframes, declick);
 
        return 0;
 }
@@ -4148,3 +4180,93 @@ Route::non_realtime_locate (framepos_t pos)
                }
        }
 }
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+       size_t n_buffers;
+       size_t i;
+       
+       /* MIDI 
+        *  
+        * We don't currently mix MIDI input together, so we don't need the
+        * complex logic of the audio case.
+        */
+
+       n_buffers = bufs.count().n_midi ();
+
+       for (i = 0; i < n_buffers; ++i) {
+
+               boost::shared_ptr<MidiPort> source_port = io->midi (i);
+               MidiBuffer& buf (bufs.get_midi (i));
+               
+               if (source_port) {
+                       buf.copy (source_port->get_midi_buffer(nframes));
+               } else {
+                       buf.silence (nframes);
+               }
+       }
+
+       /* AUDIO */
+
+       n_buffers = bufs.count().n_audio();
+
+       size_t n_ports = io->n_ports().n_audio();
+       float scaling = 1.0f;
+
+       if (n_ports > n_buffers) {
+               scaling = ((float) n_buffers) / n_ports;
+       }
+       
+       for (i = 0; i < n_ports; ++i) {
+               
+               /* if there are more ports than buffers, map them onto buffers
+                * in a round-robin fashion
+                */
+
+               boost::shared_ptr<AudioPort> source_port = io->audio (i);
+               AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+                       
+
+               if (i < n_buffers) {
+                       
+                       /* first time through just copy a channel into
+                          the output buffer.
+                       */
+
+                       buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+                       if (scaling != 1.0f) {
+                               buf.apply_gain (scaling, nframes);
+                       }
+                       
+               } else {
+                       
+                       /* on subsequent times around, merge data from
+                        * the port with what is already there 
+                        */
+
+                       if (scaling != 1.0f) {
+                               buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+                       } else {
+                               buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+                       }
+               }
+       }
+
+       /* silence any remaining buffers */
+
+       for (; i < n_buffers; ++i) {
+               AudioBuffer& buf (bufs.get_audio (i));
+               buf.silence (nframes);
+       }
+
+       /* establish the initial setup of the buffer set, reflecting what was
+          copied into it. unless, of course, we are the auditioner, in which
+          case nothing was fed into it from the inputs at all.
+       */
+
+       if (!is_auditioner()) {
+               bufs.set_count (io->n_ports());
+       }
+}