Merged with trunk (painfully)
[ardour.git] / libs / ardour / source.cc
index ee918375f65ac2e7578c5cec8507a4d422dcc1dd..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&
@@ -149,19 +141,19 @@ 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;
                        }
                        
@@ -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();
                }
        }
 
@@ -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)
 {
@@ -346,33 +357,6 @@ Source::initialize_peakfile (bool newfile, string audio_path)
                                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 << string_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 << string_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;
@@ -420,7 +399,8 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
        PeakData* staging = 0;
        Sample* raw_staging = 0;
        char * workbuf = 0;
-       
+       int peakfile = -1;
+
        expected_peaks = (cnt / (double) frames_per_peak);
        scale = npeaks/expected_peaks;
 
@@ -476,11 +456,21 @@ Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start
 
        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 " 
@@ -539,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) {
@@ -547,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;
@@ -669,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;
        } 
@@ -695,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) {
@@ -716,7 +718,7 @@ Source::build_peaks ()
        }
 
        { 
-               LockMonitor lm (_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (_lock);
 
                if (status == 0) {
                        _peaks_built = true;
@@ -754,6 +756,7 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
        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
@@ -772,6 +775,11 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
 
        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);
@@ -810,6 +818,9 @@ 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;
@@ -818,7 +829,7 @@ Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
 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));
@@ -852,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;
+}
+