Re-enable creation of stereo bundles for system IO, so that the mixer strip
[ardour.git] / libs / ardour / session.cc
index 3b9b48a2de1d8f7e9743b187f964e349eb56fcc0..ed5ff668aad41d122f9584ac59f258d38b38e13f 100644 (file)
 #include <pbd/stacktrace.h>
 #include <pbd/file_utils.h>
 
-#include <ardour/audioengine.h>
-#include <ardour/configuration.h>
-#include <ardour/session.h>
-#include <ardour/session_directory.h>
-#include <ardour/session_metadata.h>
-#include <ardour/utils.h>
+#include <ardour/analyser.h>
+#include <ardour/audio_buffer.h>
 #include <ardour/audio_diskstream.h>
+#include <ardour/audio_track.h>
+#include <ardour/audioengine.h>
+#include <ardour/audiofilesource.h>
 #include <ardour/audioplaylist.h>
 #include <ardour/audioregion.h>
-#include <ardour/audiofilesource.h>
+#include <ardour/auditioner.h>
+#include <ardour/buffer_set.h>
+#include <ardour/bundle.h>
+#include <ardour/click.h>
+#include <ardour/configuration.h>
+#include <ardour/crossfade.h>
+#include <ardour/cycle_timer.h>
+#include <ardour/data_type.h>
+#include <ardour/filename_extensions.h>
+#include <ardour/internal_send.h>
+#include <ardour/io_processor.h>
 #include <ardour/midi_diskstream.h>
 #include <ardour/midi_playlist.h>
 #include <ardour/midi_region.h>
-#include <ardour/smf_source.h>
-#include <ardour/auditioner.h>
-#include <ardour/recent_sessions.h>
-#include <ardour/io_processor.h>
-#include <ardour/send.h>
-#include <ardour/processor.h>
-#include <ardour/plugin_insert.h>
-#include <ardour/port_insert.h>
-#include <ardour/auto_bundle.h>
-#include <ardour/slave.h>
-#include <ardour/tempo.h>
-#include <ardour/audio_track.h>
 #include <ardour/midi_track.h>
-#include <ardour/cycle_timer.h>
 #include <ardour/named_selection.h>
-#include <ardour/crossfade.h>
 #include <ardour/playlist.h>
-#include <ardour/click.h>
-#include <ardour/data_type.h>
-#include <ardour/buffer_set.h>
-#include <ardour/source_factory.h>
+#include <ardour/plugin_insert.h>
+#include <ardour/port_insert.h>
+#include <ardour/processor.h>
+#include <ardour/recent_sessions.h>
 #include <ardour/region_factory.h>
-#include <ardour/filename_extensions.h>
+#include <ardour/route_group.h>
+#include <ardour/send.h>
+#include <ardour/session.h>
+#include <ardour/session_directory.h>
 #include <ardour/session_directory.h>
+#include <ardour/session_metadata.h>
+#include <ardour/slave.h>
+#include <ardour/smf_source.h>
+#include <ardour/source_factory.h>
 #include <ardour/tape_file_matcher.h>
-#include <ardour/analyser.h>
-
-#ifdef HAVE_LIBLO
-#include <ardour/osc.h>
-#endif
+#include <ardour/tempo.h>
+#include <ardour/utils.h>
 
 #include "i18n.h"
 
@@ -120,26 +119,36 @@ Session::Session (AudioEngine &eng,
                  string mix_template)
 
        : _engine (eng),
+         _requested_return_frame (-1),
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
          _mix_buffers(new BufferSet()),
+         mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
          _midi_port (default_midi_port),
          _midi_clock_port (default_midi_clock_port),
          _session_dir (new SessionDirectory(fullpath)),
          pending_events (2048),
+         state_tree (0),
+         butler_mixdown_buffer (0),
+         butler_gain_buffer (0),
          post_transport_work((PostTransportWork)0),
          _send_smpte_update (false),
-         midi_requests (128),
+         midi_thread (pthread_t (0)),
+         midi_requests (128), // the size of this should match the midi request pool size
          diskstreams (new DiskstreamList),
          routes (new RouteList),
          auditioner ((Auditioner*) 0),
          _total_free_4k_blocks (0),
+         _bundles (new BundleList),
          _bundle_xml_node (0),
          _click_io ((IO*) 0),
+         click_data (0),
+         click_emphasis_data (0),
          main_outs (0),
          _metadata (new SessionMetadata())
+
 {
        bool new_session;
 
@@ -193,24 +202,35 @@ Session::Session (AudioEngine &eng,
                  nframes_t initial_length)
 
        : _engine (eng),
+         _requested_return_frame (-1),
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
          _mix_buffers(new BufferSet()),
+         mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
          _midi_port (default_midi_port),
          _midi_clock_port (default_midi_clock_port),
          _session_dir ( new SessionDirectory(fullpath)),
          pending_events (2048),
+         state_tree (0),
+         butler_mixdown_buffer (0),
+         butler_gain_buffer (0),
          post_transport_work((PostTransportWork)0),
          _send_smpte_update (false),
+         midi_thread (pthread_t (0)),
          midi_requests (16),
          diskstreams (new DiskstreamList),
          routes (new RouteList),
+         auditioner ((Auditioner *) 0),
          _total_free_4k_blocks (0),
+         _bundles (new BundleList),
          _bundle_xml_node (0),
-         main_outs (0)
-
+         _click_io ((IO *) 0),
+         click_data (0),
+         click_emphasis_data (0),
+         main_outs (0),
+         _metadata (new SessionMetadata())
 {
        bool new_session;
 
@@ -316,18 +336,16 @@ Session::destroy ()
 
        /* clear state tree so that no references to objects are held any more */
 
-       if (state_tree) {
-               delete state_tree;
-       }
+       delete state_tree;
 
        terminate_butler_thread ();
        //terminate_midi_thread ();
 
-       if (click_data && click_data != default_click) {
+       if (click_data != default_click) {
                delete [] click_data;
        }
 
-       if (click_emphasis_data && click_emphasis_data != default_click_emphasis) {
+       if (click_emphasis_data != default_click_emphasis) {
                delete [] click_emphasis_data;
        }
 
@@ -471,19 +489,12 @@ Session::destroy ()
                i = tmp;
        }
 
-       if (butler_mixdown_buffer) {
-               delete [] butler_mixdown_buffer;
-       }
-
-       if (butler_gain_buffer) {
-               delete [] butler_gain_buffer;
-       }
+       delete [] butler_mixdown_buffer;
+       delete [] butler_gain_buffer;
 
        Crossfade::set_buffer_size (0);
 
-       if (mmc) {
-               delete mmc;
-       }
+       delete mmc;
 }
 
 void
@@ -581,64 +592,66 @@ Session::when_engine_running ()
                // XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO?
        }
 
-       /* Create a set of Bundle objects that map
-          to the physical outputs currently available
-       */
-
        BootMessage (_("Set up standard connections"));
 
-       /* ONE: MONO */
+       /* Create a set of Bundle objects that map
+          to the physical I/O currently available.  We create both
+          mono and stereo bundles, so that the common cases of mono
+          and stereo tracks get bundles to put in their mixer strip
+          in / out menus.  There may be a nicer way of achieving that;
+          it doesn't really scale that well to higher channel counts */
 
        for (uint32_t np = 0; np < n_physical_outputs; ++np) {
                char buf[32];
                snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
 
-               shared_ptr<AutoBundle> c (new AutoBundle (buf, true));
-               c->set_channels (1);
+               shared_ptr<Bundle> c (new Bundle (buf, true));
+               c->add_channel (_("mono"));
                c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
 
                add_bundle (c);
        }
 
-       for (uint32_t np = 0; np < n_physical_inputs; ++np) {
-               char buf[32];
-               snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
+       for (uint32_t np = 0; np < n_physical_outputs; np += 2) {
+               if (np + 1 < n_physical_outputs) {
+                       char buf[32];
+                       snprintf (buf, sizeof(buf), _("out %" PRIu32 "+%" PRIu32), np + 1, np + 2);
+                       shared_ptr<Bundle> c (new Bundle (buf, true));
+                       c->add_channel (_("L"));
+                       c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
+                       c->add_channel (_("R"));
+                       c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
 
-               shared_ptr<AutoBundle> c (new AutoBundle (buf, false));
-               c->set_channels (1);
-               c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
-
-               add_bundle (c);
+                       add_bundle (c);
+               }
        }
 
-       /* TWO: STEREO */
-
-       for (uint32_t np = 0; np < n_physical_outputs; np +=2) {
+       for (uint32_t np = 0; np < n_physical_inputs; ++np) {
                char buf[32];
-               snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2);
+               snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
 
-               shared_ptr<AutoBundle> c (new AutoBundle (buf, true));
-               c->set_channels (2);
-               c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
-               c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
+               shared_ptr<Bundle> c (new Bundle (buf, false));
+               c->add_channel (_("mono"));
+               c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
 
                add_bundle (c);
        }
 
-       for (uint32_t np = 0; np < n_physical_inputs; np +=2) {
-               char buf[32];
-               snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2);
+       for (uint32_t np = 0; np < n_physical_inputs; np += 2) {
+               if (np + 1 < n_physical_inputs) {
+                       char buf[32];
+                       snprintf (buf, sizeof(buf), _("in %" PRIu32 "+%" PRIu32), np + 1, np + 2);
 
-               shared_ptr<AutoBundle> c (new AutoBundle (buf, false));
-               c->set_channels (2);
-               c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
-               c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
+                       shared_ptr<Bundle> c (new Bundle (buf, false));
+                       c->add_channel (_("L"));
+                       c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+                       c->add_channel (_("R"));
+                       c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
 
-               add_bundle (c);
+                       add_bundle (c);
+               }
        }
 
-       /* THREE MASTER */
-
        if (_master_out) {
 
                /* create master/control ports */
@@ -678,14 +691,6 @@ Session::when_engine_running ()
                        _master_out->allow_pan_reset ();
 
                }
-
-               shared_ptr<AutoBundle> c (new AutoBundle (_("Master Out"), true));
-
-               c->set_channels (_master_out->n_inputs().n_total());
-               for (uint32_t n = 0; n < _master_out->n_inputs ().n_total(); ++n) {
-                       c->set_port (n, _master_out->input(n)->name());
-               }
-               add_bundle (c);
        }
 
        BootMessage (_("Setup signal flow and plugins"));
@@ -728,15 +733,6 @@ Session::when_engine_running ()
        BootMessage (_("Connect to engine"));
 
        _engine.set_session (this);
-
-#ifdef HAVE_LIBLO
-       /* and to OSC */
-
-       BootMessage (_("OSC startup"));
-
-       osc->set_session (*this);
-#endif
-
 }
 
 void
@@ -1213,6 +1209,10 @@ Session::audible_frame () const
        nframes_t offset;
        nframes_t tf;
 
+       if (_transport_speed == 0.0f && non_realtime_work_pending()) {
+               return last_stop_frame;
+       }
+
        /* the first of these two possible settings for "offset"
           mean that the audible frame is stationary until
           audio emerges from the latency compensation
@@ -1241,24 +1241,43 @@ Session::audible_frame () const
        } else {
                tf = _transport_frame;
        }
-
-       if (_transport_speed == 0) {
-               return tf;
-       }
-
-       if (tf < offset) {
-               return 0;
-       }
-
+       
        ret = tf;
 
        if (!non_realtime_work_pending()) {
 
                /* MOVING */
 
-               /* take latency into account */
+               /* check to see if we have passed the first guaranteed
+                  audible frame past our last start position. if not,
+                  return that last start point because in terms
+                  of audible frames, we have not moved yet.
+               */
+
+               if (_transport_speed > 0.0f) {
+
+                       if (!play_loop || !have_looped) {
+                               if (tf < _last_roll_location + offset) {
+                                       return _last_roll_location;
+                                       
+                               }
+                       } 
+                       
+
+                       /* forwards */
+                       ret -= offset;
+
+               } else if (_transport_speed < 0.0f) {
 
-               ret -= offset;
+                       /* XXX wot? no backward looping? */
+
+                       if (tf > _last_roll_location - offset) {
+                               return _last_roll_location;
+                       } else {
+                               /* backwards */
+                               ret += offset;
+                       }
+               }
        }
 
        return ret;
@@ -1305,9 +1324,7 @@ Session::set_block_size (nframes_t nframes)
 
                ensure_buffers(_scratch_buffers->available());
 
-               if (_gain_automation_buffer) {
-                       delete [] _gain_automation_buffer;
-               }
+               delete [] _gain_automation_buffer;
                _gain_automation_buffer = new gain_t[nframes];
 
                allocate_pan_automation_buffers (nframes, _npan_buffers, true);
@@ -1842,7 +1859,7 @@ Session::set_remote_control_ids ()
 }
 
 
-Session::RouteList
+RouteList
 Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
 {
        char bus_name[32];
@@ -1875,6 +1892,10 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
 
        _engine.get_physical_outputs (DataType::AUDIO, physoutputs);
        _engine.get_physical_inputs (DataType::AUDIO, physinputs);
+
+       n_physical_audio_outputs = physoutputs.size();
+       n_physical_audio_inputs = physinputs.size();
+
        control_id = ntracks() + nbusses() + 1;
 
        while (how_many) {
@@ -1900,21 +1921,24 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                goto failure;
                        }
 
-                       for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().n_audio(); ++x) {
 
-                               port = "";
 
+                       /*
+                       for (uint32_t x = 0; n_physical_audio_inputs && x < bus->n_inputs(); ++x) {
+                                       
+                               port = "";
+                               
                                if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                               port = physinputs[((n+x)%n_physical_inputs)];
-                               }
-
+                                       port = physinputs[((n+x)%n_physical_audio_inputs)];
+                               } 
+                               
                                if (port.length() && bus->connect_input (bus->input (x), port, this)) {
                                        break;
                                }
                        }
+                       */
 
-                       for (uint32_t x = 0; x < bus->n_outputs().n_audio(); ++x) {
-
+                       for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs().n_audio(); ++x) {
                                port = "";
 
                                if (Config->get_output_auto_connect() & AutoConnectPhysical) {
@@ -1988,13 +2012,6 @@ Session::add_routes (RouteList& new_routes, bool save)
                if ((*x)->is_control()) {
                        _control_out = (*x);
                }
-
-               /* only busses get automatic bundles formed */
-
-               if (!boost::dynamic_pointer_cast<Track> (*x)) {
-                       add_bundle ((*x)->bundle_for_inputs());
-                       add_bundle ((*x)->bundle_for_outputs());
-               }
        }
 
        if (_control_out && IO::connecting_legal) {
@@ -2114,6 +2131,8 @@ Session::remove_route (shared_ptr<Route> route)
 
        route->drop_references ();
 
+       sync_order_keys (N_("session"));
+
        /* save the new state of the world */
 
        if (save_state (_current_snapshot_name)) {
@@ -2238,8 +2257,6 @@ Session::update_route_solo_state ()
        bool is_track = false;
        bool signal = false;
 
-       /* caller must hold RouteLock */
-
        /* this is where we actually implement solo by changing
           the solo mute setting of each track.
        */
@@ -2339,7 +2356,24 @@ Session::catch_up_on_solo ()
           has.
        */
        update_route_solo_state();
-}
+}      
+
+void
+Session::catch_up_on_solo_mute_override ()
+{
+       if (Config->get_solo_model() != InverseMute) {
+               return;
+       }
+
+       /* this is called whenever the param solo-mute-override is
+          changed.
+       */
+       shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               (*i)->catch_up_on_solo_mute_override ();
+       }
+}      
 
 shared_ptr<Route>
 Session::route_by_name (string name)
@@ -3688,6 +3722,8 @@ Session::add_processor (Processor* processor)
                _plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
        } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
                _sends.insert (_sends.begin(), send);
+       } else if (dynamic_cast<InternalSend *> (processor) != 0) {
+               /* relax */
        } else {
                fatal << _("programming error: unknown type of Insert created!") << endmsg;
                /*NOTREACHED*/
@@ -3713,6 +3749,8 @@ Session::remove_processor (Processor* processor)
                }
        } else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
                _plugin_inserts.remove (plugin_insert);
+       } else if (dynamic_cast<InternalSend *> (processor) != 0) {
+               /* relax */
        } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
                list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
                if (x != _sends.end()) {
@@ -3766,8 +3804,9 @@ void
 Session::add_bundle (shared_ptr<Bundle> bundle)
 {
        {
-               Glib::Mutex::Lock guard (bundle_lock);
-               _bundles.push_back (bundle);
+               RCUWriter<BundleList> writer (_bundles);
+               boost::shared_ptr<BundleList> b = writer.get_copy ();
+               b->push_back (bundle);
        }
 
        BundleAdded (bundle); /* EMIT SIGNAL */
@@ -3781,11 +3820,12 @@ Session::remove_bundle (shared_ptr<Bundle> bundle)
        bool removed = false;
 
        {
-               Glib::Mutex::Lock guard (bundle_lock);
-               BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle);
+               RCUWriter<BundleList> writer (_bundles);
+               boost::shared_ptr<BundleList> b = writer.get_copy ();
+               BundleList::iterator i = find (b->begin(), b->end(), bundle);
 
-               if (i != _bundles.end()) {
-                       _bundles.erase (i);
+               if (i != b->end()) {
+                       b->erase (i);
                        removed = true;
                }
        }
@@ -3800,9 +3840,9 @@ Session::remove_bundle (shared_ptr<Bundle> bundle)
 shared_ptr<Bundle>
 Session::bundle_by_name (string name) const
 {
-       Glib::Mutex::Lock lm (bundle_lock);
-
-       for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
+       boost::shared_ptr<BundleList> b = _bundles.reader ();
+       
+       for (BundleList::const_iterator i = b->begin(); i != b->end(); ++i) {
                if ((*i)->name() == name) {
                        return* i;
                }
@@ -4218,8 +4258,13 @@ Session::get_silent_buffers (ChanCount count)
 BufferSet&
 Session::get_scratch_buffers (ChanCount count)
 {
-       assert(_scratch_buffers->available() >= count);
-       _scratch_buffers->set_count(count);
+       if (count != ChanCount::ZERO) {
+               assert(_scratch_buffers->available() >= count);
+               _scratch_buffers->set_count(count);
+       } else {
+               _scratch_buffers->set_count (_scratch_buffers->available());
+       }
+
        return *_scratch_buffers;
 }
 
@@ -4274,7 +4319,7 @@ Session::compute_initial_length ()
 }
 
 void
-Session::sync_order_keys ()
+Session::sync_order_keys (const char* base)
 {
        if (!Config->get_sync_all_route_ordering()) {
                /* leave order keys as they are */
@@ -4284,18 +4329,10 @@ Session::sync_order_keys ()
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->sync_order_keys ();
+               (*i)->sync_order_keys (base);
        }
 
-       Route::SyncOrderKeys (); // EMIT SIGNAL
+       Route::SyncOrderKeys (base); // EMIT SIGNAL
 }
 
-void
-Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl)
-{
-       Glib::Mutex::Lock lm (bundle_lock);
-       for (BundleList::iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
-               sl (*i);
-       }
-}