Move panner bypass state up to the PannerShell so that it is preserved even when...
[ardour2.git] / libs / ardour / session_playlists.cc
bloba5772c23e3b2b8f431bb65c17be218ea47a64b7e
1 /*
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.
19 #include <vector>
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"
30 #include "i18n.h"
32 using namespace std;
33 using namespace PBD;
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;
43 tmp = i;
44 ++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 ();
50 i = tmp;
53 DEBUG_TRACE (DEBUG::Destruction, "delete unused playlists\n");
54 for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ) {
55 List::iterator tmp;
57 tmp = i;
58 ++tmp;
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 ();
64 i = tmp;
67 playlists.clear ();
68 unused_playlists.clear ();
71 bool
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();
78 if (!existing) {
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))
86 return existing;
89 void
90 SessionPlaylists::remove_weak (boost::weak_ptr<Playlist> playlist)
92 boost::shared_ptr<Playlist> p = playlist.lock ();
93 if (p) {
94 remove (p);
98 void
99 SessionPlaylists::remove (boost::shared_ptr<Playlist> playlist)
101 Glib::Mutex::Lock lm (lock);
103 List::iterator i;
105 i = find (playlists.begin(), playlists.end(), playlist);
106 if (i != playlists.end()) {
107 playlists.erase (i);
110 i = find (unused_playlists.begin(), unused_playlists.end(), playlist);
111 if (i != unused_playlists.end()) {
112 unused_playlists.erase (i);
117 void
118 SessionPlaylists::track (bool inuse, boost::weak_ptr<Playlist> wpl)
120 boost::shared_ptr<Playlist> pl(wpl.lock());
122 if (!pl) {
123 return;
126 List::iterator x;
128 if (pl->hidden()) {
129 /* its not supposed to be visible */
130 return;
134 Glib::Mutex::Lock lm (lock);
136 if (!inuse) {
138 unused_playlists.insert (pl);
140 if ((x = playlists.find (pl)) != playlists.end()) {
141 playlists.erase (x);
145 } else {
147 playlists.insert (pl);
149 if ((x = unused_playlists.find (pl)) != unused_playlists.end()) {
150 unused_playlists.erase (x);
156 uint32_t
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) {
170 return* i;
174 for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
175 if ((*i)->name() == name) {
176 return* i;
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) {
190 return* i;
194 for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
195 if ((*i)->id() == id) {
196 return* i;
200 return boost::shared_ptr<Playlist>();
203 void
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")) {
210 list.push_back (*i);
214 for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
215 if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
216 list.push_back (*i);
221 void
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) {
227 s.push_back (*i);
230 for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
231 s.push_back (*i);
235 void
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);
250 void
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 */
258 uint32_t
259 SessionPlaylists::source_use_count (boost::shared_ptr<const Source> src) const
261 uint32_t count = 0;
263 for (List::const_iterator p = playlists.begin(); p != playlists.end(); ++p) {
264 if ((*p)->uses_source (src)) {
265 ++count;
266 break;
269 return count;
272 void
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 ();
282 void
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 ();
294 void
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()) {
300 if (full_state) {
301 child->add_child_nocopy ((*i)->get_state());
302 } else {
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()) {
312 if (full_state) {
313 child->add_child_nocopy ((*i)->get_state());
314 } else {
315 child->add_child_nocopy ((*i)->get_template());
322 /** @return true for `stop cleanup', otherwise false */
323 bool
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);
332 switch (status) {
333 case -1:
334 return true;
336 case 0:
337 playlists_tbd.push_back (*x);
338 break;
340 default:
341 /* leave it alone */
342 break;
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 ();
355 return false;
359 SessionPlaylists::load (Session& session, const XMLNode& node)
361 XMLNodeList nlist;
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;
374 return 0;
378 SessionPlaylists::load_unused (Session& session, const XMLNode& node)
380 XMLNodeList nlist;
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;
390 continue;
393 // now manually untrack it
395 track (false, boost::weak_ptr<Playlist> (playlist));
398 return 0;
401 boost::shared_ptr<Playlist>
402 SessionPlaylists::XMLPlaylistFactory (Session& session, const XMLNode& node)
404 try {
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);
422 if (c) {
423 return c;
427 for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
428 c = (*i)->find_crossfade (id);
429 if (c) {
430 return c;
434 return boost::shared_ptr<Crossfade> ();
437 uint32_t
438 SessionPlaylists::region_use_count (boost::shared_ptr<Region> region) const
440 Glib::Mutex::Lock lm (lock);
441 uint32_t cnt = 0;
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);
451 return cnt;