change charset for it_IT
[ardour2.git] / libs / ardour / audio_playlist.cc
blobc883856cf842d30dcf08e9459cc1404054bd82bb
1 /*
2 Copyright (C) 2003 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.
20 #include <algorithm>
22 #include <cstdlib>
24 #include <sigc++/bind.h>
26 #include <ardour/types.h>
27 #include <ardour/configuration.h>
28 #include <ardour/audioplaylist.h>
29 #include <ardour/audioregion.h>
30 #include <ardour/crossfade.h>
31 #include <ardour/crossfade_compare.h>
32 #include <ardour/session.h>
33 #include <pbd/enumwriter.h>
35 #include "i18n.h"
37 using namespace ARDOUR;
38 using namespace sigc;
39 using namespace std;
40 using namespace PBD;
42 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
43 : Playlist (session, node, hidden)
45 in_set_state++;
46 set_state (node);
47 in_set_state--;
50 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
51 : Playlist (session, name, hidden)
55 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
56 : Playlist (other, name, hidden)
58 RegionList::const_iterator in_o = other->regions.begin();
59 RegionList::iterator in_n = regions.begin();
61 while (in_o != other->regions.end()) {
62 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
64 // We look only for crossfades which begin with the current region, so we don't get doubles
65 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
66 if ((*xfades)->in() == ar) {
67 // We found one! Now copy it!
69 RegionList::const_iterator out_o = other->regions.begin();
70 RegionList::const_iterator out_n = regions.begin();
72 while (out_o != other->regions.end()) {
74 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
76 if ((*xfades)->out() == ar2) {
77 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
78 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
79 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*(*xfades), in, out));
80 add_crossfade(new_fade);
81 break;
84 out_o++;
85 out_n++;
87 // cerr << "HUH!? second region in the crossfade not found!" << endl;
91 in_o++;
92 in_n++;
96 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
97 : Playlist (other, start, cnt, name, hidden)
99 /* this constructor does NOT notify others (session) */
102 AudioPlaylist::~AudioPlaylist ()
104 GoingAway (); /* EMIT SIGNAL */
106 /* drop connections to signals */
108 notify_callbacks ();
110 _crossfades.clear ();
113 struct RegionSortByLayer {
114 bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
115 return a->layer() < b->layer();
119 nframes_t
120 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
121 nframes_t cnt, unsigned chan_n)
123 nframes_t ret = cnt;
124 nframes_t end;
125 nframes_t read_frames;
126 nframes_t skip_frames;
128 /* optimizing this memset() away involves a lot of conditionals
129 that may well cause more of a hit due to cache misses
130 and related stuff than just doing this here.
132 it would be great if someone could measure this
133 at some point.
135 one way or another, parts of the requested area
136 that are not written to by Region::region_at()
137 for all Regions that cover the area need to be
138 zeroed.
141 memset (buf, 0, sizeof (Sample) * cnt);
143 /* this function is never called from a realtime thread, so
144 its OK to block (for short intervals).
147 Glib::Mutex::Lock rm (region_lock);
149 end = start + cnt - 1;
151 read_frames = 0;
152 skip_frames = 0;
153 _read_data_count = 0;
155 RegionList* rlist = regions_to_read (start, start+cnt);
157 if (rlist->empty()) {
158 delete rlist;
159 return cnt;
162 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
163 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
164 vector<uint32_t> relevant_layers;
166 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
167 if ((*i)->coverage (start, end) != OverlapNone) {
168 relevant_regions[(*i)->layer()].push_back (*i);
169 relevant_layers.push_back ((*i)->layer());
173 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
174 if ((*i)->coverage (start, end) != OverlapNone) {
175 relevant_xfades[(*i)->upper_layer()].push_back (*i);
179 // RegionSortByLayer layer_cmp;
180 // relevant_regions.sort (layer_cmp);
182 /* XXX this whole per-layer approach is a hack that
183 should be removed once Crossfades become
184 CrossfadeRegions and we just grab a list of relevant
185 regions and call read_at() on all of them.
188 sort (relevant_layers.begin(), relevant_layers.end());
190 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
192 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
193 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
195 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
196 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
197 assert(ar);
198 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
199 _read_data_count += ar->read_data_count();
202 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
203 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
205 /* don't JACK up _read_data_count, since its the same data as we just
206 read from the regions, and the OS should handle that for us.
211 delete rlist;
212 return ret;
216 void
217 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
219 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
221 if (in_set_state) {
222 return;
225 if (r == 0) {
226 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
227 << endmsg;
228 return;
231 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
233 if ((*i)->involves (r)) {
234 i = _crossfades.erase (i);
235 } else {
236 ++i;
242 void
243 AudioPlaylist::flush_notifications ()
245 Playlist::flush_notifications();
247 if (in_flush) {
248 return;
251 in_flush = true;
253 Crossfades::iterator a;
254 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
255 NewCrossfade (*a); /* EMIT SIGNAL */
258 _pending_xfade_adds.clear ();
260 in_flush = false;
263 void
264 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
266 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
267 set<boost::shared_ptr<Crossfade> > updated;
269 if (ar == 0) {
270 return;
273 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
275 Crossfades::iterator tmp;
277 tmp = x;
278 ++tmp;
280 /* only update them once */
282 if ((*x)->involves (ar)) {
284 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
286 if (u.second) {
287 /* x was succesfully inserted into the set, so it has not already been updated */
288 try {
289 (*x)->refresh ();
292 catch (Crossfade::NoCrossfadeHere& err) {
293 // relax, Invalidated during refresh
298 x = tmp;
302 void
303 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
305 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
306 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
307 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
309 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
310 Crossfades::iterator tmp;
311 tmp = x;
312 ++tmp;
314 boost::shared_ptr<Crossfade> fade;
316 if ((*x)->_in == orig) {
317 if (! (*x)->covers(right->position())) {
318 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
319 } else {
320 // Overlap, the crossfade is copied on the left side of the right region instead
321 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, right, (*x)->_out));
325 if ((*x)->_out == orig) {
326 if (! (*x)->covers(right->position())) {
327 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
328 } else {
329 // Overlap, the crossfade is copied on the right side of the left region instead
330 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, left));
334 if (fade) {
335 _crossfades.remove (*x);
336 add_crossfade (fade);
338 x = tmp;
342 void
343 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
345 boost::shared_ptr<AudioRegion> other;
346 boost::shared_ptr<AudioRegion> region;
347 boost::shared_ptr<AudioRegion> top;
348 boost::shared_ptr<AudioRegion> bottom;
349 boost::shared_ptr<Crossfade> xfade;
351 if (in_set_state || in_partition) {
352 return;
355 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
356 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
357 << endmsg;
358 return;
361 if (!norefresh) {
362 refresh_dependents (r);
366 if (!Config->get_auto_xfade()) {
367 return;
370 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
372 nframes_t xfade_length;
374 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
376 if (other == region) {
377 continue;
380 if (other->muted() || region->muted()) {
381 continue;
385 if (other->layer() < region->layer()) {
386 top = region;
387 bottom = other;
388 } else {
389 top = other;
390 bottom = region;
393 if (!(top->opaque())) {
394 continue;
399 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
401 try {
402 switch (c) {
403 case OverlapNone:
404 break;
406 case OverlapInternal:
407 /* {=============== top =============}
408 * [ ----- bottom ------- ]
410 break;
412 case OverlapExternal:
414 /* [ -------- top ------- ]
415 * {=========== bottom =============}
418 /* to avoid discontinuities at the region boundaries of an internal
419 overlap (this region is completely within another), we create
420 two hidden crossfades at each boundary. this is not dependent
421 on the auto-xfade option, because we require it as basic
422 audio engineering.
425 xfade_length = min ((nframes_t) 720, top->length());
427 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
428 add_crossfade (xfade);
430 if (top_region_at (top->last_frame() - 1) == top) {
432 only add a fade out if there is no region on top of the end of 'top' (which
433 would cover it).
436 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
437 add_crossfade (xfade);
439 break;
441 default:
442 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
443 add_crossfade (xfade);
447 catch (failed_constructor& err) {
448 continue;
451 catch (Crossfade::NoCrossfadeHere& err) {
452 continue;
458 void
459 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
461 Crossfades::iterator ci;
463 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
464 if (*(*ci) == *xfade) { // Crossfade::operator==()
465 break;
469 if (ci != _crossfades.end()) {
470 // it will just go away
471 } else {
472 _crossfades.push_back (xfade);
474 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
475 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
477 notify_crossfade_added (xfade);
481 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
483 if (g_atomic_int_get(&block_notifications)) {
484 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
485 } else {
486 NewCrossfade (x); /* EMIT SIGNAL */
490 void
491 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
493 Crossfades::iterator i;
495 xfade->in()->resume_fade_in ();
496 xfade->out()->resume_fade_out ();
498 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
499 _crossfades.erase (i);
504 AudioPlaylist::set_state (const XMLNode& node)
506 XMLNode *child;
507 XMLNodeList nlist;
508 XMLNodeConstIterator niter;
510 in_set_state++;
511 freeze ();
513 Playlist::set_state (node);
515 nlist = node.children();
517 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
519 child = *niter;
521 if (child->name() != "Crossfade") {
522 continue;
525 try {
526 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
527 _crossfades.push_back (xfade);
528 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
529 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
530 NewCrossfade(xfade);
533 catch (failed_constructor& err) {
534 // cout << string_compose (_("could not create crossfade object in playlist %1"),
535 // _name)
536 // << endl;
537 continue;
541 thaw ();
542 in_set_state--;
544 return 0;
547 void
548 AudioPlaylist::clear (bool with_signals)
550 _crossfades.clear ();
551 Playlist::clear (with_signals);
554 XMLNode&
555 AudioPlaylist::state (bool full_state)
557 XMLNode& node = Playlist::state (full_state);
559 if (full_state) {
560 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
561 node.add_child_nocopy ((*i)->get_state());
565 return node;
568 void
569 AudioPlaylist::dump () const
571 boost::shared_ptr<Region>r;
572 boost::shared_ptr<Crossfade> x;
574 cerr << "Playlist \"" << _name << "\" " << endl
575 << regions.size() << " regions "
576 << _crossfades.size() << " crossfades"
577 << endl;
579 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
580 r = *i;
581 cerr << " " << r->name() << " @ " << r << " ["
582 << r->start() << "+" << r->length()
583 << "] at "
584 << r->position()
585 << " on layer "
586 << r->layer ()
587 << endl;
590 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
591 x = *i;
592 cerr << " xfade ["
593 << x->out()->name()
594 << ','
595 << x->in()->name()
596 << " @ "
597 << x->position()
598 << " length = "
599 << x->length ()
600 << " active ? "
601 << (x->active() ? "yes" : "no")
602 << endl;
606 bool
607 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
609 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
610 bool changed = false;
611 Crossfades::iterator c, ctmp;
612 set<boost::shared_ptr<Crossfade> > unique_xfades;
614 if (r == 0) {
615 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
616 << endmsg;
617 /*NOTREACHED*/
618 return false;
622 RegionLock rlock (this);
624 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
626 RegionList::iterator tmp = i;
627 ++tmp;
629 if ((*i) == region) {
630 regions.erase (i);
631 changed = true;
634 i = tmp;
637 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
639 set<boost::shared_ptr<Region> >::iterator xtmp = x;
640 ++xtmp;
642 if ((*x) == region) {
643 all_regions.erase (x);
644 changed = true;
647 x = xtmp;
650 region->set_playlist (boost::shared_ptr<Playlist>());
653 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
654 ctmp = c;
655 ++ctmp;
657 if ((*c)->involves (r)) {
658 unique_xfades.insert (*c);
659 _crossfades.erase (c);
662 c = ctmp;
665 if (changed) {
666 /* overload this, it normally means "removed", not destroyed */
667 notify_region_removed (region);
670 return changed;
673 void
674 AudioPlaylist::crossfade_changed (Change ignored)
676 if (in_flush || in_set_state) {
677 return;
680 /* XXX is there a loop here? can an xfade change not happen
681 due to a playlist change? well, sure activation would
682 be an example. maybe we should check the type of change
683 that occured.
686 notify_modified ();
689 bool
690 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
692 if (in_flush || in_set_state) {
693 return false;
696 Change our_interests = Change (AudioRegion::FadeInChanged|
697 AudioRegion::FadeOutChanged|
698 AudioRegion::FadeInActiveChanged|
699 AudioRegion::FadeOutActiveChanged|
700 AudioRegion::EnvelopeActiveChanged|
701 AudioRegion::ScaleAmplitudeChanged|
702 AudioRegion::EnvelopeChanged);
703 bool parent_wants_notify;
705 parent_wants_notify = Playlist::region_changed (what_changed, region);
707 if ((parent_wants_notify || (what_changed & our_interests))) {
708 notify_modified ();
711 return true;
714 void
715 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
717 RegionLock rlock (this);
719 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
720 nframes_t start, end;
722 start = (*i)->position();
723 end = start + (*i)->overlap_length(); // not length(), important difference
725 if (frame >= start && frame <= end) {
726 clist.push_back (*i);