pulling trunk
[ardour.git] / libs / ardour / source.cc
index c7db3337cab1da60ae34b399b23025c0eac52ca6..7d790a036d7f24c6a345872bb36925076a7cc543 100644 (file)
 #include <iomanip>
 #include <algorithm>
 
-#include <pbd/lockmonitor.h>
+#include <glibmm/thread.h>
 #include <pbd/xml++.h>
 #include <pbd/pthread_utils.h>
 
 #include <ardour/source.h>
-#include <ardour/filesource.h>
-#include <ardour/sndfilesource.h>
 
 #include "i18n.h"
 
@@ -43,13 +41,12 @@ using std::min;
 using std::max;
 
 using namespace ARDOUR;
-using namespace PBD;
 
-sigc::signal<void,Source *> Source::SourceCreated;
+sigc::signal<void,Source *>  Source::SourceCreated;
 pthread_t                    Source::peak_thread;
 bool                         Source::have_peak_thread = false;
 vector<Source*>              Source::pending_peak_sources;
-PBD::Lock                    Source::pending_peak_sources_lock;
+Glib::StaticMutex            Source::pending_peak_sources_lock = GLIBMM_STATIC_MUTEX_INIT;
 int                          Source::peak_request_pipe[2];
 
 bool Source::_build_missing_peakfiles = false;
@@ -61,7 +58,6 @@ Source::Source (bool announce)
        _use_cnt = 0;
        _peaks_built = false;
        next_peak_clear_should_notify = true;
-       peakfile = -1;
        _timestamp = 0;
        _read_data_count = 0;
        _write_data_count = 0;
@@ -72,7 +68,6 @@ Source::Source (const XMLNode& node)
        _use_cnt = 0;
        _peaks_built = false;
        next_peak_clear_should_notify = true;
-       peakfile = -1;
        _timestamp = 0;
        _read_data_count = 0;
        _write_data_count = 0;
@@ -84,9 +79,6 @@ Source::Source (const XMLNode& node)
 
 Source::~Source ()
 {
-       if (peakfile >= 0) {
-               close (peakfile);
-       }
 }
 
 XMLNode&
@@ -96,7 +88,7 @@ Source::get_state ()
        char buf[64];
 
        node->add_property ("name", _name);
-       snprintf (buf, sizeof(buf)-1, "%llu", _id);
+       snprintf (buf, sizeof(buf)-1, "%" PRIu64, _id);
        node->add_property ("id", buf);
 
        if (_timestamp != 0) {
@@ -123,7 +115,7 @@ Source::set_state (const XMLNode& node)
        }
        
        if ((prop = node.property ("id")) != 0) {
-               sscanf (prop->value().c_str(), "%llu", &_id);
+               sscanf (prop->value().c_str(), "%" PRIu64, &_id);
        } else {
                return -1;
        }
@@ -149,23 +141,23 @@ Source::peak_thread_work (void* arg)
        PBD::ThreadCreated (pthread_self(), X_("Peak"));
        struct pollfd pfd[1];
 
-       LockMonitor lm (pending_peak_sources_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (pending_peak_sources_lock);
 
        while (true) {
 
                pfd[0].fd = peak_request_pipe[0];
                pfd[0].events = POLLIN|POLLERR|POLLHUP;
 
-               pthread_mutex_unlock (pending_peak_sources_lock.mutex());
+               pending_peak_sources_lock.unlock();
 
                if (poll (pfd, 1, -1) < 0) {
 
                        if (errno == EINTR) {
-                               pthread_mutex_lock (pending_peak_sources_lock.mutex());
+                               pending_peak_sources_lock.lock();
                                continue;
                        }
                        
-                       error << compose (_("poll on peak request pipe failed (%1)"),
+                       error << string_compose (_("poll on peak request pipe failed (%1)"),
                                          strerror (errno))
                              << endmsg;
                        break;
@@ -211,16 +203,16 @@ Source::peak_thread_work (void* arg)
                        }
                }
 
-               pthread_mutex_lock (pending_peak_sources_lock.mutex());
+               pending_peak_sources_lock.lock();
 
                while (!pending_peak_sources.empty()) {
 
                        Source* s = pending_peak_sources.front();
                        pending_peak_sources.erase (pending_peak_sources.begin());
 
-                       pthread_mutex_unlock (pending_peak_sources_lock.mutex());
+                       pending_peak_sources_lock.unlock();
                        s->build_peaks();
-                       pthread_mutex_lock (pending_peak_sources_lock.mutex());
+                       pending_peak_sources_lock.lock();
                }
        }
 
@@ -237,17 +229,17 @@ Source::start_peak_thread ()
        }
 
        if (pipe (peak_request_pipe)) {
-               error << compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg;
+               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 << compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
+               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 << compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
+               error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
                return -1;
        }
 
@@ -279,7 +271,7 @@ Source::queue_for_peaks (Source& source)
 {
        if (have_peak_thread) {
 
-               LockMonitor lm (pending_peak_sources_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (pending_peak_sources_lock);
 
                source.next_peak_clear_should_notify = true;
 
@@ -298,29 +290,48 @@ void Source::clear_queue_for_peaks ()
 {
        /* this is done to cancel a group of running peak builds */
        if (have_peak_thread) {
-               LockMonitor lm (pending_peak_sources_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (pending_peak_sources_lock);
                pending_peak_sources.clear ();
        }
 }
 
 
 bool
-Source::peaks_ready (sigc::slot<void> the_slot) const
+Source::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
 {
        bool ret;
-       LockMonitor lm (_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (_lock);
 
        /* check to see if the peak data is ready. if not
           connect the slot while still holding the lock.
        */
 
        if (!(ret = _peaks_built)) {
-               PeaksReady.connect (the_slot);
+               conn = PeaksReady.connect (the_slot);
        }
 
        return ret;
 }
 
+int
+Source::rename_peakfile (string newpath)
+{
+       /* caller must hold _lock */
+
+       string oldpath = peakpath;
+
+       if (access (oldpath.c_str(), F_OK) == 0) {
+               if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
+                       error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
+                       return -1;
+               }
+       }
+
+       peakpath = newpath;
+
+       return 0;
+}
+
 int
 Source::initialize_peakfile (bool newfile, string audio_path)
 {
@@ -342,37 +353,10 @@ Source::initialize_peakfile (bool newfile, string audio_path)
                        if (errno != ENOENT) {
                                /* it exists in the peaks dir, but there is some kind of error */
                                
-                               error << compose(_("Source: cannot stat peakfile \"%1\""), peakpath) << endmsg;
+                               error << string_compose(_("Source: cannot stat peakfile \"%1\""), peakpath) << endmsg;
                                return -1;
                        }
 
-                       /* older sessions stored peaks in the same directory
-                          as the audio. so check there as well.
-                       */
-                       
-                       string oldpeakpath = old_peak_path (audio_path);
-                       
-                       if (stat (oldpeakpath.c_str(), &statbuf)) {
-                               
-                               if (errno == ENOENT) {
-
-                                       statbuf.st_size = 0;
-
-                               } else {
-                                       
-                                       /* it exists in the audio dir , but there is some kind of error */
-                                       
-                                       error << compose(_("Source: cannot stat peakfile \"%1\" or \"%2\""), peakpath, oldpeakpath) << endmsg;
-                                       return -1;
-                               }
-                               
-                       } else {
-
-                               /* we found it in the sound dir, where they lived once upon a time, in a land ... etc. */
-
-                               peakpath = oldpeakpath;
-                       }
-
                } else {
                        
                        /* we found it in the peaks dir */
@@ -393,11 +377,6 @@ Source::initialize_peakfile (bool newfile, string audio_path)
                }
        }
 
-       if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
-               error << compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
-               return -1;
-       }
-
        if (!newfile && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
                build_peaks_from_scratch ();
        } 
@@ -408,7 +387,7 @@ Source::initialize_peakfile (bool newfile, string audio_path)
 int 
 Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start, jack_nframes_t cnt, double samples_per_visual_peak) const
 {
-       LockMonitor lm (_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (_lock);
        double scale;
        double expected_peaks;
        PeakData::PeakDatum xmax;
@@ -419,6 +398,8 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
        int ret = -1;
        PeakData* staging = 0;
        Sample* raw_staging = 0;
+       char * workbuf = 0;
+       int peakfile = -1;
 
        expected_peaks = (cnt / (double) frames_per_peak);
        scale = npeaks/expected_peaks;
@@ -456,8 +437,9 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
                */
 
                Sample* raw_staging = new Sample[cnt];
+               workbuf = new char[cnt*4];
                
-               if (read_unlocked (raw_staging, start, cnt) != cnt) {
+               if (read_unlocked (raw_staging, start, cnt, workbuf) != cnt) {
                        error << _("cannot read sample data for unscaled peak computation") << endmsg;
                        return -1;
                }
@@ -468,17 +450,27 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
                }
 
                delete [] raw_staging;
-               
+               delete [] workbuf;
                return 0;
        }
 
        if (scale == 1.0) {
 
+               off_t first_peak_byte = (start / frames_per_peak) * sizeof (PeakData);
+
+               /* open, read, close */
+
+               if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
+                       error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+                       return -1;
+               }
+
                // cerr << "DIRECT PEAKS\n";
                
-               off_t first_peak_byte = (start / frames_per_peak) * sizeof (PeakData);
+               nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
+               close (peakfile);
 
-               if ((nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte)) != sizeof (PeakData) * npeaks) {
+               if (nread != sizeof (PeakData) * npeaks) {
                        cerr << "Source["
                             << _name
                             << "]: cannot read peaks from peakfile! (read only " 
@@ -537,6 +529,13 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
 
                current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
 
+               /* open ... close during out: handling */
+
+               if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
+                       error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+                       return 0;
+               }
+
                while (nvisual_peaks < npeaks) {
 
                        if (i == stored_peaks_read) {
@@ -545,19 +544,21 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
                                tnp = min ((_length/frames_per_peak - current_stored_peak), (jack_nframes_t) expected_peaks);
                                to_read = min (chunksize, tnp);
                                
+                               off_t fend = lseek (peakfile, 0, SEEK_END);
+                               
                                if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte))
                                    != sizeof (PeakData) * to_read) {
                                        cerr << "Source["
                                             << _name
                                             << "]: cannot read peak data from peakfile ("
-                                            << nread 
+                                            << (nread / sizeof(PeakData))
                                             << " peaks instead of "
                                             << to_read
                                             << ") ("
                                             << strerror (errno)
                                             << ')'
                                             << " at start_byte = " << start_byte 
-                                            << " _length = " << _length
+                                            << " _length = " << _length << " versus len = " << fend
                                             << " expected maxpeaks = " << (_length - current_frame)/frames_per_peak
                                             << " npeaks was " << npeaks
                                             << endl;
@@ -615,7 +616,8 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
                jack_nframes_t nvisual_peaks = 0;
                jack_nframes_t chunksize = (jack_nframes_t) min (cnt, (jack_nframes_t) 4096);
                raw_staging = new Sample[chunksize];
-
+               workbuf = new char[chunksize *4];
+               
                jack_nframes_t frame_pos = start;
                double pixel_pos = floor (frame_pos / samples_per_visual_peak);
                double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
@@ -630,8 +632,8 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
                                
                                to_read = min (chunksize, (_length - current_frame));
                                
-                               if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) < 0) {
-                                       error << compose(_("Source[%1]: peak read - cannot read %2 samples at offset %3")
+                               if ((frames_read = read_unlocked (raw_staging, current_frame, to_read, workbuf)) < 0) {
+                                       error << string_compose(_("Source[%1]: peak read - cannot read %2 samples at offset %3")
                                                         , _name, to_read, current_frame) 
                                              << endmsg;
                                        goto out;
@@ -666,6 +668,10 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
        }
 
   out:
+       if (peakfile >= 0) {
+               close (peakfile);
+       }
+
        if (staging) {
                delete [] staging;
        } 
@@ -674,6 +680,10 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
                delete [] raw_staging;
        }
 
+       if (workbuf) {
+               delete [] workbuf;
+       }
+       
        return ret;
 }
 
@@ -688,14 +698,13 @@ Source::build_peaks ()
        list<PeakBuildRecord*> copy;
 
        {
-               LockMonitor lm (_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (_lock);
                copy = pending_peak_builds;
                pending_peak_builds.clear ();
        }
                
-
 #ifdef DEBUG_PEAK_BUILD
-       cerr << "build peaks with " << pending_peak_builds.size() << " requests pending\n";
+       cerr << "build peaks with " << copy.size() << " requests pending\n";
 #endif         
 
        for (list<PeakBuildRecord *>::iterator i = copy.begin(); i != copy.end(); ++i) {
@@ -709,7 +718,7 @@ Source::build_peaks ()
        }
 
        { 
-               LockMonitor lm (_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (_lock);
 
                if (status == 0) {
                        _peaks_built = true;
@@ -743,9 +752,11 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
        Sample xmin, xmax;
        uint32_t  peaki;
        PeakData* peakbuf;
+       char * workbuf = 0;
        jack_nframes_t frames_read;
        jack_nframes_t frames_to_read;
        off_t first_peak_byte;
+       int peakfile = -1;
        int ret = -1;
 
 #ifdef DEBUG_PEAK_BUILD
@@ -762,12 +773,19 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
        peakbuf = new PeakData[(cnt/frames_per_peak)+1];
        peaki = 0;
 
+       workbuf = new char[max(frames_per_peak, cnt) * 4];
+       
+       if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
+               error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+               return -1;
+       }
+       
        while (cnt) {
 
                frames_to_read = min (frames_per_peak, cnt);
 
-               if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
-                       error << compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
+               if ((frames_read = read_unlocked (buf, current_frame, frames_to_read, workbuf)) != frames_to_read) {
+                       error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
                        goto out;
                }
 
@@ -791,8 +809,8 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
                cnt -= frames_read;
        }
 
-       if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (size_t) sizeof (PeakData) * peaki) {
-               error << compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
+       if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) {
+               error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
                goto out;
        }
 
@@ -800,13 +818,18 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
 
   out:
        delete [] peakbuf;
+       if (peakfile >= 0) {
+               close (peakfile);
+       }
+       if (workbuf)
+               delete [] workbuf;
        return ret;
 }
 
 void
 Source::build_peaks_from_scratch ()
 {
-       LockMonitor lp (_lock, __LINE__, __FILE__); 
+       Glib::Mutex::Lock lp (_lock); 
 
        next_peak_clear_should_notify = true;
        pending_peak_builds.push_back (new PeakBuildRecord (0, _length));
@@ -840,3 +863,31 @@ Source::release ()
 {
        if (_use_cnt) --_use_cnt;
 }
+
+jack_nframes_t
+Source::available_peaks (double zoom_factor) const
+{
+       int peakfile;
+       off_t end;
+
+       if (zoom_factor < frames_per_peak) {
+               return length(); // peak data will come from the audio file
+       } 
+       
+       /* peak data comes from peakfile */
+
+       if ((peakfile = ::open (peakpath.c_str(), O_RDONLY)) < 0) {
+               error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+               return 0;
+       }
+
+       { 
+               Glib::Mutex::Lock lm (_lock);
+               end = lseek (peakfile, 0, SEEK_END);
+       }
+
+       close (peakfile);
+
+       return (end/sizeof(PeakData)) * frames_per_peak;
+}
+