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.
33 #include <glibmm/fileutils.h>
34 #include <glibmm/miscutils.h>
36 #include "pbd/xml++.h"
38 #include "ardour/audiosource.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/runtime_functions.h"
44 #include "ardour/debug.h"
47 using namespace ARDOUR;
50 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
51 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
52 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
53 size_t AudioSource::_working_buffers_size = 0;
54 bool AudioSource::_build_missing_peakfiles = false;
56 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
57 bool AudioSource::_build_peakfiles = false;
61 AudioSource::AudioSource (Session& s, string name)
62 : Source (s, DataType::AUDIO, name)
67 _peakfile_descriptor = 0;
68 peak_leftover_cnt = 0;
69 peak_leftover_size = 0;
73 AudioSource::AudioSource (Session& s, const XMLNode& node)
80 _peakfile_descriptor = 0;
81 peak_leftover_cnt = 0;
82 peak_leftover_size = 0;
85 if (set_state (node, Stateful::loading_state_version)) {
86 throw failed_constructor();
90 AudioSource::~AudioSource ()
92 /* shouldn't happen but make sure we don't leak file descriptors anyway */
94 if (peak_leftover_cnt) {
95 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
98 delete _peakfile_descriptor;
99 delete [] peak_leftovers;
103 AudioSource::get_state ()
105 XMLNode& node (Source::get_state());
107 if (_captured_for.length()) {
108 node.add_property ("captured-for", _captured_for);
115 AudioSource::set_state (const XMLNode& node, int /*version*/)
117 const XMLProperty* prop;
119 if ((prop = node.property ("captured-for")) != 0) {
120 _captured_for = prop->value();
127 AudioSource::empty () const
133 AudioSource::length (framepos_t /*pos*/) const
139 AudioSource::update_length (framecnt_t len)
147 /***********************************************************************
149 ***********************************************************************/
151 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
152 * things are set up so that doThisWhenReady is called when the peaks are ready.
153 * A new PBD::ScopedConnection is created for the associated connection and written to
154 * *connect_here_if_not.
156 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
157 * @param connect_here_if_not Address to write new ScopedConnection to.
158 * @param event_loop Event loop for doThisWhenReady to be called in.
161 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
164 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
166 if (!(ret = _peaks_built)) {
167 *connect_here_if_not = new ScopedConnection;
168 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
175 AudioSource::touch_peakfile ()
179 if (stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
185 tbuf.actime = statbuf.st_atime;
186 tbuf.modtime = time ((time_t) 0);
188 utime (peakpath.c_str(), &tbuf);
192 AudioSource::rename_peakfile (string newpath)
194 /* caller must hold _lock */
196 string oldpath = peakpath;
198 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
199 if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
200 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
211 AudioSource::initialize_peakfile (string audio_path)
215 peakpath = peak_path (audio_path);
217 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", peakpath, audio_path));
219 /* if the peak file should be there, but isn't .... */
221 if (!empty() && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
222 peakpath = find_broken_peakfile (peakpath, audio_path);
225 if (stat (peakpath.c_str(), &statbuf)) {
226 if (errno != ENOENT) {
227 /* it exists in the peaks dir, but there is some kind of error */
229 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
233 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 does not exist\n", peakpath));
235 _peaks_built = false;
239 /* we found it in the peaks dir, so check it out */
241 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
242 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", peakpath));
243 _peaks_built = false;
245 // Check if the audio file has changed since the peakfile was built.
246 struct stat stat_file;
247 int err = stat (audio_path.c_str(), &stat_file);
251 /* no audio path - nested source or we can't
252 read it or ... whatever, use the peakfile as-is.
254 DEBUG_TRACE(DEBUG::Peaks, string_compose("Error when calling stat on Peakfile %1\n", peakpath));
257 _peak_byte_max = statbuf.st_size;
261 /* allow 6 seconds slop on checking peak vs. file times because of various
265 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
266 _peaks_built = false;
270 _peak_byte_max = statbuf.st_size;
276 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
277 build_peaks_from_scratch ();
284 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
288 Glib::Threads::Mutex::Lock lm (_lock);
289 return read_unlocked (dst, start, cnt);
293 AudioSource::write (Sample *dst, framecnt_t cnt)
295 Glib::Threads::Mutex::Lock lm (_lock);
296 /* any write makes the fill not removable */
297 _flags = Flag (_flags & ~Removable);
298 return write_unlocked (dst, cnt);
302 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
304 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
307 /** @param peaks Buffer to write peak data.
308 * @param npeaks Number of peaks to write.
312 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
313 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
315 Glib::Threads::Mutex::Lock lm (_lock);
317 double expected_peaks;
318 PeakData::PeakDatum xmax;
319 PeakData::PeakDatum xmin;
322 framecnt_t zero_fill = 0;
324 PeakData* staging = 0;
325 Sample* raw_staging = 0;
327 FdFileDescriptor* peakfile_descriptor = new FdFileDescriptor (peakpath, false, 0664);
328 int peakfile_fd = -1;
330 expected_peaks = (cnt / (double) samples_per_file_peak);
331 scale = npeaks/expected_peaks;
333 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"
334 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
336 /* fix for near-end-of-file conditions */
338 if (cnt > _length - start) {
339 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << endl;
340 cnt = _length - start;
341 framecnt_t old = npeaks;
342 npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
343 zero_fill = old - npeaks;
346 // cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl;
350 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
352 /* no scaling at all, just get the sample data and duplicate it for
353 both max and min peak values.
356 Sample* raw_staging = new Sample[cnt];
358 if (read_unlocked (raw_staging, start, cnt) != cnt) {
359 error << _("cannot read sample data for unscaled peak computation") << endmsg;
363 for (framecnt_t i = 0; i < npeaks; ++i) {
364 peaks[i].max = raw_staging[i];
365 peaks[i].min = raw_staging[i];
368 delete peakfile_descriptor;
369 delete [] raw_staging;
375 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
377 /* open, read, close */
379 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
380 error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
381 delete peakfile_descriptor;
385 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
388 nread = ::pread (peakfile_fd, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
391 if (nread != sizeof (PeakData) * npeaks) {
392 DEBUG_TRACE (DEBUG::Peaks, string_compose ("[%1]: Cannot read peaks from peakfile! (read only %2 not %3 at sample %4 = byte %5 )\n"
393 , _name, nread, npeaks, start, first_peak_byte));
394 delete peakfile_descriptor;
399 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
402 delete peakfile_descriptor;
411 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
415 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
416 - less peaks than the peakfile holds for the same range
418 So, read a block into a staging area, and then downsample from there.
420 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
423 const framecnt_t chunksize = (framecnt_t) min (expected_peaks, 65536.0);
425 staging = new PeakData[chunksize];
427 /* compute the rounded up frame position */
429 framepos_t current_frame = start;
430 framepos_t current_stored_peak = (framepos_t) ceil (current_frame / (double) samples_per_file_peak);
431 framepos_t next_visual_peak = (framepos_t) ceil (current_frame / samples_per_visual_peak);
432 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
433 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
434 framecnt_t nvisual_peaks = 0;
435 framecnt_t stored_peaks_read = 0;
438 /* handle the case where the initial visual peak is on a pixel boundary */
440 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
442 /* open ... close during out: handling */
444 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
445 error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
446 delete peakfile_descriptor;
451 while (nvisual_peaks < npeaks) {
453 if (i == stored_peaks_read) {
455 uint32_t start_byte = current_stored_peak * sizeof(PeakData);
456 tnp = min ((framecnt_t)(_length/samples_per_file_peak - current_stored_peak), (framecnt_t) expected_peaks);
457 to_read = min (chunksize, tnp);
459 DEBUG_TRACE (DEBUG::Peaks, string_compose ("reading %1 bytes from peakfile @ %2\n"
460 , sizeof (PeakData) * to_read, start_byte));
463 if ((nread = ::pread (peakfile_fd, staging, sizeof (PeakData) * to_read, start_byte))
464 != sizeof (PeakData) * to_read) {
466 off_t fend = lseek (peakfile_fd, 0, SEEK_END);
468 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"
469 , _name, (nread / sizeof(PeakData)), to_read, g_strerror (errno), start_byte, _length, fend, ((_length - current_frame)/samples_per_file_peak), npeaks));
474 stored_peaks_read = nread / sizeof(PeakData);
480 while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
482 xmax = max (xmax, staging[i].max);
483 xmin = min (xmin, staging[i].min);
485 ++current_stored_peak;
489 peaks[nvisual_peaks].max = xmax;
490 peaks[nvisual_peaks].min = xmin;
494 //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
495 next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
496 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
500 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
507 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
511 - less frames-per-peak (more resolution)
512 - more peaks than stored in the Peakfile
514 So, fetch data from the raw source, and generate peak
518 framecnt_t frames_read = 0;
519 framepos_t current_frame = start;
521 framecnt_t nvisual_peaks = 0;
522 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
523 raw_staging = new Sample[chunksize];
525 framepos_t frame_pos = start;
526 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
527 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
528 double pixels_per_frame = 1.0 / samples_per_visual_peak;
533 while (nvisual_peaks < npeaks) {
535 if (i == frames_read) {
537 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
539 if (current_frame >= _length) {
541 /* hmm, error condition - we've reached the end of the file
542 without generating all the peak data. cook up a zero-filled
543 data buffer and then use it. this is simpler than
544 adjusting zero_fill and npeaks and then breaking out of
548 memset (raw_staging, 0, sizeof (Sample) * chunksize);
552 to_read = min (chunksize, (_length - current_frame));
555 if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
556 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
557 _name, to_read, current_frame, _length, strerror (errno))
566 xmax = max (xmax, raw_staging[i]);
567 xmin = min (xmin, raw_staging[i]);
570 pixel_pos += pixels_per_frame;
572 if (pixel_pos >= next_pixel_pos) {
574 peaks[nvisual_peaks].max = xmax;
575 peaks[nvisual_peaks].min = xmin;
580 next_pixel_pos = ceil (pixel_pos + 0.5);
585 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
592 delete peakfile_descriptor;
595 delete [] raw_staging;
597 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
603 AudioSource::build_peaks_from_scratch ()
607 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
609 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
614 /* hold lock while building peaks */
616 Glib::Threads::Mutex::Lock lp (_lock);
618 if (prepare_for_peakfile_writes ()) {
622 framecnt_t current_frame = 0;
623 framecnt_t cnt = _length;
625 _peaks_built = false;
626 buf = new Sample[bufsize];
630 framecnt_t frames_to_read = min (bufsize, cnt);
631 framecnt_t frames_read;
633 if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
634 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
635 done_with_peakfile_writes (false);
639 if (compute_and_write_peaks (buf, current_frame, frames_read, true, false, _FPP)) {
643 current_frame += frames_read;
652 done_with_peakfile_writes ((cnt == 0));
660 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", peakpath));
661 unlink (peakpath.c_str());
670 AudioSource::prepare_for_peakfile_writes ()
672 _peakfile_descriptor = new FdFileDescriptor (peakpath, true, 0664);
673 if ((_peakfile_fd = _peakfile_descriptor->allocate()) < 0) {
674 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
681 AudioSource::done_with_peakfile_writes (bool done)
683 if (peak_leftover_cnt) {
684 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
688 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
690 PeaksReady (); /* EMIT SIGNAL */
693 delete _peakfile_descriptor;
694 _peakfile_descriptor = 0;
697 /** @param first_frame Offset from the source start of the first frame to process */
699 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
700 bool force, bool intermediate_peaks_ready)
702 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
706 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
707 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
711 uint32_t peaks_computed;
712 PeakData* peakbuf = 0;
714 framepos_t current_frame;
715 framecnt_t frames_done;
716 const size_t blocksize = (128 * 1024);
717 off_t first_peak_byte;
719 if (_peakfile_descriptor == 0) {
720 prepare_for_peakfile_writes ();
724 if (peak_leftover_cnt) {
726 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
728 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
729 and we have leftovers. flush a single peak (since the leftovers
730 never represent more than that, and restart.
735 x.min = peak_leftovers[0];
736 x.max = peak_leftovers[0];
738 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
741 if (::pwrite (_peakfile_fd, &x, sizeof (PeakData), byte) != 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 = new Sample[to_do];
772 memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
775 memcpy (buf2+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 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 if (::pwrite (_peakfile_fd, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
857 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
862 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
865 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
866 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
867 if (intermediate_peaks_ready) {
868 PeaksReady (); /* EMIT SIGNAL */
882 AudioSource::truncate_peakfile ()
884 if (_peakfile_descriptor == 0) {
885 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
890 /* truncate the peakfile down to its natural length if necessary */
892 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
894 if (end > _peak_byte_max) {
895 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", peakpath));
896 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
897 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
898 peakpath, _peak_byte_max, errno) << endmsg;
904 AudioSource::available_peaks (double zoom_factor) const
906 if (zoom_factor < _FPP) {
907 return length(_timeline_position); // peak data will come from the audio file
910 /* peak data comes from peakfile, but the filesize might not represent
911 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
912 XXX - there might be some atomicity issues here, we should probably add a lock,
913 but _peak_byte_max only monotonically increases after initialization.
916 off_t end = _peak_byte_max;
918 return (end/sizeof(PeakData)) * _FPP;
922 AudioSource::mark_streaming_write_completed ()
924 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
927 PeaksReady (); /* EMIT SIGNAL */
932 AudioSource::allocate_working_buffers (framecnt_t framerate)
934 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
937 /* Note: we don't need any buffers allocated until
938 a level 1 audiosource is created, at which
939 time we'll call ::ensure_buffers_for_level()
940 with the right value and do the right thing.
943 if (!_mixdown_buffers.empty()) {
944 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
949 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
951 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
952 ensure_buffers_for_level_locked (level, frame_rate);
956 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
958 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
960 /* this may be called because either "level" or "frame_rate" have
961 * changed. and it may be called with "level" smaller than the current
962 * number of buffers, because a new compound region has been created at
963 * a more shallow level than the deepest one we currently have.
966 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
968 _mixdown_buffers.clear ();
969 _gain_buffers.clear ();
971 for (uint32_t n = 0; n < limit; ++n) {
972 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
973 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));