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