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