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.
34 #include <glibmm/fileutils.h>
35 #include <glibmm/miscutils.h>
37 #include "pbd/xml++.h"
39 #include "ardour/audiosource.h"
40 #include "ardour/rc_configuration.h"
41 #include "ardour/runtime_functions.h"
46 using namespace ARDOUR;
49 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
50 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
51 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
52 size_t AudioSource::_working_buffers_size = 0;
53 bool AudioSource::_build_missing_peakfiles = false;
55 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
56 bool AudioSource::_build_peakfiles = false;
60 AudioSource::AudioSource (Session& s, string name)
61 : Source (s, DataType::AUDIO, name)
66 _peakfile_descriptor = 0;
67 peak_leftover_cnt = 0;
68 peak_leftover_size = 0;
72 AudioSource::AudioSource (Session& s, const XMLNode& node)
79 _peakfile_descriptor = 0;
80 peak_leftover_cnt = 0;
81 peak_leftover_size = 0;
84 if (set_state (node, Stateful::loading_state_version)) {
85 throw failed_constructor();
89 AudioSource::~AudioSource ()
91 /* shouldn't happen but make sure we don't leak file descriptors anyway */
93 if (peak_leftover_cnt) {
94 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
97 delete _peakfile_descriptor;
98 delete [] peak_leftovers;
102 AudioSource::get_state ()
104 XMLNode& node (Source::get_state());
106 if (_captured_for.length()) {
107 node.add_property ("captured-for", _captured_for);
114 AudioSource::set_state (const XMLNode& node, int /*version*/)
116 const XMLProperty* prop;
118 if ((prop = node.property ("captured-for")) != 0) {
119 _captured_for = prop->value();
126 AudioSource::empty () const
132 AudioSource::length (framepos_t /*pos*/) const
138 AudioSource::update_length (framecnt_t len)
146 /***********************************************************************
148 ***********************************************************************/
150 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
151 * things are set up so that doThisWhenReady is called when the peaks are ready.
152 * A new PBD::ScopedConnection is created for the associated connection and written to
153 * *connect_here_if_not.
155 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
156 * @param connect_here_if_not Address to write new ScopedConnection to.
157 * @param event_loop Event loop for doThisWhenReady to be called in.
160 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
163 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
165 if (!(ret = _peaks_built)) {
166 *connect_here_if_not = new ScopedConnection;
167 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
174 AudioSource::touch_peakfile ()
178 if (stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
184 tbuf.actime = statbuf.st_atime;
185 tbuf.modtime = time ((time_t*) 0);
187 utime (peakpath.c_str(), &tbuf);
191 AudioSource::rename_peakfile (string newpath)
193 /* caller must hold _lock */
195 string oldpath = peakpath;
197 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
198 if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
199 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
210 AudioSource::initialize_peakfile (string audio_path)
214 peakpath = peak_path (audio_path);
216 /* if the peak file should be there, but isn't .... */
218 if (!empty() && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
219 peakpath = find_broken_peakfile (peakpath, audio_path);
222 if (stat (peakpath.c_str(), &statbuf)) {
223 if (errno != ENOENT) {
224 /* it exists in the peaks dir, but there is some kind of error */
226 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
230 /* peakfile does not exist */
232 _peaks_built = false;
236 /* we found it in the peaks dir, so check it out */
238 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
240 _peaks_built = false;
242 // Check if the audio file has changed since the peakfile was built.
243 struct stat stat_file;
244 int err = stat (audio_path.c_str(), &stat_file);
248 /* no audio path - nested source or we can't
249 read it or ... whatever, use the peakfile as-is.
253 _peak_byte_max = statbuf.st_size;
257 /* allow 6 seconds slop on checking peak vs. file times because of various
261 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
262 _peaks_built = false;
266 _peak_byte_max = statbuf.st_size;
272 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
273 build_peaks_from_scratch ();
280 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
284 Glib::Threads::Mutex::Lock lm (_lock);
285 return read_unlocked (dst, start, cnt);
289 AudioSource::write (Sample *dst, framecnt_t cnt)
291 Glib::Threads::Mutex::Lock lm (_lock);
292 /* any write makes the fill not removable */
293 _flags = Flag (_flags & ~Removable);
294 return write_unlocked (dst, cnt);
298 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
300 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
303 /** @param peaks Buffer to write peak data.
304 * @param npeaks Number of peaks to write.
308 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
309 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
311 Glib::Threads::Mutex::Lock lm (_lock);
313 double expected_peaks;
314 PeakData::PeakDatum xmax;
315 PeakData::PeakDatum xmin;
318 framecnt_t zero_fill = 0;
320 PeakData* staging = 0;
321 Sample* raw_staging = 0;
323 FdFileDescriptor* peakfile_descriptor = new FdFileDescriptor (peakpath, false, 0664);
324 int peakfile_fd = -1;
326 expected_peaks = (cnt / (double) samples_per_file_peak);
327 scale = npeaks/expected_peaks;
329 #undef DEBUG_READ_PEAKS
330 #ifdef DEBUG_READ_PEAKS
331 cerr << "======>RP: npeaks = " << npeaks
332 << " start = " << start
334 << " len = " << _length
335 << " samples_per_visual_peak =" << samples_per_visual_peak
336 << " expected was " << expected_peaks << " ... scale = " << scale
337 << " PD ptr = " << peaks
342 /* fix for near-end-of-file conditions */
344 if (cnt > _length - start) {
345 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
346 cnt = _length - start;
347 framecnt_t old = npeaks;
348 npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
349 zero_fill = old - npeaks;
352 // cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl;
356 #ifdef DEBUG_READ_PEAKS
357 cerr << "RAW DATA\n";
359 /* no scaling at all, just get the sample data and duplicate it for
360 both max and min peak values.
363 Sample* raw_staging = new Sample[cnt];
365 if (read_unlocked (raw_staging, start, cnt) != cnt) {
366 error << _("cannot read sample data for unscaled peak computation") << endmsg;
370 for (framecnt_t i = 0; i < npeaks; ++i) {
371 peaks[i].max = raw_staging[i];
372 peaks[i].min = raw_staging[i];
375 delete peakfile_descriptor;
376 delete [] raw_staging;
382 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
384 /* open, read, close */
386 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
387 error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
388 delete peakfile_descriptor;
392 #ifdef DEBUG_READ_PEAKS
393 cerr << "DIRECT PEAKS\n";
396 nread = ::pread (peakfile_fd, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
398 if (nread != sizeof (PeakData) * npeaks) {
399 cerr << "AudioSource["
401 << "]: cannot read peaks from peakfile! (read only "
411 delete peakfile_descriptor;
416 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
419 delete peakfile_descriptor;
428 #ifdef DEBUG_READ_PEAKS
429 cerr << "DOWNSAMPLE\n";
433 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
434 - less peaks than the peakfile holds for the same range
436 So, read a block into a staging area, and then downsample from there.
438 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
441 const framecnt_t chunksize = (framecnt_t) min (expected_peaks, 65536.0);
443 staging = new PeakData[chunksize];
445 /* compute the rounded up frame position */
447 framepos_t current_frame = start;
448 framepos_t current_stored_peak = (framepos_t) ceil (current_frame / (double) samples_per_file_peak);
449 framepos_t next_visual_peak = (framepos_t) ceil (current_frame / samples_per_visual_peak);
450 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
451 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
452 framecnt_t nvisual_peaks = 0;
453 framecnt_t stored_peaks_read = 0;
456 /* handle the case where the initial visual peak is on a pixel boundary */
458 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
460 /* open ... close during out: handling */
462 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
463 error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
464 delete peakfile_descriptor;
469 while (nvisual_peaks < npeaks) {
471 if (i == stored_peaks_read) {
473 uint32_t start_byte = current_stored_peak * sizeof(PeakData);
474 tnp = min ((framecnt_t)(_length/samples_per_file_peak - current_stored_peak), (framecnt_t) expected_peaks);
475 to_read = min (chunksize, tnp);
477 #ifdef DEBUG_READ_PEAKS
478 cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
481 if ((nread = ::pread (peakfile_fd, staging, sizeof (PeakData) * to_read, start_byte))
482 != sizeof (PeakData) * to_read) {
484 off_t fend = lseek (peakfile_fd, 0, SEEK_END);
486 cerr << "AudioSource["
488 << "]: cannot read peak data from peakfile ("
489 << (nread / sizeof(PeakData))
490 << " peaks instead of "
495 << " at start_byte = " << start_byte
496 << " _length = " << _length << " versus len = " << fend
497 << " expected maxpeaks = " << (_length - current_frame)/samples_per_file_peak
498 << " npeaks was " << npeaks
504 stored_peaks_read = nread / sizeof(PeakData);
510 while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
512 xmax = max (xmax, staging[i].max);
513 xmin = min (xmin, staging[i].min);
515 ++current_stored_peak;
519 peaks[nvisual_peaks].max = xmax;
520 peaks[nvisual_peaks].min = xmin;
524 //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
525 next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
526 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
530 cerr << "Zero fill end of peaks (@ " << npeaks << " with " << zero_fill << endl;
531 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
538 #ifdef DEBUG_READ_PEAKS
539 cerr << "UPSAMPLE\n";
543 - less frames-per-peak (more resolution)
544 - more peaks than stored in the Peakfile
546 So, fetch data from the raw source, and generate peak
550 framecnt_t frames_read = 0;
551 framepos_t current_frame = start;
553 framecnt_t nvisual_peaks = 0;
554 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
555 raw_staging = new Sample[chunksize];
557 framepos_t frame_pos = start;
558 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
559 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
560 double pixels_per_frame = 1.0 / samples_per_visual_peak;
565 while (nvisual_peaks < npeaks) {
567 if (i == frames_read) {
569 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
571 if (current_frame >= _length) {
573 /* hmm, error condition - we've reached the end of the file
574 without generating all the peak data. cook up a zero-filled
575 data buffer and then use it. this is simpler than
576 adjusting zero_fill and npeaks and then breaking out of
580 memset (raw_staging, 0, sizeof (Sample) * chunksize);
584 to_read = min (chunksize, (_length - current_frame));
587 if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
588 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
589 _name, to_read, current_frame, _length, strerror (errno))
598 xmax = max (xmax, raw_staging[i]);
599 xmin = min (xmin, raw_staging[i]);
602 pixel_pos += pixels_per_frame;
604 if (pixel_pos >= next_pixel_pos) {
606 peaks[nvisual_peaks].max = xmax;
607 peaks[nvisual_peaks].min = xmin;
612 next_pixel_pos = ceil (pixel_pos + 0.5);
617 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
624 delete peakfile_descriptor;
627 delete [] raw_staging;
629 #ifdef DEBUG_READ_PEAKS
636 #undef DEBUG_PEAK_BUILD
639 AudioSource::build_peaks_from_scratch ()
643 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
648 /* hold lock while building peaks */
650 Glib::Threads::Mutex::Lock lp (_lock);
652 if (prepare_for_peakfile_writes ()) {
656 framecnt_t current_frame = 0;
657 framecnt_t cnt = _length;
659 _peaks_built = false;
660 buf = new Sample[bufsize];
664 framecnt_t frames_to_read = min (bufsize, cnt);
665 framecnt_t frames_read;
667 if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
668 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
669 done_with_peakfile_writes (false);
673 if (compute_and_write_peaks (buf, current_frame, frames_read, true, false, _FPP)) {
677 current_frame += frames_read;
686 done_with_peakfile_writes ((cnt == 0));
694 unlink (peakpath.c_str());
703 AudioSource::prepare_for_peakfile_writes ()
705 _peakfile_descriptor = new FdFileDescriptor (peakpath, true, 0664);
706 if ((_peakfile_fd = _peakfile_descriptor->allocate()) < 0) {
707 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
714 AudioSource::done_with_peakfile_writes (bool done)
716 if (peak_leftover_cnt) {
717 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
721 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
723 PeaksReady (); /* EMIT SIGNAL */
726 delete _peakfile_descriptor;
727 _peakfile_descriptor = 0;
730 /** @param first_frame Offset from the source start of the first frame to process */
732 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
733 bool force, bool intermediate_peaks_ready)
735 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
739 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
740 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
744 uint32_t peaks_computed;
745 PeakData* peakbuf = 0;
747 framepos_t current_frame;
748 framecnt_t frames_done;
749 const size_t blocksize = (128 * 1024);
750 off_t first_peak_byte;
752 if (_peakfile_descriptor == 0) {
753 prepare_for_peakfile_writes ();
757 if (peak_leftover_cnt) {
759 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
761 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
762 and we have leftovers. flush a single peak (since the leftovers
763 never represent more than that, and restart.
768 x.min = peak_leftovers[0];
769 x.max = peak_leftovers[0];
771 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
773 if (::pwrite (_peakfile_fd, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
774 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
778 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
781 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
782 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
783 if (intermediate_peaks_ready) {
784 PeaksReady (); /* EMIT SIGNAL */
788 /* left overs are done */
790 peak_leftover_cnt = 0;
794 /* else ... had leftovers, but they immediately preceed the new data, so just
795 merge them and compute.
798 /* make a new contiguous buffer containing leftovers and the new stuff */
800 to_do = cnt + peak_leftover_cnt;
801 buf2 = new Sample[to_do];
804 memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
807 memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
809 /* no more leftovers */
810 peak_leftover_cnt = 0;
812 /* use the temporary buffer */
815 /* make sure that when we write into the peakfile, we startup where we left off */
817 first_frame = peak_leftover_frame;
823 peakbuf = new PeakData[(to_do/fpp)+1];
825 current_frame = first_frame;
830 /* if some frames were passed in (i.e. we're not flushing leftovers)
831 and there are less than fpp to do, save them till
835 if (force && (to_do < fpp)) {
836 /* keep the left overs around for next time */
838 if (peak_leftover_size < to_do) {
839 delete [] peak_leftovers;
840 peak_leftovers = new Sample[to_do];
841 peak_leftover_size = to_do;
843 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
844 peak_leftover_cnt = to_do;
845 peak_leftover_frame = current_frame;
852 framecnt_t this_time = min (fpp, to_do);
854 peakbuf[peaks_computed].max = buf[0];
855 peakbuf[peaks_computed].min = buf[0];
857 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
862 frames_done += this_time;
863 current_frame += this_time;
866 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
868 if (can_truncate_peaks()) {
870 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
871 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
872 it does not cause single-extent allocation even for peakfiles of
873 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
876 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
877 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
879 if (endpos < target_length) {
880 if (ftruncate (_peakfile_fd, target_length)) {
881 /* error doesn't actually matter so continue on without testing */
886 if (::pwrite (_peakfile_fd, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
887 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
891 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
894 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
895 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
896 if (intermediate_peaks_ready) {
897 PeaksReady (); /* EMIT SIGNAL */
911 AudioSource::truncate_peakfile ()
913 if (_peakfile_descriptor == 0) {
914 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
919 /* truncate the peakfile down to its natural length if necessary */
921 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
923 if (end > _peak_byte_max) {
924 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
925 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
926 peakpath, _peak_byte_max, errno) << endmsg;
932 AudioSource::available_peaks (double zoom_factor) const
934 if (zoom_factor < _FPP) {
935 return length(_timeline_position); // peak data will come from the audio file
938 /* peak data comes from peakfile, but the filesize might not represent
939 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
940 XXX - there might be some atomicity issues here, we should probably add a lock,
941 but _peak_byte_max only monotonically increases after initialization.
944 off_t end = _peak_byte_max;
946 return (end/sizeof(PeakData)) * _FPP;
950 AudioSource::mark_streaming_write_completed ()
952 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
955 PeaksReady (); /* EMIT SIGNAL */
960 AudioSource::allocate_working_buffers (framecnt_t framerate)
962 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
965 /* Note: we don't need any buffers allocated until
966 a level 1 audiosource is created, at which
967 time we'll call ::ensure_buffers_for_level()
968 with the right value and do the right thing.
971 if (!_mixdown_buffers.empty()) {
972 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
977 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
979 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
980 ensure_buffers_for_level_locked (level, frame_rate);
984 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
986 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
988 /* this may be called because either "level" or "frame_rate" have
989 * changed. and it may be called with "level" smaller than the current
990 * number of buffers, because a new compound region has been created at
991 * a more shallow level than the deepest one we currently have.
994 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
996 _mixdown_buffers.clear ();
997 _gain_buffers.clear ();
999 for (uint32_t n = 0; n < limit; ++n) {
1000 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1001 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));