summaryrefslogtreecommitdiff
path: root/libs/ardour/audiosource.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/audiosource.cc')
-rw-r--r--libs/ardour/audiosource.cc116
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;
}