diff options
Diffstat (limited to 'libs/ardour/smf_source.cc')
-rw-r--r-- | libs/ardour/smf_source.cc | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc new file mode 100644 index 0000000000..10cf7ab335 --- /dev/null +++ b/libs/ardour/smf_source.cc @@ -0,0 +1,406 @@ +/* + Copyright (C) 2006 Paul Davis + Written by Dave Robillard, 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <vector> + +#include <sys/time.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include <pbd/mountpoint.h> +#include <pbd/pathscanner.h> +#include <pbd/stl_delete.h> +#include <pbd/strsplit.h> + +#include <glibmm/miscutils.h> + +#include <ardour/smf_source.h> +#include <ardour/session.h> + +#include "i18n.h" + +using namespace ARDOUR; + +string SMFSource::_search_path; + +/*sigc::signal<void,struct tm*, time_t> SMFSource::HeaderPositionOffsetChanged; +bool SMFSource::header_position_negative; +uint64_t SMFSource::header_position_offset; +*/ + +SMFSource::SMFSource (std::string path, Flag flags) + : MidiSource (path), _flags (flags) +{ + /* constructor used for new internal-to-session files. file cannot exist */ + + if (init (path, false)) { + throw failed_constructor (); + } +} + +SMFSource::SMFSource (const XMLNode& node) + : MidiSource (node), _flags (Flag (Writable|CanRename)) +{ + /* constructor used for existing internal-to-session files. file must exist */ + + if (set_state (node)) { + throw failed_constructor (); + } + + if (init (_name, true)) { + throw failed_constructor (); + } +} + +SMFSource::~SMFSource () +{ + if (removable()) { + unlink (_path.c_str()); + } +} + +bool +SMFSource::removable () const +{ + return (_flags & Removable) && ((_flags & RemoveAtDestroy) || + ((_flags & RemovableIfEmpty) && is_empty (_path))); +} + +int +SMFSource::init (string pathstr, bool must_exist) +{ + bool is_new = false; + + _length = 0; + + if (!find (pathstr, must_exist, is_new)) { + cerr << "cannot find " << pathstr << " with me = " << must_exist << endl; + return -1; + } + + if (is_new && must_exist) { + return -1; + } + + return 0; +} + + +XMLNode& +SMFSource::get_state () +{ + XMLNode& root (MidiSource::get_state()); + char buf[16]; + snprintf (buf, sizeof (buf), "0x%x", (int)_flags); + root.add_property ("flags", buf); + return root; +} + +int +SMFSource::set_state (const XMLNode& node) +{ + const XMLProperty* prop; + + if (MidiSource::set_state (node)) { + return -1; + } + + if ((prop = node.property (X_("flags"))) != 0) { + + int ival; + sscanf (prop->value().c_str(), "0x%x", &ival); + _flags = Flag (ival); + + } else { + + _flags = Flag (0); + + } + + return 0; +} + +void +SMFSource::mark_for_remove () +{ + if (!writable()) { + return; + } + _flags = Flag (_flags | RemoveAtDestroy); +} + +void +SMFSource::mark_streaming_write_completed () +{ + if (!writable()) { + return; + } +#if 0 + Glib::Mutex::Lock lm (_lock); + + + next_peak_clear_should_notify = true; + + if (_peaks_built || pending_peak_builds.empty()) { + _peaks_built = true; + PeaksReady (); /* EMIT SIGNAL */ + } +#endif +} + +void +SMFSource::mark_take (string id) +{ + if (writable()) { + _take_id = id; + } +} + +int +SMFSource::move_to_trash (const string trash_dir_name) +{ + string newpath; + + if (!writable()) { + return -1; + } + + /* don't move the file across filesystems, just + stick it in the `trash_dir_name' directory + on whichever filesystem it was already on. + */ + + newpath = Glib::path_get_dirname (_path); + newpath = Glib::path_get_dirname (newpath); + + newpath += '/'; + newpath += trash_dir_name; + newpath += '/'; + newpath += Glib::path_get_basename (_path); + + if (access (newpath.c_str(), F_OK) == 0) { + + /* the new path already exists, try versioning */ + + char buf[PATH_MAX+1]; + int version = 1; + string newpath_v; + + snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version); + newpath_v = buf; + + while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) { + snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version); + newpath_v = buf; + } + + if (version == 999) { + PBD::error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"), + newpath) + << endmsg; + } else { + newpath = newpath_v; + } + + } else { + + /* it doesn't exist, or we can't read it or something */ + + } + + if (::rename (_path.c_str(), newpath.c_str()) != 0) { + PBD::error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"), + _path, newpath, strerror (errno)) + << endmsg; + return -1; + } +#if 0 + if (::unlink (peakpath.c_str()) != 0) { + PBD::error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), + peakpath, _path, strerror (errno)) + << endmsg; + /* try to back out */ + rename (newpath.c_str(), _path.c_str()); + return -1; + } + + _path = newpath; + peakpath = ""; +#endif + /* file can not be removed twice, since the operation is not idempotent */ + + _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty)); + + return 0; +} + +// FIXME: Merge this with audiofilesource somehow (make a generic filesource?) +bool +SMFSource::find (string pathstr, bool must_exist, bool& isnew) +{ + string::size_type pos; + bool ret = false; + + isnew = false; + + /* clean up PATH:CHANNEL notation so that we are looking for the correct path */ + + if ((pos = pathstr.find_last_of (':')) == string::npos) { + pathstr = pathstr; + } else { + pathstr = pathstr.substr (0, pos); + } + + if (pathstr[0] != '/') { + + /* non-absolute pathname: find pathstr in search path */ + + vector<string> dirs; + int cnt; + string fullpath; + string keeppath; + + if (_search_path.length() == 0) { + PBD::error << _("FileSource: search path not set") << endmsg; + goto out; + } + + split (_search_path, dirs, ':'); + + cnt = 0; + + for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) { + + fullpath = *i; + if (fullpath[fullpath.length()-1] != '/') { + fullpath += '/'; + } + fullpath += pathstr; + + if (access (fullpath.c_str(), R_OK) == 0) { + keeppath = fullpath; + ++cnt; + } + } + + if (cnt > 1) { + + PBD::error << string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr, _search_path) << endmsg; + goto out; + + } else if (cnt == 0) { + + if (must_exist) { + PBD::error << string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr, _search_path) << endmsg; + goto out; + } else { + isnew = true; + } + } + + _name = pathstr; + _path = keeppath; + ret = true; + + } else { + + /* external files and/or very very old style sessions include full paths */ + + _path = pathstr; + _name = pathstr.substr (pathstr.find_last_of ('/') + 1); + + if (access (_path.c_str(), R_OK) != 0) { + + /* file does not exist or we cannot read it */ + + if (must_exist) { + PBD::error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg; + goto out; + } + + if (errno != ENOENT) { + PBD::error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), _path, strerror (errno)) << endmsg; + goto out; + } + + /* a new file */ + + isnew = true; + ret = true; + + } else { + + /* already exists */ + + ret = true; + } + } + + out: + return ret; +} + +void +SMFSource::set_search_path (string p) +{ + _search_path = p; +} + + +void +SMFSource::set_allow_remove_if_empty (bool yn) +{ + if (writable()) { + _allow_remove_if_empty = yn; + } +} + +int +SMFSource::set_name (string newname, bool destructive) +{ + //Glib::Mutex::Lock lm (_lock); FIXME + string oldpath = _path; + string newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive); + + if (newpath.empty()) { + PBD::error << string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg; + return -1; + } + + if (rename (oldpath.c_str(), newpath.c_str()) != 0) { + PBD::error << string_compose (_("cannot rename audio file for %1 to %2"), _name, newpath) << endmsg; + return -1; + } + + _name = Glib::path_get_basename (newpath); + _path = newpath; + + return 0;//rename_peakfile (peak_path (_path)); +} + +bool +SMFSource::is_empty (string path) +{ + /* XXX fix me */ + + return false; +} + |