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