pulling trunk
[ardour.git] / libs / ardour / session_state.cc
index bd80ad50a5459611e25a083b9d5ed2fb64f3e3ff..cf510e9881d2dc30490d4a0756e372b2a9ed4ffe 100644 (file)
 #include <sys/param.h>
 #endif
 
+#include <glibmm.h>
+
 #include <midi++/mmc.h>
 #include <midi++/port.h>
 #include <pbd/error.h>
-#include <pbd/dirname.h>
-#include <pbd/lockmonitor.h>
+
+#include <glibmm/thread.h>
 #include <pbd/pathscanner.h>
 #include <pbd/pthread_utils.h>
-#include <pbd/basename.h>
 #include <pbd/strsplit.h>
 
 #include <ardour/audioengine.h>
@@ -62,6 +63,7 @@
 #include <ardour/audioplaylist.h>
 #include <ardour/source.h>
 #include <ardour/filesource.h>
+#include <ardour/destructive_filesource.h>
 #include <ardour/sndfilesource.h>
 #include <ardour/sndfile_helpers.h>
 #include <ardour/auditioner.h>
@@ -80,6 +82,7 @@
 #include <ardour/location.h>
 #include <ardour/audioregion.h>
 #include <ardour/crossfade.h>
+#include <ardour/control_protocol_manager.h>
 
 #include "i18n.h"
 #include <locale.h>
@@ -116,7 +119,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _tempo_map = new TempoMap (_current_frame_rate);
        _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
 
-       atomic_set (&processing_prohibited, 0);
+       g_atomic_int_set (&processing_prohibited, 0);
        send_cnt = 0;
        insert_cnt = 0;
        _transport_speed = 0;
@@ -125,8 +128,9 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _transport_frame = 0;
        last_stop_frame = 0;
        end_location = new Location (0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
+       start_location = new Location (0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
        _end_location_is_free = true;
-       atomic_set (&_record_status, Disabled);
+       g_atomic_int_set (&_record_status, Disabled);
        auto_play = false;
        punch_in = false;
        punch_out = false;
@@ -153,6 +157,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _solo_model = InverseMute;
        solo_update_disabled = false;
        currently_soloing = false;
+       _have_captured = false;
        _worst_output_latency = 0;
        _worst_input_latency = 0;
        _worst_track_latency = 0;
@@ -163,16 +168,15 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        butler_gain_buffer = 0;
        auditioner = 0;
        mmc_control = false;
-       midi_feedback = false;
        midi_control = true;
        mmc = 0;
        post_transport_work = PostTransportWork (0);
-       atomic_set (&butler_should_do_transport_work, 0);
-       atomic_set (&butler_active, 0);
-       atomic_set (&_playback_load, 100);
-       atomic_set (&_capture_load, 100);
-       atomic_set (&_playback_load_min, 100);
-       atomic_set (&_capture_load_min, 100);
+       g_atomic_int_set (&butler_should_do_transport_work, 0);
+       g_atomic_int_set (&butler_active, 0);
+       g_atomic_int_set (&_playback_load, 100);
+       g_atomic_int_set (&_capture_load, 100);
+       g_atomic_int_set (&_playback_load_min, 100);
+       g_atomic_int_set (&_capture_load_min, 100);
        pending_audition_region = 0;
        _edit_mode = Slide;
        pending_edit_mode = _edit_mode;
@@ -181,7 +185,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _master_out = 0;
        input_auto_connect = AutoConnectOption (0);
        output_auto_connect = AutoConnectOption (0);
-       _have_captured = false;
        waiting_to_start = false;
        _exporting = false;
        _gain_automation_buffer = 0;
@@ -190,6 +193,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        pending_abort = false;
        layer_model = MoveAddHigher;
        xfade_model = ShortCrossfade;
+       destructive_index = 0;
 
        /* allocate conversion buffers */
        _conversion_buffers[ButlerContext] = new char[DiskStream::disk_io_frames() * 4];
@@ -281,7 +285,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
 int
 Session::second_stage_init (bool new_session)
 {
-       SndFileSource::set_peak_dir (peak_dir());
+       ExternalSource::set_peak_dir (peak_dir());
 
        if (!new_session) {
                if (load_state (_current_snapshot_name)) {
@@ -298,10 +302,6 @@ Session::second_stage_init (bool new_session)
                return -1;
        }
 
-       if (init_feedback ()) {
-               return -1;
-       }
-
        if (state_tree) {
                if (set_state (*state_tree->root())) {
                        return -1;
@@ -341,7 +341,8 @@ Session::second_stage_init (bool new_session)
        _engine.transport_locate (0);
        deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0);
        deliver_mmc (MIDI::MachineControl::cmdLocate, 0);
-       send_all_midi_feedback();
+
+       ControlProtocolManager::instance().set_session (*this);
 
        if (new_session) {
                _end_location_is_free = true;
@@ -399,13 +400,32 @@ Session::setup_raid_path (string path)
 
        if (colons == 0) {
 
-               /* no multiple search path, just one directory (common case) */
+               /* no multiple search path, just one location (common case) */
 
                sp.path = path;
                sp.blocks = 0;
                session_dirs.push_back (sp);
+
+               string fspath;
+
+               /* sounds dir */
+
+               fspath += sp.path;
+               if (fspath[fspath.length()-1] != '/') {
+                       fspath += '/';
+               }
+               fspath += sound_dir_name;
+               fspath += ':';
+
+               /* tape dir */
+
+               fspath += sp.path;
+               if (fspath[fspath.length()-1] != '/') {
+                       fspath += '/';
+               }
+               fspath += tape_dir_name;
                
-               FileSource::set_search_path (path + sound_dir_name);
+               FileSource::set_search_path (fspath);
 
                return;
        }
@@ -416,6 +436,9 @@ Session::setup_raid_path (string path)
                
                sp.blocks = 0;
                sp.path = remaining.substr (0, colon);
+               session_dirs.push_back (sp);
+
+               /* add sounds to file search path */
 
                fspath += sp.path;
                if (fspath[fspath.length()-1] != '/') {
@@ -424,7 +447,14 @@ Session::setup_raid_path (string path)
                fspath += sound_dir_name;
                fspath += ':';
 
-               session_dirs.push_back (sp);
+               /* add tape dir to file search path */
+
+               fspath += sp.path;
+               if (fspath[fspath.length()-1] != '/') {
+                       fspath += '/';
+               }
+               fspath += tape_dir_name;
+               fspath += ':';
 
                remaining = remaining.substr (colon+1);
        }
@@ -434,11 +464,19 @@ Session::setup_raid_path (string path)
                sp.blocks = 0;
                sp.path = remaining;
 
+               fspath += ':';
                fspath += sp.path;
                if (fspath[fspath.length()-1] != '/') {
                        fspath += '/';
                }
                fspath += sound_dir_name;
+               fspath += ':';
+
+               fspath += sp.path;
+               if (fspath[fspath.length()-1] != '/') {
+                       fspath += '/';
+               }
+               fspath += tape_dir_name;
 
                session_dirs.push_back (sp);
        }
@@ -559,11 +597,14 @@ Session::create (bool& new_session, string* mix_template, jack_nframes_t initial
 
        if (new_session) {
 
-               /* set an initial end point */
+               /* set initial start + end point */
+
+               start_location->set_end (0);
+               _locations.add (start_location);
 
                end_location->set_end (initial_length);
                _locations.add (end_location);
-
+               
                _state_of_the_state = Clean;
 
                if (save_state (_current_snapshot_name)) {
@@ -676,7 +717,7 @@ Session::save_state (string snapshot_name, bool pending)
        if (!pending) {
 
                bool was_dirty = dirty();
-               
+
                _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
                
                if (was_dirty) {
@@ -980,6 +1021,12 @@ Session::load_options (const XMLNode& node)
                }
        }
 
+       if ((child = find_named_node (node, "end-marker-is-free")) != 0) {
+               if ((prop = child->property ("val")) != 0) {
+                       _end_location_is_free = (prop->value() == "yes");
+               }
+       }
+
        if ((child = find_named_node (node, "layer-model")) != 0) {
                if ((prop = child->property ("val")) != 0) {
                        if (prop->value() == X_("LaterHigher")) {
@@ -1165,6 +1212,8 @@ Session::get_options () const
        child->add_property ("val", get_crossfades_active () ? "yes" : "no");
        child = opthead->add_child ("audible-click");
        child->add_property ("val", get_clicking () ? "yes" : "no");
+       child = opthead->add_child ("end-marker-is-free");
+       child->add_property ("val", _end_location_is_free ? "yes" : "no");
 
        if (click_sound.length()) {
                child = opthead->add_child ("click-sound");
@@ -1227,7 +1276,7 @@ Session::get_template()
           sources in their state node. 
        */
        
-       disable_record ();
+       disable_record (false);
 
        return state(false);
 }
@@ -1286,17 +1335,25 @@ Session::state(bool full_state)
        child = node->add_child ("Sources");
 
        if (full_state) {
-               LockMonitor sl (source_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock sl (source_lock);
 
                for (SourceList::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
                        
                        /* Don't save information about FileSources that are empty */
                        
                        FileSource* fs;
-                       
+
                        if ((fs = dynamic_cast<FileSource*> ((*siter).second)) != 0) {
-                               if (fs->length() == 0) {
-                                       continue;
+                               DestructiveFileSource* dfs = dynamic_cast<DestructiveFileSource*> (fs);
+
+                               /* destructive file sources are OK if they are empty, because
+                                  we will re-use them every time.
+                               */
+
+                               if (!dfs) {
+                                       if (fs->length() == 0) {
+                                               continue;
+                                       }
                                }
                        }
                        
@@ -1307,7 +1364,7 @@ Session::state(bool full_state)
        child = node->add_child ("Regions");
 
        if (full_state) { 
-               LockMonitor rl (region_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock rl (region_lock);
 
                for (AudioRegionList::const_iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) {
                        
@@ -1322,7 +1379,7 @@ Session::state(bool full_state)
        child = node->add_child ("DiskStreams");
 
        { 
-               RWLockMonitor dl (diskstream_lock, false, __LINE__, __FILE__);
+               Glib::RWLock::ReaderLock dl (diskstream_lock);
                for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                        if (!(*i)->hidden()) {
                                child->add_child_nocopy ((*i)->get_state());
@@ -1334,7 +1391,7 @@ Session::state(bool full_state)
        
        child = node->add_child ("Connections");
        {
-               LockMonitor lm (connection_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (connection_lock);
                for (ConnectionList::iterator i = _connections.begin(); i != _connections.end(); ++i) {
                        if (!(*i)->system_dependent()) {
                                child->add_child_nocopy ((*i)->get_state());
@@ -1344,7 +1401,7 @@ Session::state(bool full_state)
 
        child = node->add_child ("Routes");
        {
-               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+               Glib::RWLock::ReaderLock lm (route_lock);
                
                RoutePublicOrderSorter cmp;
                RouteList public_order(routes);
@@ -1550,9 +1607,17 @@ Session::set_state (const XMLNode& node)
        if ((location = _locations.end_location()) == 0) {
                _locations.add (end_location);
        } else {
+               delete end_location;
                end_location = location;
        }
 
+       if ((location = _locations.start_location()) == 0) {
+               _locations.add (start_location);
+       } else {
+               delete start_location;
+               start_location = location;
+       }
+
        _locations.save_state (_("initial state"));
 
        if ((child = find_named_node (node, "EditGroups")) == 0) {
@@ -1739,7 +1804,7 @@ Session::get_sources_as_xml ()
 
 {
        XMLNode* node = new XMLNode (X_("Sources"));
-       LockMonitor lm (source_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (source_lock);
 
        for (SourceList::iterator i = sources.begin(); i != sources.end(); ++i) {
                node->add_child_nocopy ((*i).second->get_state());
@@ -1802,13 +1867,17 @@ Session::XMLSourceFactory (const XMLNode& node)
        }
 
        try {
-               src = new FileSource (node, frame_rate());
+               if (node.property (X_("destructive")) != 0) {
+                       src = new DestructiveFileSource (node, frame_rate());
+               } else {
+                       src = new FileSource (node, frame_rate());
+               }
        }
        
        catch (failed_constructor& err) {
 
                try {
-                       src = new SndFileSource (node);
+                       src = ExternalSource::create (node);
                }
 
                catch (failed_constructor& err) {
@@ -1890,7 +1959,7 @@ Session::refresh_disk_space ()
 #if HAVE_SYS_VFS_H
        struct statfs statfsbuf;
        vector<space_and_path>::iterator i;
-       LockMonitor lm (space_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (space_lock);
        double scale;
 
        /* get freespace on every FS that is part of the session path */
@@ -2192,13 +2261,7 @@ Session::sound_dir () const
 string
 Session::tape_dir () const
 {
-       string res = Config->get_tape_dir();
-
-       if (!res.empty()) {
-               return res;
-       }
-
-       res = _path;
+       string res = _path;
        res += tape_dir_name;
        res += '/';
        return res;
@@ -2224,22 +2287,27 @@ Session::automation_dir () const
 string
 Session::template_dir ()
 {
-       string path = Config->get_user_ardour_path();
+       string path = get_user_ardour_path();
        path += "templates/";
 
        return path;
 }
 
 string
-Session::template_path ()
+Session::suffixed_search_path (string suffix, bool data)
 {
        string path;
 
-       path += Config->get_user_ardour_path();
+       path += get_user_ardour_path();
        if (path[path.length()-1] != ':') {
                path += ':';
        }
-       path += Config->get_system_ardour_path();
+
+       if (data) {
+               path += get_system_data_path();
+       } else {
+               path += get_system_module_path();
+       }
 
        vector<string> split_path;
        
@@ -2248,7 +2316,8 @@ Session::template_path ()
 
        for (vector<string>::iterator i = split_path.begin(); i != split_path.end(); ++i) {
                path += *i;
-               path += "templates/";
+               path += suffix;
+               path += '/';
                
                if (distance (i, split_path.end()) != 1) {
                        path += ':';
@@ -2258,6 +2327,18 @@ Session::template_path ()
        return path;
 }
 
+string
+Session::template_path ()
+{
+       return suffixed_search_path (X_("templates"), true);
+}
+
+string
+Session::control_protocol_path ()
+{
+       return suffixed_search_path (X_("surfaces"), false);
+}
+
 int
 Session::load_connections (const XMLNode& node)
 {
@@ -2297,18 +2378,18 @@ Session::load_route_groups (const XMLNode& node, bool edit)
 {
        XMLNodeList nlist = node.children();
        XMLNodeConstIterator niter;
-       RouteGroup* route;
+       RouteGroup* rg;
 
        set_dirty();
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
                if ((*niter)->name() == "RouteGroup") {
                        if (edit) {
-                               route = add_edit_group ("");
-                               route->set_state (**niter);
+                               rg = add_edit_group ("");
+                               rg->set_state (**niter);
                        } else {
-                               route = add_mix_group ("");
-                               route->set_state (**niter);
+                               rg = add_mix_group ("");
+                               rg->set_state (**niter);
                        }
                }
        }
@@ -2319,7 +2400,7 @@ Session::load_route_groups (const XMLNode& node, bool edit)
 void
 Session::swap_configuration(Configuration** new_config)
 {
-       RWLockMonitor lm (route_lock, true, __LINE__, __FILE__); // jlc - WHY?
+       Glib::RWLock::WriterLock lm (route_lock); // jlc - WHY?
        Configuration* tmp = *new_config;
        *new_config = Config;
        Config = tmp;
@@ -2329,7 +2410,7 @@ Session::swap_configuration(Configuration** new_config)
 void
 Session::copy_configuration(Configuration* new_config)
 {
-       RWLockMonitor lm (route_lock, true, __LINE__, __FILE__);
+       Glib::RWLock::WriterLock lm (route_lock);
        new_config = new Configuration(*Config);
 }
 
@@ -2392,7 +2473,7 @@ Session::auto_save()
 RouteGroup *
 Session::add_edit_group (string name)
 {
-       RouteGroup* rg = new RouteGroup (name);
+       RouteGroup* rg = new RouteGroup (*this, name);
        edit_groups.push_back (rg);
        edit_group_added (rg); /* EMIT SIGNAL */
        set_dirty();
@@ -2402,13 +2483,41 @@ Session::add_edit_group (string name)
 RouteGroup *
 Session::add_mix_group (string name)
 {
-       RouteGroup* rg = new RouteGroup (name, RouteGroup::Relative);
+       RouteGroup* rg = new RouteGroup (*this, name, RouteGroup::Relative);
        mix_groups.push_back (rg);
        mix_group_added (rg); /* EMIT SIGNAL */
        set_dirty();
        return rg;
 }
 
+void
+Session::remove_edit_group (RouteGroup& rg)
+{
+       list<RouteGroup*>::iterator i;
+
+       if ((i = find (edit_groups.begin(), edit_groups.end(), &rg)) != edit_groups.end()) {
+               (*i)->apply (&Route::drop_edit_group, this);
+               edit_groups.erase (i);
+               edit_group_removed (); /* EMIT SIGNAL */
+       }
+
+       delete &rg;
+}
+
+void
+Session::remove_mix_group (RouteGroup& rg)
+{
+       list<RouteGroup*>::iterator i;
+
+       if ((i = find (mix_groups.begin(), mix_groups.end(), &rg)) != mix_groups.end()) {
+               (*i)->apply (&Route::drop_mix_group, this);
+               mix_groups.erase (i);
+               mix_group_removed (); /* EMIT SIGNAL */
+       }
+
+       delete &rg;
+}
+
 RouteGroup *
 Session::mix_group_by_name (string name)
 {
@@ -2480,7 +2589,7 @@ Session::GlobalRouteBooleanState
 Session::get_global_route_boolean (bool (Route::*method)(void) const)
 {
        GlobalRouteBooleanState s;
-       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock lm (route_lock);
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                if (!(*i)->hidden()) {
@@ -2500,7 +2609,7 @@ Session::GlobalRouteMeterState
 Session::get_global_route_metering ()
 {
        GlobalRouteMeterState s;
-       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+       Glib::RWLock::ReaderLock lm (route_lock);
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                if (!(*i)->hidden()) {
@@ -2609,7 +2718,7 @@ Session::get_template_list (list<string> &template_names)
 int
 Session::read_favorite_dirs (FavoriteDirs & favs)
 {
-       string path = Config->get_user_ardour_path();
+       string path = get_user_ardour_path();
        path += "/favorite_dirs";
 
        ifstream fav (path.c_str());
@@ -2644,7 +2753,7 @@ Session::read_favorite_dirs (FavoriteDirs & favs)
 int
 Session::write_favorite_dirs (FavoriteDirs & favs)
 {
-       string path = Config->get_user_ardour_path();
+       string path = get_user_ardour_path();
        path += "/favorite_dirs";
 
        ofstream fav (path.c_str());
@@ -2912,11 +3021,11 @@ Session::cleanup_sources (Session::cleanup_report& rep)
 
        for (SourceList::iterator i = sources.begin(); i != sources.end(); ++i) {
                FileSource* fs;
-               SndFileSource* sfs;
+               ExternalSource* sfs;
                
                if ((fs = dynamic_cast<FileSource*> ((*i).second)) != 0) {
                        all_sources.insert (fs->path());
-               } else if ((sfs = dynamic_cast<SndFileSource*> ((*i).second)) != 0) {
+               } else if ((sfs = dynamic_cast<ExternalSource*> ((*i).second)) != 0) {
                        all_sources.insert (sfs->path());
                } 
        }
@@ -2957,13 +3066,13 @@ Session::cleanup_sources (Session::cleanup_report& rep)
                   on whichever filesystem it was already on.
                */
 
-               newpath = PBD::dirname (*x);
-               newpath = PBD::dirname (newpath);
+               newpath = Glib::path_get_dirname (*x);
+               newpath = Glib::path_get_dirname (newpath);
 
                newpath += '/';
                newpath += dead_sound_dir_name;
                newpath += '/';
-               newpath += PBD::basename ((*x));
+               newpath += Glib::path_get_basename ((*x));
                
                if (access (newpath.c_str(), F_OK) == 0) {
                        
@@ -3104,7 +3213,7 @@ void
 Session::set_dirty ()
 {
        bool was_dirty = dirty();
-       
+
        _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
 
        if (!was_dirty) {