fully implement and deploy explicit x-thread signal connection syntax (testing comes...
[ardour.git] / libs / ardour / audioregion.cc
1 /*
2     Copyright (C) 2000-2006 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
20 #include <cmath>
21 #include <climits>
22 #include <cfloat>
23 #include <algorithm>
24
25 #include <set>
26
27
28 #include <glibmm/thread.h>
29
30 #include "pbd/basename.h"
31 #include "pbd/xml++.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/convert.h"
35
36 #include "evoral/Curve.hpp"
37
38 #include "ardour/audioregion.h"
39 #include "ardour/session.h"
40 #include "ardour/gain.h"
41 #include "ardour/dB.h"
42 #include "ardour/playlist.h"
43 #include "ardour/audiofilesource.h"
44 #include "ardour/region_factory.h"
45 #include "ardour/runtime_functions.h"
46 #include "ardour/transient_detector.h"
47
48 #include "i18n.h"
49 #include <locale.h>
50
51 using namespace std;
52 using namespace ARDOUR;
53 using namespace PBD;
54
55 /* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
56
57 Change AudioRegion::FadeInChanged         = ARDOUR::new_change();
58 Change AudioRegion::FadeOutChanged        = ARDOUR::new_change();
59 Change AudioRegion::FadeInActiveChanged   = ARDOUR::new_change();
60 Change AudioRegion::FadeOutActiveChanged  = ARDOUR::new_change();
61 Change AudioRegion::EnvelopeActiveChanged = ARDOUR::new_change();
62 Change AudioRegion::ScaleAmplitudeChanged = ARDOUR::new_change();
63 Change AudioRegion::EnvelopeChanged       = ARDOUR::new_change();
64
65 void
66 AudioRegion::init ()
67 {
68         _scale_amplitude = 1.0;
69
70         set_default_fades ();
71         set_default_envelope ();
72
73         listen_to_my_curves ();
74         connect_to_analysis_changed ();
75 }
76
77 /** Constructor for use by derived types only */
78 AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string name)
79         : Region (s, start, length, name, DataType::AUDIO)
80         , _automatable(s)
81         , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
82         , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
83         , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
84 {
85         init ();
86         assert (_sources.size() == _master_sources.size());
87 }
88
89 /** Basic AudioRegion constructor (one channel) */
90 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length)
91         : Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0,  Region::Flag(Region::DefaultFlags|Region::External))
92         , _automatable(src->session())
93         , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
94         , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
95         , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
96 {
97         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
98         if (afs) {
99                 afs->HeaderPositionOffsetChanged.connect_same_thread (*this, boost::bind (&AudioRegion::source_offset_changed, this));
100         }
101
102         init ();
103         assert (_sources.size() == _master_sources.size());
104 }
105
106 /* Basic AudioRegion constructor (one channel) */
107 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
108         : Region (src, start, length, name, DataType::AUDIO, layer, flags)
109         , _automatable(src->session())
110         , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
111         , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
112         , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
113 {
114         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
115         if (afs) {
116                 afs->HeaderPositionOffsetChanged.connect_same_thread (*this, boost::bind (&AudioRegion::source_offset_changed, this));
117         }
118
119         init ();
120         assert (_sources.size() == _master_sources.size());
121 }
122
123 /** Basic AudioRegion constructor (many channels) */
124 AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
125         : Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
126         , _automatable(srcs[0]->session())
127         , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
128         , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
129         , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
130 {
131         init ();
132         connect_to_analysis_changed ();
133         assert (_sources.size() == _master_sources.size());
134 }
135
136 /** Create a new AudioRegion, that is part of an existing one */
137 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
138         : Region (other, offset, length, name, layer, flags)
139         , _automatable(other->session())
140         , _fade_in (new AutomationList(*other->_fade_in))
141         , _fade_out (new AutomationList(*other->_fade_out))
142         , _envelope (new AutomationList(*other->_envelope, offset, offset + length))
143 {
144         connect_to_header_position_offset_changed ();
145
146         /* return to default fades if the existing ones are too long */
147
148         if (_flags & LeftOfSplit) {
149                 if (_fade_in->back()->when >= _length) {
150                         set_default_fade_in ();
151                 } else {
152                         _fade_in_disabled = other->_fade_in_disabled;
153                 }
154                 set_default_fade_out ();
155                 _flags = Flag (_flags & ~Region::LeftOfSplit);
156         }
157
158         if (_flags & RightOfSplit) {
159                 if (_fade_out->back()->when >= _length) {
160                         set_default_fade_out ();
161                 } else {
162                         _fade_out_disabled = other->_fade_out_disabled;
163                 }
164                 set_default_fade_in ();
165                 _flags = Flag (_flags & ~Region::RightOfSplit);
166         }
167
168         _scale_amplitude = other->_scale_amplitude;
169
170         assert(_type == DataType::AUDIO);
171
172         listen_to_my_curves ();
173         connect_to_analysis_changed ();
174
175         assert (_sources.size() == _master_sources.size());
176 }
177
178 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
179         : Region (other)
180         , _automatable (other->session())
181         , _fade_in (new AutomationList (*other->_fade_in))
182         , _fade_out (new AutomationList (*other->_fade_out))
183         , _envelope (new AutomationList (*other->_envelope))
184 {
185         assert(_type == DataType::AUDIO);
186         _scale_amplitude = other->_scale_amplitude;
187
188         listen_to_my_curves ();
189         connect_to_analysis_changed ();
190
191         assert (_sources.size() == _master_sources.size());
192 }
193
194 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const SourceList& /*srcs*/,
195                           nframes_t length, const string& name, layer_t layer, Flag flags)
196         : Region (other, length, name, layer, flags)
197         , _automatable (other->session())
198         , _fade_in (new AutomationList (*other->_fade_in))
199         , _fade_out (new AutomationList (*other->_fade_out))
200         , _envelope (new AutomationList (*other->_envelope))
201 {
202         /* make-a-sort-of-copy-with-different-sources constructor (used by audio filter) */
203
204         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
205
206                 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> ((*i));
207                 if (afs) {
208                         afs->HeaderPositionOffsetChanged.connect_same_thread (*this, boost::bind (&AudioRegion::source_offset_changed, this));
209                 }
210         }
211
212         _scale_amplitude = other->_scale_amplitude;
213
214         _fade_in_disabled = 0;
215         _fade_out_disabled = 0;
216
217         listen_to_my_curves ();
218         connect_to_analysis_changed ();
219
220         assert (_sources.size() == _master_sources.size());
221 }
222
223 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
224         : Region (src, node)
225         , _automatable(src->session())
226         , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
227         , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
228         , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
229 {
230         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
231         if (afs) {
232                 afs->HeaderPositionOffsetChanged.connect_same_thread (*this, boost::bind (&AudioRegion::source_offset_changed, this));
233         }
234
235         init ();
236
237         if (set_state (node, Stateful::loading_state_version)) {
238                 throw failed_constructor();
239         }
240
241         assert(_type == DataType::AUDIO);
242         connect_to_analysis_changed ();
243
244         assert (_sources.size() == _master_sources.size());
245 }
246
247 AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
248         : Region (srcs, node)
249         , _automatable(srcs[0]->session())
250         , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
251         , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
252         , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
253 {
254         init ();
255
256         if (set_state (node, Stateful::loading_state_version)) {
257                 throw failed_constructor();
258         }
259
260         assert(_type == DataType::AUDIO);
261         connect_to_analysis_changed ();
262         assert (_sources.size() == _master_sources.size());
263 }
264
265 AudioRegion::~AudioRegion ()
266 {
267 }
268
269 void
270 AudioRegion::connect_to_analysis_changed ()
271 {
272         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
273                 (*i)->AnalysisChanged.connect_same_thread (*this, boost::bind (&AudioRegion::invalidate_transients, this));
274         }
275 }
276
277 void
278 AudioRegion::connect_to_header_position_offset_changed ()
279 {
280         set<boost::shared_ptr<Source> > unique_srcs;
281
282         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
283
284                 if (unique_srcs.find (*i) == unique_srcs.end ()) {
285                         unique_srcs.insert (*i);
286                         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
287                         if (afs) {
288                                 afs->HeaderPositionOffsetChanged.connect_same_thread (*this, boost::bind (&AudioRegion::source_offset_changed, this));
289                         }
290                 }
291         }
292 }
293
294 void
295 AudioRegion::listen_to_my_curves ()
296 {
297         _envelope->StateChanged.connect_same_thread (*this, boost::bind (&AudioRegion::envelope_changed, this));
298         _fade_in->StateChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fade_in_changed, this));
299         _fade_out->StateChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fade_out_changed, this));
300 }
301
302 void
303 AudioRegion::set_envelope_active (bool yn)
304 {
305         if (envelope_active() != yn) {
306                 char buf[64];
307                 if (yn) {
308                         snprintf (buf, sizeof (buf), "envelope active");
309                         _flags = Flag (_flags|EnvelopeActive);
310                 } else {
311                         snprintf (buf, sizeof (buf), "envelope off");
312                         _flags = Flag (_flags & ~EnvelopeActive);
313                 }
314                 send_change (EnvelopeActiveChanged);
315         }
316 }
317
318 ARDOUR::nframes_t
319 AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
320 {
321         if (chan_n >= _sources.size()) {
322                 return 0;
323         }
324
325         if (audio_source(chan_n)->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
326                 return 0;
327         } else {
328                 if (_scale_amplitude != 1.0) {
329                         for (nframes_t n = 0; n < npeaks; ++n) {
330                                 buf[n].max *= _scale_amplitude;
331                                 buf[n].min *= _scale_amplitude;
332                         }
333                 }
334                 return cnt;
335         }
336 }
337
338 nframes_t
339 AudioRegion::read (Sample* buf, sframes_t timeline_position, nframes_t cnt, int channel) const
340 {
341         /* raw read, no fades, no gain, nada */
342         return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, 0, 0, ReadOps (0));
343 }
344
345 nframes_t
346 AudioRegion::read_with_ops (Sample* buf, sframes_t file_position, nframes_t cnt, int channel, ReadOps rops) const
347 {
348         return _read_at (_sources, _length, buf, 0, 0, file_position, cnt, channel, 0, 0, rops);
349 }
350
351 nframes_t
352 AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
353                 sframes_t file_position, nframes_t cnt, uint32_t chan_n,
354                 nframes_t read_frames, nframes_t skip_frames) const
355 {
356         /* regular diskstream/butler read complete with fades etc */
357         return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer,
358                         file_position, cnt, chan_n, read_frames, skip_frames, ReadOps (~0));
359 }
360
361 nframes_t
362 AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
363                 sframes_t position, nframes_t cnt, uint32_t chan_n) const
364 {
365         /* do not read gain/scaling/fades and do not count this disk i/o in statistics */
366
367         return _read_at (_master_sources, _master_sources.front()->length(_master_sources.front()->timeline_position()),
368                          buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0, ReadOps (0));
369 }
370
371 nframes_t
372 AudioRegion::_read_at (const SourceList& /*srcs*/, nframes_t limit,
373                 Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
374                 sframes_t position, nframes_t cnt,
375                 uint32_t chan_n,
376                 nframes_t /*read_frames*/,
377                 nframes_t /*skip_frames*/,
378                 ReadOps rops) const
379 {
380         nframes_t internal_offset;
381         nframes_t buf_offset;
382         nframes_t to_read;
383         bool raw = (rops == ReadOpsNone);
384
385         if (muted() && !raw) {
386                 return 0; /* read nothing */
387         }
388
389         /* precondition: caller has verified that we cover the desired section */
390
391         if (position < _position) {
392                 internal_offset = 0;
393                 buf_offset = _position - position;
394                 cnt -= buf_offset;
395         } else {
396                 internal_offset = position - _position;
397                 buf_offset = 0;
398         }
399
400         if (internal_offset >= limit) {
401                 return 0; /* read nothing */
402         }
403
404         if ((to_read = min (cnt, limit - internal_offset)) == 0) {
405                 return 0; /* read nothing */
406         }
407
408         if (opaque() || raw) {
409                 /* overwrite whatever is there */
410                 mixdown_buffer = buf + buf_offset;
411         } else {
412                 mixdown_buffer += buf_offset;
413         }
414
415         if (rops & ReadOpsCount) {
416                 _read_data_count = 0;
417         }
418
419         if (chan_n < n_channels()) {
420
421                 boost::shared_ptr<AudioSource> src = audio_source(chan_n);
422                 if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
423                         return 0; /* "read nothing" */
424                 }
425
426                 if (rops & ReadOpsCount) {
427                         _read_data_count += src->read_data_count();
428                 }
429
430         } else {
431
432                 /* track is N-channel, this region has less channels; silence the ones
433                    we don't have.
434                 */
435
436                 memset (mixdown_buffer, 0, sizeof (Sample) * cnt);
437         }
438
439         if (rops & ReadOpsFades) {
440
441                 /* fade in */
442
443                 if ((_flags & FadeIn) && _session.config.get_use_region_fades()) {
444
445                         nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
446
447                         /* see if this read is within the fade in */
448
449                         if (internal_offset < fade_in_length) {
450
451                                 nframes_t fi_limit;
452
453                                 fi_limit = min (to_read, fade_in_length - internal_offset);
454
455
456                                 _fade_in->curve().get_vector (internal_offset, internal_offset+fi_limit, gain_buffer, fi_limit);
457
458                                 for (nframes_t n = 0; n < fi_limit; ++n) {
459                                         mixdown_buffer[n] *= gain_buffer[n];
460                                 }
461                         }
462                 }
463
464                 /* fade out */
465
466                 if ((_flags & FadeOut) && _session.config.get_use_region_fades()) {
467
468                         /* see if some part of this read is within the fade out */
469
470                 /* .................        >|            REGION
471                                              limit
472
473                                  {           }            FADE
474                                              fade_out_length
475                                  ^
476                                  limit - fade_out_length
477                         |--------------|
478                         ^internal_offset
479                                        ^internal_offset + to_read
480
481                                        we need the intersection of [internal_offset,internal_offset+to_read] with
482                                        [limit - fade_out_length, limit]
483
484                 */
485
486
487                         nframes_t fade_out_length = (nframes_t) _fade_out->back()->when;
488                         nframes_t fade_interval_start = max(internal_offset, limit-fade_out_length);
489                         nframes_t fade_interval_end   = min(internal_offset + to_read, limit);
490
491                         if (fade_interval_end > fade_interval_start) {
492                                 /* (part of the) the fade out is  in this buffer */
493
494                                 nframes_t fo_limit = fade_interval_end - fade_interval_start;
495                                 nframes_t curve_offset = fade_interval_start - (limit-fade_out_length);
496                                 nframes_t fade_offset = fade_interval_start - internal_offset;
497
498                                 _fade_out->curve().get_vector (curve_offset, curve_offset+fo_limit, gain_buffer, fo_limit);
499
500                                 for (nframes_t n = 0, m = fade_offset; n < fo_limit; ++n, ++m) {
501                                         mixdown_buffer[m] *= gain_buffer[n];
502                                 }
503                         }
504
505                 }
506         }
507
508         /* Regular gain curves and scaling */
509
510         if ((rops & ReadOpsOwnAutomation) && envelope_active())  {
511                 _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
512
513                 if ((rops & ReadOpsOwnScaling) && _scale_amplitude != 1.0f) {
514                         for (nframes_t n = 0; n < to_read; ++n) {
515                                 mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
516                         }
517                 } else {
518                         for (nframes_t n = 0; n < to_read; ++n) {
519                                 mixdown_buffer[n] *= gain_buffer[n];
520                         }
521                 }
522         } else if ((rops & ReadOpsOwnScaling) && _scale_amplitude != 1.0f) {
523
524                 // XXX this should be using what in 2.0 would have been:
525                 // Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
526
527                 for (nframes_t n = 0; n < to_read; ++n) {
528                         mixdown_buffer[n] *= _scale_amplitude;
529                 }
530         }
531
532         if (!opaque()) {
533
534                 /* gack. the things we do for users.
535                  */
536
537                 buf += buf_offset;
538
539                 for (nframes_t n = 0; n < to_read; ++n) {
540                         buf[n] += mixdown_buffer[n];
541                 }
542         }
543
544         return to_read;
545 }
546
547 XMLNode&
548 AudioRegion::state (bool full)
549 {
550         XMLNode& node (Region::state (full));
551         XMLNode *child;
552         char buf[64];
553         char buf2[64];
554         LocaleGuard lg (X_("POSIX"));
555
556         node.add_property ("flags", enum_2_string (_flags));
557
558         snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude);
559         node.add_property ("scale-gain", buf);
560
561         // XXX these should move into Region
562
563         for (uint32_t n=0; n < _sources.size(); ++n) {
564                 snprintf (buf2, sizeof(buf2), "source-%d", n);
565                 _sources[n]->id().print (buf, sizeof (buf));
566                 node.add_property (buf2, buf);
567         }
568
569         for (uint32_t n=0; n < _master_sources.size(); ++n) {
570                 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
571                 _master_sources[n]->id().print (buf, sizeof (buf));
572                 node.add_property (buf2, buf);
573         }
574
575         snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
576         node.add_property ("channels", buf);
577
578         if (full) {
579
580                 child = node.add_child (X_("FadeIn"));
581
582                 if ((_flags & DefaultFadeIn)) {
583                         child->add_property (X_("default"), X_("yes"));
584                 } else {
585                         child->add_child_nocopy (_fade_in->get_state ());
586                 }
587
588                 child->add_property (X_("active"), fade_in_active () ? X_("yes") : X_("no"));
589
590                 child = node.add_child (X_("FadeOut"));
591
592                 if ((_flags & DefaultFadeOut)) {
593                         child->add_property (X_("default"), X_("yes"));
594                 } else {
595                         child->add_child_nocopy (_fade_out->get_state ());
596                 }
597
598                 child->add_property (X_("active"), fade_out_active () ? X_("yes") : X_("no"));
599         }
600
601         child = node.add_child ("Envelope");
602
603         if (full) {
604                 bool default_env = false;
605
606                 // If there are only two points, the points are in the start of the region and the end of the region
607                 // so, if they are both at 1.0f, that means the default region.
608
609                 if (_envelope->size() == 2 &&
610                     _envelope->front()->value == 1.0f &&
611                     _envelope->back()->value==1.0f) {
612                         if (_envelope->front()->when == 0 && _envelope->back()->when == _length) {
613                                 default_env = true;
614                         }
615                 }
616
617                 if (default_env) {
618                         child->add_property ("default", "yes");
619                 } else {
620                         child->add_child_nocopy (_envelope->get_state ());
621                 }
622
623         } else {
624                 child->add_property ("default", "yes");
625         }
626
627         if (full && _extra_xml) {
628                 node.add_child_copy (*_extra_xml);
629         }
630
631         return node;
632 }
633
634 int
635 AudioRegion::set_live_state (const XMLNode& node, int version, Change& what_changed, bool send)
636 {
637         const XMLNodeList& nlist = node.children();
638         const XMLProperty *prop;
639         LocaleGuard lg (X_("POSIX"));
640
641         Region::set_live_state (node, version, what_changed, false);
642
643         uint32_t old_flags = _flags;
644
645         if ((prop = node.property ("flags")) != 0) {
646                 _flags = Flag (string_2_enum (prop->value(), _flags));
647
648                 //_flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
649
650                 _flags = Flag (_flags & ~Region::LeftOfSplit);
651                 _flags = Flag (_flags & ~Region::RightOfSplit);
652         }
653
654         /* leave this flag setting in place, no matter what */
655
656         if ((old_flags & DoNotSendPropertyChanges)) {
657                 _flags = Flag (_flags | DoNotSendPropertyChanges);
658         }
659
660         /* find out if any flags changed that we signal about */
661
662         if ((old_flags ^ _flags) & Muted) {
663                 what_changed = Change (what_changed|MuteChanged);
664         }
665         if ((old_flags ^ _flags) & Opaque) {
666                 what_changed = Change (what_changed|OpacityChanged);
667         }
668         if ((old_flags ^ _flags) & Locked) {
669                 what_changed = Change (what_changed|LockChanged);
670         }
671
672         if ((prop = node.property ("scale-gain")) != 0) {
673                 _scale_amplitude = atof (prop->value().c_str());
674                 what_changed = Change (what_changed|ScaleAmplitudeChanged);
675         } else {
676                 _scale_amplitude = 1.0;
677         }
678
679         /* Now find envelope description and other misc child items */
680
681         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
682
683                 XMLNode *child;
684                 XMLProperty *prop;
685
686                 child = (*niter);
687
688                 if (child->name() == "Envelope") {
689
690                         _envelope->clear ();
691
692                         if ((prop = child->property ("default")) != 0 || _envelope->set_state (*child, version)) {
693                                 set_default_envelope ();
694                         }
695
696                         _envelope->set_max_xval (_length);
697                         _envelope->truncate_end (_length);
698
699                 } else if (child->name() == "FadeIn") {
700
701                         _fade_in->clear ();
702
703                         if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
704                                 set_default_fade_in ();
705                         } else {
706                                 XMLNode* grandchild = child->child ("AutomationList");
707                                 if (grandchild) {
708                                         _fade_in->set_state (*grandchild, version);
709                                 }
710                         }
711
712                         if ((prop = child->property ("active")) != 0) {
713                                 if (string_is_affirmative (prop->value())) {
714                                         set_fade_in_active (true);
715                                 } else {
716                                         set_fade_in_active (false);
717                                 }
718                         }
719
720                 } else if (child->name() == "FadeOut") {
721
722                         _fade_out->clear ();
723
724                         if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
725                                 set_default_fade_out ();
726                         } else {
727                                 XMLNode* grandchild = child->child ("AutomationList");
728                                 if (grandchild) {
729                                         _fade_out->set_state (*grandchild, version);
730                                 }
731                         }
732
733                         if ((prop = child->property ("active")) != 0) {
734                                 if (string_is_affirmative (prop->value())) {
735                                         set_fade_out_active (true);
736                                 } else {
737                                         set_fade_out_active (false);
738                                 }
739                         }
740
741                 }
742         }
743
744         if (send) {
745                 send_change (what_changed);
746         }
747
748         return 0;
749 }
750
751 int
752 AudioRegion::set_state (const XMLNode& node, int version)
753 {
754         /* Region::set_state() calls the virtual set_live_state(),
755            which will get us back to AudioRegion::set_live_state()
756            to handle the relevant stuff.
757         */
758
759         return Region::set_state (node, version);
760 }
761
762 void
763 AudioRegion::set_fade_in_shape (FadeShape shape)
764 {
765         set_fade_in (shape, (nframes_t) _fade_in->back()->when);
766 }
767
768 void
769 AudioRegion::set_fade_out_shape (FadeShape shape)
770 {
771         set_fade_out (shape, (nframes_t) _fade_out->back()->when);
772 }
773
774 void
775 AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
776 {
777         _fade_in->freeze ();
778         _fade_in->clear ();
779
780         switch (shape) {
781         case Linear:
782                 _fade_in->fast_simple_add (0.0, 0.0);
783                 _fade_in->fast_simple_add (len, 1.0);
784                 break;
785
786         case Fast:
787                 _fade_in->fast_simple_add (0, 0);
788                 _fade_in->fast_simple_add (len * 0.389401, 0.0333333);
789                 _fade_in->fast_simple_add (len * 0.629032, 0.0861111);
790                 _fade_in->fast_simple_add (len * 0.829493, 0.233333);
791                 _fade_in->fast_simple_add (len * 0.9447, 0.483333);
792                 _fade_in->fast_simple_add (len * 0.976959, 0.697222);
793                 _fade_in->fast_simple_add (len, 1);
794                 break;
795
796         case Slow:
797                 _fade_in->fast_simple_add (0, 0);
798                 _fade_in->fast_simple_add (len * 0.0207373, 0.197222);
799                 _fade_in->fast_simple_add (len * 0.0645161, 0.525);
800                 _fade_in->fast_simple_add (len * 0.152074, 0.802778);
801                 _fade_in->fast_simple_add (len * 0.276498, 0.919444);
802                 _fade_in->fast_simple_add (len * 0.481567, 0.980556);
803                 _fade_in->fast_simple_add (len * 0.767281, 1);
804                 _fade_in->fast_simple_add (len, 1);
805                 break;
806
807         case LogA:
808                 _fade_in->fast_simple_add (0, 0);
809                 _fade_in->fast_simple_add (len * 0.0737327, 0.308333);
810                 _fade_in->fast_simple_add (len * 0.246544, 0.658333);
811                 _fade_in->fast_simple_add (len * 0.470046, 0.886111);
812                 _fade_in->fast_simple_add (len * 0.652074, 0.972222);
813                 _fade_in->fast_simple_add (len * 0.771889, 0.988889);
814                 _fade_in->fast_simple_add (len, 1);
815                 break;
816
817         case LogB:
818                 _fade_in->fast_simple_add (0, 0);
819                 _fade_in->fast_simple_add (len * 0.304147, 0.0694444);
820                 _fade_in->fast_simple_add (len * 0.529954, 0.152778);
821                 _fade_in->fast_simple_add (len * 0.725806, 0.333333);
822                 _fade_in->fast_simple_add (len * 0.847926, 0.558333);
823                 _fade_in->fast_simple_add (len * 0.919355, 0.730556);
824                 _fade_in->fast_simple_add (len, 1);
825                 break;
826         }
827
828         _fade_in->thaw ();
829         _fade_in_shape = shape;
830
831         send_change (FadeInChanged);
832 }
833
834 void
835 AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
836 {
837         _fade_out->freeze ();
838         _fade_out->clear ();
839
840         switch (shape) {
841         case Fast:
842                 _fade_out->fast_simple_add (len * 0, 1);
843                 _fade_out->fast_simple_add (len * 0.023041, 0.697222);
844                 _fade_out->fast_simple_add (len * 0.0553,   0.483333);
845                 _fade_out->fast_simple_add (len * 0.170507, 0.233333);
846                 _fade_out->fast_simple_add (len * 0.370968, 0.0861111);
847                 _fade_out->fast_simple_add (len * 0.610599, 0.0333333);
848                 _fade_out->fast_simple_add (len * 1, 0);
849                 break;
850
851         case LogA:
852                 _fade_out->fast_simple_add (len * 0, 1);
853                 _fade_out->fast_simple_add (len * 0.228111, 0.988889);
854                 _fade_out->fast_simple_add (len * 0.347926, 0.972222);
855                 _fade_out->fast_simple_add (len * 0.529954, 0.886111);
856                 _fade_out->fast_simple_add (len * 0.753456, 0.658333);
857                 _fade_out->fast_simple_add (len * 0.9262673, 0.308333);
858                 _fade_out->fast_simple_add (len * 1, 0);
859                 break;
860
861         case Slow:
862                 _fade_out->fast_simple_add (len * 0, 1);
863                 _fade_out->fast_simple_add (len * 0.305556, 1);
864                 _fade_out->fast_simple_add (len * 0.548611, 0.991736);
865                 _fade_out->fast_simple_add (len * 0.759259, 0.931129);
866                 _fade_out->fast_simple_add (len * 0.918981, 0.68595);
867                 _fade_out->fast_simple_add (len * 0.976852, 0.22865);
868                 _fade_out->fast_simple_add (len * 1, 0);
869                 break;
870
871         case LogB:
872                 _fade_out->fast_simple_add (len * 0, 1);
873                 _fade_out->fast_simple_add (len * 0.080645, 0.730556);
874                 _fade_out->fast_simple_add (len * 0.277778, 0.289256);
875                 _fade_out->fast_simple_add (len * 0.470046, 0.152778);
876                 _fade_out->fast_simple_add (len * 0.695853, 0.0694444);
877                 _fade_out->fast_simple_add (len * 1, 0);
878                 break;
879
880         case Linear:
881                 _fade_out->fast_simple_add (len * 0, 1);
882                 _fade_out->fast_simple_add (len * 1, 0);
883                 break;
884         }
885
886         _fade_out->thaw ();
887         _fade_out_shape = shape;
888
889         send_change (FadeOutChanged);
890 }
891
892 void
893 AudioRegion::set_fade_in_length (nframes_t len)
894 {
895         if (len > _length) {
896                 len = _length - 1;
897         }
898
899         bool changed = _fade_in->extend_to (len);
900
901         if (changed) {
902                 _flags = Flag (_flags & ~DefaultFadeIn);
903                 send_change (FadeInChanged);
904         }
905 }
906
907 void
908 AudioRegion::set_fade_out_length (nframes_t len)
909 {
910         if (len > _length) {
911                 len = _length - 1;
912         }
913
914         bool changed =  _fade_out->extend_to (len);
915
916         if (changed) {
917                 _flags = Flag (_flags & ~DefaultFadeOut);
918                 send_change (FadeOutChanged);
919         }
920 }
921
922 void
923 AudioRegion::set_fade_in_active (bool yn)
924 {
925         if (yn == (_flags & FadeIn)) {
926                 return;
927         }
928         if (yn) {
929                 _flags = Flag (_flags|FadeIn);
930         } else {
931                 _flags = Flag (_flags & ~FadeIn);
932         }
933
934         send_change (FadeInActiveChanged);
935 }
936
937 void
938 AudioRegion::set_fade_out_active (bool yn)
939 {
940         if (yn == (_flags & FadeOut)) {
941                 return;
942         }
943         if (yn) {
944                 _flags = Flag (_flags | FadeOut);
945         } else {
946                 _flags = Flag (_flags & ~FadeOut);
947         }
948
949         send_change (FadeOutActiveChanged);
950 }
951
952 bool
953 AudioRegion::fade_in_is_default () const
954 {
955         return _fade_in_shape == Linear && _fade_in->back()->when == 64;
956 }
957
958 bool
959 AudioRegion::fade_out_is_default () const
960 {
961         return _fade_out_shape == Linear && _fade_out->back()->when == 64;
962 }
963
964 void
965 AudioRegion::set_default_fade_in ()
966 {
967         _fade_in_disabled = 0;
968         set_fade_in (Linear, 64);
969 }
970
971 void
972 AudioRegion::set_default_fade_out ()
973 {
974         _fade_out_disabled = 0;
975         set_fade_out (Linear, 64);
976 }
977
978 void
979 AudioRegion::set_default_fades ()
980 {
981         set_default_fade_in ();
982         set_default_fade_out ();
983 }
984
985 void
986 AudioRegion::set_default_envelope ()
987 {
988         _envelope->freeze ();
989         _envelope->clear ();
990         _envelope->fast_simple_add (0, 1.0f);
991         _envelope->fast_simple_add (_length, 1.0f);
992         _envelope->thaw ();
993 }
994
995 void
996 AudioRegion::recompute_at_end ()
997 {
998         /* our length has changed. recompute a new final point by interpolating
999            based on the the existing curve.
1000         */
1001
1002         _envelope->freeze ();
1003         _envelope->truncate_end (_length);
1004         _envelope->set_max_xval (_length);
1005         _envelope->thaw ();
1006
1007         if (_fade_in->back()->when > _length) {
1008                 _fade_in->extend_to (_length);
1009                 send_change (FadeInChanged);
1010         }
1011
1012         if (_fade_out->back()->when > _length) {
1013                 _fade_out->extend_to (_length);
1014                 send_change (FadeOutChanged);
1015         }
1016 }
1017
1018 void
1019 AudioRegion::recompute_at_start ()
1020 {
1021         /* as above, but the shift was from the front */
1022
1023         _envelope->truncate_start (_length);
1024
1025         if (_fade_in->back()->when > _length) {
1026                 _fade_in->extend_to (_length);
1027                 send_change (FadeInChanged);
1028         }
1029
1030         if (_fade_out->back()->when > _length) {
1031                 _fade_out->extend_to (_length);
1032                 send_change (FadeOutChanged);
1033         }
1034 }
1035
1036 int
1037 AudioRegion::separate_by_channel (Session& /*session*/, vector<boost::shared_ptr<Region> >& v) const
1038 {
1039         SourceList srcs;
1040         string new_name;
1041         int n = 0;
1042
1043         if (_sources.size() < 2) {
1044                 return 0;
1045         }
1046
1047         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1048                 srcs.clear ();
1049                 srcs.push_back (*i);
1050
1051                 new_name = _name;
1052
1053                 if (_sources.size() == 2) {
1054                         if (n == 0) {
1055                                 new_name += "-L";
1056                         } else {
1057                                 new_name += "-R";
1058                         }
1059                 } else {
1060                         new_name += '-';
1061                         new_name += ('0' + n + 1);
1062                 }
1063
1064                 /* create a copy with just one source. prevent if from being thought of as
1065                    "whole file" even if it covers the entire source file(s).
1066                  */
1067
1068                 Flag f = Flag (_flags & ~WholeFile);
1069
1070                 v.push_back(RegionFactory::create (srcs, _start, _length, new_name, _layer, f));
1071
1072                 ++n;
1073         }
1074
1075         return 0;
1076 }
1077
1078 nframes_t
1079 AudioRegion::read_raw_internal (Sample* buf, sframes_t pos, nframes_t cnt, int channel) const
1080 {
1081         return audio_source()->read (buf, pos, cnt, channel);
1082 }
1083
1084 int
1085 AudioRegion::exportme (Session& /*session*/, ARDOUR::ExportSpecification& /*spec*/)
1086 {
1087         // TODO EXPORT
1088 //      const nframes_t blocksize = 4096;
1089 //      nframes_t to_read;
1090 //      int status = -1;
1091 //
1092 //      spec.channels = _sources.size();
1093 //
1094 //      if (spec.prepare (blocksize, session.frame_rate())) {
1095 //              goto out;
1096 //      }
1097 //
1098 //      spec.pos = 0;
1099 //      spec.total_frames = _length;
1100 //
1101 //      while (spec.pos < _length && !spec.stop) {
1102 //
1103 //
1104 //              /* step 1: interleave */
1105 //
1106 //              to_read = min (_length - spec.pos, blocksize);
1107 //
1108 //              if (spec.channels == 1) {
1109 //
1110 //                      if (read_raw_internal (spec.dataF, _start + spec.pos, to_read) != to_read) {
1111 //                              goto out;
1112 //                      }
1113 //
1114 //              } else {
1115 //
1116 //                      Sample buf[blocksize];
1117 //
1118 //                      for (uint32_t chan = 0; chan < spec.channels; ++chan) {
1119 //
1120 //                              if (audio_source(chan)->read (buf, _start + spec.pos, to_read) != to_read) {
1121 //                                      goto out;
1122 //                              }
1123 //
1124 //                              for (nframes_t x = 0; x < to_read; ++x) {
1125 //                                      spec.dataF[chan+(x*spec.channels)] = buf[x];
1126 //                              }
1127 //                      }
1128 //              }
1129 //
1130 //              if (spec.process (to_read)) {
1131 //                      goto out;
1132 //              }
1133 //
1134 //              spec.pos += to_read;
1135 //              spec.progress = (double) spec.pos /_length;
1136 //
1137 //      }
1138 //
1139 //      status = 0;
1140 //
1141 //  out:
1142 //      spec.running = false;
1143 //      spec.status = status;
1144 //      spec.clear();
1145 //
1146 //      return status;
1147         return 0;
1148 }
1149
1150 void
1151 AudioRegion::set_scale_amplitude (gain_t g)
1152 {
1153         boost::shared_ptr<Playlist> pl (playlist());
1154
1155         _scale_amplitude = g;
1156
1157         /* tell the diskstream we're in */
1158
1159         if (pl) {
1160                 pl->Modified();
1161         }
1162
1163         /* tell everybody else */
1164
1165         send_change (ScaleAmplitudeChanged);
1166 }
1167
1168 void
1169 AudioRegion::normalize_to (float target_dB)
1170 {
1171         const nframes_t blocksize = 64 * 1024;
1172         Sample buf[blocksize];
1173         nframes_t fpos;
1174         nframes_t fend;
1175         nframes_t to_read;
1176         double maxamp = 0;
1177         gain_t target = dB_to_coefficient (target_dB);
1178
1179         if (target == 1.0f) {
1180                 /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
1181                    that we may have clipped.
1182                 */
1183                 target -= FLT_EPSILON;
1184         }
1185
1186         fpos = _start;
1187         fend = _start + _length;
1188
1189         /* first pass: find max amplitude */
1190
1191         while (fpos < fend) {
1192
1193                 uint32_t n;
1194
1195                 to_read = min (fend - fpos, blocksize);
1196
1197                 for (n = 0; n < n_channels(); ++n) {
1198
1199                         /* read it in */
1200
1201                         if (read_raw_internal (buf, fpos, to_read, 0) != to_read) {
1202                                 return;
1203                         }
1204
1205                         maxamp = compute_peak (buf, to_read, maxamp);
1206                 }
1207
1208                 fpos += to_read;
1209         };
1210
1211         if (maxamp == 0.0f) {
1212                 /* don't even try */
1213                 return;
1214         }
1215
1216         if (maxamp == target) {
1217                 /* we can't do anything useful */
1218                 return;
1219         }
1220
1221         /* compute scale factor */
1222
1223         _scale_amplitude = target/maxamp;
1224
1225         /* tell the diskstream we're in */
1226
1227         boost::shared_ptr<Playlist> pl (playlist());
1228
1229         if (pl) {
1230                 pl->Modified();
1231         }
1232
1233         /* tell everybody else */
1234
1235         send_change (ScaleAmplitudeChanged);
1236 }
1237
1238 void
1239 AudioRegion::fade_in_changed ()
1240 {
1241         send_change (FadeInChanged);
1242 }
1243
1244 void
1245 AudioRegion::fade_out_changed ()
1246 {
1247         send_change (FadeOutChanged);
1248 }
1249
1250 void
1251 AudioRegion::envelope_changed ()
1252 {
1253         send_change (EnvelopeChanged);
1254 }
1255
1256 void
1257 AudioRegion::suspend_fade_in ()
1258 {
1259         if (++_fade_in_disabled == 1) {
1260                 if (fade_in_is_default()) {
1261                         set_fade_in_active (false);
1262                 }
1263         }
1264 }
1265
1266 void
1267 AudioRegion::resume_fade_in ()
1268 {
1269         if (--_fade_in_disabled == 0 && _fade_in_disabled) {
1270                 set_fade_in_active (true);
1271         }
1272 }
1273
1274 void
1275 AudioRegion::suspend_fade_out ()
1276 {
1277         if (++_fade_out_disabled == 1) {
1278                 if (fade_out_is_default()) {
1279                         set_fade_out_active (false);
1280                 }
1281         }
1282 }
1283
1284 void
1285 AudioRegion::resume_fade_out ()
1286 {
1287         if (--_fade_out_disabled == 0 &&_fade_out_disabled) {
1288                 set_fade_out_active (true);
1289         }
1290 }
1291
1292 bool
1293 AudioRegion::speed_mismatch (float sr) const
1294 {
1295         if (_sources.empty()) {
1296                 /* impossible, but ... */
1297                 return false;
1298         }
1299
1300         float fsr = audio_source()->sample_rate();
1301
1302         return fsr != sr;
1303 }
1304
1305 void
1306 AudioRegion::source_offset_changed ()
1307 {
1308         /* XXX this fixes a crash that should not occur. It does occur
1309            becauses regions are not being deleted when a session
1310            is unloaded. That bug must be fixed.
1311         */
1312
1313         if (_sources.empty()) {
1314                 return;
1315         }
1316
1317         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front());
1318
1319         if (afs && afs->destructive()) {
1320                 // set_start (source()->natural_position(), this);
1321                 set_position (source()->natural_position(), this);
1322         }
1323 }
1324
1325 boost::shared_ptr<AudioSource>
1326 AudioRegion::audio_source (uint32_t n) const
1327 {
1328         // Guaranteed to succeed (use a static cast for speed?)
1329         return boost::dynamic_pointer_cast<AudioSource>(source(n));
1330 }
1331
1332 int
1333 AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
1334 {
1335         boost::shared_ptr<Playlist> pl = playlist();
1336
1337         if (!pl) {
1338                 return -1;
1339         }
1340
1341         if (_valid_transients && !force_new) {
1342                 results = _transients;
1343                 return 0;
1344         }
1345
1346         SourceList::iterator s;
1347
1348         for (s = _sources.begin() ; s != _sources.end(); ++s) {
1349                 if (!(*s)->has_been_analysed()) {
1350                         cerr << "For " << name() << " source " << (*s)->name() << " has not been analyzed\n";
1351                         break;
1352                 }
1353         }
1354
1355         if (s == _sources.end()) {
1356                 /* all sources are analyzed, merge data from each one */
1357
1358                 for (s = _sources.begin() ; s != _sources.end(); ++s) {
1359
1360                         /* find the set of transients within the bounds of this region */
1361
1362                         AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
1363                                                                          (*s)->transients.end(),
1364                                                                          _start);
1365
1366                         AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
1367                                                                           (*s)->transients.end(),
1368                                                                           _start + _length);
1369
1370                         /* and add them */
1371
1372                         results.insert (results.end(), low, high);
1373                 }
1374
1375                 TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1376
1377                 /* translate all transients to current position */
1378
1379                 for (AnalysisFeatureList::iterator x = results.begin(); x != results.end(); ++x) {
1380                         (*x) -= _start;
1381                         (*x) += _position;
1382                 }
1383
1384                 _transients = results;
1385                 _valid_transients = true;
1386
1387                 return 0;
1388         }
1389
1390         /* no existing/complete transient info */
1391
1392         if (!Config->get_auto_analyse_audio()) {
1393                 pl->session().Dialog (_("\
1394 You have requested an operation that requires audio analysis.\n\n\
1395 You currently have \"auto-analyse-audio\" disabled, which means\n\
1396 that transient data must be generated every time it is required.\n\n\
1397 If you are doing work that will require transient data on a\n\
1398 regular basis, you should probably enable \"auto-analyse-audio\"\n\
1399 then quit ardour and restart."));
1400         }
1401
1402         TransientDetector t (pl->session().frame_rate());
1403         bool existing_results = !results.empty();
1404
1405         _transients.clear ();
1406         _valid_transients = false;
1407
1408         for (uint32_t i = 0; i < n_channels(); ++i) {
1409
1410                 AnalysisFeatureList these_results;
1411
1412                 t.reset ();
1413
1414                 if (t.run ("", this, i, these_results)) {
1415                         return -1;
1416                 }
1417
1418                 /* translate all transients to give absolute position */
1419
1420                 for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
1421                         (*i) += _position;
1422                 }
1423
1424                 /* merge */
1425
1426                 _transients.insert (_transients.end(), these_results.begin(), these_results.end());
1427         }
1428
1429         if (!results.empty()) {
1430                 if (existing_results) {
1431
1432                         /* merge our transients into the existing ones, then clean up
1433                            those.
1434                         */
1435
1436                         results.insert (results.end(), _transients.begin(), _transients.end());
1437                         TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1438                 }
1439
1440                 /* make sure ours are clean too */
1441
1442                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1443
1444         } else {
1445
1446                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1447                 results = _transients;
1448         }
1449
1450         _valid_transients = true;
1451
1452         return 0;
1453 }
1454
1455 /** Find areas of `silence' within a region.
1456  *
1457  *  @param threshold Threshold below which signal is considered silence (as a sample value)
1458  *  @param min_length Minimum length of silent period to be reported.
1459  *  @return Silent periods; first of pair is the offset within the region, second is the length of the period
1460  */
1461
1462 std::list<std::pair<nframes_t, nframes_t> >
1463 AudioRegion::find_silence (Sample threshold, nframes_t min_length) const
1464 {
1465         nframes_t const block_size = 64 * 1024;
1466         Sample loudest[block_size];
1467         Sample buf[block_size];
1468
1469         nframes_t pos = _start;
1470         nframes_t const end = _start + _length - 1;
1471
1472         std::list<std::pair<nframes_t, nframes_t> > silent_periods;
1473
1474         bool in_silence = false;
1475         nframes_t silence_start = 0;
1476         bool silence;
1477
1478         while (pos < end) {
1479
1480                 /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
1481                 memset (loudest, 0, sizeof (Sample) * block_size);
1482                 for (uint32_t n = 0; n < n_channels(); ++n) {
1483
1484                         read_raw_internal (buf, pos, block_size, n);
1485                         for (nframes_t i = 0; i < block_size; ++i) {
1486                                 loudest[i] = max (loudest[i], abs (buf[i]));
1487                         }
1488                 }
1489
1490                 /* now look for silence */
1491                 for (nframes_t i = 0; i < block_size; ++i) {
1492                         silence = abs (loudest[i]) < threshold;
1493                         if (silence && !in_silence) {
1494                                 /* non-silence to silence */
1495                                 in_silence = true;
1496                                 silence_start = pos + i;
1497                         } else if (!silence && in_silence) {
1498                                 /* silence to non-silence */
1499                                 in_silence = false;
1500                                 if (pos + i - 1 - silence_start >= min_length) {
1501                                         silent_periods.push_back (std::make_pair (silence_start, pos + i - 1));
1502                                 }
1503                         }
1504                 }
1505
1506                 pos += block_size;
1507         }
1508
1509         if (in_silence && end - 1 - silence_start >= min_length) {
1510                 /* last block was silent, so finish off the last period */
1511                 silent_periods.push_back (std::make_pair (silence_start, end));
1512         }
1513
1514         return silent_periods;
1515 }
1516
1517
1518 extern "C" {
1519
1520         int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit)
1521 {
1522         return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (nframes_t) npeaks, (nframes_t) start, (nframes_t) cnt, n_chan,samples_per_unit);
1523 }
1524
1525 uint32_t region_length_from_c (void *arg)
1526 {
1527
1528         return ((AudioRegion *) arg)->length();
1529 }
1530
1531 uint32_t sourcefile_length_from_c (void *arg, double zoom_factor)
1532 {
1533         return ( (AudioRegion *) arg)->audio_source()->available_peaks (zoom_factor) ;
1534 }
1535
1536 } /* extern "C" */