diff options
Diffstat (limited to 'libs/ardour/audiosource.cc')
-rw-r--r-- | libs/ardour/audiosource.cc | 116 |
1 files changed, 87 insertions, 29 deletions
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index 93165b7fe4..203590a4e1 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -35,6 +35,7 @@ #include <pbd/pthread_utils.h> #include <ardour/audiosource.h> +#include <ardour/cycle_timer.h> #include "i18n.h" @@ -59,6 +60,7 @@ AudioSource::AudioSource (Session& s, string name) } _peaks_built = false; + _peak_byte_max = 0; next_peak_clear_should_notify = true; _read_data_count = 0; _write_data_count = 0; @@ -72,6 +74,7 @@ AudioSource::AudioSource (Session& s, const XMLNode& node) } _peaks_built = false; + _peak_byte_max = 0; next_peak_clear_should_notify = true; _read_data_count = 0; _write_data_count = 0; @@ -251,13 +254,13 @@ AudioSource::stop_peak_thread () } void -AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source) +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 = true; + source->next_peak_clear_should_notify = notify; if (find (pending_peak_sources.begin(), pending_peak_sources.end(), @@ -384,8 +387,10 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path) if (!err && stat_file.st_mtime > statbuf.st_mtime){ _peaks_built = false; + _peak_byte_max = 0; } else { _peaks_built = true; + _peak_byte_max = statbuf.st_size; } } } @@ -431,7 +436,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr expected_peaks = (cnt / (double) frames_per_peak); scale = npeaks/expected_peaks; -#if 0 +#undef DEBUG_READ_PEAKS +#ifdef DEBUG_READ_PEAKS cerr << "======>RP: npeaks = " << npeaks << " start = " << start << " cnt = " << cnt @@ -457,8 +463,9 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr if (npeaks == cnt) { +#ifdef DEBUG_READ_PEAKS cerr << "RAW DATA\n"; - +#endif /* no scaling at all, just get the sample data and duplicate it for both max and min peak values. */ @@ -485,12 +492,14 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr /* open, read, close */ - if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 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; } - // cerr << "DIRECT PEAKS\n"; +#ifdef DEBUG_READ_PEAKS + cerr << "DIRECT PEAKS\n"; +#endif nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte); close (peakfile); @@ -523,8 +532,9 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr if (scale < 1.0) { - // cerr << "DOWNSAMPLE\n"; - +#ifdef DEBUG_READ_PEAKS + cerr << "DOWNSAMPLE\n"; +#endif /* the caller wants: - more frames-per-peak (lower resolution) than the peakfile, or to put it another way, @@ -535,7 +545,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks */ - const uint32_t chunksize = (uint32_t) min (expected_peaks, 4096.0); + const uint32_t chunksize = (uint32_t) min (expected_peaks, 65536.0); staging = new PeakData[chunksize]; @@ -556,7 +566,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_RDWR|O_CREAT, 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; } @@ -569,10 +579,15 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr tnp = min ((_length/frames_per_peak - current_stored_peak), (nframes_t) expected_peaks); to_read = min (chunksize, tnp); - off_t fend = lseek (peakfile, 0, SEEK_END); +#ifdef DEBUG_READ_PEAKS + cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl; +#endif if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte)) != sizeof (PeakData) * to_read) { + + off_t fend = lseek (peakfile, 0, SEEK_END); + cerr << "AudioSource[" << _name << "]: cannot read peak data from peakfile (" @@ -589,11 +604,11 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr << endl; goto out; } - + i = 0; stored_peaks_read = nread / sizeof(PeakData); } - + xmax = -1.0; xmin = 1.0; @@ -624,8 +639,9 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr } else { - // cerr << "UPSAMPLE\n"; - +#ifdef DEBUG_READ_PEAKS + cerr << "UPSAMPLE\n"; +#endif /* the caller wants - less frames-per-peak (more resolution) @@ -704,6 +720,10 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr delete [] raw_staging; } +#ifdef DEBUG_READ_PEAKS + cerr << "RP DONE\n"; +#endif + return ret; } @@ -757,6 +777,7 @@ AudioSource::build_peaks () } if (pr_signal) { + truncate_peakfile(); PeaksReady (); /* EMIT SIGNAL */ } } @@ -777,6 +798,8 @@ AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt) off_t first_peak_byte; int peakfile = -1; int ret = -1; + off_t target_length; + off_t endpos; #ifdef DEBUG_PEAK_BUILD cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl; @@ -828,11 +851,32 @@ AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt) cnt -= frames_read; } +#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); + + 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; + + /* 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)) { 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)); + ret = 0; out: @@ -850,7 +894,28 @@ AudioSource::build_peaks_from_scratch () next_peak_clear_should_notify = true; pending_peak_builds.push_back (new PeakBuildRecord (0, _length)); - queue_for_peaks (shared_from_this()); + queue_for_peaks (shared_from_this(), true); +} + +void +AudioSource::truncate_peakfile () +{ + int peakfile = -1; + + /* 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); + } } bool @@ -872,26 +937,19 @@ AudioSource::file_changed (string path) nframes_t AudioSource::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(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; - return 0; - } - - { - Glib::Mutex::Lock lm (_lock); - end = lseek (peakfile, 0, SEEK_END); - } + /* peak data comes from peakfile, but the filesize might not represent + the valid data due to ftruncate optimizations, so use _peak_byte_max state. + XXX - there might be some atomicity issues here, we should probably add a lock, + but _peak_byte_max only monotonically increases after initialization. + */ - close (peakfile); + end = _peak_byte_max; return (end/sizeof(PeakData)) * frames_per_peak; } |