Replace missing .mid files with silence

This fixes a crash: missing playlist due to missing .mid,
and retains regions for missing MIDI files.

As opposed to missing Audio, we cannot use a SilentFileSource,
because MIDI files are destructive.

This also adds an API to query missing files that have been replaced
with silence to report them to the user.
This commit is contained in:
Robin Gareus 2020-02-18 01:26:20 +01:00
parent 2ac90f5598
commit 6f205f857b
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
4 changed files with 39 additions and 16 deletions

View File

@ -1161,6 +1161,8 @@ public:
std::list<std::string> unknown_processors () const;
std::list<std::string> missing_filesources (DataType) const;
/** Emitted when a feedback cycle has been detected within Ardour's signal
processing path. Until it is fixed (by the user) some (unspecified)
routes will not be run.

View File

@ -56,6 +56,7 @@ public:
Destructive = 0x80,
Empty = 0x100, /* used for MIDI only */
RF64_RIFF = 0x200,
Missing = 0x400, /* used for MIDI only */
};
typedef Glib::Threads::Mutex::Lock Lock;

View File

@ -103,6 +103,7 @@
#include "ardour/route_graph.h"
#include "ardour/route_group.h"
#include "ardour/rt_tasklist.h"
#include "ardour/silentfilesource.h"
#include "ardour/send.h"
#include "ardour/selection.h"
#include "ardour/session.h"
@ -6338,6 +6339,22 @@ Session::unknown_processors () const
return p;
}
list<string>
Session::missing_filesources (DataType dt) const
{
list<string> p;
for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
if (dt == DataType::AUDIO && 0 != boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
p.push_back (i->second->name());
}
else if (dt == DataType::MIDI && 0 != boost::dynamic_pointer_cast<SMFSource> (i->second) && (i->second->flags() & Source::Missing) != 0) {
p.push_back (i->second->name());
}
}
p.sort ();
return p;
}
void
Session::initialize_latencies ()
{

View File

@ -156,23 +156,24 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
}
} catch (MissingSource& err) {
if (_flags & Source::Empty) {
/* we don't care that the file was not found, because
it was empty. But FileSource::init() will have
failed to set our _path correctly, so we have to do
this ourselves. Use the first entry in the search
path for MIDI files, which is assumed to be the
correct "main" location.
*/
std::vector<string> sdirs = s.source_search_path (DataType::MIDI);
_path = Glib::build_filename (sdirs.front(), _path);
/* This might be important, too */
_file_is_new = true;
} else {
/* pass it on */
throw;
if (0 == (_flags & Source::Empty)) {
/* Don't throw, create the source.
* Since MIDI is writable, we cannot use a SilentFileSource.
*/
_flags = Source::Flag (_flags | Source::Empty | Source::Missing);
}
/* we don't care that the file was not found, because
it was empty. But FileSource::init() will have
failed to set our _path correctly, so we have to do
this ourselves. Use the first entry in the search
path for MIDI files, which is assumed to be the
correct "main" location.
*/
std::vector<string> sdirs = s.source_search_path (DataType::MIDI);
_path = Glib::build_filename (sdirs.front(), _path);
/* This might be important, too */
_file_is_new = true;
}
if (!(_flags & Source::Empty)) {
@ -451,6 +452,7 @@ SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
_last_ev_time_beats = time;
_flags = Source::Flag (_flags & ~Empty);
_flags = Source::Flag (_flags & ~Missing);
}
/** Append an event with a timestamp in samples (samplepos_t) */
@ -501,6 +503,7 @@ SMFSource::append_event_samples (const Glib::Threads::Mutex::Lock& lock,
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
_last_ev_time_samples = ev.time();
_flags = Source::Flag (_flags & ~Empty);
_flags = Source::Flag (_flags & ~Missing);
}
XMLNode&