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