summaryrefslogtreecommitdiff
path: root/libs/ardour/smf_source.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/smf_source.cc')
-rw-r--r--libs/ardour/smf_source.cc406
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;
+}
+