Generic MIDI control now saves+restores its state; PBD::ID now requires a buffer...
[ardour.git] / libs / ardour / audioregion.cc
index 659d638ad617c69f2217df38ce76dfd3d22c32a8..855ff074ca2d6db7aa2bf5f368d04366538d90c8 100644 (file)
@@ -38,7 +38,8 @@
 #include <ardour/dB.h>
 #include <ardour/playlist.h>
 #include <ardour/audiofilter.h>
-#include <ardour/audiosource.h>
+#include <ardour/audiofilesource.h>
+#include <ardour/destructive_filesource.h>
 
 #include "i18n.h"
 #include <locale.h>
@@ -64,7 +65,7 @@ AudioRegionState::AudioRegionState (string why)
 {
 }
 
-AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t start, jack_nframes_t length)
+AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length)
        : Region (start, length, PBD::basename_nosuffix(src->name()), 0,  Region::Flag(Region::DefaultFlags|Region::External)),
          _fade_in (0.0, 2.0, 1.0, false),
          _fade_out (0.0, 2.0, 1.0, false),
@@ -76,6 +77,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
        master_sources.push_back (src);
        src->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), src));
 
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
+       if (afs) {
+               afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+       }
+
        _scale_amplitude = 1.0;
 
        set_default_fades ();
@@ -86,7 +92,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
        _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
 }
 
-AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (start, length, name, layer, flags),
          _fade_in (0.0, 2.0, 1.0, false),
          _fade_out (0.0, 2.0, 1.0, false),
@@ -98,6 +104,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
        master_sources.push_back (src);
        src->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), src));
 
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
+       if (afs) {
+               afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+       }
+
        _scale_amplitude = 1.0;
 
        set_default_fades ();
@@ -107,7 +118,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
        _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
 }
 
-AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (start, length, name, layer, flags),
          _fade_in (0.0, 2.0, 1.0, false),
          _fade_out (0.0, 2.0, 1.0, false),
@@ -119,6 +130,11 @@ AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t
                sources.push_back (*i);
                master_sources.push_back (*i);
                (*i)->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), (*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 = 1.0;
@@ -131,7 +147,7 @@ AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t
 }
 
 
-AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+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),
          _fade_in (other->_fade_in),
          _fade_out (other->_fade_out),
@@ -144,7 +160,17 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, jack_nfram
        for (SourceList::const_iterator i= other->sources.begin(); i != other->sources.end(); ++i) {
                sources.push_back (*i);
                (*i)->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), *i));
-               unique_srcs.insert (*i);
+
+               pair<set<boost::shared_ptr<AudioSource> >::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));
+                       }
+               }
        }
 
        for (SourceList::const_iterator i = other->master_sources.begin(); i != other->master_sources.end(); ++i) {
@@ -199,7 +225,16 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        for (SourceList::const_iterator i = other->sources.begin(); i != other->sources.end(); ++i) {
                sources.push_back (*i);
                (*i)->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), *i));
-               unique_srcs.insert (*i);
+               pair<set<boost::shared_ptr<AudioSource> >::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));
+                       }
+               }
        }
 
        for (SourceList::const_iterator i = other->master_sources.begin(); i != other->master_sources.end(); ++i) {
@@ -218,8 +253,6 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        save_state ("initial state");
 
        _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
-
-       /* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */
 }
 
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
@@ -232,6 +265,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
        master_sources.push_back (src);
        src->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), src));
 
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
+       if (afs) {
+               afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+       }
+
        set_default_fades ();
 
        if (set_state (node)) {
@@ -254,7 +292,16 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
        for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
                sources.push_back (*i);
                (*i)->GoingAway.connect (bind (mem_fun (*this, &AudioRegion::source_deleted), *i));
-               unique_srcs.insert (*i);
+               pair<set<boost::shared_ptr<AudioSource> >::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));
+                       }
+               }
        }
 
        for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
@@ -364,8 +411,12 @@ AudioRegion::get_memento() const
 }
 
 bool
-AudioRegion::verify_length (jack_nframes_t len)
+AudioRegion::verify_length (nframes_t len)
 {
+       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+               return true;
+       }
+
        for (uint32_t n=0; n < sources.size(); ++n) {
                if (_start > sources[n]->length() - len) {
                        return false;
@@ -375,8 +426,12 @@ AudioRegion::verify_length (jack_nframes_t len)
 }
 
 bool
-AudioRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
+AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length)
 {
+       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+               return true;
+       }
+
        for (uint32_t n=0; n < sources.size(); ++n) {
                if (new_length > sources[n]->length() - new_start) {
                        return false;
@@ -385,8 +440,12 @@ AudioRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t n
        return true;
 }
 bool
-AudioRegion::verify_start (jack_nframes_t pos)
+AudioRegion::verify_start (nframes_t pos)
 {
+       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+               return true;
+       }
+
        for (uint32_t n=0; n < sources.size(); ++n) {
                if (pos > sources[n]->length() - _length) {
                        return false;
@@ -396,8 +455,12 @@ AudioRegion::verify_start (jack_nframes_t pos)
 }
 
 bool
-AudioRegion::verify_start_mutable (jack_nframes_t& new_start)
+AudioRegion::verify_start_mutable (nframes_t& new_start)
 {
+       if (boost::dynamic_pointer_cast<DestructiveFileSource>(source())) {
+               return true;
+       }
+
        for (uint32_t n=0; n < sources.size(); ++n) {
                if (new_start > sources[n]->length() - _length) {
                        new_start = sources[n]->length() - _length;
@@ -425,8 +488,8 @@ AudioRegion::set_envelope_active (bool yn)
        }
 }
 
-jack_nframes_t
-AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t offset, jack_nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
+nframes_t
+AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
 {
        if (chan_n >= sources.size()) {
                return 0; 
@@ -436,7 +499,7 @@ AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t of
                return 0;
        } else {
                if (_scale_amplitude != 1.0) {
-                       for (jack_nframes_t n = 0; n < npeaks; ++n) {
+                       for (nframes_t n = 0; n < npeaks; ++n) {
                                buf[n].max *= _scale_amplitude;
                                buf[n].min *= _scale_amplitude;
                        }
@@ -445,30 +508,30 @@ AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t of
        }
 }
 
-jack_nframes_t
-AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, 
-                     jack_nframes_t cnt, 
-                     uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
+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
 {
        return _read_at (sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames);
 }
 
-jack_nframes_t
-AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, 
-                            jack_nframes_t cnt, uint32_t chan_n) const
+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);
 }
 
-jack_nframes_t
+nframes_t
 AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
-                      jack_nframes_t position, jack_nframes_t cnt, 
-                      uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
+                      nframes_t position, nframes_t cnt, 
+                      uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
 {
-       jack_nframes_t internal_offset;
-       jack_nframes_t buf_offset;
-       jack_nframes_t to_read;
-       
+       nframes_t internal_offset;
+       nframes_t buf_offset;
+       nframes_t to_read;
+
        /* precondition: caller has verified that we cover the desired section */
 
        if (chan_n >= sources.size()) {
@@ -487,7 +550,6 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
        if (internal_offset >= _length) {
                return 0; /* read nothing */
        }
-       
 
        if ((to_read = min (cnt, _length - internal_offset)) == 0) {
                return 0; /* read nothing */
@@ -516,19 +578,19 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
        if (_flags & FadeIn) {
 
-               jack_nframes_t fade_in_length = (jack_nframes_t) _fade_in.back()->when;
+               nframes_t fade_in_length = (nframes_t) _fade_in.back()->when;
                
                /* see if this read is within the fade in */
 
                if (internal_offset < fade_in_length) {
                        
-                       jack_nframes_t limit;
+                       nframes_t limit;
 
                        limit = min (to_read, fade_in_length - internal_offset);
 
                        _fade_in.get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
 
-                       for (jack_nframes_t n = 0; n < limit; ++n) {
+                       for (nframes_t n = 0; n < limit; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n];
                        }
                }
@@ -538,9 +600,6 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
        if (_flags & FadeOut) {
        
-
-
-       
                /* see if some part of this read is within the fade out */
 
                /* .................        >|            REGION
@@ -560,20 +619,20 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                */
 
        
-               jack_nframes_t fade_out_length = (jack_nframes_t) _fade_out.back()->when;
-               jack_nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
-               jack_nframes_t fade_interval_end   = min(internal_offset + to_read, _length);
+               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);
 
                if (fade_interval_end > fade_interval_start) {
                        /* (part of the) the fade out is  in this buffer */
                        
-                       jack_nframes_t limit = fade_interval_end - fade_interval_start;
-                       jack_nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
-                       jack_nframes_t fade_offset = fade_interval_start - internal_offset;
+                       nframes_t limit = fade_interval_end - fade_interval_start;
+                       nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
+                       nframes_t fade_offset = fade_interval_start - internal_offset;
                                                                       
                        _fade_out.get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
 
-                       for (jack_nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
+                       for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
                                mixdown_buffer[m] *= gain_buffer[n];
                        }
                } 
@@ -586,11 +645,11 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                _envelope.get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
                
                if (_scale_amplitude != 1.0f) {
-                       for (jack_nframes_t n = 0; n < to_read; ++n) {
+                       for (nframes_t n = 0; n < to_read; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
                        }
                } else {
-                       for (jack_nframes_t n = 0; n < to_read; ++n) {
+                       for (nframes_t n = 0; n < to_read; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n];
                        }
                }
@@ -605,7 +664,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
                buf += buf_offset;
 
-               for (jack_nframes_t n = 0; n < to_read; ++n) {
+               for (nframes_t n = 0; n < to_read; ++n) {
                        buf[n] += mixdown_buffer[n];
                }
        } 
@@ -629,7 +688,7 @@ AudioRegion::state (bool full)
 
        for (uint32_t n=0; n < sources.size(); ++n) {
                snprintf (buf2, sizeof(buf2), "source-%d", n);
-               sources[n]->id().print (buf);
+               sources[n]->id().print (buf, sizeof (buf));
                node.add_property (buf2, buf);
        }
 
@@ -759,17 +818,17 @@ AudioRegion::set_state (const XMLNode& node)
 void
 AudioRegion::set_fade_in_shape (FadeShape shape)
 {
-       set_fade_in (shape, (jack_nframes_t) _fade_in.back()->when);
+       set_fade_in (shape, (nframes_t) _fade_in.back()->when);
 }
 
 void
 AudioRegion::set_fade_out_shape (FadeShape shape)
 {
-       set_fade_out (shape, (jack_nframes_t) _fade_out.back()->when);
+       set_fade_out (shape, (nframes_t) _fade_out.back()->when);
 }
 
 void
-AudioRegion::set_fade_in (FadeShape shape, jack_nframes_t len)
+AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
 {
        _fade_in.freeze ();
        _fade_in.clear ();
@@ -833,7 +892,7 @@ AudioRegion::set_fade_in (FadeShape shape, jack_nframes_t len)
 }
 
 void
-AudioRegion::set_fade_out (FadeShape shape, jack_nframes_t len)
+AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
 {
        _fade_out.freeze ();
        _fade_out.clear ();
@@ -895,7 +954,7 @@ AudioRegion::set_fade_out (FadeShape shape, jack_nframes_t len)
 }
 
 void
-AudioRegion::set_fade_in_length (jack_nframes_t len)
+AudioRegion::set_fade_in_length (nframes_t len)
 {
        bool changed = _fade_in.extend_to (len);
 
@@ -913,7 +972,7 @@ AudioRegion::set_fade_in_length (jack_nframes_t len)
 }
 
 void
-AudioRegion::set_fade_out_length (jack_nframes_t len)
+AudioRegion::set_fade_out_length (nframes_t len)
 {
        bool changed =  _fade_out.extend_to (len);
 
@@ -1111,8 +1170,8 @@ AudioRegion::apply (AudioFilter& filter)
 int
 AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
 {
-       const jack_nframes_t blocksize = 4096;
-       jack_nframes_t to_read;
+       const nframes_t blocksize = 4096;
+       nframes_t to_read;
        int status = -1;
 
        spec.channels = sources.size();
@@ -1147,7 +1206,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
                                        goto out;
                                }
                                
-                               for (jack_nframes_t x = 0; x < to_read; ++x) {
+                               for (nframes_t x = 0; x < to_read; ++x) {
                                        spec.dataF[chan+(x*spec.channels)] = buf[x];
                                }
                        }
@@ -1203,11 +1262,11 @@ AudioRegion::set_scale_amplitude (gain_t g)
 void
 AudioRegion::normalize_to (float target_dB)
 {
-       const jack_nframes_t blocksize = 64 * 1024;
+       const nframes_t blocksize = 64 * 1024;
        Sample buf[blocksize];
-       jack_nframes_t fpos;
-       jack_nframes_t fend;
-       jack_nframes_t to_read;
+       nframes_t fpos;
+       nframes_t fend;
+       nframes_t to_read;
        double maxamp = 0;
        gain_t target = dB_to_coefficient (target_dB);
 
@@ -1326,11 +1385,22 @@ AudioRegion::speed_mismatch (float sr) const
        return fsr != sr;
 }
 
+void
+AudioRegion::source_offset_changed ()
+{
+       if (boost::dynamic_pointer_cast<DestructiveFileSource>(sources.front())) {
+               set_start (source()->natural_position(), this);
+               set_position (source()->natural_position(), this);
+       } else {
+               set_position (source()->natural_position() + start(), this);
+       }
+}
+
 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) 
 {
-       return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (jack_nframes_t) npeaks, (jack_nframes_t) start, (jack_nframes_t) cnt, n_chan,samples_per_unit);
+       return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (nframes_t) npeaks, (nframes_t) start, (nframes_t) cnt, n_chan,samples_per_unit);
 }
 
 uint32_t region_length_from_c (void *arg)