Fix some unused parameter warnings.
[ardour.git] / libs / ardour / audioregion.cc
index c5c04bc33df0ad9d4f839e9fbe4baff3166ee271..89c0c3a3ccdcfe24daa05d37e570b6d80e3c8077 100644 (file)
 
 #include <glibmm/thread.h>
 
-#include <pbd/basename.h>
-#include <pbd/xml++.h>
-#include <pbd/stacktrace.h>
-#include <pbd/enumwriter.h>
-#include <pbd/convert.h>
-
-#include <ardour/audioregion.h>
-#include <ardour/session.h>
-#include <ardour/gain.h>
-#include <ardour/dB.h>
-#include <ardour/playlist.h>
-#include <ardour/audiofilesource.h>
-#include <ardour/region_factory.h>
-#include <ardour/runtime_functions.h>
-#include <ardour/transient_detector.h>
+#include "pbd/basename.h"
+#include "pbd/xml++.h"
+#include "pbd/stacktrace.h"
+#include "pbd/enumwriter.h"
+#include "pbd/convert.h"
+
+#include "evoral/Curve.hpp"
+
+#include "ardour/audioregion.h"
+#include "ardour/session.h"
+#include "ardour/gain.h"
+#include "ardour/dB.h"
+#include "ardour/playlist.h"
+#include "ardour/audiofilesource.h"
+#include "ardour/region_factory.h"
+#include "ardour/runtime_functions.h"
+#include "ardour/transient_detector.h"
 
 #include "i18n.h"
 #include <locale.h>
@@ -71,10 +73,10 @@ AudioRegion::init ()
        set_default_envelope ();
 
        listen_to_my_curves ();
-       listen_to_my_sources ();
+       connect_to_analysis_changed ();
 }
 
-/* constructor for use by derived types only */
+/** Constructor for use by derived types only */
 AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string name)
        : Region (s, start, length, name, DataType::AUDIO)
        , _automatable(s)
@@ -83,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) */
@@ -99,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) */
@@ -115,9 +119,10 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
        }
 
        init ();
+       assert (_sources.size() == _master_sources.size());
 }
 
-/* Basic AudioRegion constructor (many channels) */
+/** Basic AudioRegion constructor (many channels) */
 AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
        , _automatable(srcs[0]->session())
@@ -126,36 +131,21 @@ 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 */
 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (other, offset, length, name, layer, flags)
        , _automatable(other->session())
-       , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
-       , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
-       , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
+       , _fade_in (new AutomationList(*other->_fade_in))
+       , _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 */
-       init ();
 
        if (_flags & LeftOfSplit) {
                if (_fade_in->back()->when >= _length) {
@@ -180,24 +170,58 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
        _scale_amplitude = other->_scale_amplitude;
 
        assert(_type == DataType::AUDIO);
-       listen_to_my_sources ();
+       
+       listen_to_my_curves ();
+       connect_to_analysis_changed ();
+
+       assert (_sources.size() == _master_sources.size());
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        : Region (other)
-       , _automatable(other->session())
-       , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
-       , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
-       , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
+       , _automatable (other->session())
+       , _fade_in (new AutomationList (*other->_fade_in))
+       , _fade_out (new AutomationList (*other->_fade_out))
+       , _envelope (new AutomationList (*other->_envelope))
 {
        assert(_type == DataType::AUDIO);
        _scale_amplitude = other->_scale_amplitude;
-       _envelope = other->_envelope;
 
        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*/,
+                         nframes_t length, const string& name, layer_t layer, Flag flags)
+       : Region (other, length, name, layer, flags)
+       , _automatable (other->session())
+       , _fade_in (new AutomationList (*other->_fade_in))
+       , _fade_out (new AutomationList (*other->_fade_out))
+       , _envelope (new AutomationList (*other->_envelope))
+{
+       /* make-a-sort-of-copy-with-different-sources constructor (used by audio filter) */
+
+       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+
+               boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> ((*i));
+               if (afs) {
+                       afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+               }
+       }
+
+       _scale_amplitude = other->_scale_amplitude;
+
+       _fade_in_disabled = 0;
+       _fade_out_disabled = 0;
+
+       listen_to_my_curves ();
+       connect_to_analysis_changed ();
+
+       assert (_sources.size() == _master_sources.size());
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
@@ -219,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)
@@ -236,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 ()
@@ -244,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 ()
 {
@@ -295,41 +339,52 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
        }
 }
 
-nframes64_t
-AudioRegion::read (Sample* buf, nframes64_t position, nframes64_t cnt, int channel) const
+nframes_t
+AudioRegion::read (Sample* buf, sframes_t timeline_position, nframes_t cnt, int channel) const
 {
        /* raw read, no fades, no gain, nada */
-       return _read_at (_sources, _length, buf, 0, 0, _position + position, cnt, channel, 0, 0, true);
+       return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, 0, 0, ReadOps (0));
+}
+
+nframes_t
+AudioRegion::read_with_ops (Sample* buf, sframes_t file_position, nframes_t cnt, int channel, ReadOps rops) const
+{
+       return _read_at (_sources, _length, buf, 0, 0, file_position, cnt, channel, 0, 0, rops);
 }
 
 nframes_t
-AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, 
-                     nframes_t cnt, 
-                     uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
+AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
+               sframes_t file_position, nframes_t cnt, uint32_t chan_n,
+               nframes_t read_frames, nframes_t skip_frames) const
 {
        /* regular diskstream/butler read complete with fades etc */
-       return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false);
+       return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer,
+                       file_position, cnt, chan_n, read_frames, skip_frames, ReadOps (~0));
 }
 
 nframes_t
-AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, 
-                            nframes_t cnt, uint32_t chan_n) const
+AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
+               sframes_t position, nframes_t cnt, uint32_t chan_n) const
 {
-       return _read_at (_master_sources, _master_sources.front()->length(), buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
+       /* do not read gain/scaling/fades and do not count this disk i/o in statistics */
+
+       return _read_at (_master_sources, _master_sources.front()->length(_master_sources.front()->timeline_position()), 
+                        buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0, ReadOps (0));
 }
 
 nframes_t
-AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
-                      Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
-                      nframes_t position, nframes_t cnt, 
-                      uint32_t chan_n, 
-                      nframes_t read_frames
-                      nframes_t skip_frames,
-                      bool raw) const
+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*/,
+               ReadOps rops) const
 {
        nframes_t internal_offset;
        nframes_t buf_offset;
        nframes_t to_read;
+       bool raw = (rops == ReadOpsNone);
 
        if (muted() && !raw) {
                return 0; /* read nothing */
@@ -361,7 +416,7 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
                mixdown_buffer += buf_offset;
        }
 
-       if (!raw) {
+       if (rops & ReadOpsCount) {
                _read_data_count = 0;
        }
 
@@ -372,7 +427,7 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
                        return 0; /* "read nothing" */
                }
                
-               if (!raw) {
+               if (rops & ReadOpsCount) {
                        _read_data_count += src->read_data_count();
                }
 
@@ -383,19 +438,13 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
                */
 
                memset (mixdown_buffer, 0, sizeof (Sample) * cnt);
-
-               /* no fades required */
-
-               if (!raw) {
-                       goto merge;
-               }
        }
 
-       /* fade in */
-
-       if (!raw) {
+       if (rops & ReadOpsFades) {
        
-               if ((_flags & FadeIn) && Config->get_use_region_fades()) {
+               /* fade in */
+
+               if ((_flags & FadeIn) && _session.config.get_use_region_fades()) {
                        
                        nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
                        
@@ -407,6 +456,7 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
                                
                                fi_limit = min (to_read, fade_in_length - internal_offset);
                                
+
                                _fade_in->curve().get_vector (internal_offset, internal_offset+fi_limit, gain_buffer, fi_limit);
                                
                                for (nframes_t n = 0; n < fi_limit; ++n) {
@@ -417,17 +467,17 @@ 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 */
                        
                /* .................        >|            REGION
-                                           limit
+                                            limit
                                            
                                  {           }            FADE
                                             fade_out_length
                                  ^                                          
-                                limit - fade_out_length
+                                 limit - fade_out_length
                         |--------------|
                         ^internal_offset
                                        ^internal_offset + to_read
@@ -457,39 +507,43 @@ AudioRegion::_read_at (const SourceList& srcs, nframes_t limit,
                        } 
                        
                }
+       }
                
-               /* Regular gain curves */
-               
-               if (envelope_active())  {
-                       _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
+       /* Regular gain curves and scaling */
+       
+       if ((rops & ReadOpsOwnAutomation) && envelope_active())  {
+               _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
                        
-                       if (_scale_amplitude != 1.0f) {
-                               for (nframes_t n = 0; n < to_read; ++n) {
-                                       mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
-                               }
-                       } else {
-                               for (nframes_t n = 0; n < to_read; ++n) {
-                                       mixdown_buffer[n] *= gain_buffer[n];
-                               }
+               if ((rops & ReadOpsOwnScaling) && _scale_amplitude != 1.0f) {
+                       for (nframes_t n = 0; n < to_read; ++n) {
+                               mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
                        }
-               } else if (_scale_amplitude != 1.0f) {
-                       apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
+               } else {
+                       for (nframes_t n = 0; n < to_read; ++n) {
+                               mixdown_buffer[n] *= gain_buffer[n];
+                       }
+               }
+       } else if ((rops & ReadOpsOwnScaling) && _scale_amplitude != 1.0f) {
+
+               // XXX this should be using what in 2.0 would have been: 
+               // Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
+
+               for (nframes_t n = 0; n < to_read; ++n) {
+                       mixdown_buffer[n] *= _scale_amplitude;
                }
+       }
        
-         merge:
+       if (!opaque()) {
                
-               if (!opaque()) {
-                       
-                       /* gack. the things we do for users.
-                        */
-                       
-                       buf += buf_offset;
+               /* gack. the things we do for users.
+                */
+               
+               buf += buf_offset;
                        
-                       for (nframes_t n = 0; n < to_read; ++n) {
-                               buf[n] += mixdown_buffer[n];
-                       }
-               } 
-       }
+               for (nframes_t n = 0; n < to_read; ++n) {
+                       buf[n] += mixdown_buffer[n];
+               }
+       } 
 
        return to_read;
 }
@@ -601,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);
        }
@@ -976,20 +1038,17 @@ AudioRegion::recompute_at_start ()
 }
 
 int
-AudioRegion::separate_by_channel (Session& session, vector<boost::shared_ptr<AudioRegion> >& v) const
+AudioRegion::separate_by_channel (Session& /*session*/, vector<boost::shared_ptr<Region> >& v) const
 {
        SourceList srcs;
        string new_name;
-       int n;
+       int n = 0;
 
        if (_sources.size() < 2) {
                return 0;
        }
 
-       n = 0;
-
        for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
-
                srcs.clear ();
                srcs.push_back (*i);
 
@@ -1006,16 +1065,13 @@ AudioRegion::separate_by_channel (Session& session, vector<boost::shared_ptr<Aud
                        new_name += ('0' + n + 1);
                }
 
-               /* create a copy with just one source. prevent if from being thought of as "whole file" even if 
-                  it covers the entire source file(s).
+               /* create a copy with just one source. prevent if from being thought of as
+                  "whole file" even if it covers the entire source file(s).
                 */
 
                Flag f = Flag (_flags & ~WholeFile);
 
-               boost::shared_ptr<Region> r = RegionFactory::create (srcs, _start, _length, new_name, _layer, f);
-               boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
-
-               v.push_back (ar);
+               v.push_back(RegionFactory::create (srcs, _start, _length, new_name, _layer, f));
                
                ++n;
        }
@@ -1024,13 +1080,13 @@ AudioRegion::separate_by_channel (Session& session, vector<boost::shared_ptr<Aud
 }
 
 nframes_t
-AudioRegion::read_raw_internal (Sample* buf, nframes_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;
@@ -1146,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;
                        }
                        
@@ -1400,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)