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