Add option to normalize across all selected regions. Clean up the region context...
[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 /** @return the maximum (linear) amplitude of the region */
1115 double
1116 AudioRegion::maximum_amplitude () const
1117 {
1118         framepos_t fpos = _start;
1119         framepos_t const fend = _start + _length;
1120         double maxamp = 0;
1121
1122         framecnt_t const blocksize = 64 * 1024;
1123         Sample buf[blocksize];
1124         
1125         while (fpos < fend) {
1126
1127                 uint32_t n;
1128
1129                 framecnt_t const to_read = min (fend - fpos, blocksize);
1130
1131                 for (n = 0; n < n_channels(); ++n) {
1132
1133                         /* read it in */
1134
1135                         if (read_raw_internal (buf, fpos, to_read, 0) != to_read) {
1136                                 return 0;
1137                         }
1138
1139                         maxamp = compute_peak (buf, to_read, maxamp);
1140                 }
1141
1142                 fpos += to_read;
1143         }
1144
1145         return maxamp;
1146 }
1147
1148 /** Normalize using a given maximum amplitude and target, so that region
1149  *  _scale_amplitude becomes target / max_amplitude.
1150  */
1151 void
1152 AudioRegion::normalize (float max_amplitude, float target_dB)
1153 {
1154         gain_t target = dB_to_coefficient (target_dB);
1155
1156         if (target == 1.0f) {
1157                 /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
1158                    that we may have clipped.
1159                 */
1160                 target -= FLT_EPSILON;
1161         }
1162
1163         if (max_amplitude == 0.0f) {
1164                 /* don't even try */
1165                 return;
1166         }
1167
1168         if (max_amplitude == target) {
1169                 /* we can't do anything useful */
1170                 return;
1171         }
1172
1173         set_scale_amplitude (target / max_amplitude);
1174 }
1175
1176 void
1177 AudioRegion::fade_in_changed ()
1178 {
1179         send_change (PropertyChange (Properties::fade_in));
1180 }
1181
1182 void
1183 AudioRegion::fade_out_changed ()
1184 {
1185         send_change (PropertyChange (Properties::fade_out));
1186 }
1187
1188 void
1189 AudioRegion::envelope_changed ()
1190 {
1191         send_change (PropertyChange (Properties::envelope));
1192 }
1193
1194 void
1195 AudioRegion::suspend_fade_in ()
1196 {
1197         if (++_fade_in_suspended == 1) {
1198                 if (fade_in_is_default()) {
1199                         set_fade_in_active (false);
1200                 }
1201         }
1202 }
1203
1204 void
1205 AudioRegion::resume_fade_in ()
1206 {
1207         if (--_fade_in_suspended == 0 && _fade_in_suspended) {
1208                 set_fade_in_active (true);
1209         }
1210 }
1211
1212 void
1213 AudioRegion::suspend_fade_out ()
1214 {
1215         if (++_fade_out_suspended == 1) {
1216                 if (fade_out_is_default()) {
1217                         set_fade_out_active (false);
1218                 }
1219         }
1220 }
1221
1222 void
1223 AudioRegion::resume_fade_out ()
1224 {
1225         if (--_fade_out_suspended == 0 &&_fade_out_suspended) {
1226                 set_fade_out_active (true);
1227         }
1228 }
1229
1230 bool
1231 AudioRegion::speed_mismatch (float sr) const
1232 {
1233         if (_sources.empty()) {
1234                 /* impossible, but ... */
1235                 return false;
1236         }
1237
1238         float fsr = audio_source()->sample_rate();
1239
1240         return fsr != sr;
1241 }
1242
1243 void
1244 AudioRegion::source_offset_changed ()
1245 {
1246         /* XXX this fixes a crash that should not occur. It does occur
1247            becauses regions are not being deleted when a session
1248            is unloaded. That bug must be fixed.
1249         */
1250
1251         if (_sources.empty()) {
1252                 return;
1253         }
1254
1255         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front());
1256
1257         if (afs && afs->destructive()) {
1258                 // set_start (source()->natural_position(), this);
1259                 set_position (source()->natural_position(), this);
1260         }
1261 }
1262
1263 boost::shared_ptr<AudioSource>
1264 AudioRegion::audio_source (uint32_t n) const
1265 {
1266         // Guaranteed to succeed (use a static cast for speed?)
1267         return boost::dynamic_pointer_cast<AudioSource>(source(n));
1268 }
1269
1270 int 
1271 AudioRegion::adjust_transients (nframes64_t delta)
1272 {
1273         for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) {
1274                 (*x) = (*x) + delta;
1275         }
1276         
1277         send_change (PropertyChange (Properties::valid_transients));
1278         
1279         return 0;  
1280
1281
1282 int
1283 AudioRegion::update_transient (nframes64_t old_position, nframes64_t new_position)
1284 {
1285         for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) {
1286                 if ((*x) == old_position) {
1287                         (*x) = new_position;
1288                         send_change (PropertyChange (Properties::valid_transients));
1289                         
1290                         break;
1291                 }
1292         }
1293         
1294         return 0;
1295 }
1296
1297 void
1298 AudioRegion::add_transient (nframes64_t where)
1299 {
1300         _transients.push_back(where);
1301         _valid_transients = true;
1302         
1303         send_change (PropertyChange (Properties::valid_transients));
1304 }
1305
1306 void
1307 AudioRegion::remove_transient (nframes64_t where)
1308 {
1309         _transients.remove(where);
1310         _valid_transients = true;
1311         
1312         send_change (PropertyChange (Properties::valid_transients));
1313 }
1314
1315 int
1316 AudioRegion::set_transients (AnalysisFeatureList& results)
1317 {
1318         _transients.clear();
1319         _transients = results;
1320         _valid_transients = true;
1321         
1322         send_change (PropertyChange (Properties::valid_transients));
1323         
1324         return 0;
1325 }
1326
1327 int
1328 AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
1329 {
1330         boost::shared_ptr<Playlist> pl = playlist();
1331
1332         if (!pl) {
1333                 return -1;
1334         }
1335
1336         if (_valid_transients && !force_new) {
1337                 results = _transients;
1338                 return 0;
1339         }
1340
1341         SourceList::iterator s;
1342
1343         for (s = _sources.begin() ; s != _sources.end(); ++s) {
1344                 if (!(*s)->has_been_analysed()) {
1345                         cerr << "For " << name() << " source " << (*s)->name() << " has not been analyzed\n";
1346                         break;
1347                 }
1348         }
1349
1350         if (s == _sources.end()) {
1351                 /* all sources are analyzed, merge data from each one */
1352
1353                 for (s = _sources.begin() ; s != _sources.end(); ++s) {
1354
1355                         /* find the set of transients within the bounds of this region */
1356
1357                         AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
1358                                                                          (*s)->transients.end(),
1359                                                                          _start);
1360
1361                         AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
1362                                                                           (*s)->transients.end(),
1363                                                                           _start + _length);
1364
1365                         /* and add them */
1366
1367                         results.insert (results.end(), low, high);
1368                 }
1369
1370                 TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1371
1372                 /* translate all transients to current position */
1373
1374                 for (AnalysisFeatureList::iterator x = results.begin(); x != results.end(); ++x) {
1375                         (*x) -= _start;
1376                         (*x) += _position;
1377                 }
1378
1379                 _transients = results;
1380                 _valid_transients = true;
1381
1382                 return 0;
1383         }
1384
1385         /* no existing/complete transient info */
1386
1387         static bool analyse_dialog_shown = false; /* global per instance of Ardour */
1388
1389         if (!Config->get_auto_analyse_audio()) {
1390                 if (!analyse_dialog_shown) {
1391                         pl->session().Dialog (_("\
1392 You have requested an operation that requires audio analysis.\n\n       \
1393 You currently have \"auto-analyse-audio\" disabled, which means\n\
1394 that transient data must be generated every time it is required.\n\n\
1395 If you are doing work that will require transient data on a\n\
1396 regular basis, you should probably enable \"auto-analyse-audio\"\n\
1397 +then quit ardour and restart.\n\n\
1398 +This dialog will not display again.  But you may notice a slight delay\n\
1399 +in this and future transient-detection operations.\n\
1400 +"));
1401                         analyse_dialog_shown = true;
1402                 }
1403         }
1404
1405         TransientDetector t (pl->session().frame_rate());
1406         bool existing_results = !results.empty();
1407
1408         _transients.clear ();
1409         _valid_transients = false;
1410
1411         for (uint32_t i = 0; i < n_channels(); ++i) {
1412
1413                 AnalysisFeatureList these_results;
1414
1415                 t.reset ();
1416
1417                 if (t.run ("", this, i, these_results)) {
1418                         return -1;
1419                 }
1420
1421                 /* translate all transients to give absolute position */
1422
1423                 for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
1424                         (*i) += _position;
1425                 }
1426
1427                 /* merge */
1428
1429                 _transients.insert (_transients.end(), these_results.begin(), these_results.end());
1430         }
1431
1432         if (!results.empty()) {
1433                 if (existing_results) {
1434
1435                         /* merge our transients into the existing ones, then clean up
1436                            those.
1437                         */
1438
1439                         results.insert (results.end(), _transients.begin(), _transients.end());
1440                         TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1441                 }
1442
1443                 /* make sure ours are clean too */
1444
1445                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1446
1447         } else {
1448
1449                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1450                 results = _transients;
1451         }
1452
1453         _valid_transients = true;
1454
1455         return 0;
1456 }
1457
1458 /** Find areas of `silence' within a region.
1459  *
1460  *  @param threshold Threshold below which signal is considered silence (as a sample value)
1461  *  @param min_length Minimum length of silent period to be reported.
1462  *  @return Silent periods; first of pair is the offset within the region, second is the length of the period
1463  */
1464
1465 std::list<std::pair<frameoffset_t, framecnt_t> >
1466 AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadInfo& itt) const
1467 {
1468         framecnt_t const block_size = 64 * 1024;
1469         Sample loudest[block_size];
1470         Sample buf[block_size];
1471
1472         framepos_t pos = _start;
1473         framepos_t const end = _start + _length - 1;
1474
1475         std::list<std::pair<frameoffset_t, framecnt_t> > silent_periods;
1476
1477         bool in_silence = false;
1478         frameoffset_t silence_start = 0;
1479         bool silence;
1480
1481         while (pos < end && !itt.cancel) {
1482
1483                 /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
1484                 memset (loudest, 0, sizeof (Sample) * block_size);
1485                 for (uint32_t n = 0; n < n_channels(); ++n) {
1486
1487                         read_raw_internal (buf, pos, block_size, n);
1488                         for (framecnt_t i = 0; i < block_size; ++i) {
1489                                 loudest[i] = max (loudest[i], abs (buf[i]));
1490                         }
1491                 }
1492
1493                 /* now look for silence */
1494                 for (framecnt_t i = 0; i < block_size; ++i) {
1495                         silence = abs (loudest[i]) < threshold;
1496                         if (silence && !in_silence) {
1497                                 /* non-silence to silence */
1498                                 in_silence = true;
1499                                 silence_start = pos + i;
1500                         } else if (!silence && in_silence) {
1501                                 /* silence to non-silence */
1502                                 in_silence = false;
1503                                 if (pos + i - 1 - silence_start >= min_length) {
1504                                         silent_periods.push_back (std::make_pair (silence_start, pos + i - 1));
1505                                 }
1506                         }
1507                 }
1508
1509                 pos += block_size;
1510                 itt.progress = (end-pos)/(double)_length;
1511         }
1512
1513         if (in_silence && end - 1 - silence_start >= min_length) {
1514                 /* last block was silent, so finish off the last period */
1515                 silent_periods.push_back (std::make_pair (silence_start, end));
1516         }
1517
1518         itt.done = true;
1519
1520         return silent_periods;
1521 }
1522
1523
1524
1525 extern "C" {
1526
1527         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)
1528 {
1529         return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (framecnt_t) npeaks, (framepos_t) start, (framecnt_t) cnt, n_chan,samples_per_unit);
1530 }
1531
1532 uint32_t region_length_from_c (void *arg)
1533 {
1534
1535         return ((AudioRegion *) arg)->length();
1536 }
1537
1538 uint32_t sourcefile_length_from_c (void *arg, double zoom_factor)
1539 {
1540         return ( (AudioRegion *) arg)->audio_source()->available_peaks (zoom_factor) ;
1541 }
1542
1543 } /* extern "C" */