change PropertyChange from a bitfield into a real object, with all the many widesprea...
[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                         cerr << _name << " envelope changd\n";
629                 
630
631                 } else if (child->name() == "FadeIn") {
632
633                         _fade_in->clear ();
634
635                         if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
636                                 set_default_fade_in ();
637                         } else {
638                                 XMLNode* grandchild = child->child ("AutomationList");
639                                 if (grandchild) {
640                                         _fade_in->set_state (*grandchild, version);
641                                 }
642                         }
643
644                         if ((prop = child->property ("active")) != 0) {
645                                 if (string_is_affirmative (prop->value())) {
646                                         set_fade_in_active (true);
647                                 } else {
648                                         set_fade_in_active (false);
649                                 }
650                         }
651                         cerr << _name << " fadein changd\n";
652
653                 } else if (child->name() == "FadeOut") {
654
655                         _fade_out->clear ();
656
657                         if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
658                                 set_default_fade_out ();
659                         } else {
660                                 XMLNode* grandchild = child->child ("AutomationList");
661                                 if (grandchild) {
662                                         _fade_out->set_state (*grandchild, version);
663                                 }
664                         }
665
666                         if ((prop = child->property ("active")) != 0) {
667                                 if (string_is_affirmative (prop->value())) {
668                                         set_fade_out_active (true);
669                                 } else {
670                                         set_fade_out_active (false);
671                                 }
672                         }
673                         cerr << _name << " fadeout changd\n";
674
675                 }
676         }
677
678         _envelope->thaw ();
679         thaw ();
680
681         if (send) {
682                 send_change (what_changed);
683         }
684
685         if (the_playlist) {
686                 the_playlist->thaw ();
687         }
688
689         return 0;
690 }
691
692 bool
693 AudioRegion::set_property (const PropertyBase& prop)
694 {
695         DEBUG_TRACE (DEBUG::Properties,  string_compose ("audio region %1 set property %2\n", _name.val(), prop.property_name()));
696
697         if (prop == Properties::envelope_active.id) {
698                 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
699                 if (val != _envelope_active) {
700                         _envelope_active = val;
701                         return true;
702                 }
703         } else if (prop == Properties::default_fade_in.id) {
704                 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
705                 if (val != _default_fade_in) {
706                         _default_fade_in = val;
707                         return true;
708                 }
709         } else if (prop == Properties::default_fade_out.id) {
710                 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
711                 if (val != _default_fade_out) {
712                         _default_fade_out = val;
713                         return true;
714                 }
715         } else if (prop == Properties::fade_in_active.id) {
716                 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
717                 if (val != _fade_in_active) {
718                         _fade_in_active = val;
719                         return true;
720                 }
721         } else if (prop == Properties::fade_out_active.id) {
722                 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
723                 if (val != _fade_out_active) {
724                         _fade_out_active = val;
725                         return true;
726                 }
727         } else if (prop == Properties::scale_amplitude.id) {
728                 gain_t val = dynamic_cast<const PropertyTemplate<gain_t>*>(&prop)->val();
729                 if (val != _scale_amplitude) {
730                         _scale_amplitude = val;
731                         return true;
732                 }
733         } else {
734                 return Region::set_property (prop);
735         }
736         
737         return false;
738 }
739
740 int
741 AudioRegion::set_state (const XMLNode& node, int version)
742 {
743         PropertyChange what_changed;
744         return _set_state (node, version, what_changed, true);
745 }
746
747 void
748 AudioRegion::set_fade_in_shape (FadeShape shape)
749 {
750         set_fade_in (shape, (nframes_t) _fade_in->back()->when);
751 }
752
753 void
754 AudioRegion::set_fade_out_shape (FadeShape shape)
755 {
756         set_fade_out (shape, (nframes_t) _fade_out->back()->when);
757 }
758
759 void
760 AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
761 {
762         _fade_in->freeze ();
763         *_fade_in = *f;
764         _fade_in->thaw ();
765         
766         send_change (PropertyChange (Properties::fade_in));
767 }
768
769 void
770 AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
771 {
772         _fade_in->freeze ();
773         _fade_in->clear ();
774
775         switch (shape) {
776         case Linear:
777                 _fade_in->fast_simple_add (0.0, 0.0);
778                 _fade_in->fast_simple_add (len, 1.0);
779                 break;
780
781         case Fast:
782                 _fade_in->fast_simple_add (0, 0);
783                 _fade_in->fast_simple_add (len * 0.389401, 0.0333333);
784                 _fade_in->fast_simple_add (len * 0.629032, 0.0861111);
785                 _fade_in->fast_simple_add (len * 0.829493, 0.233333);
786                 _fade_in->fast_simple_add (len * 0.9447, 0.483333);
787                 _fade_in->fast_simple_add (len * 0.976959, 0.697222);
788                 _fade_in->fast_simple_add (len, 1);
789                 break;
790
791         case Slow:
792                 _fade_in->fast_simple_add (0, 0);
793                 _fade_in->fast_simple_add (len * 0.0207373, 0.197222);
794                 _fade_in->fast_simple_add (len * 0.0645161, 0.525);
795                 _fade_in->fast_simple_add (len * 0.152074, 0.802778);
796                 _fade_in->fast_simple_add (len * 0.276498, 0.919444);
797                 _fade_in->fast_simple_add (len * 0.481567, 0.980556);
798                 _fade_in->fast_simple_add (len * 0.767281, 1);
799                 _fade_in->fast_simple_add (len, 1);
800                 break;
801
802         case LogA:
803                 _fade_in->fast_simple_add (0, 0);
804                 _fade_in->fast_simple_add (len * 0.0737327, 0.308333);
805                 _fade_in->fast_simple_add (len * 0.246544, 0.658333);
806                 _fade_in->fast_simple_add (len * 0.470046, 0.886111);
807                 _fade_in->fast_simple_add (len * 0.652074, 0.972222);
808                 _fade_in->fast_simple_add (len * 0.771889, 0.988889);
809                 _fade_in->fast_simple_add (len, 1);
810                 break;
811
812         case LogB:
813                 _fade_in->fast_simple_add (0, 0);
814                 _fade_in->fast_simple_add (len * 0.304147, 0.0694444);
815                 _fade_in->fast_simple_add (len * 0.529954, 0.152778);
816                 _fade_in->fast_simple_add (len * 0.725806, 0.333333);
817                 _fade_in->fast_simple_add (len * 0.847926, 0.558333);
818                 _fade_in->fast_simple_add (len * 0.919355, 0.730556);
819                 _fade_in->fast_simple_add (len, 1);
820                 break;
821         }
822
823         _fade_in->thaw ();
824 }
825
826 void
827 AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
828 {
829         _fade_out->freeze ();
830         *_fade_out = *f;
831         _fade_out->thaw ();
832
833         send_change (PropertyChange (Properties::fade_in));
834 }
835
836 void
837 AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
838 {
839         _fade_out->freeze ();
840         _fade_out->clear ();
841
842         switch (shape) {
843         case Fast:
844                 _fade_out->fast_simple_add (len * 0, 1);
845                 _fade_out->fast_simple_add (len * 0.023041, 0.697222);
846                 _fade_out->fast_simple_add (len * 0.0553,   0.483333);
847                 _fade_out->fast_simple_add (len * 0.170507, 0.233333);
848                 _fade_out->fast_simple_add (len * 0.370968, 0.0861111);
849                 _fade_out->fast_simple_add (len * 0.610599, 0.0333333);
850                 _fade_out->fast_simple_add (len * 1, 0);
851                 break;
852
853         case LogA:
854                 _fade_out->fast_simple_add (len * 0, 1);
855                 _fade_out->fast_simple_add (len * 0.228111, 0.988889);
856                 _fade_out->fast_simple_add (len * 0.347926, 0.972222);
857                 _fade_out->fast_simple_add (len * 0.529954, 0.886111);
858                 _fade_out->fast_simple_add (len * 0.753456, 0.658333);
859                 _fade_out->fast_simple_add (len * 0.9262673, 0.308333);
860                 _fade_out->fast_simple_add (len * 1, 0);
861                 break;
862
863         case Slow:
864                 _fade_out->fast_simple_add (len * 0, 1);
865                 _fade_out->fast_simple_add (len * 0.305556, 1);
866                 _fade_out->fast_simple_add (len * 0.548611, 0.991736);
867                 _fade_out->fast_simple_add (len * 0.759259, 0.931129);
868                 _fade_out->fast_simple_add (len * 0.918981, 0.68595);
869                 _fade_out->fast_simple_add (len * 0.976852, 0.22865);
870                 _fade_out->fast_simple_add (len * 1, 0);
871                 break;
872
873         case LogB:
874                 _fade_out->fast_simple_add (len * 0, 1);
875                 _fade_out->fast_simple_add (len * 0.080645, 0.730556);
876                 _fade_out->fast_simple_add (len * 0.277778, 0.289256);
877                 _fade_out->fast_simple_add (len * 0.470046, 0.152778);
878                 _fade_out->fast_simple_add (len * 0.695853, 0.0694444);
879                 _fade_out->fast_simple_add (len * 1, 0);
880                 break;
881
882         case Linear:
883                 _fade_out->fast_simple_add (len * 0, 1);
884                 _fade_out->fast_simple_add (len * 1, 0);
885                 break;
886         }
887
888         _fade_out->thaw ();
889 }
890
891 void
892 AudioRegion::set_fade_in_length (framecnt_t len)
893 {
894         if (len > _length) {
895                 len = _length - 1;
896         }
897
898         bool changed = _fade_in->extend_to (len);
899
900         if (changed) {
901                 _default_fade_in = false;
902                 send_change (PropertyChange (Properties::fade_in));
903         }
904 }
905
906 void
907 AudioRegion::set_fade_out_length (framecnt_t len)
908 {
909         if (len > _length) {
910                 len = _length - 1;
911         }
912
913         bool changed =  _fade_out->extend_to (len);
914
915         if (changed) {
916                 _default_fade_out = false;
917                 send_change (PropertyChange (Properties::fade_out));
918         }
919 }
920
921 void
922 AudioRegion::set_fade_in_active (bool yn)
923 {
924         if (yn == _fade_in_active) {
925                 return;
926         }
927
928         _fade_in_active = yn;
929         send_change (PropertyChange (Properties::fade_in_active));
930 }
931
932 void
933 AudioRegion::set_fade_out_active (bool yn)
934 {
935         if (yn == _fade_out_active) {
936                 return;
937         }
938         _fade_out_active = yn;
939         send_change (PropertyChange (Properties::fade_out_active));
940 }
941
942 bool
943 AudioRegion::fade_in_is_default () const
944 {
945         return _fade_in->size() == 2 && _fade_in->front()->when == 0 && _fade_in->back()->when == 64;
946 }
947
948 bool
949 AudioRegion::fade_out_is_default () const
950 {
951         return _fade_out->size() == 2 && _fade_out->front()->when == 0 && _fade_out->back()->when == 64;
952 }
953
954 void
955 AudioRegion::set_default_fade_in ()
956 {
957         _fade_in_suspended = 0;
958         set_fade_in (Linear, 64);
959 }
960
961 void
962 AudioRegion::set_default_fade_out ()
963 {
964         _fade_out_suspended = 0;
965         set_fade_out (Linear, 64);
966 }
967
968 void
969 AudioRegion::set_default_fades ()
970 {
971         set_default_fade_in ();
972         set_default_fade_out ();
973 }
974
975 void
976 AudioRegion::set_default_envelope ()
977 {
978         _envelope->freeze ();
979         _envelope->clear ();
980         _envelope->fast_simple_add (0, 1.0f);
981         _envelope->fast_simple_add (_length, 1.0f);
982         _envelope->thaw ();
983 }
984
985 void
986 AudioRegion::recompute_at_end ()
987 {
988         /* our length has changed. recompute a new final point by interpolating
989            based on the the existing curve.
990         */
991
992         _envelope->freeze ();
993         _envelope->truncate_end (_length);
994         _envelope->set_max_xval (_length);
995         _envelope->thaw ();
996
997         if (_fade_in->back()->when > _length) {
998                 _fade_in->extend_to (_length);
999                 send_change (PropertyChange (Properties::fade_in));
1000         }
1001
1002         if (_fade_out->back()->when > _length) {
1003                 _fade_out->extend_to (_length);
1004                 send_change (PropertyChange (Properties::fade_out));
1005         }
1006 }
1007
1008 void
1009 AudioRegion::recompute_at_start ()
1010 {
1011         /* as above, but the shift was from the front */
1012
1013         _envelope->truncate_start (_length);
1014
1015         if (_fade_in->back()->when > _length) {
1016                 _fade_in->extend_to (_length);
1017                 send_change (PropertyChange (Properties::fade_in));
1018         }
1019
1020         if (_fade_out->back()->when > _length) {
1021                 _fade_out->extend_to (_length);
1022                 send_change (PropertyChange (Properties::fade_out));
1023         }
1024 }
1025
1026 int
1027 AudioRegion::separate_by_channel (Session& /*session*/, vector<boost::shared_ptr<Region> >& v) const
1028 {
1029         SourceList srcs;
1030         string new_name;
1031         int n = 0;
1032
1033         if (_sources.size() < 2) {
1034                 return 0;
1035         }
1036
1037         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1038                 srcs.clear ();
1039                 srcs.push_back (*i);
1040
1041                 new_name = _name;
1042
1043                 if (_sources.size() == 2) {
1044                         if (n == 0) {
1045                                 new_name += "-L";
1046                         } else {
1047                                 new_name += "-R";
1048                         }
1049                 } else {
1050                         new_name += '-';
1051                         new_name += ('0' + n + 1);
1052                 }
1053
1054                 /* create a copy with just one source. prevent if from being thought of as
1055                    "whole file" even if it covers the entire source file(s).
1056                  */
1057
1058                 PropertyList plist;
1059                 
1060                 plist.add (Properties::start, _start.val());
1061                 plist.add (Properties::length, _length.val());
1062                 plist.add (Properties::name, new_name);
1063                 plist.add (Properties::layer, _layer.val());
1064
1065                 v.push_back(RegionFactory::create (srcs, plist));
1066                 v.back()->set_whole_file (false);
1067
1068                 ++n;
1069         }
1070
1071         return 0;
1072 }
1073
1074 framecnt_t
1075 AudioRegion::read_raw_internal (Sample* buf, framepos_t pos, framecnt_t cnt, int channel) const
1076 {
1077         return audio_source()->read (buf, pos, cnt, channel);
1078 }
1079
1080 int
1081 AudioRegion::exportme (Session& /*session*/, ARDOUR::ExportSpecification& /*spec*/)
1082 {
1083         // TODO EXPORT
1084 //      const nframes_t blocksize = 4096;
1085 //      nframes_t to_read;
1086 //      int status = -1;
1087 //
1088 //      spec.channels = _sources.size();
1089 //
1090 //      if (spec.prepare (blocksize, session.frame_rate())) {
1091 //              goto out;
1092 //      }
1093 //
1094 //      spec.pos = 0;
1095 //      spec.total_frames = _length;
1096 //
1097 //      while (spec.pos < _length && !spec.stop) {
1098 //
1099 //
1100 //              /* step 1: interleave */
1101 //
1102 //              to_read = min (_length - spec.pos, blocksize);
1103 //
1104 //              if (spec.channels == 1) {
1105 //
1106 //                      if (read_raw_internal (spec.dataF, _start + spec.pos, to_read) != to_read) {
1107 //                              goto out;
1108 //                      }
1109 //
1110 //              } else {
1111 //
1112 //                      Sample buf[blocksize];
1113 //
1114 //                      for (uint32_t chan = 0; chan < spec.channels; ++chan) {
1115 //
1116 //                              if (audio_source(chan)->read (buf, _start + spec.pos, to_read) != to_read) {
1117 //                                      goto out;
1118 //                              }
1119 //
1120 //                              for (nframes_t x = 0; x < to_read; ++x) {
1121 //                                      spec.dataF[chan+(x*spec.channels)] = buf[x];
1122 //                              }
1123 //                      }
1124 //              }
1125 //
1126 //              if (spec.process (to_read)) {
1127 //                      goto out;
1128 //              }
1129 //
1130 //              spec.pos += to_read;
1131 //              spec.progress = (double) spec.pos /_length;
1132 //
1133 //      }
1134 //
1135 //      status = 0;
1136 //
1137 //  out:
1138 //      spec.running = false;
1139 //      spec.status = status;
1140 //      spec.clear();
1141 //
1142 //      return status;
1143         return 0;
1144 }
1145
1146 void
1147 AudioRegion::set_scale_amplitude (gain_t g)
1148 {
1149         boost::shared_ptr<Playlist> pl (playlist());
1150
1151         _scale_amplitude = g;
1152
1153         /* tell the diskstream we're in */
1154
1155         if (pl) {
1156                 pl->ContentsChanged();
1157         }
1158
1159         /* tell everybody else */
1160
1161         send_change (PropertyChange (Properties::scale_amplitude));
1162 }
1163
1164 void
1165 AudioRegion::normalize_to (float target_dB)
1166 {
1167         const framecnt_t blocksize = 64 * 1024;
1168         Sample buf[blocksize];
1169         framepos_t fpos;
1170         framepos_t fend;
1171         framecnt_t to_read;
1172         double maxamp = 0;
1173         gain_t target = dB_to_coefficient (target_dB);
1174
1175         if (target == 1.0f) {
1176                 /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
1177                    that we may have clipped.
1178                 */
1179                 target -= FLT_EPSILON;
1180         }
1181
1182         fpos = _start;
1183         fend = _start + _length;
1184
1185         /* first pass: find max amplitude */
1186
1187         while (fpos < fend) {
1188
1189                 uint32_t n;
1190
1191                 to_read = min (fend - fpos, blocksize);
1192
1193                 for (n = 0; n < n_channels(); ++n) {
1194
1195                         /* read it in */
1196
1197                         if (read_raw_internal (buf, fpos, to_read, 0) != to_read) {
1198                                 return;
1199                         }
1200
1201                         maxamp = compute_peak (buf, to_read, maxamp);
1202                 }
1203
1204                 fpos += to_read;
1205         };
1206
1207         if (maxamp == 0.0f) {
1208                 /* don't even try */
1209                 return;
1210         }
1211
1212         if (maxamp == target) {
1213                 /* we can't do anything useful */
1214                 return;
1215         }
1216
1217         /* compute scale factor */
1218
1219         _scale_amplitude = target/maxamp;
1220
1221         /* tell the diskstream we're in */
1222
1223         boost::shared_ptr<Playlist> pl (playlist());
1224
1225         if (pl) {
1226                 pl->ContentsChanged();
1227         }
1228
1229         /* tell everybody else */
1230
1231         send_change (PropertyChange (Properties::scale_amplitude));
1232 }
1233
1234 void
1235 AudioRegion::fade_in_changed ()
1236 {
1237         send_change (PropertyChange (Properties::fade_in));
1238 }
1239
1240 void
1241 AudioRegion::fade_out_changed ()
1242 {
1243         send_change (PropertyChange (Properties::fade_out));
1244 }
1245
1246 void
1247 AudioRegion::envelope_changed ()
1248 {
1249         send_change (PropertyChange (Properties::envelope));
1250 }
1251
1252 void
1253 AudioRegion::suspend_fade_in ()
1254 {
1255         if (++_fade_in_suspended == 1) {
1256                 if (fade_in_is_default()) {
1257                         set_fade_in_active (false);
1258                 }
1259         }
1260 }
1261
1262 void
1263 AudioRegion::resume_fade_in ()
1264 {
1265         if (--_fade_in_suspended == 0 && _fade_in_suspended) {
1266                 set_fade_in_active (true);
1267         }
1268 }
1269
1270 void
1271 AudioRegion::suspend_fade_out ()
1272 {
1273         if (++_fade_out_suspended == 1) {
1274                 if (fade_out_is_default()) {
1275                         set_fade_out_active (false);
1276                 }
1277         }
1278 }
1279
1280 void
1281 AudioRegion::resume_fade_out ()
1282 {
1283         if (--_fade_out_suspended == 0 &&_fade_out_suspended) {
1284                 set_fade_out_active (true);
1285         }
1286 }
1287
1288 bool
1289 AudioRegion::speed_mismatch (float sr) const
1290 {
1291         if (_sources.empty()) {
1292                 /* impossible, but ... */
1293                 return false;
1294         }
1295
1296         float fsr = audio_source()->sample_rate();
1297
1298         return fsr != sr;
1299 }
1300
1301 void
1302 AudioRegion::source_offset_changed ()
1303 {
1304         /* XXX this fixes a crash that should not occur. It does occur
1305            becauses regions are not being deleted when a session
1306            is unloaded. That bug must be fixed.
1307         */
1308
1309         if (_sources.empty()) {
1310                 return;
1311         }
1312
1313         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front());
1314
1315         if (afs && afs->destructive()) {
1316                 // set_start (source()->natural_position(), this);
1317                 set_position (source()->natural_position(), this);
1318         }
1319 }
1320
1321 boost::shared_ptr<AudioSource>
1322 AudioRegion::audio_source (uint32_t n) const
1323 {
1324         // Guaranteed to succeed (use a static cast for speed?)
1325         return boost::dynamic_pointer_cast<AudioSource>(source(n));
1326 }
1327
1328 int
1329 AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
1330 {
1331         boost::shared_ptr<Playlist> pl = playlist();
1332
1333         if (!pl) {
1334                 return -1;
1335         }
1336
1337         if (_valid_transients && !force_new) {
1338                 results = _transients;
1339                 return 0;
1340         }
1341
1342         SourceList::iterator s;
1343
1344         for (s = _sources.begin() ; s != _sources.end(); ++s) {
1345                 if (!(*s)->has_been_analysed()) {
1346                         cerr << "For " << name() << " source " << (*s)->name() << " has not been analyzed\n";
1347                         break;
1348                 }
1349         }
1350
1351         if (s == _sources.end()) {
1352                 /* all sources are analyzed, merge data from each one */
1353
1354                 for (s = _sources.begin() ; s != _sources.end(); ++s) {
1355
1356                         /* find the set of transients within the bounds of this region */
1357
1358                         AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
1359                                                                          (*s)->transients.end(),
1360                                                                          _start);
1361
1362                         AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
1363                                                                           (*s)->transients.end(),
1364                                                                           _start + _length);
1365
1366                         /* and add them */
1367
1368                         results.insert (results.end(), low, high);
1369                 }
1370
1371                 TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1372
1373                 /* translate all transients to current position */
1374
1375                 for (AnalysisFeatureList::iterator x = results.begin(); x != results.end(); ++x) {
1376                         (*x) -= _start;
1377                         (*x) += _position;
1378                 }
1379
1380                 _transients = results;
1381                 _valid_transients = true;
1382
1383                 return 0;
1384         }
1385
1386         /* no existing/complete transient info */
1387
1388         if (!Config->get_auto_analyse_audio()) {
1389                 pl->session().Dialog (_("\
1390 You have requested an operation that requires audio analysis.\n\n\
1391 You currently have \"auto-analyse-audio\" disabled, which means\n\
1392 that transient data must be generated every time it is required.\n\n\
1393 If you are doing work that will require transient data on a\n\
1394 regular basis, you should probably enable \"auto-analyse-audio\"\n\
1395 then quit ardour and restart."));
1396         }
1397
1398         TransientDetector t (pl->session().frame_rate());
1399         bool existing_results = !results.empty();
1400
1401         _transients.clear ();
1402         _valid_transients = false;
1403
1404         for (uint32_t i = 0; i < n_channels(); ++i) {
1405
1406                 AnalysisFeatureList these_results;
1407
1408                 t.reset ();
1409
1410                 if (t.run ("", this, i, these_results)) {
1411                         return -1;
1412                 }
1413
1414                 /* translate all transients to give absolute position */
1415
1416                 for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
1417                         (*i) += _position;
1418                 }
1419
1420                 /* merge */
1421
1422                 _transients.insert (_transients.end(), these_results.begin(), these_results.end());
1423         }
1424
1425         if (!results.empty()) {
1426                 if (existing_results) {
1427
1428                         /* merge our transients into the existing ones, then clean up
1429                            those.
1430                         */
1431
1432                         results.insert (results.end(), _transients.begin(), _transients.end());
1433                         TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1434                 }
1435
1436                 /* make sure ours are clean too */
1437
1438                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1439
1440         } else {
1441
1442                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1443                 results = _transients;
1444         }
1445
1446         _valid_transients = true;
1447
1448         return 0;
1449 }
1450
1451 /** Find areas of `silence' within a region.
1452  *
1453  *  @param threshold Threshold below which signal is considered silence (as a sample value)
1454  *  @param min_length Minimum length of silent period to be reported.
1455  *  @return Silent periods; first of pair is the offset within the region, second is the length of the period
1456  */
1457
1458 std::list<std::pair<frameoffset_t, framecnt_t> >
1459 AudioRegion::find_silence (Sample threshold, framecnt_t min_length) const
1460 {
1461         framecnt_t const block_size = 64 * 1024;
1462         Sample loudest[block_size];
1463         Sample buf[block_size];
1464
1465         framepos_t pos = _start;
1466         framepos_t const end = _start + _length - 1;
1467
1468         std::list<std::pair<frameoffset_t, framecnt_t> > silent_periods;
1469
1470         bool in_silence = false;
1471         frameoffset_t silence_start = 0;
1472         bool silence;
1473
1474         while (pos < end) {
1475
1476                 /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
1477                 memset (loudest, 0, sizeof (Sample) * block_size);
1478                 for (uint32_t n = 0; n < n_channels(); ++n) {
1479
1480                         read_raw_internal (buf, pos, block_size, n);
1481                         for (framecnt_t i = 0; i < block_size; ++i) {
1482                                 loudest[i] = max (loudest[i], abs (buf[i]));
1483                         }
1484                 }
1485
1486                 /* now look for silence */
1487                 for (framecnt_t i = 0; i < block_size; ++i) {
1488                         silence = abs (loudest[i]) < threshold;
1489                         if (silence && !in_silence) {
1490                                 /* non-silence to silence */
1491                                 in_silence = true;
1492                                 silence_start = pos + i;
1493                         } else if (!silence && in_silence) {
1494                                 /* silence to non-silence */
1495                                 in_silence = false;
1496                                 if (pos + i - 1 - silence_start >= min_length) {
1497                                         silent_periods.push_back (std::make_pair (silence_start, pos + i - 1));
1498                                 }
1499                         }
1500                 }
1501
1502                 pos += block_size;
1503         }
1504
1505         if (in_silence && end - 1 - silence_start >= min_length) {
1506                 /* last block was silent, so finish off the last period */
1507                 silent_periods.push_back (std::make_pair (silence_start, end));
1508         }
1509
1510         return silent_periods;
1511 }
1512
1513
1514
1515 extern "C" {
1516
1517         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)
1518 {
1519         return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (framecnt_t) npeaks, (framepos_t) start, (framecnt_t) cnt, n_chan,samples_per_unit);
1520 }
1521
1522 uint32_t region_length_from_c (void *arg)
1523 {
1524
1525         return ((AudioRegion *) arg)->length();
1526 }
1527
1528 uint32_t sourcefile_length_from_c (void *arg, double zoom_factor)
1529 {
1530         return ( (AudioRegion *) arg)->audio_source()->available_peaks (zoom_factor) ;
1531 }
1532
1533 } /* extern "C" */