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