fixes from chris cannam for rb_effect bugs
[ardour.git] / libs / ardour / audioregion.cc
index fd39e0563687e65aefb7faf4b1302e64409fea01..b6c1a131de124474121bbf0ecce64129b27174cd 100644 (file)
@@ -80,12 +80,12 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
        }
 
        _scale_amplitude = 1.0;
-       valid_transients = false;
 
        set_default_fades ();
        set_default_envelope ();
 
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
@@ -106,12 +106,12 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
        }
 
        _scale_amplitude = 1.0;
-       valid_transients = false;
 
        set_default_fades ();
        set_default_envelope ();
 
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
@@ -134,12 +134,12 @@ AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t len
        }
 
        _scale_amplitude = 1.0;
-       valid_transients = false;
 
        set_default_fades ();
        set_default_envelope ();
 
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 
@@ -203,9 +203,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
        }
 
        _scale_amplitude = other->_scale_amplitude;
-       valid_transients = false;
 
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
@@ -241,13 +241,13 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        }
 
        _scale_amplitude = other->_scale_amplitude;
-       valid_transients = false;
        _envelope = other->_envelope;
 
        _fade_in_disabled = 0;
        _fade_out_disabled = 0;
        
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
@@ -266,13 +266,13 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
        }
 
        set_default_fades ();
-       valid_transients = false;
 
        if (set_state (node)) {
                throw failed_constructor();
        }
 
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
@@ -307,13 +307,13 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
 
        set_default_fades ();
        _scale_amplitude = 1.0;
-       valid_transients = false;
 
        if (set_state (node)) {
                throw failed_constructor();
        }
 
        listen_to_my_curves ();
+       listen_to_my_sources ();
 }
 
 AudioRegion::~AudioRegion ()
@@ -331,10 +331,11 @@ AudioRegion::~AudioRegion ()
 }
 
 void
-AudioRegion::invalidate_transients ()
+AudioRegion::listen_to_my_sources ()
 {
-       valid_transients = false;
-       _transients.clear ();
+       for (SourceList::const_iterator i = sources.begin(); i != sources.end(); ++i) {
+               (*i)->AnalysisChanged.connect (mem_fun (*this, &AudioRegion::invalidate_transients));
+       }
 }
 
 void
@@ -457,7 +458,7 @@ nframes64_t
 AudioRegion::read (Sample* buf, nframes64_t position, nframes64_t cnt, int channel) const
 {
        /* raw read, no fades, no gain, nada */
-       return _read_at (sources, buf, 0, 0, _position + position, cnt, channel, 0, 0, true);
+       return _read_at (sources, _length, buf, 0, 0, _position + position, cnt, channel, 0, 0, true);
 }
 
 nframes_t
@@ -466,18 +467,19 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, n
                      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, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false);
+       return _read_at (sources, _length, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false);
 }
 
 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
 {
-       return _read_at (master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
+       return _read_at (master_sources, master_sources.front()->length(), buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
 }
 
 nframes_t
-AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
+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, 
@@ -503,11 +505,11 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                buf_offset = 0;
        }
 
-       if (internal_offset >= _length) {
+       if (internal_offset >= limit) {
                return 0; /* read nothing */
        }
 
-       if ((to_read = min (cnt, _length - internal_offset)) == 0) {
+       if ((to_read = min (cnt, limit - internal_offset)) == 0) {
                return 0; /* read nothing */
        }
 
@@ -579,31 +581,31 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                        /* see if some part of this read is within the fade out */
                        
                /* .................        >|            REGION
-                                           _length
+                                           limit
                                            
                                  {           }            FADE
                                             fade_out_length
                                  ^                                          
-                               _length - fade_out_length
+                                limit - fade_out_length
                         |--------------|
                         ^internal_offset
                                        ^internal_offset + to_read
                                       
                                       we need the intersection of [internal_offset,internal_offset+to_read] with
-                                      [_length - fade_out_length, _length]
+                                      [limit - fade_out_length, limit]
                                       
                */
 
        
                        nframes_t fade_out_length = (nframes_t) _fade_out.back()->when;
-                       nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
-                       nframes_t fade_interval_end   = min(internal_offset + to_read, _length);
+                       nframes_t fade_interval_start = max(internal_offset, limit-fade_out_length);
+                       nframes_t fade_interval_end   = min(internal_offset + to_read, limit);
                        
                        if (fade_interval_end > fade_interval_start) {
                                /* (part of the) the fade out is  in this buffer */
                                
                                nframes_t limit = fade_interval_end - fade_interval_start;
-                               nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
+                               nframes_t curve_offset = fade_interval_start - (limit-fade_out_length);
                                nframes_t fade_offset = fade_interval_start - internal_offset;
                                
                                _fade_out.get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
@@ -1199,7 +1201,7 @@ AudioRegion::master_source_names ()
 }
 
 void
-AudioRegion::set_master_sources (SourceList& srcs)
+AudioRegion::set_master_sources (const SourceList& srcs)
 {
        master_sources = srcs;
 }
@@ -1517,36 +1519,12 @@ AudioRegion::set_playlist (boost::weak_ptr<Playlist> wpl)
        }
 }
 
-void
-AudioRegion::cleanup_transients (vector<nframes64_t>& t)
-{
-       sort (t.begin(), t.end());
-       
-       /* remove duplicates or other things that are too close */
-       
-       vector<nframes64_t>::iterator i = t.begin();
-       nframes64_t curr = (*i);
-       
-       /* XXX force a 3msec gap - use a config variable */
-       
-       nframes64_t gap_frames = (nframes64_t) floor (3.0 * (playlist()->session().frame_rate() / 1000.0));
-       
-       ++i;
-       
-       while (i != t.end()) {
-               if (((*i) == curr) || (((*i) - curr) < gap_frames)) {
-                                   i = t.erase (i);
-               } else {
-                       ++i;
-                       curr = *i;
-               }
-       }
-}
-
 int
-AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
+AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
 {
-       if (!playlist()) {
+       boost::shared_ptr<Playlist> pl = playlist();
+
+       if (!pl) {
                return -1;
        }
 
@@ -1555,7 +1533,53 @@ AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
                return 0;
        }
 
-       TransientDetector t (playlist()->session().frame_rate());
+       SourceList::iterator s;
+       
+       for (s = sources.begin() ; s != sources.end(); ++s) {
+               if (!(*s)->has_been_analysed()) {
+                       cerr << "For " << name() << " source " << (*s)->name() << " has not been analyzed\n";
+                       break;
+               }
+       }
+       
+       if (s == sources.end()) {
+               /* all sources are analyzed, merge data from each one */
+
+               for (s = sources.begin() ; s != sources.end(); ++s) {
+
+                       /* find the set of transients within the bounds of this region */
+
+                       AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
+                                                                        (*s)->transients.end(),
+                                                                        _start);
+
+                       AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
+                                                                         (*s)->transients.end(),
+                                                                         _start + _length);
+                                                                        
+                       /* and add them */
+
+                       results.insert (results.end(), low, high);
+               }
+
+               TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
+               
+               /* translate all transients to current position */
+
+               for (AnalysisFeatureList::iterator x = results.begin(); x != results.end(); ++x) {
+                       (*x) -= _start;
+                       (*x) += _position;
+               }
+
+               _transients = results;
+               valid_transients = true;
+
+               return 0;
+       }
+
+       cerr << "startup analysis of " << _name << endl;
+
+       TransientDetector t (pl->session().frame_rate());
        bool existing_results = !results.empty();
 
        _transients.clear ();
@@ -1563,17 +1587,21 @@ AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
 
        for (uint32_t i = 0; i < n_channels(); ++i) {
 
-               vector<nframes64_t> these_results;
+               AnalysisFeatureList these_results;
 
                t.reset ();
 
+               cerr << "working on channel " << i << endl;
+
                if (t.run ("", this, i, these_results)) {
                        return -1;
                }
 
+               cerr << "done\n";
+
                /* translate all transients to give absolute position */
                
-               for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) {
+               for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
                        (*i) += _position;
                }
 
@@ -1590,12 +1618,17 @@ AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
                        */
 
                        results.insert (results.end(), _transients.begin(), _transients.end());
-                       cleanup_transients (results);
+                       TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
                }
 
                /* make sure ours are clean too */
 
-               cleanup_transients (_transients);
+               TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
+
+       } else {
+
+               TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
+               results = _transients;
        }
 
        valid_transients = true;
@@ -1603,7 +1636,6 @@ AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
        return 0;
 }
 
-
 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)