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