Don't raise an error when trying to auto-connect master to physical outputs if the...
[ardour.git] / libs / ardour / audioregion.cc
index 085296281cebc8d9d477c1d6f66784092de34efc..2c6c9fc0aaf2a63a00d2f7ceea2290ce234fdd4a 100644 (file)
@@ -73,7 +73,7 @@ AudioRegion::init ()
        set_default_envelope ();
 
        listen_to_my_curves ();
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
 }
 
 /** Constructor for use by derived types only */
@@ -85,6 +85,7 @@ AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string
        , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
 {
        init ();
+       assert (_sources.size() == _master_sources.size());
 }
 
 /** Basic AudioRegion constructor (one channel) */
@@ -101,6 +102,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
        }
 
        init ();
+       assert (_sources.size() == _master_sources.size());
 }
 
 /* Basic AudioRegion constructor (one channel) */
@@ -117,6 +119,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
        }
 
        init ();
+       assert (_sources.size() == _master_sources.size());
 }
 
 /** Basic AudioRegion constructor (many channels) */
@@ -128,7 +131,8 @@ AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t len
        , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
 {
        init ();
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
+       assert (_sources.size() == _master_sources.size());
 }
 
 /** Create a new AudioRegion, that is part of an existing one */
@@ -139,22 +143,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
        , _fade_out (new AutomationList(*other->_fade_out))
        , _envelope (new AutomationList(*other->_envelope, offset, offset + length))
 {
-       set<boost::shared_ptr<Source> > unique_srcs;
-
-       for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
-               _sources.push_back (*i);
-
-               pair<set<boost::shared_ptr<Source> >::iterator,bool> result;
-
-               result = unique_srcs.insert (*i);
-               
-               if (result.second) {
-                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
-                       if (afs) {
-                               afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
-                       }
-               }
-       }
+       connect_to_header_position_offset_changed ();
 
        /* return to default fades if the existing ones are too long */
 
@@ -183,7 +172,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
        assert(_type == DataType::AUDIO);
        
        listen_to_my_curves ();
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
+
+       assert (_sources.size() == _master_sources.size());
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
@@ -199,10 +190,12 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        set_default_fades ();
 
        listen_to_my_curves ();
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
+
+       assert (_sources.size() == _master_sources.size());
 }
 
-AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const SourceList& srcs,
+AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const SourceList& /*srcs*/,
                          nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (other, length, name, layer, flags)
        , _automatable (other->session())
@@ -212,12 +205,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const Sour
 {
        /* make-a-sort-of-copy-with-different-sources constructor (used by audio filter) */
 
-       set<boost::shared_ptr<AudioSource> > unique_srcs;
-
-       for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
-
-               _sources.push_back (*i);
-               _master_sources.push_back (*i);
+       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
 
                boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> ((*i));
                if (afs) {
@@ -231,7 +219,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const Sour
        _fade_out_disabled = 0;
 
        listen_to_my_curves ();
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
+
+       assert (_sources.size() == _master_sources.size());
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
@@ -253,7 +243,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
        }
 
        assert(_type == DataType::AUDIO);
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
+
+       assert (_sources.size() == _master_sources.size());
 }
 
 AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
@@ -270,7 +262,8 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
        }
 
        assert(_type == DataType::AUDIO);
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
+       assert (_sources.size() == _master_sources.size());
 }
 
 AudioRegion::~AudioRegion ()
@@ -278,13 +271,30 @@ AudioRegion::~AudioRegion ()
 }
 
 void
-AudioRegion::listen_to_my_sources ()
+AudioRegion::connect_to_analysis_changed ()
 {
        for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
                (*i)->AnalysisChanged.connect (mem_fun (*this, &AudioRegion::invalidate_transients));
        }
 }
 
+void
+AudioRegion::connect_to_header_position_offset_changed ()
+{
+       set<boost::shared_ptr<Source> > unique_srcs;
+
+       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+
+               if (unique_srcs.find (*i) == unique_srcs.end ()) {
+                       unique_srcs.insert (*i);
+                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
+                       if (afs) {
+                               afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+                       }
+               }
+       }
+}
+
 void
 AudioRegion::listen_to_my_curves ()
 {
@@ -363,12 +373,12 @@ AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_bu
 }
 
 nframes_t
-AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
+AudioRegion::_read_at (const SourceList& /*srcs*/, nframes_t limit,
                Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
                sframes_t position, nframes_t cnt, 
                uint32_t chan_n, 
-               nframes_t read_frames
-               nframes_t skip_frames,
+               nframes_t /*read_frames*/
+               nframes_t /*skip_frames*/,
                ReadOps rops) const
 {
        nframes_t internal_offset;
@@ -434,7 +444,7 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
        
                /* fade in */
 
-               if ((_flags & FadeIn) && Config->get_use_region_fades()) {
+               if ((_flags & FadeIn) && _session.config.get_use_region_fades()) {
                        
                        nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
                        
@@ -457,7 +467,7 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
                
                /* fade out */
                
-               if ((_flags & FadeOut) && Config->get_use_region_fades()) {
+               if ((_flags & FadeOut) && _session.config.get_use_region_fades()) {
 
                        /* see if some part of this read is within the fade out */
                        
@@ -645,6 +655,14 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
                _flags = Flag (_flags & ~Region::RightOfSplit);
        }
 
+       /* leave this flag setting in place, no matter what */
+
+       if ((old_flags & DoNotSendPropertyChanges)) {
+               _flags = Flag (_flags | DoNotSendPropertyChanges);
+       }
+
+       /* find out if any flags changed that we signal about */
+
        if ((old_flags ^ _flags) & Muted) {
                what_changed = Change (what_changed|MuteChanged);
        }
@@ -950,20 +968,20 @@ AudioRegion::fade_out_is_default () const
 void
 AudioRegion::set_default_fade_in ()
 {
+       _fade_in_disabled = 0;
        set_fade_in (Linear, 64);
 }
 
 void
 AudioRegion::set_default_fade_out ()
 {
+       _fade_out_disabled = 0;
        set_fade_out (Linear, 64);
 }
 
 void
 AudioRegion::set_default_fades ()
 {
-       _fade_in_disabled = 0;
-       _fade_out_disabled = 0;
        set_default_fade_in ();
        set_default_fade_out ();
 }
@@ -1020,7 +1038,7 @@ AudioRegion::recompute_at_start ()
 }
 
 int
-AudioRegion::separate_by_channel (Session& session, vector<boost::shared_ptr<Region> >& v) const
+AudioRegion::separate_by_channel (Session& /*session*/, vector<boost::shared_ptr<Region> >& v) const
 {
        SourceList srcs;
        string new_name;
@@ -1062,13 +1080,13 @@ AudioRegion::separate_by_channel (Session& session, vector<boost::shared_ptr<Reg
 }
 
 nframes_t
-AudioRegion::read_raw_internal (Sample* buf, sframes_t pos, nframes_t cnt) const
+AudioRegion::read_raw_internal (Sample* buf, sframes_t pos, nframes_t cnt, int channel) const
 {
-       return audio_source()->read  (buf, pos, cnt);
+       return audio_source()->read (buf, pos, cnt, channel);
 }
 
 int
-AudioRegion::exportme (Session& session, ARDOUR::ExportSpecification& spec)
+AudioRegion::exportme (Session& /*session*/, ARDOUR::ExportSpecification& /*spec*/)
 {
        // TODO EXPORT
 //     const nframes_t blocksize = 4096;
@@ -1184,7 +1202,7 @@ AudioRegion::normalize_to (float target_dB)
 
                        /* read it in */
 
-                       if (read_raw_internal (buf, fpos, to_read) != to_read) {
+                       if (read_raw_internal (buf, fpos, to_read, 0) != to_read) {
                                return;
                        }
                        
@@ -1438,6 +1456,69 @@ then quit ardour and restart."));
        return 0;
 }
 
+/** Find areas of `silence' within a region.
+ *
+ *  @param threshold Threshold below which signal is considered silence (as a sample value)
+ *  @param min_length Minimum length of silent period to be reported.
+ *  @return Silent periods; first of pair is the offset within the region, second is the length of the period
+ */
+
+std::list<std::pair<nframes_t, nframes_t> >
+AudioRegion::find_silence (Sample threshold, nframes_t min_length) const
+{
+       nframes_t const block_size = 64 * 1024;
+       Sample loudest[block_size];
+       Sample buf[block_size];
+       
+       nframes_t pos = _start;
+       nframes_t const end = _start + _length - 1;
+
+       std::list<std::pair<nframes_t, nframes_t> > silent_periods;
+
+       bool in_silence = false;
+       nframes_t silence_start = 0;
+       bool silence;
+
+       while (pos < end) {
+
+               /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
+               memset (loudest, 0, sizeof (Sample) * block_size);
+               for (uint32_t n = 0; n < n_channels(); ++n) {
+
+                       read_raw_internal (buf, pos, block_size, n);
+                       for (nframes_t i = 0; i < block_size; ++i) {
+                               loudest[i] = max (loudest[i], abs (buf[i]));
+                       }
+               }
+
+               /* now look for silence */
+               for (nframes_t i = 0; i < block_size; ++i) {
+                       silence = abs (loudest[i]) < threshold;
+                       if (silence && !in_silence) {
+                               /* non-silence to silence */
+                               in_silence = true;
+                               silence_start = pos + i;
+                       } else if (!silence && in_silence) {
+                               /* silence to non-silence */
+                               in_silence = false;
+                               if (pos + i - 1 - silence_start >= min_length) {
+                                       silent_periods.push_back (std::make_pair (silence_start, pos + i - 1));
+                               }
+                       }
+               }
+
+               pos += block_size;
+       }
+
+       if (in_silence && end - 1 - silence_start >= min_length) {
+               /* last block was silent, so finish off the last period */
+               silent_periods.push_back (std::make_pair (silence_start, end));
+       }
+
+       return silent_periods;
+}
+
+
 extern "C" {
 
        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)