X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Fsource.cc;h=ee32e508e2c46b4853f242c14527ce8bb51c5e5b;hb=e845b9f9357c4ff471c02b1f63a61275bb4a7d28;hp=0d32ea4a216ec6134dbb93281819747bd24ec8c5;hpb=b5db1f624d347c8865c27fdae23bf4595be372d2;p=ardour.git diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index 0d32ea4a21..ee32e508e2 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000 Paul Davis 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 @@ -15,13 +15,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include #include -#include -#include #include #include #include @@ -29,39 +26,68 @@ #include #include -#include -#include -#include +#include "pbd/gstdio_compat.h" +#include +#include +#include +#include "pbd/xml++.h" +#include "pbd/pthread_utils.h" +#include "pbd/enumwriter.h" -#include +#include "ardour/debug.h" +#include "ardour/profile.h" +#include "ardour/session.h" +#include "ardour/source.h" +#include "ardour/transient_detector.h" #include "i18n.h" -using std::min; -using std::max; - +using namespace std; using namespace ARDOUR; +using namespace PBD; -Source::Source (string name) +Source::Source (Session& s, DataType type, const string& name, Flag flags) + : SessionObject(s, name) + , _type(type) + , _flags(flags) + , _timeline_position(0) + , _use_count (0) + , _level (0) { - _name = name; - _id = ARDOUR::new_id(); - _use_cnt = 0; + _analysed = false; _timestamp = 0; + fix_writable_flags (); } -Source::Source (const XMLNode& node) +Source::Source (Session& s, const XMLNode& node) + : SessionObject(s, "unnamed source") + , _type(DataType::AUDIO) + , _flags (Flag (Writable|CanRename)) + , _timeline_position(0) + , _use_count (0) + , _level (0) { - _use_cnt = 0; _timestamp = 0; + _analysed = false; - if (set_state (node)) { + if (set_state (node, Stateful::loading_state_version) || _type == DataType::NIL) { throw failed_constructor(); } + + fix_writable_flags (); } Source::~Source () { + DEBUG_TRACE (DEBUG::Destruction, string_compose ("Source %1 destructor %2\n", _name, this)); +} + +void +Source::fix_writable_flags () +{ + if (!_session.writable()) { + _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); + } } XMLNode& @@ -70,8 +96,10 @@ Source::get_state () XMLNode *node = new XMLNode ("Source"); char buf[64]; - node->add_property ("name", _name); - snprintf (buf, sizeof(buf)-1, "%" PRIu64, _id); + node->add_property ("name", name()); + node->add_property ("type", _type.to_string()); + node->add_property (X_("flags"), enum_2_string (_flags)); + id().print (buf, sizeof (buf)); node->add_property ("id", buf); if (_timestamp != 0) { @@ -83,38 +111,205 @@ Source::get_state () } int -Source::set_state (const XMLNode& node) +Source::set_state (const XMLNode& node, int version) { - const XMLProperty* prop; + XMLProperty const * prop; if ((prop = node.property ("name")) != 0) { _name = prop->value(); } else { return -1; } - - if ((prop = node.property ("id")) != 0) { - sscanf (prop->value().c_str(), "%" PRIu64, &_id); - } else { + + if (!set_id (node)) { return -1; } + if ((prop = node.property ("type")) != 0) { + _type = DataType(prop->value()); + } + if ((prop = node.property ("timestamp")) != 0) { sscanf (prop->value().c_str(), "%ld", &_timestamp); } + if ((prop = node.property (X_("flags"))) != 0) { + _flags = Flag (string_2_enum (prop->value(), _flags)); + } else { + _flags = Flag (0); + + } + + /* old style, from the period when we had DestructiveFileSource */ + if ((prop = node.property (X_("destructive"))) != 0) { + _flags = Flag (_flags | Destructive); + } + + if (Profile->get_trx() && (_flags & Destructive)) { + error << string_compose (_("%1: this session uses destructive tracks, which are not supported"), PROGRAM_NAME) << endmsg; + return -1; + } + + if (version < 3000) { + /* a source with an XML node must necessarily already exist, + and therefore cannot be removable/writable etc. etc.; 2.X + sometimes marks sources as removable which shouldn't be. + */ + if (!(_flags & Destructive)) { + _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); + } + } + return 0; } +bool +Source::has_been_analysed() const +{ + Glib::Threads::Mutex::Lock lm (_analysis_lock); + return _analysed; +} + +void +Source::set_been_analysed (bool yn) +{ + if (yn) { + if (0 == load_transients (get_transients_path())) { + yn = false; + } + } + if (yn != _analysed) { + Glib::Threads::Mutex::Lock lm (_analysis_lock); + _analysed = yn; + } + AnalysisChanged(); // EMIT SIGNAL +} + +int +Source::load_transients (const string& path) +{ + int rv = 0; + FILE *tf; + if (! (tf = g_fopen (path.c_str (), "rb"))) { + return -1; + } + + transients.clear (); + while (!feof (tf) && !ferror(tf)) { + double val; + if (1 != fscanf (tf, "%lf", &val)) { + rv = -1; + break; + } + + framepos_t frame = (framepos_t) floor (val * _session.frame_rate()); + transients.push_back (frame); + } + + ::fclose (tf); + return rv; +} + +string +Source::get_transients_path () const +{ + vector parts; + string s; + + /* old sessions may not have the analysis directory */ + + _session.ensure_subdirs (); + + s = _session.analysis_dir (); + parts.push_back (s); + + s = id().to_s(); + s += '.'; + s += TransientDetector::operational_identifier(); + parts.push_back (s); + + return Glib::build_filename (parts); +} + +bool +Source::check_for_analysis_data_on_disk () +{ + /* looks to see if the analysis files for this source are on disk. + if so, mark us already analysed. + */ + + string path = get_transients_path (); + bool ok = true; + + if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { + ok = false; + } + + // XXX add other tests here as appropriate + + set_been_analysed (ok); + return ok; +} + +void +Source::mark_for_remove () +{ + // This operation is not allowed for sources for destructive tracks or out-of-session files. + + /* XXX need a way to detect _within_session() condition here - move it from FileSource? + */ + + if ((_flags & Destructive)) { + return; + } + + _flags = Flag (_flags | Removable | RemoveAtDestroy); +} + +void +Source::set_timeline_position (framepos_t pos) +{ + _timeline_position = pos; +} + +void +Source::set_allow_remove_if_empty (bool yn) +{ + if (!writable()) { + return; + } + + if (yn) { + _flags = Flag (_flags | RemovableIfEmpty); + } else { + _flags = Flag (_flags & ~RemovableIfEmpty); + } +} + void -Source::use () +Source::inc_use_count () { - _use_cnt++; + g_atomic_int_inc (&_use_count); } void -Source::release () +Source::dec_use_count () +{ +#ifndef NDEBUG + gint oldval = g_atomic_int_add (&_use_count, -1); + if (oldval <= 0) { + cerr << "Bad use dec for " << name() << endl; + abort (); + } + assert (oldval > 0); +#else + g_atomic_int_add (&_use_count, -1); +#endif +} + +bool +Source::writable () const { - if (_use_cnt) --_use_cnt; + return (_flags & Writable) && _session.writable(); }