debug flag for session destruction and waf option for boost SP debug
[ardour.git] / libs / ardour / session.cc
index e4de8ea6c4d55ea6c0dc7ec79f0f86164f3d04a2..ce1fbca84624fe5410e70f92a0412dc09ecd0f35 100644 (file)
@@ -56,6 +56,7 @@
 #include "ardour/auditioner.h"
 #include "ardour/buffer_set.h"
 #include "ardour/bundle.h"
+#include "ardour/butler.h"
 #include "ardour/click.h"
 #include "ardour/configuration.h"
 #include "ardour/crossfade.h"
@@ -73,6 +74,7 @@
 #include "ardour/plugin_insert.h"
 #include "ardour/port_insert.h"
 #include "ardour/processor.h"
+#include "ardour/rc_configuration.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region_factory.h"
 #include "ardour/return.h"
@@ -103,7 +105,7 @@ sigc::signal<int> Session::AskAboutPendingState;
 sigc::signal<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
 sigc::signal<void> Session::SendFeedback;
 
-sigc::signal<void> Session::SMPTEOffsetChanged;
+sigc::signal<void> Session::TimecodeOffsetChanged;
 sigc::signal<void> Session::StartTimeChanged;
 sigc::signal<void> Session::EndTimeChanged;
 sigc::signal<void> Session::AutoBindingOn;
@@ -129,8 +131,9 @@ Session::Session (AudioEngine &eng,
          _session_dir (new SessionDirectory(fullpath)),
          pending_events (2048),
          state_tree (0),
-         post_transport_work((PostTransportWork)0),
-         _send_smpte_update (false),
+         _butler (new Butler (this)),
+         _post_transport_work (0),
+         _send_timecode_update (false),
          midi_thread (pthread_t (0)),
          midi_requests (128), // the size of this should match the midi request pool size
          diskstreams (new DiskstreamList),
@@ -214,8 +217,9 @@ Session::Session (AudioEngine &eng,
          _session_dir ( new SessionDirectory(fullpath)),
          pending_events (2048),
          state_tree (0),
-         post_transport_work((PostTransportWork)0),
-         _send_smpte_update (false),
+         _butler (new Butler (this)),
+         _post_transport_work (0),
+         _send_timecode_update (false),
          midi_thread (pthread_t (0)),
          midi_requests (16),
          diskstreams (new DiskstreamList),
@@ -350,10 +354,10 @@ Session::destroy ()
        delete state_tree;
 
        /* reset dynamic state version back to default */
-       
+
        Stateful::loading_state_version = 0;
 
-       terminate_butler_thread ();
+       _butler->terminate_thread ();
        //terminate_midi_thread ();
 
        if (click_data != default_click) {
@@ -867,8 +871,13 @@ Session::playlist_length_changed ()
 }
 
 void
-Session::diskstream_playlist_changed (boost::shared_ptr<Diskstream> dstream)
+Session::diskstream_playlist_changed (boost::weak_ptr<Diskstream> wp)
 {
+       boost::shared_ptr<Diskstream> dstream = wp.lock ();
+       if (!dstream) {
+               return;
+       }
+       
        boost::shared_ptr<Playlist> playlist;
 
        if ((playlist = dstream->playlist()) != 0) {
@@ -954,9 +963,10 @@ Session::auto_loop_changed (Location* location)
 
        if (transport_rolling() && play_loop) {
 
-               //if (_transport_frame < location->start() || _transport_frame > location->end()) {
 
-               if (_transport_frame > location->end()) {
+               // if (_transport_frame > location->end()) {
+
+               if (_transport_frame < location->start() || _transport_frame > location->end()) {
                        // relocate to beginning of loop
                        clear_events (Event::LocateRoll);
 
@@ -1054,9 +1064,12 @@ Session::set_auto_loop_location (Location* location)
        auto_loop_end_changed_connection.disconnect();
        auto_loop_changed_connection.disconnect();
 
-       auto_loop_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_loop_changed));
-       auto_loop_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_loop_changed));
-       auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed));
+       auto_loop_start_changed_connection = location->start_changed.connect (
+                       mem_fun (this, &Session::auto_loop_changed));
+       auto_loop_end_changed_connection = location->end_changed.connect (
+                       mem_fun (this, &Session::auto_loop_changed));
+       auto_loop_changed_connection = location->changed.connect (
+                       mem_fun (this, &Session::auto_loop_changed));
 
        location->set_auto_loop (true, this);
 
@@ -1224,12 +1237,12 @@ Session::maybe_enable_record ()
        set_dirty();
 }
 
-nframes_t
+nframes64_t
 Session::audible_frame () const
 {
-       nframes_t ret;
+       nframes64_t ret;
+       nframes64_t tf;
        nframes_t offset;
-       nframes_t tf;
 
        /* the first of these two possible settings for "offset"
           mean that the audible frame is stationary until
@@ -1891,7 +1904,7 @@ Session::set_remote_control_ids ()
 
 
 RouteList
-Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many)
+Session::new_audio_route (bool aux, int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many)
 {
        char bus_name[32];
        uint32_t bus_id = 1;
@@ -1994,6 +2007,10 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                        bus->set_remote_control_id (control_id);
                        ++control_id;
 
+                       if (aux) {
+                               bus->add_internal_return ();
+                       }
+
                        ret.push_back (bus);
                }
 
@@ -2241,7 +2258,6 @@ Session::globally_add_internal_sends (boost::shared_ptr<Route> dest, Placement p
        add_internal_sends (dest, p, t);
 }
 
-
 void
 Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::shared_ptr<RouteList> senders)
 {
@@ -2261,6 +2277,8 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::
 
                (*i)->listen_via (dest, p, true, true);
        }
+
+       graph_reordered ();
 }
 
 void
@@ -2278,9 +2296,9 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
                /* writer goes out of scope, copies ds back to main */
        }
 
-       dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream));
+       dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), boost::weak_ptr<Diskstream> (dstream)));
        /* this will connect to future changes, and check the current length */
-       diskstream_playlist_changed (dstream);
+       diskstream_playlist_changed (boost::weak_ptr<Diskstream> (dstream));
 
        dstream->RecordEnableChanged.connect (mem_fun (*this, &Session::update_have_rec_enabled_diskstream));
 
@@ -2408,7 +2426,7 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
        shared_ptr<RouteList> r = routes.reader ();
        int32_t delta;
 
-       if (route->soloed()) {
+       if (route->self_soloed()) {
                delta = 1;
        } else {
                delta = -1;
@@ -2419,24 +2437,30 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
        */
 
        solo_update_disabled = true;
+
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               bool via_sends_only;
 
-               if ((*i)->feeds (route) && !(*i)->is_hidden() && !(*i)->is_master() && !(*i)->is_control()) {
-                       /* do it */
-                       (*i)->mod_solo_level (delta);
-               }
+
+               if ((*i) == route || !(*i)->solo_isolated() || !(*i)->is_master() || !(*i)->is_control() || (*i)->is_hidden()) {
+                       continue;
+               } else if ((*i)->feeds (route, &via_sends_only)) {
+                       if (!via_sends_only) {
+                               (*i)->mod_solo_by_others (delta);
+                       }
+               } 
        }
 
        /* make sure master is never muted by solo */
 
-       if (route != _master_out && _master_out->solo_level() == 0 && !_master_out->soloed()) {
-               _master_out->mod_solo_level (1);
-       }
-
+       if (_master_out && route != _master_out && _master_out->soloed_by_others() == 0 && !_master_out->soloed()) {
+               _master_out->mod_solo_by_others (1);
+       }
        /* ditto for control outs make sure master is never muted by solo */
 
-       if (route != _control_out && _control_out && _control_out->solo_level() == 0) {
-               _control_out->mod_solo_level (1);
+       if (_control_out && route != _control_out && _control_out && _control_out->soloed_by_others() == 0) {
+               _control_out->mod_solo_by_others (1);
        }
 
        solo_update_disabled = false;
@@ -2457,7 +2481,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        }
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->is_master() && !(*i)->is_control() && !(*i)->is_hidden() && (*i)->soloed()) {
+               if (!(*i)->is_master() && !(*i)->is_control() && !(*i)->is_hidden() && (*i)->self_soloed()) {
                        something_soloed = true;
                        break;
                }
@@ -2469,6 +2493,20 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        }
 }
 
+boost::shared_ptr<RouteList> 
+Session::get_routes_with_internal_returns() const
+{
+       shared_ptr<RouteList> r = routes.reader ();
+       boost::shared_ptr<RouteList> rl (new RouteList);
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if ((*i)->internal_return ()) {
+                       rl->push_back (*i);
+               }
+       }
+       return rl;
+}
+
 shared_ptr<Route>
 Session::route_by_name (string name)
 {
@@ -3001,6 +3039,23 @@ Session::remove_source (boost::weak_ptr<Source> src)
        }
 }
 
+/** Return the number of playlists (not regions) that contain @a src */
+uint32_t
+Session::source_use_count (boost::shared_ptr<const Source> src) const
+{
+       uint32_t count = 0;
+       for (PlaylistList::const_iterator p = playlists.begin(); p != playlists.end(); ++p) {
+               for (Playlist::RegionList::const_iterator r = (*p)->region_list().begin();
+                               r != (*p)->region_list().end(); ++r) {
+                       if ((*r)->uses_source(src)) {
+                               ++count;
+                               break;
+                       }
+               }
+       }
+       return count;
+}
+
 boost::shared_ptr<Source>
 Session::source_by_id (const PBD::ID& id)
 {
@@ -3495,8 +3550,8 @@ void
 Session::set_audition (boost::shared_ptr<Region> r)
 {
        pending_audition_region = r;
-       post_transport_work = PostTransportWork (post_transport_work | PostTransportAudition);
-       schedule_butler_transport_work ();
+       add_post_transport_work (PostTransportAudition);
+       _butler->schedule_transport_work ();
 }
 
 void
@@ -4421,3 +4476,21 @@ Session::route_group_changed ()
 {
        RouteGroupChanged (); /* EMIT SIGNAL */
 }
+
+vector<SyncSource>
+Session::get_available_sync_options () const
+{
+       vector<SyncSource> ret;
+       
+       ret.push_back (JACK);
+
+       if (mtc_port()) {
+               ret.push_back (MTC);
+       } 
+
+       if (midi_clock_port()) {
+               ret.push_back (MIDIClock);
+       } 
+
+       return ret;
+}