midway snapshot of work done on managing Region & Source lifetimes correctly. may...
[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                 /* connect only once to HeaderPositionOffsetChanged, even if sources are replicated
267                  */
268
269                 if (unique_srcs.find (*i) == unique_srcs.end ()) {
270                         unique_srcs.insert (*i);
271                         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
272                         if (afs) {
273                                 afs->HeaderPositionOffsetChanged.connect_same_thread (*this, boost::bind (&AudioRegion::source_offset_changed, this));
274                         }
275                 }
276         }
277 }
278
279 void
280 AudioRegion::listen_to_my_curves ()
281 {
282         _envelope->StateChanged.connect_same_thread (*this, boost::bind (&AudioRegion::envelope_changed, this));
283         _fade_in->StateChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fade_in_changed, this));
284         _fade_out->StateChanged.connect_same_thread (*this, boost::bind (&AudioRegion::fade_out_changed, this));
285 }
286
287 void
288 AudioRegion::set_envelope_active (bool yn)
289 {
290         if (envelope_active() != yn) {
291                 _envelope_active = yn;
292                 send_change (PropertyChange (Properties::envelope_active));
293         }
294 }
295
296 ARDOUR::nframes_t
297 AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
298 {
299         if (chan_n >= _sources.size()) {
300                 return 0;
301         }
302
303         if (audio_source(chan_n)->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
304                 return 0;
305         } else {
306                 if (_scale_amplitude != 1.0f) {
307                         for (nframes_t n = 0; n < npeaks; ++n) {
308                                 buf[n].max *= _scale_amplitude;
309                                 buf[n].min *= _scale_amplitude;
310                         }
311                 }
312                 return cnt;
313         }
314 }
315
316 framecnt_t
317 AudioRegion::read (Sample* buf, framepos_t timeline_position, framecnt_t cnt, int channel) const
318 {
319         /* raw read, no fades, no gain, nada */
320         return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, 0, 0, ReadOps (0));
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         LocaleGuard lg (X_("POSIX"));
527
528         snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
529         node.add_property ("channels", buf);
530
531         if (full) {
532                 Stateful::add_properties (node);
533         }
534
535         child = node.add_child ("Envelope");
536
537         if (full) {
538                 bool default_env = false;
539
540                 // If there are only two points, the points are in the start of the region and the end of the region
541                 // so, if they are both at 1.0f, that means the default region.
542
543                 if (_envelope->size() == 2 &&
544                     _envelope->front()->value == 1.0f &&
545                     _envelope->back()->value==1.0f) {
546                         if (_envelope->front()->when == 0 && _envelope->back()->when == _length) {
547                                 default_env = true;
548                         }
549                 }
550
551                 if (default_env) {
552                         child->add_property ("default", "yes");
553                 } else {
554                         child->add_child_nocopy (_envelope->get_state ());
555                 }
556
557         } else {
558                 child->add_property ("default", "yes");
559         }
560
561         return node;
562 }
563
564 int
565 AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_changed, bool send)
566 {
567         const XMLNodeList& nlist = node.children();
568         const XMLProperty *prop;
569         LocaleGuard lg (X_("POSIX"));
570         boost::shared_ptr<Playlist> the_playlist (_playlist.lock());    
571
572         suspend_property_changes ();
573
574         if (the_playlist) {
575                 the_playlist->freeze ();
576         }
577
578
579         /* this will set all our State members and stuff controlled by the Region.
580            It should NOT send any changed signals - that is our responsibility.
581         */
582
583         Region::_set_state (node, version, what_changed, false);
584
585         if ((prop = node.property ("scale-gain")) != 0) {
586                 float a = atof (prop->value().c_str());
587                 if (a != _scale_amplitude) {
588                         _scale_amplitude = a;
589                         what_changed.add (Properties::scale_amplitude);
590                 }
591         }
592
593         /* Now find envelope description and other related child items */
594
595         _envelope->freeze ();
596
597         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
598                 XMLNode *child;
599                 XMLProperty *prop;
600
601                 child = (*niter);
602
603                 if (child->name() == "Envelope") {
604
605                         _envelope->clear ();
606
607                         if ((prop = child->property ("default")) != 0 || _envelope->set_state (*child, version)) {
608                                 set_default_envelope ();
609                         }
610
611                         _envelope->set_max_xval (_length);
612                         _envelope->truncate_end (_length);
613
614
615                 } else if (child->name() == "FadeIn") {
616
617                         _fade_in->clear ();
618
619                         if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
620                                 set_default_fade_in ();
621                         } else {
622                                 XMLNode* grandchild = child->child ("AutomationList");
623                                 if (grandchild) {
624                                         _fade_in->set_state (*grandchild, version);
625                                 }
626                         }
627
628                         if ((prop = child->property ("active")) != 0) {
629                                 if (string_is_affirmative (prop->value())) {
630                                         set_fade_in_active (true);
631                                 } else {
632                                         set_fade_in_active (false);
633                                 }
634                         }
635
636                 } else if (child->name() == "FadeOut") {
637
638                         _fade_out->clear ();
639
640                         if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
641                                 set_default_fade_out ();
642                         } else {
643                                 XMLNode* grandchild = child->child ("AutomationList");
644                                 if (grandchild) {
645                                         _fade_out->set_state (*grandchild, version);
646                                 }
647                         }
648
649                         if ((prop = child->property ("active")) != 0) {
650                                 if (string_is_affirmative (prop->value())) {
651                                         set_fade_out_active (true);
652                                 } else {
653                                         set_fade_out_active (false);
654                                 }
655                         }
656
657                 }
658         }
659
660         _envelope->thaw ();
661         resume_property_changes ();
662         
663         if (send) {
664                 send_change (what_changed);
665         }
666
667         if (the_playlist) {
668                 the_playlist->thaw ();
669         }
670
671         return 0;
672 }
673
674 int
675 AudioRegion::set_state (const XMLNode& node, int version)
676 {
677         PropertyChange what_changed;
678         return _set_state (node, version, what_changed, true);
679 }
680
681 void
682 AudioRegion::set_fade_in_shape (FadeShape shape)
683 {
684         set_fade_in (shape, (nframes_t) _fade_in->back()->when);
685 }
686
687 void
688 AudioRegion::set_fade_out_shape (FadeShape shape)
689 {
690         set_fade_out (shape, (nframes_t) _fade_out->back()->when);
691 }
692
693 void
694 AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
695 {
696         _fade_in->freeze ();
697         *_fade_in = *f;
698         _fade_in->thaw ();
699         
700         send_change (PropertyChange (Properties::fade_in));
701 }
702
703 void
704 AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
705 {
706         _fade_in->freeze ();
707         _fade_in->clear ();
708
709         switch (shape) {
710         case Linear:
711                 _fade_in->fast_simple_add (0.0, 0.0);
712                 _fade_in->fast_simple_add (len, 1.0);
713                 break;
714
715         case Fast:
716                 _fade_in->fast_simple_add (0, 0);
717                 _fade_in->fast_simple_add (len * 0.389401, 0.0333333);
718                 _fade_in->fast_simple_add (len * 0.629032, 0.0861111);
719                 _fade_in->fast_simple_add (len * 0.829493, 0.233333);
720                 _fade_in->fast_simple_add (len * 0.9447, 0.483333);
721                 _fade_in->fast_simple_add (len * 0.976959, 0.697222);
722                 _fade_in->fast_simple_add (len, 1);
723                 break;
724
725         case Slow:
726                 _fade_in->fast_simple_add (0, 0);
727                 _fade_in->fast_simple_add (len * 0.0207373, 0.197222);
728                 _fade_in->fast_simple_add (len * 0.0645161, 0.525);
729                 _fade_in->fast_simple_add (len * 0.152074, 0.802778);
730                 _fade_in->fast_simple_add (len * 0.276498, 0.919444);
731                 _fade_in->fast_simple_add (len * 0.481567, 0.980556);
732                 _fade_in->fast_simple_add (len * 0.767281, 1);
733                 _fade_in->fast_simple_add (len, 1);
734                 break;
735
736         case LogA:
737                 _fade_in->fast_simple_add (0, 0);
738                 _fade_in->fast_simple_add (len * 0.0737327, 0.308333);
739                 _fade_in->fast_simple_add (len * 0.246544, 0.658333);
740                 _fade_in->fast_simple_add (len * 0.470046, 0.886111);
741                 _fade_in->fast_simple_add (len * 0.652074, 0.972222);
742                 _fade_in->fast_simple_add (len * 0.771889, 0.988889);
743                 _fade_in->fast_simple_add (len, 1);
744                 break;
745
746         case LogB:
747                 _fade_in->fast_simple_add (0, 0);
748                 _fade_in->fast_simple_add (len * 0.304147, 0.0694444);
749                 _fade_in->fast_simple_add (len * 0.529954, 0.152778);
750                 _fade_in->fast_simple_add (len * 0.725806, 0.333333);
751                 _fade_in->fast_simple_add (len * 0.847926, 0.558333);
752                 _fade_in->fast_simple_add (len * 0.919355, 0.730556);
753                 _fade_in->fast_simple_add (len, 1);
754                 break;
755         }
756
757         _fade_in->thaw ();
758 }
759
760 void
761 AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
762 {
763         _fade_out->freeze ();
764         *_fade_out = *f;
765         _fade_out->thaw ();
766
767         send_change (PropertyChange (Properties::fade_in));
768 }
769
770 void
771 AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
772 {
773         _fade_out->freeze ();
774         _fade_out->clear ();
775
776         switch (shape) {
777         case Fast:
778                 _fade_out->fast_simple_add (len * 0, 1);
779                 _fade_out->fast_simple_add (len * 0.023041, 0.697222);
780                 _fade_out->fast_simple_add (len * 0.0553,   0.483333);
781                 _fade_out->fast_simple_add (len * 0.170507, 0.233333);
782                 _fade_out->fast_simple_add (len * 0.370968, 0.0861111);
783                 _fade_out->fast_simple_add (len * 0.610599, 0.0333333);
784                 _fade_out->fast_simple_add (len * 1, 0);
785                 break;
786
787         case LogA:
788                 _fade_out->fast_simple_add (len * 0, 1);
789                 _fade_out->fast_simple_add (len * 0.228111, 0.988889);
790                 _fade_out->fast_simple_add (len * 0.347926, 0.972222);
791                 _fade_out->fast_simple_add (len * 0.529954, 0.886111);
792                 _fade_out->fast_simple_add (len * 0.753456, 0.658333);
793                 _fade_out->fast_simple_add (len * 0.9262673, 0.308333);
794                 _fade_out->fast_simple_add (len * 1, 0);
795                 break;
796
797         case Slow:
798                 _fade_out->fast_simple_add (len * 0, 1);
799                 _fade_out->fast_simple_add (len * 0.305556, 1);
800                 _fade_out->fast_simple_add (len * 0.548611, 0.991736);
801                 _fade_out->fast_simple_add (len * 0.759259, 0.931129);
802                 _fade_out->fast_simple_add (len * 0.918981, 0.68595);
803                 _fade_out->fast_simple_add (len * 0.976852, 0.22865);
804                 _fade_out->fast_simple_add (len * 1, 0);
805                 break;
806
807         case LogB:
808                 _fade_out->fast_simple_add (len * 0, 1);
809                 _fade_out->fast_simple_add (len * 0.080645, 0.730556);
810                 _fade_out->fast_simple_add (len * 0.277778, 0.289256);
811                 _fade_out->fast_simple_add (len * 0.470046, 0.152778);
812                 _fade_out->fast_simple_add (len * 0.695853, 0.0694444);
813                 _fade_out->fast_simple_add (len * 1, 0);
814                 break;
815
816         case Linear:
817                 _fade_out->fast_simple_add (len * 0, 1);
818                 _fade_out->fast_simple_add (len * 1, 0);
819                 break;
820         }
821
822         _fade_out->thaw ();
823 }
824
825 void
826 AudioRegion::set_fade_in_length (framecnt_t len)
827 {
828         if (len > _length) {
829                 len = _length - 1;
830         }
831
832         bool changed = _fade_in->extend_to (len);
833
834         if (changed) {
835                 _default_fade_in = false;
836                 send_change (PropertyChange (Properties::fade_in));
837         }
838 }
839
840 void
841 AudioRegion::set_fade_out_length (framecnt_t len)
842 {
843         if (len > _length) {
844                 len = _length - 1;
845         }
846
847         bool changed =  _fade_out->extend_to (len);
848
849         if (changed) {
850                 _default_fade_out = false;
851                 send_change (PropertyChange (Properties::fade_out));
852         }
853 }
854
855 void
856 AudioRegion::set_fade_in_active (bool yn)
857 {
858         if (yn == _fade_in_active) {
859                 return;
860         }
861
862         _fade_in_active = yn;
863         send_change (PropertyChange (Properties::fade_in_active));
864 }
865
866 void
867 AudioRegion::set_fade_out_active (bool yn)
868 {
869         if (yn == _fade_out_active) {
870                 return;
871         }
872         _fade_out_active = yn;
873         send_change (PropertyChange (Properties::fade_out_active));
874 }
875
876 bool
877 AudioRegion::fade_in_is_default () const
878 {
879         return _fade_in->size() == 2 && _fade_in->front()->when == 0 && _fade_in->back()->when == 64;
880 }
881
882 bool
883 AudioRegion::fade_out_is_default () const
884 {
885         return _fade_out->size() == 2 && _fade_out->front()->when == 0 && _fade_out->back()->when == 64;
886 }
887
888 void
889 AudioRegion::set_default_fade_in ()
890 {
891         _fade_in_suspended = 0;
892         set_fade_in (Linear, 64);
893 }
894
895 void
896 AudioRegion::set_default_fade_out ()
897 {
898         _fade_out_suspended = 0;
899         set_fade_out (Linear, 64);
900 }
901
902 void
903 AudioRegion::set_default_fades ()
904 {
905         set_default_fade_in ();
906         set_default_fade_out ();
907 }
908
909 void
910 AudioRegion::set_default_envelope ()
911 {
912         _envelope->freeze ();
913         _envelope->clear ();
914         _envelope->fast_simple_add (0, 1.0f);
915         _envelope->fast_simple_add (_length, 1.0f);
916         _envelope->thaw ();
917 }
918
919 void
920 AudioRegion::recompute_at_end ()
921 {
922         /* our length has changed. recompute a new final point by interpolating
923            based on the the existing curve.
924         */
925
926         _envelope->freeze ();
927         _envelope->truncate_end (_length);
928         _envelope->set_max_xval (_length);
929         _envelope->thaw ();
930
931         if (_left_of_split) {
932                 set_default_fade_out ();
933                 _left_of_split = false;
934         } else if (_fade_out->back()->when > _length) {
935                 _fade_out->extend_to (_length);
936                 send_change (PropertyChange (Properties::fade_out));
937         }
938         
939         if (_fade_in->back()->when > _length) {
940                 _fade_in->extend_to (_length);
941                 send_change (PropertyChange (Properties::fade_in));
942         }
943 }
944
945 void
946 AudioRegion::recompute_at_start ()
947 {
948         /* as above, but the shift was from the front */
949
950         _envelope->truncate_start (_length);
951
952         if (_right_of_split) {
953                 set_default_fade_in ();
954                 _right_of_split = false;
955         } else if (_fade_in->back()->when > _length) {
956                 _fade_in->extend_to (_length);
957                 send_change (PropertyChange (Properties::fade_in));
958         }
959
960         if (_fade_out->back()->when > _length) {
961                 _fade_out->extend_to (_length);
962                 send_change (PropertyChange (Properties::fade_out));
963         }
964 }
965
966 int
967 AudioRegion::separate_by_channel (Session& /*session*/, vector<boost::shared_ptr<Region> >& v) const
968 {
969         SourceList srcs;
970         string new_name;
971         int n = 0;
972
973         if (_sources.size() < 2) {
974                 return 0;
975         }
976
977         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
978                 srcs.clear ();
979                 srcs.push_back (*i);
980
981                 new_name = _name;
982
983                 if (_sources.size() == 2) {
984                         if (n == 0) {
985                                 new_name += "-L";
986                         } else {
987                                 new_name += "-R";
988                         }
989                 } else {
990                         new_name += '-';
991                         new_name += ('0' + n + 1);
992                 }
993
994                 /* create a copy with just one source. prevent if from being thought of as
995                    "whole file" even if it covers the entire source file(s).
996                  */
997
998                 PropertyList plist;
999                 
1000                 plist.add (Properties::start, _start.val());
1001                 plist.add (Properties::length, _length.val());
1002                 plist.add (Properties::name, new_name);
1003                 plist.add (Properties::layer, _layer.val());
1004
1005                 v.push_back(RegionFactory::create (srcs, plist));
1006                 v.back()->set_whole_file (false);
1007
1008                 ++n;
1009         }
1010
1011         return 0;
1012 }
1013
1014 framecnt_t
1015 AudioRegion::read_raw_internal (Sample* buf, framepos_t pos, framecnt_t cnt, int channel) const
1016 {
1017         return audio_source()->read (buf, pos, cnt, channel);
1018 }
1019
1020 int
1021 AudioRegion::exportme (Session& /*session*/, ARDOUR::ExportSpecification& /*spec*/)
1022 {
1023         // TODO EXPORT
1024 //      const nframes_t blocksize = 4096;
1025 //      nframes_t to_read;
1026 //      int status = -1;
1027 //
1028 //      spec.channels = _sources.size();
1029 //
1030 //      if (spec.prepare (blocksize, session.frame_rate())) {
1031 //              goto out;
1032 //      }
1033 //
1034 //      spec.pos = 0;
1035 //      spec.total_frames = _length;
1036 //
1037 //      while (spec.pos < _length && !spec.stop) {
1038 //
1039 //
1040 //              /* step 1: interleave */
1041 //
1042 //              to_read = min (_length - spec.pos, blocksize);
1043 //
1044 //              if (spec.channels == 1) {
1045 //
1046 //                      if (read_raw_internal (spec.dataF, _start + spec.pos, to_read) != to_read) {
1047 //                              goto out;
1048 //                      }
1049 //
1050 //              } else {
1051 //
1052 //                      Sample buf[blocksize];
1053 //
1054 //                      for (uint32_t chan = 0; chan < spec.channels; ++chan) {
1055 //
1056 //                              if (audio_source(chan)->read (buf, _start + spec.pos, to_read) != to_read) {
1057 //                                      goto out;
1058 //                              }
1059 //
1060 //                              for (nframes_t x = 0; x < to_read; ++x) {
1061 //                                      spec.dataF[chan+(x*spec.channels)] = buf[x];
1062 //                              }
1063 //                      }
1064 //              }
1065 //
1066 //              if (spec.process (to_read)) {
1067 //                      goto out;
1068 //              }
1069 //
1070 //              spec.pos += to_read;
1071 //              spec.progress = (double) spec.pos /_length;
1072 //
1073 //      }
1074 //
1075 //      status = 0;
1076 //
1077 //  out:
1078 //      spec.running = false;
1079 //      spec.status = status;
1080 //      spec.clear();
1081 //
1082 //      return status;
1083         return 0;
1084 }
1085
1086 void
1087 AudioRegion::set_scale_amplitude (gain_t g)
1088 {
1089         boost::shared_ptr<Playlist> pl (playlist());
1090
1091         _scale_amplitude = g;
1092
1093         /* tell the diskstream we're in */
1094
1095         if (pl) {
1096                 pl->ContentsChanged();
1097         }
1098
1099         /* tell everybody else */
1100
1101         send_change (PropertyChange (Properties::scale_amplitude));
1102 }
1103
1104 void
1105 AudioRegion::normalize_to (float target_dB)
1106 {
1107         const framecnt_t blocksize = 64 * 1024;
1108         Sample buf[blocksize];
1109         framepos_t fpos;
1110         framepos_t fend;
1111         framecnt_t to_read;
1112         double maxamp = 0;
1113         gain_t target = dB_to_coefficient (target_dB);
1114
1115         if (target == 1.0f) {
1116                 /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
1117                    that we may have clipped.
1118                 */
1119                 target -= FLT_EPSILON;
1120         }
1121
1122         fpos = _start;
1123         fend = _start + _length;
1124
1125         /* first pass: find max amplitude */
1126
1127         while (fpos < fend) {
1128
1129                 uint32_t n;
1130
1131                 to_read = min (fend - fpos, blocksize);
1132
1133                 for (n = 0; n < n_channels(); ++n) {
1134
1135                         /* read it in */
1136
1137                         if (read_raw_internal (buf, fpos, to_read, 0) != to_read) {
1138                                 return;
1139                         }
1140
1141                         maxamp = compute_peak (buf, to_read, maxamp);
1142                 }
1143
1144                 fpos += to_read;
1145         };
1146
1147         if (maxamp == 0.0f) {
1148                 /* don't even try */
1149                 return;
1150         }
1151
1152         if (maxamp == target) {
1153                 /* we can't do anything useful */
1154                 return;
1155         }
1156
1157         /* compute scale factor */
1158
1159         _scale_amplitude = target/maxamp;
1160
1161         /* tell the diskstream we're in */
1162
1163         boost::shared_ptr<Playlist> pl (playlist());
1164
1165         if (pl) {
1166                 pl->ContentsChanged();
1167         }
1168
1169         /* tell everybody else */
1170
1171         send_change (PropertyChange (Properties::scale_amplitude));
1172 }
1173
1174 void
1175 AudioRegion::fade_in_changed ()
1176 {
1177         send_change (PropertyChange (Properties::fade_in));
1178 }
1179
1180 void
1181 AudioRegion::fade_out_changed ()
1182 {
1183         send_change (PropertyChange (Properties::fade_out));
1184 }
1185
1186 void
1187 AudioRegion::envelope_changed ()
1188 {
1189         send_change (PropertyChange (Properties::envelope));
1190 }
1191
1192 void
1193 AudioRegion::suspend_fade_in ()
1194 {
1195         if (++_fade_in_suspended == 1) {
1196                 if (fade_in_is_default()) {
1197                         set_fade_in_active (false);
1198                 }
1199         }
1200 }
1201
1202 void
1203 AudioRegion::resume_fade_in ()
1204 {
1205         if (--_fade_in_suspended == 0 && _fade_in_suspended) {
1206                 set_fade_in_active (true);
1207         }
1208 }
1209
1210 void
1211 AudioRegion::suspend_fade_out ()
1212 {
1213         if (++_fade_out_suspended == 1) {
1214                 if (fade_out_is_default()) {
1215                         set_fade_out_active (false);
1216                 }
1217         }
1218 }
1219
1220 void
1221 AudioRegion::resume_fade_out ()
1222 {
1223         if (--_fade_out_suspended == 0 &&_fade_out_suspended) {
1224                 set_fade_out_active (true);
1225         }
1226 }
1227
1228 bool
1229 AudioRegion::speed_mismatch (float sr) const
1230 {
1231         if (_sources.empty()) {
1232                 /* impossible, but ... */
1233                 return false;
1234         }
1235
1236         float fsr = audio_source()->sample_rate();
1237
1238         return fsr != sr;
1239 }
1240
1241 void
1242 AudioRegion::source_offset_changed ()
1243 {
1244         /* XXX this fixes a crash that should not occur. It does occur
1245            becauses regions are not being deleted when a session
1246            is unloaded. That bug must be fixed.
1247         */
1248
1249         if (_sources.empty()) {
1250                 return;
1251         }
1252
1253         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front());
1254
1255         if (afs && afs->destructive()) {
1256                 // set_start (source()->natural_position(), this);
1257                 set_position (source()->natural_position(), this);
1258         }
1259 }
1260
1261 boost::shared_ptr<AudioSource>
1262 AudioRegion::audio_source (uint32_t n) const
1263 {
1264         // Guaranteed to succeed (use a static cast for speed?)
1265         return boost::dynamic_pointer_cast<AudioSource>(source(n));
1266 }
1267
1268 int
1269 AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
1270 {
1271         boost::shared_ptr<Playlist> pl = playlist();
1272
1273         if (!pl) {
1274                 return -1;
1275         }
1276
1277         if (_valid_transients && !force_new) {
1278                 results = _transients;
1279                 return 0;
1280         }
1281
1282         SourceList::iterator s;
1283
1284         for (s = _sources.begin() ; s != _sources.end(); ++s) {
1285                 if (!(*s)->has_been_analysed()) {
1286                         cerr << "For " << name() << " source " << (*s)->name() << " has not been analyzed\n";
1287                         break;
1288                 }
1289         }
1290
1291         if (s == _sources.end()) {
1292                 /* all sources are analyzed, merge data from each one */
1293
1294                 for (s = _sources.begin() ; s != _sources.end(); ++s) {
1295
1296                         /* find the set of transients within the bounds of this region */
1297
1298                         AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
1299                                                                          (*s)->transients.end(),
1300                                                                          _start);
1301
1302                         AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
1303                                                                           (*s)->transients.end(),
1304                                                                           _start + _length);
1305
1306                         /* and add them */
1307
1308                         results.insert (results.end(), low, high);
1309                 }
1310
1311                 TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1312
1313                 /* translate all transients to current position */
1314
1315                 for (AnalysisFeatureList::iterator x = results.begin(); x != results.end(); ++x) {
1316                         (*x) -= _start;
1317                         (*x) += _position;
1318                 }
1319
1320                 _transients = results;
1321                 _valid_transients = true;
1322
1323                 return 0;
1324         }
1325
1326         /* no existing/complete transient info */
1327
1328         static bool analyse_dialog_shown = false; /* global per instance of Ardour */
1329
1330         if (!Config->get_auto_analyse_audio()) {
1331                 if (!analyse_dialog_shown) {
1332                         pl->session().Dialog (_("\
1333 You have requested an operation that requires audio analysis.\n\n       \
1334 You currently have \"auto-analyse-audio\" disabled, which means\n\
1335 that transient data must be generated every time it is required.\n\n\
1336 If you are doing work that will require transient data on a\n\
1337 regular basis, you should probably enable \"auto-analyse-audio\"\n\
1338 +then quit ardour and restart.\n\n\
1339 +This dialog will not display again.  But you may notice a slight delay\n\
1340 +in this and future transient-detection operations.\n\
1341 +"));
1342                         analyse_dialog_shown = true;
1343                 }
1344         }
1345
1346         TransientDetector t (pl->session().frame_rate());
1347         bool existing_results = !results.empty();
1348
1349         _transients.clear ();
1350         _valid_transients = false;
1351
1352         for (uint32_t i = 0; i < n_channels(); ++i) {
1353
1354                 AnalysisFeatureList these_results;
1355
1356                 t.reset ();
1357
1358                 if (t.run ("", this, i, these_results)) {
1359                         return -1;
1360                 }
1361
1362                 /* translate all transients to give absolute position */
1363
1364                 for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
1365                         (*i) += _position;
1366                 }
1367
1368                 /* merge */
1369
1370                 _transients.insert (_transients.end(), these_results.begin(), these_results.end());
1371         }
1372
1373         if (!results.empty()) {
1374                 if (existing_results) {
1375
1376                         /* merge our transients into the existing ones, then clean up
1377                            those.
1378                         */
1379
1380                         results.insert (results.end(), _transients.begin(), _transients.end());
1381                         TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
1382                 }
1383
1384                 /* make sure ours are clean too */
1385
1386                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1387
1388         } else {
1389
1390                 TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
1391                 results = _transients;
1392         }
1393
1394         _valid_transients = true;
1395
1396         return 0;
1397 }
1398
1399 /** Find areas of `silence' within a region.
1400  *
1401  *  @param threshold Threshold below which signal is considered silence (as a sample value)
1402  *  @param min_length Minimum length of silent period to be reported.
1403  *  @return Silent periods; first of pair is the offset within the region, second is the length of the period
1404  */
1405
1406 std::list<std::pair<frameoffset_t, framecnt_t> >
1407 AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadInfo& itt) const
1408 {
1409         framecnt_t const block_size = 64 * 1024;
1410         Sample loudest[block_size];
1411         Sample buf[block_size];
1412
1413         framepos_t pos = _start;
1414         framepos_t const end = _start + _length - 1;
1415
1416         std::list<std::pair<frameoffset_t, framecnt_t> > silent_periods;
1417
1418         bool in_silence = false;
1419         frameoffset_t silence_start = 0;
1420         bool silence;
1421
1422         while (pos < end && !itt.cancel) {
1423
1424                 /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
1425                 memset (loudest, 0, sizeof (Sample) * block_size);
1426                 for (uint32_t n = 0; n < n_channels(); ++n) {
1427
1428                         read_raw_internal (buf, pos, block_size, n);
1429                         for (framecnt_t i = 0; i < block_size; ++i) {
1430                                 loudest[i] = max (loudest[i], abs (buf[i]));
1431                         }
1432                 }
1433
1434                 /* now look for silence */
1435                 for (framecnt_t i = 0; i < block_size; ++i) {
1436                         silence = abs (loudest[i]) < threshold;
1437                         if (silence && !in_silence) {
1438                                 /* non-silence to silence */
1439                                 in_silence = true;
1440                                 silence_start = pos + i;
1441                         } else if (!silence && in_silence) {
1442                                 /* silence to non-silence */
1443                                 in_silence = false;
1444                                 if (pos + i - 1 - silence_start >= min_length) {
1445                                         silent_periods.push_back (std::make_pair (silence_start, pos + i - 1));
1446                                 }
1447                         }
1448                 }
1449
1450                 pos += block_size;
1451                 itt.progress = (end-pos)/(double)_length;
1452         }
1453
1454         if (in_silence && end - 1 - silence_start >= min_length) {
1455                 /* last block was silent, so finish off the last period */
1456                 silent_periods.push_back (std::make_pair (silence_start, end));
1457         }
1458
1459         itt.done = true;
1460
1461         return silent_periods;
1462 }
1463
1464
1465
1466 extern "C" {
1467
1468         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)
1469 {
1470         return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (framecnt_t) npeaks, (framepos_t) start, (framecnt_t) cnt, n_chan,samples_per_unit);
1471 }
1472
1473 uint32_t region_length_from_c (void *arg)
1474 {
1475
1476         return ((AudioRegion *) arg)->length();
1477 }
1478
1479 uint32_t sourcefile_length_from_c (void *arg, double zoom_factor)
1480 {
1481         return ( (AudioRegion *) arg)->audio_source()->available_peaks (zoom_factor) ;
1482 }
1483
1484 } /* extern "C" */