2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "pbd/xml++.h"
22 #include "pbd/compose.h"
23 #include "ardour/debug.h"
24 #include "ardour/session_playlists.h"
25 #include "ardour/playlist.h"
26 #include "ardour/region.h"
27 #include "ardour/playlist_factory.h"
28 #include "ardour/session.h"
29 #include "ardour/source.h"
34 using namespace ARDOUR
;
36 SessionPlaylists::~SessionPlaylists ()
38 DEBUG_TRACE (DEBUG::Destruction
, "delete playlists\n");
40 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ) {
41 SessionPlaylists::List::iterator tmp
;
46 DEBUG_TRACE(DEBUG::Destruction
, string_compose ("Dropping for used playlist %1 ; pre-ref = %2\n", (*i
)->name(), (*i
).use_count()));
47 boost::shared_ptr
<Playlist
> keeper (*i
);
48 (*i
)->drop_references ();
53 DEBUG_TRACE (DEBUG::Destruction
, "delete unused playlists\n");
54 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ) {
60 DEBUG_TRACE(DEBUG::Destruction
, string_compose ("Dropping for unused playlist %1 ; pre-ref = %2\n", (*i
)->name(), (*i
).use_count()));
61 boost::shared_ptr
<Playlist
> keeper (*i
);
62 (*i
)->drop_references ();
68 unused_playlists
.clear ();
72 SessionPlaylists::add (boost::shared_ptr
<Playlist
> playlist
)
74 Glib::Mutex::Lock
lm (lock
);
76 bool const existing
= find (playlists
.begin(), playlists
.end(), playlist
) != playlists
.end();
79 playlists
.insert (playlists
.begin(), playlist
);
80 playlist
->InUse
.connect_same_thread (*this, boost::bind (&SessionPlaylists::track
, this, _1
, boost::weak_ptr
<Playlist
>(playlist
)));
81 playlist
->DropReferences
.connect_same_thread (
82 *this, boost::bind (&SessionPlaylists::remove_weak
, this, boost::weak_ptr
<Playlist
> (playlist
))
90 SessionPlaylists::remove_weak (boost::weak_ptr
<Playlist
> playlist
)
92 boost::shared_ptr
<Playlist
> p
= playlist
.lock ();
99 SessionPlaylists::remove (boost::shared_ptr
<Playlist
> playlist
)
101 Glib::Mutex::Lock
lm (lock
);
105 i
= find (playlists
.begin(), playlists
.end(), playlist
);
106 if (i
!= playlists
.end()) {
110 i
= find (unused_playlists
.begin(), unused_playlists
.end(), playlist
);
111 if (i
!= unused_playlists
.end()) {
112 unused_playlists
.erase (i
);
118 SessionPlaylists::track (bool inuse
, boost::weak_ptr
<Playlist
> wpl
)
120 boost::shared_ptr
<Playlist
> pl(wpl
.lock());
129 /* its not supposed to be visible */
134 Glib::Mutex::Lock
lm (lock
);
138 unused_playlists
.insert (pl
);
140 if ((x
= playlists
.find (pl
)) != playlists
.end()) {
147 playlists
.insert (pl
);
149 if ((x
= unused_playlists
.find (pl
)) != unused_playlists
.end()) {
150 unused_playlists
.erase (x
);
157 SessionPlaylists::n_playlists () const
159 Glib::Mutex::Lock
lm (lock
);
160 return playlists
.size();
163 boost::shared_ptr
<Playlist
>
164 SessionPlaylists::by_name (string name
)
166 Glib::Mutex::Lock
lm (lock
);
168 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
169 if ((*i
)->name() == name
) {
174 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
175 if ((*i
)->name() == name
) {
180 return boost::shared_ptr
<Playlist
>();
183 boost::shared_ptr
<Playlist
>
184 SessionPlaylists::by_id (const PBD::ID
& id
)
186 Glib::Mutex::Lock
lm (lock
);
188 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
189 if ((*i
)->id() == id
) {
194 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
195 if ((*i
)->id() == id
) {
200 return boost::shared_ptr
<Playlist
>();
204 SessionPlaylists::unassigned (std::list
<boost::shared_ptr
<Playlist
> > & list
)
206 Glib::Mutex::Lock
lm (lock
);
208 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
209 if (!(*i
)->get_orig_diskstream_id().to_s().compare ("0")) {
214 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
215 if (!(*i
)->get_orig_diskstream_id().to_s().compare ("0")) {
222 SessionPlaylists::get (vector
<boost::shared_ptr
<Playlist
> >& s
)
224 Glib::Mutex::Lock
lm (lock
);
226 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
230 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
236 SessionPlaylists::destroy_region (boost::shared_ptr
<Region
> r
)
238 Glib::Mutex::Lock
lm (lock
);
240 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
241 (*i
)->destroy_region (r
);
244 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
245 (*i
)->destroy_region (r
);
251 SessionPlaylists::find_equivalent_playlist_regions (boost::shared_ptr
<Region
> region
, vector
<boost::shared_ptr
<Region
> >& result
)
253 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
)
254 (*i
)->get_region_list_equivalent_regions (region
, result
);
257 /** Return the number of playlists (not regions) that contain @a src */
259 SessionPlaylists::source_use_count (boost::shared_ptr
<const Source
> src
) const
263 for (List::const_iterator p
= playlists
.begin(); p
!= playlists
.end(); ++p
) {
264 if ((*p
)->uses_source (src
)) {
273 SessionPlaylists::sync_all_regions_with_regions ()
275 Glib::Mutex::Lock
lm (lock
);
277 for (List::const_iterator p
= playlists
.begin(); p
!= playlists
.end(); ++p
) {
278 (*p
)->sync_all_regions_with_regions ();
283 SessionPlaylists::update_after_tempo_map_change ()
285 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
286 (*i
)->update_after_tempo_map_change ();
289 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
290 (*i
)->update_after_tempo_map_change ();
295 SessionPlaylists::add_state (XMLNode
* node
, bool full_state
)
297 XMLNode
* child
= node
->add_child ("Playlists");
298 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
299 if (!(*i
)->hidden()) {
301 child
->add_child_nocopy ((*i
)->get_state());
303 child
->add_child_nocopy ((*i
)->get_template());
308 child
= node
->add_child ("UnusedPlaylists");
309 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
310 if (!(*i
)->hidden()) {
311 if (!(*i
)->empty()) {
313 child
->add_child_nocopy ((*i
)->get_state());
315 child
->add_child_nocopy ((*i
)->get_template());
322 /** @return true for `stop cleanup', otherwise false */
324 SessionPlaylists::maybe_delete_unused (boost::function
<int(boost::shared_ptr
<Playlist
>)> ask
)
326 vector
<boost::shared_ptr
<Playlist
> > playlists_tbd
;
328 for (List::iterator x
= unused_playlists
.begin(); x
!= unused_playlists
.end(); ++x
) {
330 int status
= ask (*x
);
337 playlists_tbd
.push_back (*x
);
346 /* now delete any that were marked for deletion */
348 for (vector
<boost::shared_ptr
<Playlist
> >::iterator x
= playlists_tbd
.begin(); x
!= playlists_tbd
.end(); ++x
) {
349 boost::shared_ptr
<Playlist
> keeper (*x
);
350 (*x
)->drop_references ();
353 playlists_tbd
.clear ();
359 SessionPlaylists::load (Session
& session
, const XMLNode
& node
)
362 XMLNodeConstIterator niter
;
363 boost::shared_ptr
<Playlist
> playlist
;
365 nlist
= node
.children();
367 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
369 if ((playlist
= XMLPlaylistFactory (session
, **niter
)) == 0) {
370 error
<< _("Session: cannot create Playlist from XML description.") << endmsg
;
378 SessionPlaylists::load_unused (Session
& session
, const XMLNode
& node
)
381 XMLNodeConstIterator niter
;
382 boost::shared_ptr
<Playlist
> playlist
;
384 nlist
= node
.children();
386 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
388 if ((playlist
= XMLPlaylistFactory (session
, **niter
)) == 0) {
389 error
<< _("Session: cannot create Playlist from XML description.") << endmsg
;
393 // now manually untrack it
395 track (false, boost::weak_ptr
<Playlist
> (playlist
));
401 boost::shared_ptr
<Playlist
>
402 SessionPlaylists::XMLPlaylistFactory (Session
& session
, const XMLNode
& node
)
405 return PlaylistFactory::create (session
, node
);
408 catch (failed_constructor
& err
) {
409 return boost::shared_ptr
<Playlist
>();
413 boost::shared_ptr
<Crossfade
>
414 SessionPlaylists::find_crossfade (const PBD::ID
& id
)
416 Glib::Mutex::Lock
lm (lock
);
418 boost::shared_ptr
<Crossfade
> c
;
420 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
421 c
= (*i
)->find_crossfade (id
);
427 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
428 c
= (*i
)->find_crossfade (id
);
434 return boost::shared_ptr
<Crossfade
> ();
438 SessionPlaylists::region_use_count (boost::shared_ptr
<Region
> region
) const
440 Glib::Mutex::Lock
lm (lock
);
443 for (List::iterator i
= playlists
.begin(); i
!= playlists
.end(); ++i
) {
444 cnt
+= (*i
)->region_use_count (region
);
447 for (List::iterator i
= unused_playlists
.begin(); i
!= unused_playlists
.end(); ++i
) {
448 cnt
+= (*i
)->region_use_count (region
);