add concept of an owner region (by ID) to PlaylistSource
[ardour.git] / libs / ardour / playlist_source.cc
1 /*
2  * Copyright (C) 2011-2012 David Robillard <d@drobilla.net>
3  * Copyright (C) 2011-2017 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2016 Tim Mayberry <mojofunk@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #ifdef WAF_BUILD
22 #include "libardour-config.h"
23 #endif
24
25 #include <vector>
26 #include <cstdio>
27
28 #include <glibmm/fileutils.h>
29 #include <glibmm/miscutils.h>
30
31 #include "pbd/error.h"
32 #include "pbd/types_convert.h"
33 #include "pbd/enumwriter.h"
34
35 #include "ardour/playlist.h"
36 #include "ardour/playlist_source.h"
37 #include "ardour/playlist_factory.h"
38
39 #include "pbd/i18n.h"
40
41 using namespace std;
42 using namespace ARDOUR;
43 using namespace PBD;
44
45 PlaylistSource::PlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<Playlist> p, DataType type,
46                                 sampleoffset_t begin, samplecnt_t len, Source::Flag /*flags*/)
47         : Source (s, type, name)
48         , _playlist (p)
49         , _original (orig)
50         , _owner (0) /* zero is never a legal ID for an object */
51 {
52         /* PlaylistSources are never writable, renameable, removable or destructive */
53         _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
54
55         _playlist = p;
56         _playlist->use ();
57         _playlist_offset = begin;
58         _playlist_length = len;
59
60         _level = _playlist->max_source_level () + 1;
61 }
62
63 PlaylistSource::PlaylistSource (Session& s, const XMLNode& node)
64         : Source (s, DataType::AUDIO, "toBeRenamed")
65 {
66         /* PlaylistSources are never writable, renameable, removable or destructive */
67         _flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy|Destructive));
68
69
70         if (set_state (node, Stateful::loading_state_version)) {
71                 throw failed_constructor ();
72         }
73 }
74
75 PlaylistSource::~PlaylistSource ()
76 {
77         _playlist->release ();
78 }
79
80 void
81 PlaylistSource::set_owner (PBD::ID const &id)
82 {
83         if (_owner == 0) {
84                 _owner = id;
85         }
86 }
87
88 void
89 PlaylistSource::add_state (XMLNode& node)
90 {
91         node.set_property ("playlist", _playlist->id ());
92         node.set_property ("offset", _playlist_offset);
93         node.set_property ("length", _playlist_length);
94         node.set_property ("original", _original);
95
96         if (_owner != 0) {
97                 node.set_property ("owner", _owner);
98         }
99
100         node.add_child_nocopy (_playlist->get_state());
101 }
102
103 int
104 PlaylistSource::set_state (const XMLNode& node, int /*version*/)
105 {
106         /* check that we have a playlist ID */
107
108         XMLProperty const * prop = node.property (X_("playlist"));
109
110         if (!prop) {
111                 error << _("No playlist ID in PlaylistSource XML!") << endmsg;
112                 throw failed_constructor ();
113         }
114
115         /* create playlist from child node */
116
117         XMLNodeList nlist;
118         XMLNodeConstIterator niter;
119
120         nlist = node.children();
121
122         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
123                 if ((*niter)->name() == "Playlist") {
124                         _playlist = PlaylistFactory::create (_session, **niter, true, false);
125                         break;
126                 }
127         }
128
129         if (!_playlist) {
130                 error << _("Could not construct playlist for PlaylistSource from session data!") << endmsg;
131                 throw failed_constructor ();
132         }
133
134         /* other properties */
135
136         std::string name;
137         if (!node.get_property (X_("name"), name)) {
138                 throw failed_constructor ();
139         }
140
141         set_name (name);
142
143         if (!node.get_property (X_("offset"), _playlist_offset)) {
144                 throw failed_constructor ();
145         }
146
147         if (!node.get_property (X_("length"), _playlist_length)) {
148                 throw failed_constructor ();
149         }
150
151         if (!node.get_property (X_("original"), _original)) {
152                 throw failed_constructor ();
153         }
154
155         /* this is allowed to fail. It either means an older session file
156            format, or a PlaylistSource that wasn't created for a combined
157            region (whose ID would be stored in _owner).
158         */
159         node.get_property (X_("owner"), _owner);
160
161         _level = _playlist->max_source_level () + 1;
162
163         return 0;
164 }