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