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