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