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