13
0

Fix loading playlists of old sessions

Previously when loading Ardour v2, v3-5 sessions, tracks were
created with a dummy name "toBeResetFroXML".

In v6, Track::init() creates a playlist when the track name is
not empty. Later Track::set_state() calls set_name(). When a
playlist exists, the playlist's name is set to match the track's name.

When loading v6 sessions none of this happens. A previously loaded
playlist will be assigned by ID.

Older versions identified Playlists by name and by the time the
playlist is assigned, there may be ambiguities. With the default
(track-name = playlist-name) two playlists with the same name exist:

 (1) the playlist loaded from the session file
 (2) the playlist created by Track::init()

Playlists are stored in an ordered std::set<shared_ptr<Playlist>>,
and name-lookup iterates over the set.

When loading an old session after starting Ardour, it is very
likely to always lookup the playlist (1), because new, later
allocations from (2) are on top of the heap and ordered last.

The session seemingly loads correctly, except for lingering,
unused empty playlists "toBeResetFroXML" renamed to "Track name"
that were never deleted.

However when loading an old session from a running instance,
ordering is mostly random, and many tracks end up with using
the empty playlist (2) instead of the correct playlist (1).
This commit is contained in:
Robin Gareus 2020-03-15 13:31:53 +01:00
parent 213b3cd593
commit 7f862298cf
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 19 additions and 7 deletions

View File

@ -1924,9 +1924,9 @@ Session::XMLRouteFactory_3X (const XMLNode& node, int version)
boost::shared_ptr<Track> track;
if (type == DataType::AUDIO) {
track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
track.reset (new AudioTrack (*this, string())); // name will be reset from XML in ::set_state() below
} else {
track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
track.reset (new MidiTrack (*this, string())); // name will be reset from XML in ::set_state() below
}
if (track->init()) {
@ -1986,9 +1986,9 @@ Session::XMLRouteFactory_2X (const XMLNode& node, int version)
boost::shared_ptr<Track> track;
if (type == DataType::AUDIO) {
track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
track.reset (new AudioTrack (*this, string())); // name will be reset from XML in ::set_state() below
} else {
track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
track.reset (new MidiTrack (*this, string())); // name will be reset from XML in ::set_state() below
}
if (track->init()) {

View File

@ -110,9 +110,9 @@ Track::init ()
if (!name().empty()) {
/* an empty name means that we are being constructed via
serialized state (XML). Don't create a playlist, because one
will be created or discovered during ::set_state().
*/
* serialized state (XML). Don't create a playlist, because one
* will be created or discovered during ::set_state().
*/
use_new_playlist (data_type());
}
@ -419,6 +419,18 @@ Track::set_name (const string& str)
}
}
/* When creating a track during session-load,
* do not change playlist's name, nor try to save the session.
*
* Changing the playlist name from 'toBeResetFroXML' breaks loading
* Ardour v2..5 sessions. Older versions of Arodur identified playlist
* by name, and this causes duplicate names and name conflicts.
* (new track name -> new playlist name != old playlist)
*/
if (_session.loading ()) {
return Route::set_name (str);
}
for (uint32_t n = 0; n < DataType::num_types; ++n) {
if (_playlists[n]) {
_playlists[n]->set_name (str);