Write MIDI files to interchange/sessionname/midifiles (for real this time).
authorDavid Robillard <d@drobilla.net>
Thu, 7 Jun 2007 23:12:04 +0000 (23:12 +0000)
committerDavid Robillard <d@drobilla.net>
Thu, 7 Jun 2007 23:12:04 +0000 (23:12 +0000)
git-svn-id: svn://localhost/ardour2/trunk@1979 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/directory_names.h
libs/ardour/ardour/session.h
libs/ardour/ardour/session_directory.h
libs/ardour/directory_names.cc
libs/ardour/session.cc
libs/ardour/session_directory.cc
libs/ardour/session_state.cc
libs/ardour/smf_source.cc

index 8fdec60e9c833f78324d71f7aa266db34fefe3b0..25f468b15f53c1e672102a61dbd3dec800fa3dfc 100644 (file)
@@ -10,6 +10,7 @@ extern const char* const old_sound_dir_name;
 extern const char* const sound_dir_name;
 extern const char* const midi_dir_name;
 extern const char* const dead_sound_dir_name;
+extern const char* const dead_midi_dir_name;
 extern const char* const interchange_dir_name;
 extern const char* const peak_dir_name;
 extern const char* const export_dir_name;
index 035a2bde1d261e03b5a699e40043b548804bb7d5..84c334f59020cdc9782a79605c58637f591ab88c 100644 (file)
@@ -257,6 +257,7 @@ class Session : public PBD::StatefulDestructible
        sigc::signal<void> DirtyChanged;
 
        std::string sound_dir (bool with_path = true) const;
+       std::string midi_dir (bool with_path = true) const;
        std::string peak_dir () const;
        std::string automation_dir () const;
 
@@ -1554,7 +1555,9 @@ class Session : public PBD::StatefulDestructible
        
        string old_sound_dir (bool with_path = true) const;
        string discover_best_sound_dir (bool destructive = false);
+       string discover_best_midi_dir ();
        int ensure_sound_dir (string, string&);
+       int ensure_midi_dir (string, string&);
        void refresh_disk_space ();
 
        mutable gint _playback_load;
index 7662894042d1a1900a5599f014ccefa9d552ef0a..41667a6807126362e4b481bbaf085b0983406e92 100644 (file)
@@ -73,6 +73,13 @@ public:
         * session.
         */
        const path dead_sound_path () const;
+       
+       /**
+        * @return The absolute path to the directory that midi
+        * files are moved to when they are no longer part of the
+        * session.
+        */
+       const path dead_midi_path () const;
 
        /**
         * @return The absolute path to the directory that audio
index d78d32f740d936d194f25a031df79e16cd5520cd..dfd794a2a9421d12934bbe20ada378ba3992402f 100644 (file)
@@ -9,6 +9,7 @@ const char* const sound_dir_name = X_("audiofiles");
 const char* const midi_dir_name = X_("midifiles");
 const char* const peak_dir_name = X_("peaks");
 const char* const dead_sound_dir_name = X_("dead_sounds");
+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");
index ed1947451be3ac4a52c7b0ba7d97e5ae41813e4b..7ba1e2dfb7f8cccc8a691853719386a6ef75e3ee 100644 (file)
@@ -3135,8 +3135,7 @@ Session::midi_path_from_name (string name)
 
                        spath = (*i).path;
 
-                       // FIXME: different directory from audio?
-                       spath += sound_dir(false) + "/" + legalized;
+                       spath += midi_dir(false) + "/" + legalized;
 
                        snprintf (buf, sizeof(buf), "%s-%u.mid", spath.c_str(), cnt);
 
@@ -3161,8 +3160,7 @@ Session::midi_path_from_name (string name)
 
        string foo = buf;
 
-       // FIXME: different directory than audio?
-       spath = discover_best_sound_dir ();
+       spath = discover_best_midi_dir ();
        spath += '/';
 
        string::size_type pos = foo.find_last_of ('/');
@@ -3179,9 +3177,9 @@ Session::midi_path_from_name (string name)
 boost::shared_ptr<MidiSource>
 Session::create_midi_source_for_session (MidiDiskstream& ds)
 {
-       string spath = midi_path_from_name (ds.name());
+       string mpath = midi_path_from_name (ds.name());
        
-       return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, spath, false, frame_rate()));
+       return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate()));
 }
 
 
index 0b778d85caefd0b878441083a13b5a53fd108a82..99a252ecb502be34d1abc960b1df93240d15b3b2 100644 (file)
@@ -130,6 +130,12 @@ SessionDirectory::dead_sound_path () const
        return path(m_root_path) /= dead_sound_dir_name;
 }
 
+const path
+SessionDirectory::dead_midi_path () const
+{
+       return path(m_root_path) /= dead_midi_dir_name;
+}
+
 const path
 SessionDirectory::export_path () const
 {
@@ -145,6 +151,7 @@ SessionDirectory::sub_directories () const
        tmp_paths.push_back ( midi_path () );
        tmp_paths.push_back ( peak_path () );
        tmp_paths.push_back ( dead_sound_path () );
+       tmp_paths.push_back ( dead_midi_path () );
        tmp_paths.push_back ( export_path () );
 
        return tmp_paths;
index 8d9bb55b59445d1886a436c5a7520fc968473309..793093cf7055476bc4755ff0be0d164ff6c565d9 100644 (file)
@@ -1707,6 +1707,44 @@ Session::ensure_sound_dir (string path, string& result)
        return 0;
 }      
 
+int
+Session::ensure_midi_dir (string path, string& result)
+{
+       string dead;
+
+       /* Ensure that the parent directory exists */
+       
+       if (g_mkdir_with_parents (path.c_str(), 0775)) {
+               error << string_compose(_("cannot create session directory \"%1\"; ignored"), path) << endmsg;
+               return -1;
+       }
+       
+       /* Ensure that the sounds directory exists */
+       
+       result = path;
+       result += '/';
+       result += midi_dir_name;
+       
+       if (g_mkdir_with_parents (result.c_str(), 0775)) {
+               error << string_compose(_("cannot create sounds directory \"%1\"; ignored"), result) << endmsg;
+               return -1;
+       }
+
+       dead = path;
+       dead += '/';
+       dead += dead_midi_dir_name;
+       
+       if (g_mkdir_with_parents (dead.c_str(), 0775)) {
+               error << string_compose(_("cannot create dead sounds directory \"%1\"; ignored"), dead) << endmsg;
+               return -1;
+       }
+
+       /* callers expect this to be terminated ... */
+                       
+       result += '/';
+       return 0;
+}      
+
 string
 Session::discover_best_sound_dir (bool destructive)
 {
@@ -1815,6 +1853,114 @@ Session::discover_best_sound_dir (bool destructive)
        return result;
 }
 
+string
+Session::discover_best_midi_dir ()
+{
+       vector<space_and_path>::iterator i;
+       string result;
+
+       /* handle common case without system calls */
+
+       if (session_dirs.size() == 1) {
+               return midi_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
+       get maximum performance benefits from splitting
+       the files across multiple disks.
+
+       However, in situations without much diskspace, an
+       RR approach may end up filling up a filesystem
+       with new files while others still have space.
+       Its therefore important to pay some attention to
+       the freespace in the filesystem holding each
+       directory as well. However, if we did that by
+       itself, we'd keep creating new files in the file
+       system with the most space until it was as full
+       as all others, thus negating any performance
+       benefits of this RAID-1 like approach.
+
+       So, we use a user-configurable space threshold. If
+       there are at least 2 filesystems with more than this
+       much space available, we use RR selection between them. 
+       If not, then we pick the filesystem with the most space.
+
+       This gets a good balance between the two
+       approaches.  
+       */
+       
+       refresh_disk_space ();
+       
+       int free_enough = 0;
+
+       for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+               if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
+                       free_enough++;
+               }
+       }
+
+       if (free_enough >= 2) {
+
+               bool found_it = false;
+
+               /* use RR selection process, ensuring that the one
+                  picked works OK.
+               */
+
+               i = last_rr_session_dir;
+
+               do {
+                       if (++i == session_dirs.end()) {
+                               i = session_dirs.begin();
+                       }
+
+                       if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
+                               if (ensure_midi_dir ((*i).path, result) == 0) {
+                                       last_rr_session_dir = i;
+                                       found_it = true;
+                                       break;
+                               }
+                       }
+
+               } while (i != last_rr_session_dir);
+
+               if (!found_it) {
+                       result = midi_dir();
+               }
+
+       } else {
+
+               /* pick FS with the most freespace (and that
+                  seems to actually work ...)
+               */
+               
+               vector<space_and_path> sorted;
+               space_and_path_ascending_cmp cmp;
+
+               sorted = session_dirs;
+               sort (sorted.begin(), sorted.end(), cmp);
+               
+               for (i = sorted.begin(); i != sorted.end(); ++i) {
+                       if (ensure_midi_dir ((*i).path, result) == 0) {
+                               last_rr_session_dir = i;
+                               break;
+                       }
+               }
+               
+               /* if the above fails, fall back to the most simplistic solution */
+               
+               if (i == sorted.end()) {
+                       return midi_dir();
+               } 
+       }
+
+       return result;
+}
+
 int
 Session::load_playlists (const XMLNode& node)
 {
@@ -1974,6 +2120,33 @@ Session::sound_dir (bool with_path) const
        return res;
 }
 
+string
+Session::midi_dir (bool with_path) const
+{
+       string res;
+       string full;
+
+       if (with_path) {
+               res = _path;
+       } else {
+               full = _path;
+       }
+
+       res += interchange_dir_name;
+       res += '/';
+       res += legalize_for_path (_name);
+       res += '/';
+       res += midi_dir_name;
+
+       if (with_path) {
+               full = res;
+       } else {
+               full += res;
+       }
+       
+       return res;
+}
+
 string
 Session::peak_dir () const
 {
@@ -2518,6 +2691,8 @@ struct RegionCounter {
 int
 Session::cleanup_sources (Session::cleanup_report& rep)
 {
+       // FIXME: needs adaptation to midi
+       
        vector<boost::shared_ptr<Source> > dead_sources;
        vector<boost::shared_ptr<Playlist> > playlists_tbd;
        PathScanner scanner;
@@ -2777,6 +2952,8 @@ Session::cleanup_sources (Session::cleanup_report& rep)
 int
 Session::cleanup_trash_sources (Session::cleanup_report& rep)
 {
+       // FIXME: needs adaptation for MIDI
+       
        vector<space_and_path>::iterator i;
        string dead_sound_dir;
        struct dirent* dentry;
index 9ecb961f19550c22aebb466df9e21ef91c6a680e..11b62e488fb362ed12cbaf33f6810afddfbc2a45 100644 (file)
@@ -795,7 +795,7 @@ SMFSource::load_model(bool lock)
                time += ev.time;
                ev.time = time;
                if (ret > 0) { // didn't skip (meta) event
-                       cerr << "ADDING EVENT TO MODEL: " << ev.time << endl;
+                       //cerr << "ADDING EVENT TO MODEL: " << ev.time << endl;
                        _model->append(ev);
                }
        }