2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sys/utime.h>
38 #include <glib/gstdio.h>
40 #include <boost/scoped_array.hpp>
41 #include <boost/scoped_ptr.hpp>
43 #include <glibmm/fileutils.h>
44 #include <glibmm/miscutils.h>
46 #include "pbd/scoped_file_descriptor.h"
47 #include "pbd/xml++.h"
49 #include "ardour/audiosource.h"
50 #include "ardour/rc_configuration.h"
51 #include "ardour/runtime_functions.h"
55 #include "ardour/debug.h"
58 using namespace ARDOUR;
61 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
62 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
63 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
64 size_t AudioSource::_working_buffers_size = 0;
65 bool AudioSource::_build_missing_peakfiles = false;
67 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
68 bool AudioSource::_build_peakfiles = false;
72 AudioSource::AudioSource (Session& s, string name)
73 : Source (s, DataType::AUDIO, name)
76 , _peaks_built (false)
78 , peak_leftover_cnt (0)
79 , peak_leftover_size (0)
84 AudioSource::AudioSource (Session& s, const XMLNode& node)
88 , _peaks_built (false)
90 , peak_leftover_cnt (0)
91 , peak_leftover_size (0)
94 if (set_state (node, Stateful::loading_state_version)) {
95 throw failed_constructor();
99 AudioSource::~AudioSource ()
101 /* shouldn't happen but make sure we don't leak file descriptors anyway */
103 if (peak_leftover_cnt) {
104 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
107 if ((-1) != _peakfile_fd) {
108 close (_peakfile_fd);
112 delete [] peak_leftovers;
116 AudioSource::get_state ()
118 XMLNode& node (Source::get_state());
120 if (_captured_for.length()) {
121 node.add_property ("captured-for", _captured_for);
128 AudioSource::set_state (const XMLNode& node, int /*version*/)
130 const XMLProperty* prop;
132 if ((prop = node.property ("captured-for")) != 0) {
133 _captured_for = prop->value();
140 AudioSource::empty () const
146 AudioSource::length (framepos_t /*pos*/) const
152 AudioSource::update_length (framecnt_t len)
160 /***********************************************************************
162 ***********************************************************************/
164 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
165 * things are set up so that doThisWhenReady is called when the peaks are ready.
166 * A new PBD::ScopedConnection is created for the associated connection and written to
167 * *connect_here_if_not.
169 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
170 * @param connect_here_if_not Address to write new ScopedConnection to.
171 * @param event_loop Event loop for doThisWhenReady to be called in.
174 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
177 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
179 if (!(ret = _peaks_built)) {
180 *connect_here_if_not = new ScopedConnection;
181 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
188 AudioSource::touch_peakfile ()
192 if (g_stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
198 tbuf.actime = statbuf.st_atime;
199 tbuf.modtime = time ((time_t*) 0);
201 g_utime (peakpath.c_str(), &tbuf);
205 AudioSource::rename_peakfile (string newpath)
207 /* caller must hold _lock */
209 string oldpath = peakpath;
211 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
212 if (g_rename (oldpath.c_str(), newpath.c_str()) != 0) {
213 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
224 AudioSource::initialize_peakfile (string audio_path)
228 peakpath = peak_path (audio_path);
230 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", peakpath, audio_path));
232 /* if the peak file should be there, but isn't .... */
234 if (!empty() && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
235 peakpath = find_broken_peakfile (peakpath, audio_path);
238 if (g_stat (peakpath.c_str(), &statbuf)) {
239 if (errno != ENOENT) {
240 /* it exists in the peaks dir, but there is some kind of error */
242 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
246 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 does not exist\n", peakpath));
248 _peaks_built = false;
252 /* we found it in the peaks dir, so check it out */
254 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
255 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", peakpath));
256 _peaks_built = false;
258 // Check if the audio file has changed since the peakfile was built.
259 struct stat stat_file;
260 int err = stat (audio_path.c_str(), &stat_file);
264 /* no audio path - nested source or we can't
265 read it or ... whatever, use the peakfile as-is.
267 DEBUG_TRACE(DEBUG::Peaks, string_compose("Error when calling stat on Peakfile %1\n", peakpath));
270 _peak_byte_max = statbuf.st_size;
274 /* allow 6 seconds slop on checking peak vs. file times because of various
278 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
279 _peaks_built = false;
283 _peak_byte_max = statbuf.st_size;
289 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
290 build_peaks_from_scratch ();
297 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
301 Glib::Threads::Mutex::Lock lm (_lock);
302 return read_unlocked (dst, start, cnt);
306 AudioSource::write (Sample *dst, framecnt_t cnt)
308 Glib::Threads::Mutex::Lock lm (_lock);
309 /* any write makes the file not removable */
310 _flags = Flag (_flags & ~Removable);
311 return write_unlocked (dst, cnt);
315 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
317 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
320 /** @param peaks Buffer to write peak data.
321 * @param npeaks Number of peaks to write.
325 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
326 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
328 Glib::Threads::Mutex::Lock lm (_lock);
330 double expected_peaks;
331 PeakData::PeakDatum xmax;
332 PeakData::PeakDatum xmin;
335 framecnt_t zero_fill = 0;
337 ScopedFileDescriptor sfd (::open (peakpath.c_str(), O_RDONLY));
340 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), peakpath, strerror (errno)) << endmsg;
344 expected_peaks = (cnt / (double) samples_per_file_peak);
345 scale = npeaks/expected_peaks;
347 DEBUG_TRACE (DEBUG::Peaks, string_compose (" ======>RP: npeaks = %1 start = %2 cnt = %3 len = %4 samples_per_visual_peak = %5 expected was %6 ... scale = %7 PD ptr = %8\n"
348 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
350 /* fix for near-end-of-file conditions */
352 if (cnt > _length - start) {
353 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
354 cnt = _length - start;
355 framecnt_t old = npeaks;
356 npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
357 zero_fill = old - npeaks;
360 // cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl;
364 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
366 /* no scaling at all, just get the sample data and duplicate it for
367 both max and min peak values.
370 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
372 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
373 error << _("cannot read sample data for unscaled peak computation") << endmsg;
377 for (framecnt_t i = 0; i < npeaks; ++i) {
378 peaks[i].max = raw_staging[i];
379 peaks[i].min = raw_staging[i];
388 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
389 ssize_t bytes_to_read = sizeof (PeakData)* npeaks;
390 /* open, read, close */
392 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
394 offset = lseek (sfd, first_peak_byte, SEEK_SET);
396 if (offset != first_peak_byte) {
397 error << string_compose(_("AudioSource: could not seek to correct location in peak file \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
401 nread = ::read (sfd, peaks, bytes_to_read);
403 if (nread != bytes_to_read) {
404 DEBUG_TRACE (DEBUG::Peaks, string_compose ("[%1]: Cannot read peaks from peakfile! (read only %2 not %3 at sample %4 = byte %5 )\n"
405 , _name, nread, npeaks, start, first_peak_byte));
410 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
421 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
425 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
426 - less peaks than the peakfile holds for the same range
428 So, read a block into a staging area, and then downsample from there.
430 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
433 const framecnt_t chunksize = (framecnt_t) min (expected_peaks, 65536.0);
435 boost::scoped_array<PeakData> staging(new PeakData[chunksize]);
437 /* compute the rounded up frame position */
439 framepos_t current_frame = start;
440 framepos_t current_stored_peak = (framepos_t) ceil (current_frame / (double) samples_per_file_peak);
441 framepos_t next_visual_peak = (framepos_t) ceil (current_frame / samples_per_visual_peak);
442 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
443 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
444 framecnt_t nvisual_peaks = 0;
445 framecnt_t stored_peaks_read = 0;
448 /* handle the case where the initial visual peak is on a pixel boundary */
450 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
452 /* open ... close during out: handling */
454 while (nvisual_peaks < npeaks) {
456 if (i == stored_peaks_read) {
458 uint32_t start_byte = current_stored_peak * sizeof(PeakData);
459 tnp = min ((framecnt_t)(_length/samples_per_file_peak - current_stored_peak), (framecnt_t) expected_peaks);
460 to_read = min (chunksize, tnp);
461 ssize_t bytes_to_read = sizeof (PeakData) * to_read;
463 DEBUG_TRACE (DEBUG::Peaks, string_compose ("reading %1 bytes from peakfile @ %2\n"
464 , bytes_to_read, start_byte));
467 off_t offset = lseek (sfd, start_byte, SEEK_SET);
469 if (offset != start_byte) {
470 error << string_compose(_("AudioSource: could not seek to correct location in peak file \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
474 if ((nread = ::read (sfd, staging.get(), bytes_to_read)) != bytes_to_read) {
476 off_t fend = lseek (sfd, 0, SEEK_END);
478 DEBUG_TRACE (DEBUG::Peaks, string_compose ("[%1]: cannot read peak data from peakfile (%2 peaks instead of %3) (%4) at start_byte = %5 _length = %6 versus len = %7 expected maxpeaks = %8 npeaks was %9"
479 , _name, (nread / sizeof(PeakData)), to_read, g_strerror (errno), start_byte, _length, fend, ((_length - current_frame)/samples_per_file_peak), npeaks));
483 stored_peaks_read = nread / sizeof(PeakData);
489 while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
491 xmax = max (xmax, staging[i].max);
492 xmin = min (xmin, staging[i].min);
494 ++current_stored_peak;
498 peaks[nvisual_peaks].max = xmax;
499 peaks[nvisual_peaks].min = xmin;
503 //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
504 next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
505 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
509 cerr << "Zero fill end of peaks (@ " << npeaks << " with " << zero_fill << endl;
510 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
515 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
519 - less frames-per-peak (more resolution)
520 - more peaks than stored in the Peakfile
522 So, fetch data from the raw source, and generate peak
526 framecnt_t frames_read = 0;
527 framepos_t current_frame = start;
529 framecnt_t nvisual_peaks = 0;
530 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
531 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
533 framepos_t frame_pos = start;
534 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
535 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
536 double pixels_per_frame = 1.0 / samples_per_visual_peak;
541 while (nvisual_peaks < npeaks) {
543 if (i == frames_read) {
545 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
547 if (current_frame >= _length) {
549 /* hmm, error condition - we've reached the end of the file
550 without generating all the peak data. cook up a zero-filled
551 data buffer and then use it. this is simpler than
552 adjusting zero_fill and npeaks and then breaking out of
556 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
560 to_read = min (chunksize, (_length - current_frame));
563 if ((frames_read = read_unlocked (raw_staging.get(), current_frame, to_read)) == 0) {
564 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
565 _name, to_read, current_frame, _length, strerror (errno))
574 xmax = max (xmax, raw_staging[i]);
575 xmin = min (xmin, raw_staging[i]);
578 pixel_pos += pixels_per_frame;
580 if (pixel_pos >= next_pixel_pos) {
582 peaks[nvisual_peaks].max = xmax;
583 peaks[nvisual_peaks].min = xmin;
588 next_pixel_pos = ceil (pixel_pos + 0.5);
593 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
597 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
602 AudioSource::build_peaks_from_scratch ()
604 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
606 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
611 /* hold lock while building peaks */
613 Glib::Threads::Mutex::Lock lp (_lock);
615 if (prepare_for_peakfile_writes ()) {
619 framecnt_t current_frame = 0;
620 framecnt_t cnt = _length;
622 _peaks_built = false;
623 boost::scoped_array<Sample> buf(new Sample[bufsize]);
627 framecnt_t frames_to_read = min (bufsize, cnt);
628 framecnt_t frames_read;
630 if ((frames_read = read_unlocked (buf.get(), current_frame, frames_to_read)) != frames_to_read) {
631 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
632 done_with_peakfile_writes (false);
636 if (compute_and_write_peaks (buf.get(), current_frame, frames_read, true, false, _FPP)) {
640 current_frame += frames_read;
649 done_with_peakfile_writes ((cnt == 0));
657 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", peakpath));
658 ::g_unlink (peakpath.c_str());
665 AudioSource::prepare_for_peakfile_writes ()
667 if ((_peakfile_fd = open (peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
668 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
675 AudioSource::done_with_peakfile_writes (bool done)
677 if (peak_leftover_cnt) {
678 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
682 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
684 PeaksReady (); /* EMIT SIGNAL */
687 close (_peakfile_fd);
691 /** @param first_frame Offset from the source start of the first frame to process */
693 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
694 bool force, bool intermediate_peaks_ready)
696 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
700 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
701 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
704 uint32_t peaks_computed;
705 framepos_t current_frame;
706 framecnt_t frames_done;
707 const size_t blocksize = (128 * 1024);
708 off_t first_peak_byte;
709 boost::scoped_array<Sample> buf2;
711 if (_peakfile_fd < 0) {
712 if (prepare_for_peakfile_writes ()) {
718 if (peak_leftover_cnt) {
720 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
722 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
723 and we have leftovers. flush a single peak (since the leftovers
724 never represent more than that, and restart.
729 x.min = peak_leftovers[0];
730 x.max = peak_leftovers[0];
732 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
734 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
736 if (offset != byte) {
737 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
741 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
742 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
746 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
749 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
750 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
751 if (intermediate_peaks_ready) {
752 PeaksReady (); /* EMIT SIGNAL */
756 /* left overs are done */
758 peak_leftover_cnt = 0;
762 /* else ... had leftovers, but they immediately preceed the new data, so just
763 merge them and compute.
766 /* make a new contiguous buffer containing leftovers and the new stuff */
768 to_do = cnt + peak_leftover_cnt;
769 buf2.reset(new Sample[to_do]);
772 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
775 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
777 /* no more leftovers */
778 peak_leftover_cnt = 0;
780 /* use the temporary buffer */
783 /* make sure that when we write into the peakfile, we startup where we left off */
785 first_frame = peak_leftover_frame;
791 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
793 current_frame = first_frame;
798 /* if some frames were passed in (i.e. we're not flushing leftovers)
799 and there are less than fpp to do, save them till
803 if (force && (to_do < fpp)) {
804 /* keep the left overs around for next time */
806 if (peak_leftover_size < to_do) {
807 delete [] peak_leftovers;
808 peak_leftovers = new Sample[to_do];
809 peak_leftover_size = to_do;
811 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
812 peak_leftover_cnt = to_do;
813 peak_leftover_frame = current_frame;
820 framecnt_t this_time = min (fpp, to_do);
822 peakbuf[peaks_computed].max = buf[0];
823 peakbuf[peaks_computed].min = buf[0];
825 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
830 frames_done += this_time;
831 current_frame += this_time;
834 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
836 if (can_truncate_peaks()) {
838 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
839 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
840 it does not cause single-extent allocation even for peakfiles of
841 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
844 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
845 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
847 if (endpos < target_length) {
848 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", peakpath));
849 if (ftruncate (_peakfile_fd, target_length)) {
850 /* error doesn't actually matter so continue on without testing */
856 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
858 if (offset != first_peak_byte) {
859 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
863 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
865 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
867 if (bytes_written != bytes_to_write) {
868 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
872 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
875 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
876 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
877 if (intermediate_peaks_ready) {
878 PeaksReady (); /* EMIT SIGNAL */
886 AudioSource::truncate_peakfile ()
888 if (_peakfile_fd < 0) {
889 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
894 /* truncate the peakfile down to its natural length if necessary */
896 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
898 if (end > _peak_byte_max) {
899 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", peakpath));
900 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
901 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
902 peakpath, _peak_byte_max, errno) << endmsg;
908 AudioSource::available_peaks (double zoom_factor) const
910 if (zoom_factor < _FPP) {
911 return length(_timeline_position); // peak data will come from the audio file
914 /* peak data comes from peakfile, but the filesize might not represent
915 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
916 XXX - there might be some atomicity issues here, we should probably add a lock,
917 but _peak_byte_max only monotonically increases after initialization.
920 off_t end = _peak_byte_max;
922 return (end/sizeof(PeakData)) * _FPP;
926 AudioSource::mark_streaming_write_completed ()
928 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
931 PeaksReady (); /* EMIT SIGNAL */
936 AudioSource::allocate_working_buffers (framecnt_t framerate)
938 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
941 /* Note: we don't need any buffers allocated until
942 a level 1 audiosource is created, at which
943 time we'll call ::ensure_buffers_for_level()
944 with the right value and do the right thing.
947 if (!_mixdown_buffers.empty()) {
948 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
953 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
955 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
956 ensure_buffers_for_level_locked (level, frame_rate);
960 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
962 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
964 /* this may be called because either "level" or "frame_rate" have
965 * changed. and it may be called with "level" smaller than the current
966 * number of buffers, because a new compound region has been created at
967 * a more shallow level than the deepest one we currently have.
970 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
972 _mixdown_buffers.clear ();
973 _gain_buffers.clear ();
975 for (uint32_t n = 0; n < limit; ++n) {
976 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
977 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));