no more peak building thread; don't print config var stores, but it possible to do...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 14 Mar 2007 14:24:14 +0000 (14:24 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 14 Mar 2007 14:24:14 +0000 (14:24 +0000)
git-svn-id: svn://localhost/ardour2/trunk@1588 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/ardour_ui.cc
libs/ardour/ardour/audiofilesource.h
libs/ardour/ardour/audiosource.h
libs/ardour/ardour/configuration_variable.h
libs/ardour/audio_diskstream.cc
libs/ardour/audiofilesource.cc
libs/ardour/audioregion.cc
libs/ardour/audiosource.cc
libs/ardour/configuration.cc
libs/ardour/session.cc
libs/ardour/sndfilesource.cc

index 1d6af7de698590845a2d9e1bf1c07cd9ca129300..92eb4e1343aa35f0214eba5b3f3b2cf0fc43af39 100644 (file)
@@ -263,10 +263,6 @@ ARDOUR_UI::set_engine (AudioEngine& e)
        AudioFileSource::set_build_peakfiles (true);
        AudioFileSource::set_build_missing_peakfiles (true);
 
-       if (AudioSource::start_peak_thread ()) {
-               throw failed_constructor();
-       }
-
        /* set default clock modes */
 
        primary_clock.set_mode (AudioClock::SMPTE);
@@ -304,8 +300,6 @@ ARDOUR_UI::~ARDOUR_UI ()
        if (add_route_dialog) {
                delete add_route_dialog;
        }
-
-       AudioSource::stop_peak_thread ();
 }
 
 gint
@@ -1147,8 +1141,6 @@ ARDOUR_UI::remove_last_capture()
 void
 ARDOUR_UI::transport_record ()
 {
-       cerr << "transport record\n";
-
        if (session) {
                switch (session->record_status()) {
                case Session::Disabled:
index 4daa8c24f40f3476f599a46a56a6056fab7ae88b..899b0ea3ff42affe60a3d1625dd6f074b62e72e4 100644 (file)
@@ -107,6 +107,7 @@ class AudioFileSource : public AudioSource {
 
        bool destructive() const { return (_flags & Destructive); }
        virtual bool set_destructive (bool yn) { return false; }
+       bool can_truncate_peaks() const { return !destructive(); }
 
        Flag flags() const { return _flags; }
 
index 1f2ee64ac105dd886f3cbc5e1526272e6a1dde54..efd96e94eb1c5e62deffd6664df4e92ebf83e2c0 100644 (file)
@@ -76,6 +76,8 @@ const nframes_t frames_per_peak = 256;
        virtual void mark_for_remove() = 0;
        virtual void mark_streaming_write_completed () {}
 
+       virtual bool can_truncate_peaks() const { return true; }
+
        void set_captured_for (string str) { _captured_for = str; }
        string captured_for() const { return _captured_for; }
 
@@ -92,9 +94,6 @@ const nframes_t frames_per_peak = 256;
        XMLNode& get_state ();
        int set_state (const XMLNode&);
 
-       static int  start_peak_thread ();
-       static void stop_peak_thread ();
-
        int rename_peakfile (std::string newpath);
        void touch_peakfile ();
 
@@ -108,6 +107,9 @@ const nframes_t frames_per_peak = 256;
 
        virtual int setup_peakfile () { return 0; }
 
+       int prepare_for_peakfile_writes ();
+       void done_with_peakfile_writes ();
+
   protected:
        static bool _build_missing_peakfiles;
        static bool _build_peakfiles;
@@ -115,7 +117,6 @@ const nframes_t frames_per_peak = 256;
        bool                _peaks_built;
        mutable Glib::Mutex _lock;
        nframes_t           _length;
-       bool                 next_peak_clear_should_notify;
        string               peakpath;
        string              _captured_for;
 
@@ -123,12 +124,11 @@ const nframes_t frames_per_peak = 256;
        mutable uint32_t _write_data_count; // modified in write()
 
        int initialize_peakfile (bool newfile, string path);
-       void build_peaks_from_scratch ();
-
-       int  do_build_peak (nframes_t, nframes_t);
+       int build_peaks_from_scratch ();
+       int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force);
        void truncate_peakfile();
 
-       mutable off_t _peak_byte_max; // modified in do_build_peaks()
+       mutable off_t _peak_byte_max; // modified in compute_and_write_peak()
 
        virtual nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const = 0;
        virtual nframes_t write_unlocked (Sample *dst, nframes_t cnt) = 0;
@@ -137,40 +137,13 @@ const nframes_t frames_per_peak = 256;
        
        void update_length (nframes_t pos, nframes_t cnt);
 
-       static pthread_t peak_thread;
-       static bool      have_peak_thread;
-       static void*     peak_thread_work(void*);
-
-       static int peak_request_pipe[2];
-
-       struct PeakRequest {
-           enum Type {
-                   Build,
-                   Quit
-           };
-       };
-
-       static vector<boost::shared_ptr<AudioSource> > pending_peak_sources;
-       static Glib::Mutex* pending_peak_sources_lock;
-
-       static void queue_for_peaks (boost::shared_ptr<AudioSource>, bool notify=true);
-       static void clear_queue_for_peaks ();
-       
-       struct PeakBuildRecord {
-           nframes_t frame;
-           nframes_t cnt;
-
-           PeakBuildRecord (nframes_t f, nframes_t c) 
-                   : frame (f), cnt (c) {}
-           PeakBuildRecord (const PeakBuildRecord& other) {
-                   frame = other.frame;
-                   cnt = other.cnt;
-           }
-       };
-
-       list<AudioSource::PeakBuildRecord *> pending_peak_builds;
-
   private:
+       int peakfile;
+       nframes_t peak_leftover_cnt;
+       nframes_t peak_leftover_size;
+       Sample* peak_leftovers;
+       nframes_t peak_leftover_frame;
+
        bool file_changed (string path);
 };
 
index 8710369a6431b4af4fd78de3970fda9ead1d3585..81e282ff64fcc1a6527a330fa54c468cf17c8a4c 100644 (file)
@@ -27,10 +27,13 @@ class ConfigVariableBase {
        virtual void add_to_node (XMLNode& node) = 0;
        virtual bool set_from_node (const XMLNode& node, Owner owner) = 0;
 
+       void show_stored_value (const std::string&);
+       static void set_show_stored_values (bool yn);
 
   protected:
        std::string _name;
        Owner _owner;
+       static bool show_stores;
 
        void notify ();
        void miss ();
@@ -61,7 +64,7 @@ class ConfigVariable : public ConfigVariableBase
        void add_to_node (XMLNode& node) {
                std::stringstream ss;
                ss << value;
-               cerr << "Config variable " << _name << " stored as " << ss.str() << endl;
+               show_stored_value (ss.str());
                XMLNode* child = new XMLNode ("Option");
                child->add_property ("name", _name);
                child->add_property ("value", ss.str());
index 6fe1cdc0a627cfdd276e653cc41c2b80e2f9881b..f80e03b41faef31326f85ebcaf81882607129545 100644 (file)
@@ -1322,7 +1322,6 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
 
                total = vector.len[0] + vector.len[1];
 
-               
                if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
                        goto out;
                }
@@ -1411,9 +1410,9 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
                           disk_io_chunk_frames of data, so arrange for some part 
                           of vector.len[1] to be flushed to disk as well.
                        */
-               
+                       
                        to_write = min ((nframes_t)(disk_io_chunk_frames - to_write), (nframes_t) vector.len[1]);
-               
+
                        if ((*chan).write_source->write (vector.buf[1], to_write) != to_write) {
                                error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
                                return -1;
@@ -1695,13 +1694,16 @@ AudioDiskstream::engage_record_enable ()
 
        g_atomic_int_set (&_record_enabled, 1);
        capturing_sources.clear ();
+
        if (Config->get_monitoring_model() == HardwareMonitoring) {
+
                for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
                        if ((*chan).source) {
                                (*chan).source->ensure_monitor_input (!(Config->get_auto_input() && rolling));
                        }
                        capturing_sources.push_back ((*chan).write_source);
                }
+               
        } else {
                for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
                        capturing_sources.push_back ((*chan).write_source);
@@ -1715,8 +1717,8 @@ void
 AudioDiskstream::disengage_record_enable ()
 {
        g_atomic_int_set (&_record_enabled, 0);
-       if (Config->get_monitoring_model() == HardwareMonitoring) {
-               for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+       for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+               if (Config->get_monitoring_model() == HardwareMonitoring) {
                        if ((*chan).source) {
                                (*chan).source->ensure_monitor_input (false);
                        }
@@ -1725,7 +1727,6 @@ AudioDiskstream::disengage_record_enable ()
        capturing_sources.clear ();
        RecordEnableChanged (); /* EMIT SIGNAL */
 }
-               
 
 XMLNode&
 AudioDiskstream::get_state ()
@@ -1919,6 +1920,7 @@ AudioDiskstream::use_new_write_source (uint32_t n)
        ChannelInfo &chan = channels[n];
        
        if (chan.write_source) {
+               chan.write_source->done_with_peakfile_writes ();
                chan.write_source->set_allow_remove_if_empty (true);
                chan.write_source.reset ();
        }
index 218eb783a97d44ebddde679775fde08511e75f44..f636a395423e85507c182789cf60883112cc5c2b 100644 (file)
@@ -130,7 +130,6 @@ AudioFileSource::init (string pathstr, bool must_exist)
 
        _length = 0;
        timeline_position = 0;
-       next_peak_clear_should_notify = false;
        _peaks_built = false;
        file_is_new = false;
 
@@ -260,10 +259,7 @@ AudioFileSource::mark_streaming_write_completed ()
 
        Glib::Mutex::Lock lm (_lock);
 
-       next_peak_clear_should_notify = true;
-
-       if (_peaks_built || pending_peak_builds.empty()) {
-               _peaks_built = true;
+       if (_peaks_built) {
                PeaksReady (); /* EMIT SIGNAL */
        }
 }
index 666a6a6b42cfdf30087b9976ea6b536ead71c5b9..24249a63649440b07e5680dc28015e2f4dc012d4 100644 (file)
@@ -1281,6 +1281,7 @@ AudioRegion::normalize_to (float target_dB)
        boost::shared_ptr<Playlist> pl (playlist());
 
        if (pl) {
+               cerr << "Send modified\n";
                pl->Modified();
        }
 
index 073983ac41f758de01ab982ffb38013389397cc1..ae9713bcd3b1c92de7485b0384fa4cc43f1ff955 100644 (file)
@@ -42,41 +42,33 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-pthread_t                    AudioSource::peak_thread;
-bool                         AudioSource::have_peak_thread = false;
-vector<boost::shared_ptr<AudioSource> > AudioSource::pending_peak_sources;
-Glib::Mutex*                 AudioSource::pending_peak_sources_lock = 0;
-int                          AudioSource::peak_request_pipe[2];
-
 bool AudioSource::_build_missing_peakfiles = false;
 bool AudioSource::_build_peakfiles = false;
 
 AudioSource::AudioSource (Session& s, string name)
        : Source (s, name)
 {
-       if (pending_peak_sources_lock == 0) {
-               pending_peak_sources_lock = new Glib::Mutex;
-       }
-
        _peaks_built = false;
        _peak_byte_max = 0;
-       next_peak_clear_should_notify = true;
+       peakfile = -1;
        _read_data_count = 0;
        _write_data_count = 0;
+       peak_leftover_cnt = 0;
+       peak_leftover_size = 0;
+       peak_leftovers = 0;
 }
 
 AudioSource::AudioSource (Session& s, const XMLNode& node) 
        : Source (s, node)
 {
-       if (pending_peak_sources_lock == 0) {
-               pending_peak_sources_lock = new Glib::Mutex;
-       }
-
        _peaks_built = false;
        _peak_byte_max = 0;
-       next_peak_clear_should_notify = true;
+       peakfile = -1;
        _read_data_count = 0;
        _write_data_count = 0;
+       peak_leftover_cnt = 0;
+       peak_leftover_size = 0;
+       peak_leftovers = 0;
 
        if (set_state (node)) {
                throw failed_constructor();
@@ -85,6 +77,19 @@ AudioSource::AudioSource (Session& s, const XMLNode& node)
 
 AudioSource::~AudioSource ()
 {
+       /* shouldn't happen but make sure we don't leak file descriptors anyway */
+       
+       if (peak_leftover_cnt) {
+               cerr << "AudioSource destroyed with leftover peak data pending" << endl;
+       }
+
+       if (peakfile >= 0) {
+               ::close (peakfile);
+       }
+
+       if (peak_leftovers) {
+               delete [] peak_leftovers;
+       }
 }
 
 XMLNode&
@@ -117,171 +122,6 @@ AudioSource::set_state (const XMLNode& node)
   PEAK FILE STUFF
  ***********************************************************************/
 
-void*
-AudioSource::peak_thread_work (void* arg)
-{
-       PBD::ThreadCreated (pthread_self(), X_("Peak"));
-       struct pollfd pfd[1];
-
-       if (pending_peak_sources_lock == 0) {
-               pending_peak_sources_lock = new Glib::Mutex;
-       }
-
-       Glib::Mutex::Lock lm (*pending_peak_sources_lock);
-
-       while (true) {
-
-               pfd[0].fd = peak_request_pipe[0];
-               pfd[0].events = POLLIN|POLLERR|POLLHUP;
-
-               pending_peak_sources_lock->unlock ();
-
-               if (poll (pfd, 1, -1) < 0) {
-
-                       if (errno == EINTR) {
-                               pending_peak_sources_lock->lock ();
-                               continue;
-                       }
-                       
-                       error << string_compose (_("poll on peak request pipe failed (%1)"),
-                                         strerror (errno))
-                             << endmsg;
-                       break;
-               }
-
-               if (pfd[0].revents & ~POLLIN) {
-                       error << _("Error on peak thread request pipe") << endmsg;
-                       break;
-               }
-
-               if (pfd[0].revents & POLLIN) {
-
-                       char req;
-                       
-                       /* empty the pipe of all current requests */
-
-                       while (1) {
-                               size_t nread = ::read (peak_request_pipe[0], &req, sizeof (req));
-
-                               if (nread == 1) {
-                                       switch ((PeakRequest::Type) req) {
-                                       
-                                       case PeakRequest::Build:
-                                               break;
-                                               
-                                       case PeakRequest::Quit:
-                                               pthread_exit_pbd (0);
-                                               /*NOTREACHED*/
-                                               break;
-                                               
-                                       default:
-                                               break;
-                                       }
-
-                               } else if (nread == 0) {
-                                       break;
-                               } else if (errno == EAGAIN) {
-                                       break;
-                               } else {
-                                       fatal << _("Error reading from peak request pipe") << endmsg;
-                                       /*NOTREACHED*/
-                               }
-                       }
-               }
-
-               pending_peak_sources_lock->lock ();
-
-               while (!pending_peak_sources.empty()) {
-
-                       boost::shared_ptr<AudioSource> s = pending_peak_sources.front();
-                       pending_peak_sources.erase (pending_peak_sources.begin());
-                       
-                       pending_peak_sources_lock->unlock ();
-                       s->build_peaks();
-                       pending_peak_sources_lock->lock ();
-               }
-       }
-
-       pthread_exit_pbd (0);
-       /*NOTREACHED*/
-       return 0;
-}
-
-int
-AudioSource::start_peak_thread ()
-{
-       if (!_build_peakfiles) {
-               return 0;
-       }
-
-       if (pipe (peak_request_pipe)) {
-               error << string_compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg;
-               return -1;
-       }
-
-       if (fcntl (peak_request_pipe[0], F_SETFL, O_NONBLOCK)) {
-               error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
-               return -1;
-       }
-
-       if (fcntl (peak_request_pipe[1], F_SETFL, O_NONBLOCK)) {
-               error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
-               return -1;
-       }
-
-       if (pthread_create_and_store ("peak file builder", &peak_thread, 0, peak_thread_work, 0)) {
-               error << _("AudioSource: could not create peak thread") << endmsg;
-               return -1;
-       }
-
-       have_peak_thread = true;
-       return 0;
-}
-
-void
-AudioSource::stop_peak_thread ()
-{
-       if (!have_peak_thread) {
-               return;
-       }
-
-       void* status;
-
-       char c = (char) PeakRequest::Quit;
-       ::write (peak_request_pipe[1], &c, 1);
-       pthread_join (peak_thread, &status);
-}
-
-void 
-AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source, bool notify)
-{
-       if (have_peak_thread) {
-               
-               Glib::Mutex::Lock lm (*pending_peak_sources_lock);
-               
-               source->next_peak_clear_should_notify = notify;
-               
-               if (find (pending_peak_sources.begin(),
-                         pending_peak_sources.end(),
-                         source) == pending_peak_sources.end()) {
-                       pending_peak_sources.push_back (source);
-               }
-
-               char c = (char) PeakRequest::Build;
-               ::write (peak_request_pipe[1], &c, 1);
-       }
-}
-
-void AudioSource::clear_queue_for_peaks ()
-{
-       /* this is done to cancel a group of running peak builds */
-       if (have_peak_thread) {
-               Glib::Mutex::Lock lm (*pending_peak_sources_lock);
-               pending_peak_sources.clear ();
-       }
-}
-
-
 bool
 AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
 {
@@ -430,7 +270,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
        int ret = -1;
        PeakData* staging = 0;
        Sample* raw_staging = 0;
-       int peakfile = -1;
+       int _peakfile = -1;
 
        expected_peaks = (cnt / (double) frames_per_peak);
        scale = npeaks/expected_peaks;
@@ -491,7 +331,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
 
                /* open, read, close */
 
-               if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
+               if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
                        error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
                        return -1;
                }
@@ -500,8 +340,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
                cerr << "DIRECT PEAKS\n";
 #endif
                
-               nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
-               close (peakfile);
+               nread = ::pread (_peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
+               close (_peakfile);
 
                if (nread != sizeof (PeakData) * npeaks) {
                        cerr << "AudioSource["
@@ -565,7 +405,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
 
                /* open ... close during out: handling */
 
-               if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
+               if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
                        error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
                        return 0;
                }
@@ -582,10 +422,10 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
                                cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
 #endif
                                
-                               if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte))
+                               if ((nread = ::pread (_peakfile, staging, sizeof (PeakData) * to_read, start_byte))
                                    != sizeof (PeakData) * to_read) {
 
-                                       off_t fend = lseek (peakfile, 0, SEEK_END);
+                                       off_t fend = lseek (_peakfile, 0, SEEK_END);
                                        
                                        cerr << "AudioSource["
                                             << _name
@@ -671,13 +511,21 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
                                
                                to_read = min (chunksize, (_length - current_frame));
 
+                               if (to_read == 0) {
+                                       /* XXX ARGH .. out by one error ... need to figure out why this happens
+                                          and fix it rather than do this band-aid move.
+                                       */
+                                       zero_fill = npeaks - nvisual_peaks;
+                                       break;
+                               }
+
                                if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
-                                       error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3")
-                                                        , _name, to_read, current_frame
+                                       error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
+                                                               _name, to_read, current_frame, _length, strerror (errno)
                                              << endmsg;
                                        goto out;
                                }
-
+                                       
                                i = 0;
                        }
                        
@@ -707,8 +555,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
        }
 
   out:
-       if (peakfile >= 0) {
-               close (peakfile);
+       if (_peakfile >= 0) {
+               close (_peakfile);
        }
 
        if (staging) {
@@ -729,191 +577,290 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
 #undef DEBUG_PEAK_BUILD
 
 int
-AudioSource::build_peaks ()
+AudioSource::build_peaks_from_scratch ()
 {
-       vector<PeakBuildRecord*> built;
-       int status = -1;
-       bool pr_signal = false;
-       list<PeakBuildRecord*> copy;
+       nframes_t current_frame;
+       nframes_t cnt;
+       Sample buf[frames_per_peak];
+       nframes_t frames_read;
+       nframes_t frames_to_read;
+       int ret = -1;
 
        {
-               Glib::Mutex::Lock lm (_lock);
-               copy = pending_peak_builds;
-               pending_peak_builds.clear ();
-       }
-               
-#ifdef DEBUG_PEAK_BUILD
-       cerr << "build peaks with " << copy.size() << " requests pending\n";
-#endif         
+               /* hold lock while building peaks */
 
-       for (list<PeakBuildRecord *>::iterator i = copy.begin(); i != copy.end(); ++i) {
+               Glib::Mutex::Lock lp (_lock);
                
-               if ((status = do_build_peak ((*i)->frame, (*i)->cnt)) != 0) { 
-                       unlink (peakpath.c_str());
-                       break;
+               if (prepare_for_peakfile_writes ()) {
+                       return -1;
                }
-               built.push_back (new PeakBuildRecord (*(*i)));
-               delete *i;
-       }
+               
+               current_frame = 0;
+               cnt = _length;
+               _peaks_built = false;
+               
+               while (cnt) {
+                       
+                       frames_to_read = min (frames_per_peak, cnt);
 
-       { 
-               Glib::Mutex::Lock lm (_lock);
+                       if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
+                               error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
+                               done_with_peakfile_writes ();
+                               goto out;
+                       }
 
-               if (status == 0) {
-                       _peaks_built = true;
-                       
-                       if (next_peak_clear_should_notify) {
-                               next_peak_clear_should_notify = false;
-                               pr_signal = true;
+                       if (compute_and_write_peaks (buf, current_frame, frames_read, true)) {
+                               break;
                        }
+                       
+                       current_frame += frames_read;
+                       cnt -= frames_read;
                }
+               
+               if (cnt == 0) {
+                       /* success */
+                       truncate_peakfile();
+                       _peaks_built = true;
+               } 
+
+               done_with_peakfile_writes ();
        }
 
-       if (status == 0) {
-               for (vector<PeakBuildRecord *>::iterator i = built.begin(); i != built.end(); ++i) {
-                       PeakRangeReady ((*i)->frame, (*i)->cnt); /* EMIT SIGNAL */
-                       delete *i;
-               }
+       /* lock no longer held, safe to signal */
 
-               if (pr_signal) {
-                       truncate_peakfile();
-                       PeaksReady (); /* EMIT SIGNAL */
-               }
+       if (_peaks_built) {
+               PeaksReady (); /* EMIT SIGNAL */
+               ret = 0;
        }
 
-       return status;
+  out:
+       if (ret) {
+               unlink (peakpath.c_str());
+       }
+
+       return ret;
 }
 
 int
-AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt)
+AudioSource::prepare_for_peakfile_writes ()
 {
-       nframes_t current_frame;
-       Sample buf[frames_per_peak];
+       if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
+               error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+               return -1;
+       }
+       return 0;
+}
+
+void
+AudioSource::done_with_peakfile_writes ()
+{
+       if (peak_leftover_cnt) {
+               compute_and_write_peaks (0, 0, 0, true);
+       }
+
+       if (peakfile >= 0) {
+               close (peakfile);
+               peakfile = -1;
+       }
+}
+
+static bool wrote_xmax = false;
+
+int
+AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force)
+{
+       Sample* buf2 = 0;
        Sample xmin, xmax;
-       uint32_t  peaki;
+       nframes_t to_do;
+       uint32_t  peaks_computed;
        PeakData* peakbuf;
-       nframes_t frames_read;
-       nframes_t frames_to_read;
-       off_t first_peak_byte;
-       int peakfile = -1;
        int ret = -1;
-       off_t target_length;
-       off_t endpos;
+       nframes_t current_frame;
+       nframes_t frames_done;
+       const size_t blocksize = (128 * 1024);
+       off_t first_peak_byte;
 
-#ifdef DEBUG_PEAK_BUILD
-       cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl;
-#endif
+       if (peakfile < 0) {
+               prepare_for_peakfile_writes ();
+       }
 
-       first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
+  restart:
+       if (peak_leftover_cnt) {
 
-#ifdef DEBUG_PEAK_BUILD
-       cerr << "seeking to " << first_peak_byte << " before writing new peak data\n";
-#endif
+               if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
 
-       current_frame = first_frame;
-       peakbuf = new PeakData[(cnt/frames_per_peak)+1];
-       peaki = 0;
+                       cerr << "seek, flush out " << peak_leftover_cnt << endl;
 
-       if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
-               error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
-               return -1;
+                       /* uh-oh, ::seek() since the last ::compute_and_write_peaks(), 
+                          and we have leftovers. flush a single peak (since the leftovers
+                          never represent more than that, and restart.
+                       */
+                       
+                       PeakData x;
+                       
+                       x.min = peak_leftovers[0];
+                       x.max = peak_leftovers[0];
+                       
+                       for (nframes_t n = 1; n < peak_leftover_cnt; ++n) {
+                               x.max = max (x.max, peak_leftovers[n]);
+                               x.min = min (x.min, peak_leftovers[n]);
+                       }
+
+                       off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData);
+
+                       if (::pwrite (peakfile, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
+                               error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
+                               goto out;
+                       }
+
+                       _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
+
+                       PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
+                       PeaksReady (); /* EMIT SIGNAL */
+
+                       /* left overs are done */
+
+                       peak_leftover_cnt = 0;
+                       goto restart;
+               }
+
+               /* else ... had leftovers, but they immediately preceed the new data, so just
+                  merge them and compute.
+               */
+
+               /* make a new contiguous buffer containing leftovers and the new stuff */
+
+               to_do = cnt + peak_leftover_cnt;
+               buf2 = new Sample[to_do];
+
+               /* the remnants */
+               memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
+
+               /* the new stuff */
+               memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
+
+               /* no more leftovers */
+               peak_leftover_cnt = 0;
+
+               /* use the temporary buffer */
+               buf = buf2;
+
+               /* make sure that when we write into the peakfile, we startup where we left off */
+
+               first_frame = peak_leftover_frame;
+               
+       } else {
+               to_do = cnt;
        }
-       
-       while (cnt) {
 
-               frames_to_read = min (frames_per_peak, cnt);
+       peakbuf = new PeakData[(to_do/frames_per_peak)+1];
+       peaks_computed = 0;
+       current_frame = first_frame;
+       frames_done = 0;
+
+       while (to_do) {
 
-               /* lock for every read */
+               /* if some frames were passed in (i.e. we're not flushing leftovers)
+                  and there are less than frames_per_peak to do, save them till
+                  next time
+               */
+
+               if (force && (to_do < frames_per_peak)) {
+                       /* keep the left overs around for next time */
 
-               if ((frames_read = read (buf, current_frame, frames_to_read)) != frames_to_read) {
-                       error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
-                       goto out;
+                       cerr << "save " << to_do << " leftovers\n";
+
+                       if (peak_leftover_size < to_do) {
+                               delete [] peak_leftovers;
+                               peak_leftovers = new Sample[to_do];
+                               peak_leftover_size = to_do;
+                       }
+                       memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
+                       peak_leftover_cnt = to_do;
+                       peak_leftover_frame = current_frame;
+
+                       /* done for now */
+
+                       break;
                }
+                       
+               nframes_t this_time = min (frames_per_peak, to_do);
 
                xmin = buf[0];
                xmax = buf[0];
 
-               for (nframes_t n = 1; n < frames_read; ++n) {
+               for (nframes_t n = 1; n < this_time; ++n) {
                        xmax = max (xmax, buf[n]);
                        xmin = min (xmin, buf[n]);
-
-//                     if (current_frame < frames_read) {
-//                             cerr << "sample = " << buf[n] << " max = " << xmax << " min = " << xmin << " max of 2 = " << max (xmax, buf[n]) << endl;
-//                     }
                }
+               
 
-               peakbuf[peaki].max = xmax;
-               peakbuf[peaki].min = xmin;
-               peaki++;
+               peakbuf[peaks_computed].max = xmax;
+               peakbuf[peaks_computed].min = xmin;
 
-               current_frame += frames_read;
-               cnt -= frames_read;
+               peaks_computed++;
+               buf += this_time;
+               to_do -= this_time;
+               frames_done += this_time;
+               current_frame += this_time;
        }
-
-#define BLOCKSIZE (128 * 1024)
-
-       /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
-          the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
-          it does not cause single-extent allocation even for peakfiles of 
-          less than BLOCKSIZE bytes.  only call ftruncate if we'll make the file larger.
-       */
-       endpos = lseek (peakfile, 0, SEEK_END);
                
-       target_length = BLOCKSIZE * ((first_peak_byte + BLOCKSIZE + 1) / BLOCKSIZE);
+       first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
 
-       if (endpos < target_length) {
-               // XXX - we really shouldn't be doing this for destructive source peaks
-               ftruncate (peakfile, target_length);
-               //cerr << "do build TRUNC: " << peakpath << "  " << target_length << endl;
+       if (can_truncate_peaks()) {
 
-               /* error doesn't actually matter though, so continue on without testing */
+               /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
+                  the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
+                  it does not cause single-extent allocation even for peakfiles of 
+                  less than BLOCKSIZE bytes.  only call ftruncate if we'll make the file larger.
+               */
+               
+               off_t endpos = lseek (peakfile, 0, SEEK_END);
+               off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
+               
+               if (endpos < target_length) {
+                       ftruncate (peakfile, target_length);
+                       /* error doesn't actually matter though, so continue on without testing */
+               }
        }
 
-       if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) {
+       if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
                error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
                goto out;
        }
 
-       _peak_byte_max = max(_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaki));
+       _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));     
+
+       if (frames_done) {
+               PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
+               PeaksReady (); /* EMIT SIGNAL */
+       }
 
        ret = 0;
 
   out:
        delete [] peakbuf;
-       if (peakfile >= 0) {
-               close (peakfile);
+       if (buf2) {
+               delete [] buf2;
        }
        return ret;
 }
 
-void
-AudioSource::build_peaks_from_scratch ()
-{
-       Glib::Mutex::Lock lp (_lock);
-
-       next_peak_clear_should_notify = true;
-       pending_peak_builds.push_back (new PeakBuildRecord (0, _length));
-       queue_for_peaks (shared_from_this(), true);
-}
-
 void
 AudioSource::truncate_peakfile ()
 {
-       int peakfile = -1;
+       if (peakfile < 0) {
+               error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
+                     << endmsg;
+               return;
+       }
 
        /* truncate the peakfile down to its natural length if necessary */
 
-       if ((peakfile = ::open (peakpath.c_str(), O_RDWR)) >= 0) {
-               off_t end = lseek (peakfile, 0, SEEK_END);
-               
-               if (end > _peak_byte_max) {
-                       ftruncate(peakfile, _peak_byte_max);
-                       //cerr << "truncated " << peakpath << " to " << _peak_byte_max << " bytes" << endl;
-               }
-               else {
-                       //cerr << "NOT truncated " << peakpath << " to " << _peak_byte_max << " end " << end << endl;
-               }
-               close (peakfile);
+       off_t end = lseek (peakfile, 0, SEEK_END);
+       
+       if (end > _peak_byte_max) {
+               ftruncate (peakfile, _peak_byte_max);
        }
 }
 
index e2531b3dcf7277907e07ce1fcac876bacc38c6cb..c8d71c5155b2199ea8065cb109483ba69c63189d 100644 (file)
@@ -316,6 +316,22 @@ Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
 #undef  CONFIG_VARIABLE_SPECIAL        
 }
 
+bool ConfigVariableBase::show_stores = false;
+
+void
+ConfigVariableBase::set_show_stored_values (bool yn)
+{
+       show_stores = yn;
+}
+
+void
+ConfigVariableBase::show_stored_value (const string& str)
+{
+       if (show_stores) {
+               cerr << "Config variable " << _name << " stored as " << str << endl;
+       }
+}
+
 void
 ConfigVariableBase::notify ()
 {
@@ -328,3 +344,4 @@ ConfigVariableBase::miss ()
        // placeholder for any debugging desired when a config variable 
        // is set but to the same value as it already has
 }
+
index d1531e4c968fa7bb401e94c1b4d3221249c644f1..2b08dce926a53a59560f0f61ec8d36779d4e63d8 100644 (file)
@@ -3867,6 +3867,10 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
                buffers.push_back (b);
        }
 
+       for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+               (*src)->prepare_for_peakfile_writes ();
+       }
+                       
        while (to_do && !itt.cancel) {
                
                this_chunk = min (to_do, chunk_size);
@@ -3909,15 +3913,6 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
                        }
                }
                
-               /* build peakfile for new source */
-               
-               for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
-                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
-                       if (afs) {
-                               afs->build_peaks ();
-                       }
-               }
-
                /* construct a region to represent the bounced material */
 
                boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(), 
@@ -3937,6 +3932,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
 
                        (*src)->drop_references ();
                }
+
+       } else {
+               for (vector<boost::shared_ptr<AudioSource> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
+                       (*src)->done_with_peakfile_writes ();
+               }
        }
 
        for (vector<Sample*>::iterator i = buffers.begin(); i != buffers.end(); ++i) {
index b47e0acb42756197b576ac1dbfdc20cd195d2b45..2f4c575883ee6e9ad55afedcdecef44fd8af5ab5 100644 (file)
@@ -396,28 +396,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
        update_length (oldlen, cnt);
 
        if (_build_peakfiles) {
-               PeakBuildRecord *pbr = 0;
-               
-               if (pending_peak_builds.size()) {
-                       pbr = pending_peak_builds.back();
-               }
-                       
-               if (pbr && pbr->frame + pbr->cnt == oldlen) {
-                       
-                       /* the last PBR extended to the start of the current write,
-                          so just extend it again.
-                       */
-                       pbr->cnt += cnt;
-               } else {
-                       pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
-               }
-
-               _peaks_built = false;
-       }
-       
-       
-       if (_build_peakfiles) {
-               queue_for_peaks (shared_from_this (), false);
+               compute_and_write_peaks (data, frame_pos, cnt, false);
        }
 
        _write_data_count = cnt;
@@ -507,32 +486,12 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
 
        old_file_pos = file_pos;
        update_length (file_pos, cnt);
-       file_pos += cnt;
 
        if (_build_peakfiles) {
-               PeakBuildRecord *pbr = 0;
-               
-               if (pending_peak_builds.size()) {
-                       pbr = pending_peak_builds.back();
-               }
-               
-               if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
-                       
-                       /* the last PBR extended to the start of the current write,
-                          so just extend it again.
-                       */
-                       
-                       pbr->cnt += cnt;
-               } else {
-                       pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
-               }
-               
-               _peaks_built = false;
+               compute_and_write_peaks (data, file_pos, cnt, false);
        }
 
-       if (_build_peakfiles) {
-               queue_for_peaks (shared_from_this (), true);
-       }
+       file_pos += cnt;
        
        return cnt;
 }
@@ -627,9 +586,6 @@ SndFileSource::set_header_timeline_position ()
                delete _broadcast_info;
                _broadcast_info = 0;
        }
-
-       
-
 }
 
 nframes_t