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