track templates, backported from 2.X
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 2 Mar 2009 16:52:40 +0000 (16:52 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 2 Mar 2009 16:52:40 +0000 (16:52 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@4713 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/directory_names.h
libs/ardour/ardour/io.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/template_utils.h
libs/ardour/directory_names.cc
libs/ardour/io.cc
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/template_utils.cc

index 2f9991fd650ced01d45a97acd45eaf2279dc6046..b0023bba5a9acebeaee683521ddf776e527718e8 100644 (file)
@@ -16,6 +16,7 @@ extern const char* const interchange_dir_name;
 extern const char* const peak_dir_name;
 extern const char* const export_dir_name;
 extern const char* const templates_dir_name;
+extern const char* const route_templates_dir_name;
 extern const char* const surfaces_dir_name;
 extern const char* const user_config_dir_name;
 
index 2058e2e079b6a0b1bf3ec41a5869bfdf5262a9ee..709a5368db1bd5ac818b9fec4e4629803fd4c598 100644 (file)
@@ -215,6 +215,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        static sigc::signal<int>            PortsCreated;
 
        static void update_meters();
+       static std::string name_from_state (const XMLNode&);
+       static void set_name_in_state (XMLNode&, const std::string&);
 
   private: 
        
index a5bd751d2270f3d68b79f311f3f406ac7f1731ef..2319cadb57d66a1289c178a959cf5b98efc8727d 100644 (file)
@@ -221,6 +221,8 @@ class Route : public IO
        XMLNode& get_processor_state ();
        int set_processor_state (const XMLNode&);
 
+       int save_as_template (const std::string& path, const std::string& name);
+
        sigc::signal<void,void*> SelectedChanged;
 
        int set_control_outs (const vector<std::string>& ports);
index 6e09bbd4ed1cb3e4eeaaaf88562267b34cf8175a..082e05a9bdf26584f1699479a64f797ef25ac430 100644 (file)
@@ -281,6 +281,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
        string new_audio_source_name (const string&, uint32_t nchans, uint32_t chan, bool destructive);
        string new_midi_source_name (const string&);
        string new_source_path_from_name (DataType type, const string&);
+       RouteList new_route_from_template (uint32_t how_many, const std::string& template_path);
 
        void process (nframes_t nframes);
 
index 6ba0683e1eb6ca71984aaa5e7ce2908d1d92dfca..5542e8420fc117bb3bd2740cf141e2e03baab8d3 100644 (file)
@@ -12,8 +12,17 @@ namespace ARDOUR {
        using namespace PBD;
 
        sys::path system_template_directory ();
+       sys::path system_route_template_directory ();
 
        sys::path user_template_directory ();
+       sys::path user_route_template_directory ();
+
+       struct RouteTemplateInfo {
+           std::string name;
+           std::string path;
+       };
+
+       void find_route_templates (std::vector<RouteTemplateInfo>& template_names);
 
 } // namespace ARDOUR
 
index 6afcfb4353387a721af1d81898745647f2a99b84..266147eb2e9e33d653094dc666ffc961c5267342 100644 (file)
@@ -14,6 +14,7 @@ const char* const dead_midi_dir_name = X_("dead_midi");
 const char* const interchange_dir_name = X_("interchange");
 const char* const export_dir_name = X_("export");
 const char* const templates_dir_name = X_("templates");
+const char* const route_templates_dir_name = X_("route_templates");
 const char* const surfaces_dir_name = X_("surfaces");
 const char* const user_config_dir_name = X_(".ardour3");
 
index f1c1bb1dab59529345c8312c8a8299b034e39a9b..e6dff6158a33033be70c19b0e08f05ce5dd5dac6 100644 (file)
@@ -2778,4 +2778,24 @@ IO::bundle_channel_name (uint32_t c, uint32_t n) const
        return "";
 }
 
+string
+IO::name_from_state (const XMLNode& node)
+{
+       const XMLProperty* prop;
+       
+       if ((prop = node.property ("name")) != 0) {
+               return prop->value();
+       } 
+       
+       return string();
+}
 
+void
+IO::set_name_in_state (XMLNode& node, const string& new_name)
+{
+       const XMLProperty* prop;
+       
+       if ((prop = node.property ("name")) != 0) {
+               node.add_property ("name", new_name);
+       } 
+}
index 0111ca8e103aedc059fd12855b1981cba72039da..c1f7d97d5cc87d4281413bf3dbec18fe446ecdc7 100644 (file)
@@ -3099,3 +3099,16 @@ Route::shift (nframes64_t pos, nframes64_t frames)
 #endif
 
 }
+
+
+int
+Route::save_as_template (const string& path, const string& name)
+{
+       XMLNode& node (state (false));
+       XMLTree tree;
+       
+       IO::set_name_in_state (*node.children().front(), name);
+       
+       tree.set_root (&node);
+       return tree.write (path.c_str());
+}
index 51f55cb6b9d50a93901a3687bbc432051f6917e4..d2938f666facc8d547c61d340922ad12a253a89f 100644 (file)
@@ -1980,6 +1980,88 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
 
 }
 
+RouteList
+Session::new_route_from_template (uint32_t how_many, const std::string& template_path)
+{
+       char name[32];
+       RouteList ret;
+       uint32_t control_id;
+       XMLTree tree;
+
+       if (!tree.read (template_path.c_str())) {
+               return ret;
+       }
+
+       XMLNode* node = tree.root();
+
+       control_id = ntracks() + nbusses() + 1;
+
+       while (how_many) {
+
+               XMLNode node_copy (*node); // make a copy so we can change the name if we need to
+         
+               std::string node_name = IO::name_from_state (*node_copy.children().front());
+
+               if (route_by_name (node_name) != 0) {
+
+                       /* generate a new name by adding a number to the end of the template name */
+
+                       uint32_t number = 1;
+
+                       do {
+                               snprintf (name, sizeof (name), "%s %" PRIu32, node_name.c_str(), number);
+             
+                               number++;
+             
+                               if (route_by_name (name) == 0) {
+                                       break;
+                               }
+             
+                       } while (number < UINT_MAX);
+
+                       if (number == UINT_MAX) {
+                               fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
+                               /*NOTREACHED*/
+                       }
+
+                       IO::set_name_in_state (node_copy, name);
+               }
+
+               try {
+                       shared_ptr<Route> route (XMLRouteFactory (node_copy));
+           
+                       if (route == 0) {
+                               error << _("Session: cannot create track/bus from template description") << endmsg;
+                               goto out;
+                       }
+
+                       route->set_remote_control_id (control_id);
+                       ++control_id;
+           
+                       ret.push_back (route);
+               }
+         
+               catch (failed_constructor &err) {
+                       error << _("Session: could not create new route from template") << endmsg;
+                       goto out;
+               }
+         
+               catch (AudioEngine::PortRegistrationFailure& pfe) {
+                       error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
+                       goto out;
+               }
+         
+               --how_many;
+       }
+
+  out:
+       if (!ret.empty()) {
+               add_routes (ret, true);
+       }
+
+       return ret;
+}
+
 void
 Session::add_routes (RouteList& new_routes, bool save)
 {
index 7c25b59db8b9f47a1dc85b0de761b128eaf96108..93bfd46972d037b393b092745fdf8123a3868747 100644 (file)
@@ -1,10 +1,15 @@
 #include <algorithm>
+#include <cstring>
 
 #include "pbd/filesystem.h"
+#include "pbd/pathscanner.h"
+#include "pbd/xml++.h"
 
 #include "ardour/template_utils.h"
 #include "ardour/directory_names.h"
 #include "ardour/filesystem_paths.h"
+#include "ardour/filename_extensions.h"
+#include "ardour/io.h"
 
 namespace ARDOUR {
 
@@ -22,6 +27,20 @@ system_template_directory ()
        return *i;
 }
 
+sys::path
+system_route_template_directory ()
+{
+       SearchPath spath(system_data_search_path());
+       spath.add_subdirectory_to_paths(route_templates_dir_name);
+
+       // just return the first directory in the search path that exists
+       SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
+
+       if (i == spath.end()) return sys::path();
+
+       return *i;
+}
+
 sys::path
 user_template_directory ()
 {
@@ -31,4 +50,58 @@ user_template_directory ()
        return p;
 }
 
+sys::path
+user_route_template_directory ()
+{
+       sys::path p(user_config_directory());
+       p /= route_templates_dir_name;
+
+       return p;
+}
+
+static bool
+template_filter (const string &str, void *arg)
+{
+       return (str.length() > strlen(temp_suffix) &&
+               str.find (temp_suffix) == (str.length() - strlen (temp_suffix)));
+}
+
+void
+find_route_templates (vector<RouteTemplateInfo>& template_names)
+{
+       vector<string *> *templates;
+       PathScanner scanner;
+       SearchPath spath (system_data_search_path());
+
+       spath += user_config_directory();
+       spath.add_subdirectory_to_paths(route_templates_dir_name);
+
+       templates = scanner (spath.to_string(), template_filter, 0, false, true);
+       
+       if (!templates) {
+               return;
+       }
+       
+       for (vector<string*>::iterator i = templates->begin(); i != templates->end(); ++i) {
+               string fullpath = *(*i);
+
+               XMLTree tree;
+
+               if (!tree.read (fullpath.c_str())) {
+                 continue;
+               }
+
+               XMLNode* root = tree.root();
+               
+               RouteTemplateInfo rti;
+
+               rti.name = IO::name_from_state (*root->children().front());
+               rti.path = fullpath;
+
+               template_names.push_back (rti);
+       }
+
+       free (templates);
+}
+
 } // namespace ARDOUR