new mix group interface, not yet finished and still to propagate to edit_group
[ardour.git] / libs / ardour / session_state.cc
index 53ca23a366175f2833a34861d2b80d300b173bab..8c3438649530e731223cd6a33bb180bc97e87ff0 100644 (file)
@@ -62,6 +62,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>
@@ -177,7 +178,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _edit_mode = Slide;
        pending_edit_mode = _edit_mode;
        _play_range = false;
-       align_style = ExistingMaterial;
        _control_out = 0;
        _master_out = 0;
        input_auto_connect = AutoConnectOption (0);
@@ -191,6 +191,10 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        pending_abort = false;
        layer_model = MoveAddHigher;
        xfade_model = ShortCrossfade;
+
+       /* allocate conversion buffers */
+       _conversion_buffers[ButlerContext] = new char[DiskStream::disk_io_frames() * 4];
+       _conversion_buffers[TransportContext] = new char[DiskStream::disk_io_frames() * 4];
        
        /* default short fade = 15ms */
 
@@ -231,7 +235,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
 
        /* default configuration */
 
-       recording_plugins = false;
+       do_not_record_plugins = false;
        over_length_short = 2;
        over_length_long = 10;
        send_midi_timecode = false;
@@ -483,6 +487,15 @@ Session::create (bool& new_session, string* mix_template, jack_nframes_t initial
                }
        }
 
+       dir = tape_dir ();
+
+       if (mkdir (dir.c_str(), 0755) < 0) {
+               if (errno != EEXIST) {
+                       error << string_compose(_("Session: cannot create session tape dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+                       return -1;
+               }
+       }
+
        dir = dead_sound_dir ();
 
        if (mkdir (dir.c_str(), 0755) < 0) {
@@ -506,33 +519,7 @@ Session::create (bool& new_session, string* mix_template, jack_nframes_t initial
        
        if (mix_template) {
                if (new_session){
-
-                       string lookfor = "^";
-                       lookfor += *mix_template;
-                       lookfor += _template_suffix;
-                       lookfor += '$';
-
-                       PathScanner scanner;
-                       string tpath = template_path();
-                       string in_path;
-                       string out_path;
-
-                       vector<string*>* result= scanner (tpath, lookfor, false, true);
-
-                       if (result == 0) {
-                               error << string_compose (_("Could not find a template called %1 in %2"), *mix_template, tpath)
-                                     << endmsg;
-                               *mix_template = "";
-                       }
-
-                       if (result->size() == 0) {
-                               delete result;
-                               error << string_compose (_("Could not find a template called %1 in %2"), *mix_template, tpath)
-                                     << endmsg;
-                               *mix_template = "";
-                       }
-
-                       in_path = *(result->front());
+                       std::string in_path = *mix_template;
 
                        ifstream in(in_path.c_str());
                        
@@ -972,9 +959,15 @@ Session::load_options (const XMLNode& node)
                        set_midi_feedback (prop->value() == "yes");
                }
        }
+       // Legacy support for <recording-plugins>
        if ((child = find_named_node (node, "recording-plugins")) != 0) {
                if ((prop = child->property ("val")) != 0) {
-                       set_recording_plugins (prop->value() == "yes");
+                       set_do_not_record_plugins (prop->value() == "no");
+               }
+       }
+       if ((child = find_named_node (node, "do-not-record-plugins")) != 0) {
+               if ((prop = child->property ("val")) != 0) {
+                       set_do_not_record_plugins (prop->value() == "yes");
                }
        }
        if ((child = find_named_node (node, "crossfades-active")) != 0) {
@@ -988,16 +981,6 @@ Session::load_options (const XMLNode& node)
                }
        }
 
-       if ((child = find_named_node (node, "align-style")) != 0) {
-               if ((prop = child->property ("val")) != 0) {
-                       if (prop->value() == "capture") {
-                               set_align_style (CaptureTime);
-                       } else {
-                               set_align_style (ExistingMaterial);
-                       }
-               }
-       }
-
        if ((child = find_named_node (node, "layer-model")) != 0) {
                if ((prop = child->property ("val")) != 0) {
                        if (prop->value() == X_("LaterHigher")) {
@@ -1177,8 +1160,8 @@ Session::get_options () const
        child->add_property ("val", get_midi_control () ? "yes" : "no");
        child = opthead->add_child ("midi-feedback");
        child->add_property ("val", get_midi_feedback () ? "yes" : "no");
-       child = opthead->add_child ("recording-plugins");
-       child->add_property ("val", get_recording_plugins () ? "yes" : "no");
+       child = opthead->add_child ("do-not-record-plugins");
+       child->add_property ("val", get_do_not_record_plugins () ? "yes" : "no");
        child = opthead->add_child ("auto-crossfade");
        child->add_property ("val", get_crossfades_active () ? "yes" : "no");
        child = opthead->add_child ("audible-click");
@@ -1197,9 +1180,6 @@ Session::get_options () const
        child = opthead->add_child ("solo-model");
        child->add_property ("val", _solo_model == SoloBus ? "SoloBus" : "InverseMute");
 
-       child = opthead->add_child ("align-style");
-       child->add_property ("val", (align_style == ExistingMaterial ? "existing" : "capture"));
-
        child = opthead->add_child ("layer-model");
        switch (layer_model) {
        case LaterHigher:
@@ -1250,7 +1230,6 @@ Session::get_template()
        
        disable_record ();
 
-       cerr << "STart get template\n";
        return state(false);
 }
 
@@ -1450,6 +1429,7 @@ Session::set_state (const XMLNode& node)
        XMLNodeList nlist;
        XMLNode* child;
        const XMLProperty* prop;
+       int ret = -1;
 
        _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
        
@@ -1458,6 +1438,8 @@ Session::set_state (const XMLNode& node)
                return -1;
        }
 
+       StateManager::prohibit_save ();
+
        if ((prop = node.property ("name")) != 0) {
                _name = prop->value ();
        }
@@ -1483,7 +1465,6 @@ Session::set_state (const XMLNode& node)
        */
 
        if (use_config_midi_ports ()) {
-               return -1;
        }
 
        if ((child = find_named_node (node, "Path")) != 0) {
@@ -1500,63 +1481,61 @@ Session::set_state (const XMLNode& node)
 
        if ((child = find_named_node (node, "Options")) == 0) {
                error << _("Session: XML state has no options section") << endmsg;
-               return -1;
        } else if (load_options (*child)) {
-               return -1;
        }
 
        if ((child = find_named_node (node, "Sources")) == 0) {
                error << _("Session: XML state has no sources section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_sources (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "Regions")) == 0) {
                error << _("Session: XML state has no Regions section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_regions (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "Playlists")) == 0) {
                error << _("Session: XML state has no playlists section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_playlists (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
                // this is OK
        } else if (load_unused_playlists (*child)) {
-               return -1;
+               goto out;
        }
        
        if ((child = find_named_node (node, "NamedSelections")) != 0) {
                if (load_named_selections (*child)) {
-                       return -1;
+                       goto out;
                }
        }
 
        if ((child = find_named_node (node, "DiskStreams")) == 0) {
                error << _("Session: XML state has no diskstreams section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_diskstreams (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "Connections")) == 0) {
                error << _("Session: XML state has no connections section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_connections (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "Locations")) == 0) {
                error << _("Session: XML state has no locations section") << endmsg;
-               return -1;
+               goto out;
        } else if (_locations.set_state (*child)) {
-               return -1;
+               goto out;
        }
 
        Location* location;
@@ -1579,30 +1558,30 @@ Session::set_state (const XMLNode& node)
 
        if ((child = find_named_node (node, "EditGroups")) == 0) {
                error << _("Session: XML state has no edit groups section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_edit_groups (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "MixGroups")) == 0) {
                error << _("Session: XML state has no mix groups section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_mix_groups (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "TempoMap")) == 0) {
                error << _("Session: XML state has no Tempo Map section") << endmsg;
-               return -1;
+               goto out;
        } else if (_tempo_map->set_state (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "Routes")) == 0) {
                error << _("Session: XML state has no routes section") << endmsg;
-               return -1;
+               goto out;
        } else if (load_routes (*child)) {
-               return -1;
+               goto out;
        }
 
        if ((child = find_named_node (node, "Click")) == 0) {
@@ -1621,6 +1600,8 @@ Session::set_state (const XMLNode& node)
 
        _state_of_the_state = Clean;
 
+       StateManager::allow_save (_("initial state"), true);
+
        if (state_was_pending) {
                save_state (_current_snapshot_name);
                remove_pending_capture_state ();
@@ -1628,6 +1609,11 @@ Session::set_state (const XMLNode& node)
        }
 
        return 0;
+
+  out:
+       /* we failed, re-enable state saving but don't actually save internal state */
+       StateManager::allow_save (X_("ignored"), false);
+       return ret;
 }
 
 int
@@ -1816,8 +1802,13 @@ Session::XMLSourceFactory (const XMLNode& node)
                return 0;
        }
 
+
        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) {
@@ -1980,11 +1971,17 @@ Session::ensure_sound_dir (string path, string& result)
 }      
 
 string
-Session::discover_best_sound_dir ()
+Session::discover_best_sound_dir (bool destructive)
 {
        vector<space_and_path>::iterator i;
        string result;
 
+       /* destructive files all go into the same place */
+
+       if (destructive) {
+               return tape_dir();
+       }
+
        /* handle common case without system calls */
 
        if (session_dirs.size() == 1) {
@@ -1992,7 +1989,7 @@ Session::discover_best_sound_dir ()
        }
 
        /* OK, here's the algorithm we're following here:
-
+          
        We want to select which directory to use for 
        the next file source to be created. Ideally,
        we'd like to use a round-robin process so as to
@@ -2198,6 +2195,21 @@ Session::sound_dir () const
        return res;
 }
 
+string
+Session::tape_dir () const
+{
+       string res = Config->get_tape_dir();
+
+       if (!res.empty()) {
+               return res;
+       }
+
+       res = _path;
+       res += tape_dir_name;
+       res += '/';
+       return res;
+}
+
 string
 Session::peak_dir () const
 {
@@ -2386,7 +2398,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();
@@ -2396,13 +2408,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)
 {