ardour
session_playlists.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18 */
19 #include <vector>
20 
21 #include "ardour/debug.h"
22 #include "ardour/playlist.h"
25 #include "ardour/track.h"
26 #include "i18n.h"
27 #include "pbd/compose.h"
28 #include "pbd/xml++.h"
29 
30 using namespace std;
31 using namespace PBD;
32 using namespace ARDOUR;
33 
34 SessionPlaylists::~SessionPlaylists ()
35 {
36  DEBUG_TRACE (DEBUG::Destruction, "delete playlists\n");
37 
38  for (List::iterator i = playlists.begin(); i != playlists.end(); ) {
39  SessionPlaylists::List::iterator tmp;
40 
41  tmp = i;
42  ++tmp;
43 
44  DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for used playlist %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
45  boost::shared_ptr<Playlist> keeper (*i);
46  (*i)->drop_references ();
47 
48  i = tmp;
49  }
50 
51  DEBUG_TRACE (DEBUG::Destruction, "delete unused playlists\n");
52  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ) {
53  List::iterator tmp;
54 
55  tmp = i;
56  ++tmp;
57 
58  DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for unused playlist %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
59  boost::shared_ptr<Playlist> keeper (*i);
60  (*i)->drop_references ();
61 
62  i = tmp;
63  }
64 
65  playlists.clear ();
66  unused_playlists.clear ();
67 }
68 
69 bool
70 SessionPlaylists::add (boost::shared_ptr<Playlist> playlist)
71 {
73 
74  bool const existing = find (playlists.begin(), playlists.end(), playlist) != playlists.end();
75 
76  if (!existing) {
77  playlists.insert (playlists.begin(), playlist);
78  playlist->InUse.connect_same_thread (*this, boost::bind (&SessionPlaylists::track, this, _1, boost::weak_ptr<Playlist>(playlist)));
79  playlist->DropReferences.connect_same_thread (
80  *this, boost::bind (&SessionPlaylists::remove_weak, this, boost::weak_ptr<Playlist> (playlist))
81  );
82  }
83 
84  return existing;
85 }
86 
87 void
88 SessionPlaylists::remove_weak (boost::weak_ptr<Playlist> playlist)
89 {
90  boost::shared_ptr<Playlist> p = playlist.lock ();
91  if (p) {
92  remove (p);
93  }
94 }
95 
96 void
97 SessionPlaylists::remove (boost::shared_ptr<Playlist> playlist)
98 {
100 
101  List::iterator i;
102 
103  i = find (playlists.begin(), playlists.end(), playlist);
104  if (i != playlists.end()) {
105  playlists.erase (i);
106  }
107 
108  i = find (unused_playlists.begin(), unused_playlists.end(), playlist);
109  if (i != unused_playlists.end()) {
110  unused_playlists.erase (i);
111  }
112 }
113 
114 
115 void
116 SessionPlaylists::track (bool inuse, boost::weak_ptr<Playlist> wpl)
117 {
118  boost::shared_ptr<Playlist> pl(wpl.lock());
119 
120  if (!pl) {
121  return;
122  }
123 
124  List::iterator x;
125 
126  if (pl->hidden()) {
127  /* its not supposed to be visible */
128  return;
129  }
130 
131  {
132  Glib::Threads::Mutex::Lock lm (lock);
133 
134  if (!inuse) {
135 
136  unused_playlists.insert (pl);
137 
138  if ((x = playlists.find (pl)) != playlists.end()) {
139  playlists.erase (x);
140  }
141 
142 
143  } else {
144 
145  playlists.insert (pl);
146 
147  if ((x = unused_playlists.find (pl)) != unused_playlists.end()) {
148  unused_playlists.erase (x);
149  }
150  }
151  }
152 }
153 
154 uint32_t
155 SessionPlaylists::n_playlists () const
156 {
157  Glib::Threads::Mutex::Lock lm (lock);
158  return playlists.size();
159 }
160 
162 SessionPlaylists::by_name (string name)
163 {
164  Glib::Threads::Mutex::Lock lm (lock);
165 
166  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
167  if ((*i)->name() == name) {
168  return* i;
169  }
170  }
171 
172  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
173  if ((*i)->name() == name) {
174  return* i;
175  }
176  }
177 
179 }
180 
182 SessionPlaylists::by_id (const PBD::ID& id)
183 {
184  Glib::Threads::Mutex::Lock lm (lock);
185 
186  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
187  if ((*i)->id() == id) {
188  return* i;
189  }
190  }
191 
192  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
193  if ((*i)->id() == id) {
194  return* i;
195  }
196  }
197 
199 }
200 
201 void
202 SessionPlaylists::unassigned (std::list<boost::shared_ptr<Playlist> > & list)
203 {
204  Glib::Threads::Mutex::Lock lm (lock);
205 
206  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
207  if (!(*i)->get_orig_track_id().to_s().compare ("0")) {
208  list.push_back (*i);
209  }
210  }
211 
212  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
213  if (!(*i)->get_orig_track_id().to_s().compare ("0")) {
214  list.push_back (*i);
215  }
216  }
217 }
218 
219 void
220 SessionPlaylists::get (vector<boost::shared_ptr<Playlist> >& s) const
221 {
222  Glib::Threads::Mutex::Lock lm (lock);
223 
224  for (List::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
225  s.push_back (*i);
226  }
227 
228  for (List::const_iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
229  s.push_back (*i);
230  }
231 }
232 
233 void
234 SessionPlaylists::destroy_region (boost::shared_ptr<Region> r)
235 {
236  Glib::Threads::Mutex::Lock lm (lock);
237 
238  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
239  (*i)->destroy_region (r);
240  }
241 
242  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
243  (*i)->destroy_region (r);
244  }
245 }
246 
247 
248 void
249 SessionPlaylists::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vector<boost::shared_ptr<Region> >& result)
250 {
251  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i)
252  (*i)->get_region_list_equivalent_regions (region, result);
253 }
254 
258 uint32_t
259 SessionPlaylists::source_use_count (boost::shared_ptr<const Source> src) const
260 {
261  uint32_t count = 0;
262 
263  for (List::const_iterator p = playlists.begin(); p != playlists.end(); ++p) {
264  if ((*p)->uses_source (src)) {
265  ++count;
266  break;
267  }
268  }
269 
270  for (List::const_iterator p = unused_playlists.begin(); p != unused_playlists.end(); ++p) {
271  if ((*p)->uses_source (src)) {
272  ++count;
273  break;
274  }
275  }
276 
277  return count;
278 }
279 
280 void
281 SessionPlaylists::sync_all_regions_with_regions ()
282 {
283  Glib::Threads::Mutex::Lock lm (lock);
284 
285  for (List::const_iterator p = playlists.begin(); p != playlists.end(); ++p) {
286  (*p)->sync_all_regions_with_regions ();
287  }
288 }
289 
290 void
291 SessionPlaylists::update_after_tempo_map_change ()
292 {
293  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
294  (*i)->update_after_tempo_map_change ();
295  }
296 
297  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
298  (*i)->update_after_tempo_map_change ();
299  }
300 }
301 
302 void
303 SessionPlaylists::add_state (XMLNode* node, bool full_state)
304 {
305  XMLNode* child = node->add_child ("Playlists");
306  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
307  if (!(*i)->hidden()) {
308  if (full_state) {
309  child->add_child_nocopy ((*i)->get_state());
310  } else {
311  child->add_child_nocopy ((*i)->get_template());
312  }
313  }
314  }
315 
316  child = node->add_child ("UnusedPlaylists");
317  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
318  if (!(*i)->hidden()) {
319  if (!(*i)->empty()) {
320  if (full_state) {
321  child->add_child_nocopy ((*i)->get_state());
322  } else {
323  child->add_child_nocopy ((*i)->get_template());
324  }
325  }
326  }
327  }
328 }
329 
331 bool
332 SessionPlaylists::maybe_delete_unused (boost::function<int(boost::shared_ptr<Playlist>)> ask)
333 {
334  vector<boost::shared_ptr<Playlist> > playlists_tbd;
335 
336  for (List::iterator x = unused_playlists.begin(); x != unused_playlists.end(); ++x) {
337 
338  int status = ask (*x);
339 
340  switch (status) {
341  case -1:
342  return true;
343 
344  case 0:
345  playlists_tbd.push_back (*x);
346  break;
347 
348  default:
349  /* leave it alone */
350  break;
351  }
352  }
353 
354  /* now delete any that were marked for deletion */
355 
356  for (vector<boost::shared_ptr<Playlist> >::iterator x = playlists_tbd.begin(); x != playlists_tbd.end(); ++x) {
357  boost::shared_ptr<Playlist> keeper (*x);
358  (*x)->drop_references ();
359  }
360 
361  playlists_tbd.clear ();
362 
363  return false;
364 }
365 
366 int
367 SessionPlaylists::load (Session& session, const XMLNode& node)
368 {
369  XMLNodeList nlist;
370  XMLNodeConstIterator niter;
372 
373  nlist = node.children();
374 
375  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
376 
377  if ((playlist = XMLPlaylistFactory (session, **niter)) == 0) {
378  error << _("Session: cannot create Playlist from XML description.") << endmsg;
379  }
380  }
381 
382  return 0;
383 }
384 
385 int
386 SessionPlaylists::load_unused (Session& session, const XMLNode& node)
387 {
388  XMLNodeList nlist;
389  XMLNodeConstIterator niter;
391 
392  nlist = node.children();
393 
394  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
395 
396  if ((playlist = XMLPlaylistFactory (session, **niter)) == 0) {
397  error << _("Session: cannot create Playlist from XML description.") << endmsg;
398  continue;
399  }
400 
401  // now manually untrack it
402 
403  track (false, boost::weak_ptr<Playlist> (playlist));
404  }
405 
406  return 0;
407 }
408 
410 SessionPlaylists::XMLPlaylistFactory (Session& session, const XMLNode& node)
411 {
412  try {
413  return PlaylistFactory::create (session, node);
414  }
415 
416  catch (failed_constructor& err) {
418  }
419 }
420 
422 SessionPlaylists::find_crossfade (const PBD::ID& id)
423 {
424  Glib::Threads::Mutex::Lock lm (lock);
425 
427 
428  for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) {
429  c = (*i)->find_crossfade (id);
430  if (c) {
431  return c;
432  }
433  }
434 
435  for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
436  c = (*i)->find_crossfade (id);
437  if (c) {
438  return c;
439  }
440  }
441 
443 }
444 
445 uint32_t
446 SessionPlaylists::region_use_count (boost::shared_ptr<Region> region) const
447 {
448  Glib::Threads::Mutex::Lock lm (lock);
449  uint32_t cnt = 0;
450 
451  for (List::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
452  cnt += (*i)->region_use_count (region);
453  }
454 
455  for (List::const_iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
456  cnt += (*i)->region_use_count (region);
457  }
458 
459  return cnt;
460 }
461 
463 vector<boost::shared_ptr<Playlist> >
464 SessionPlaylists::playlists_for_track (boost::shared_ptr<Track> tr) const
465 {
466  vector<boost::shared_ptr<Playlist> > pl;
467  get (pl);
468 
469  vector<boost::shared_ptr<Playlist> > pl_tr;
470 
471  for (vector<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
472  if (((*i)->get_orig_track_id() == tr->id()) || (tr->playlist()->id() == (*i)->id())) {
473  pl_tr.push_back (*i);
474  }
475  }
476 
477  return pl_tr;
478 }
PBD::Signal0< void > DropReferences
Definition: destructible.h:34
LIBARDOUR_API uint64_t Destruction
Definition: debug.cc:38
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
XMLNode * add_child(const char *)
Definition: xml++.cc:351
Definition: id.h:32
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
Definition: amp.h:29
const PBD::ID & id() const
Definition: stateful.h:68
boost::shared_ptr< Playlist > playlist()
Definition: track.cc:590
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
Definition: xml++.h:95
Definition: debug.h:30
PBD::Signal1< void, bool > InUse
Definition: playlist.h:189
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208