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