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 << 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 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
537 #ifdef DEBUG_READ_PEAKS
538 cerr << "UPSAMPLE\n";
542 - less frames-per-peak (more resolution)
543 - more peaks than stored in the Peakfile
545 So, fetch data from the raw source, and generate peak
549 framecnt_t frames_read = 0;
550 framepos_t current_frame = start;
552 framecnt_t nvisual_peaks = 0;
553 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
554 raw_staging = new Sample[chunksize];
556 framepos_t frame_pos = start;
557 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
558 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
559 double pixels_per_frame = 1.0 / samples_per_visual_peak;
564 while (nvisual_peaks < npeaks) {
566 if (i == frames_read) {
568 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
570 if (current_frame >= _length) {
572 /* hmm, error condition - we've reached the end of the file
573 without generating all the peak data. cook up a zero-filled
574 data buffer and then use it. this is simpler than
575 adjusting zero_fill and npeaks and then breaking out of
579 memset (raw_staging, 0, sizeof (Sample) * chunksize);
583 to_read = min (chunksize, (_length - current_frame));
586 if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
587 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
588 _name, to_read, current_frame, _length, strerror (errno))
597 xmax = max (xmax, raw_staging[i]);
598 xmin = min (xmin, raw_staging[i]);
601 pixel_pos += pixels_per_frame;
603 if (pixel_pos >= next_pixel_pos) {
605 peaks[nvisual_peaks].max = xmax;
606 peaks[nvisual_peaks].min = xmin;
611 next_pixel_pos = ceil (pixel_pos + 0.5);
616 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
623 delete peakfile_descriptor;
626 delete [] raw_staging;
628 #ifdef DEBUG_READ_PEAKS
635 #undef DEBUG_PEAK_BUILD
638 AudioSource::build_peaks_from_scratch ()
642 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
647 /* hold lock while building peaks */
649 Glib::Threads::Mutex::Lock lp (_lock);
651 if (prepare_for_peakfile_writes ()) {
655 framecnt_t current_frame = 0;
656 framecnt_t cnt = _length;
658 _peaks_built = false;
659 buf = new Sample[bufsize];
663 framecnt_t frames_to_read = min (bufsize, cnt);
664 framecnt_t frames_read;
666 if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
667 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
668 done_with_peakfile_writes (false);
672 if (compute_and_write_peaks (buf, current_frame, frames_read, true, false, _FPP)) {
676 current_frame += frames_read;
685 done_with_peakfile_writes ((cnt == 0));
693 unlink (peakpath.c_str());
702 AudioSource::prepare_for_peakfile_writes ()
704 _peakfile_descriptor = new FdFileDescriptor (peakpath, true, 0664);
705 if ((_peakfile_fd = _peakfile_descriptor->allocate()) < 0) {
706 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
713 AudioSource::done_with_peakfile_writes (bool done)
715 if (peak_leftover_cnt) {
716 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
720 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
722 PeaksReady (); /* EMIT SIGNAL */
725 delete _peakfile_descriptor;
726 _peakfile_descriptor = 0;
729 /** @param first_frame Offset from the source start of the first frame to process */
731 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
732 bool force, bool intermediate_peaks_ready)
734 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
738 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
739 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
743 uint32_t peaks_computed;
744 PeakData* peakbuf = 0;
746 framepos_t current_frame;
747 framecnt_t frames_done;
748 const size_t blocksize = (128 * 1024);
749 off_t first_peak_byte;
751 if (_peakfile_descriptor == 0) {
752 prepare_for_peakfile_writes ();
756 if (peak_leftover_cnt) {
758 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
760 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
761 and we have leftovers. flush a single peak (since the leftovers
762 never represent more than that, and restart.
767 x.min = peak_leftovers[0];
768 x.max = peak_leftovers[0];
770 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
772 if (::pwrite (_peakfile_fd, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
773 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
777 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
780 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
781 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
782 if (intermediate_peaks_ready) {
783 PeaksReady (); /* EMIT SIGNAL */
787 /* left overs are done */
789 peak_leftover_cnt = 0;
793 /* else ... had leftovers, but they immediately preceed the new data, so just
794 merge them and compute.
797 /* make a new contiguous buffer containing leftovers and the new stuff */
799 to_do = cnt + peak_leftover_cnt;
800 buf2 = new Sample[to_do];
803 memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
806 memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
808 /* no more leftovers */
809 peak_leftover_cnt = 0;
811 /* use the temporary buffer */
814 /* make sure that when we write into the peakfile, we startup where we left off */
816 first_frame = peak_leftover_frame;
822 peakbuf = new PeakData[(to_do/fpp)+1];
824 current_frame = first_frame;
829 /* if some frames were passed in (i.e. we're not flushing leftovers)
830 and there are less than fpp to do, save them till
834 if (force && (to_do < fpp)) {
835 /* keep the left overs around for next time */
837 if (peak_leftover_size < to_do) {
838 delete [] peak_leftovers;
839 peak_leftovers = new Sample[to_do];
840 peak_leftover_size = to_do;
842 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
843 peak_leftover_cnt = to_do;
844 peak_leftover_frame = current_frame;
851 framecnt_t this_time = min (fpp, to_do);
853 peakbuf[peaks_computed].max = buf[0];
854 peakbuf[peaks_computed].min = buf[0];
856 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
861 frames_done += this_time;
862 current_frame += this_time;
865 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
867 if (can_truncate_peaks()) {
869 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
870 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
871 it does not cause single-extent allocation even for peakfiles of
872 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
875 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
876 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
878 if (endpos < target_length) {
879 if (ftruncate (_peakfile_fd, target_length)) {
880 /* error doesn't actually matter so continue on without testing */
885 if (::pwrite (_peakfile_fd, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
886 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
890 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
893 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
894 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
895 if (intermediate_peaks_ready) {
896 PeaksReady (); /* EMIT SIGNAL */
910 AudioSource::truncate_peakfile ()
912 if (_peakfile_descriptor == 0) {
913 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
918 /* truncate the peakfile down to its natural length if necessary */
920 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
922 if (end > _peak_byte_max) {
923 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
924 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
925 peakpath, _peak_byte_max, errno) << endmsg;
931 AudioSource::available_peaks (double zoom_factor) const
933 if (zoom_factor < _FPP) {
934 return length(_timeline_position); // peak data will come from the audio file
937 /* peak data comes from peakfile, but the filesize might not represent
938 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
939 XXX - there might be some atomicity issues here, we should probably add a lock,
940 but _peak_byte_max only monotonically increases after initialization.
943 off_t end = _peak_byte_max;
945 return (end/sizeof(PeakData)) * _FPP;
949 AudioSource::mark_streaming_write_completed ()
951 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
954 PeaksReady (); /* EMIT SIGNAL */
959 AudioSource::allocate_working_buffers (framecnt_t framerate)
961 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
964 /* Note: we don't need any buffers allocated until
965 a level 1 audiosource is created, at which
966 time we'll call ::ensure_buffers_for_level()
967 with the right value and do the right thing.
970 if (!_mixdown_buffers.empty()) {
971 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
976 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
978 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
979 ensure_buffers_for_level_locked (level, frame_rate);
983 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
985 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
987 /* this may be called because either "level" or "frame_rate" have
988 * changed. and it may be called with "level" smaller than the current
989 * number of buffers, because a new compound region has been created at
990 * a more shallow level than the deepest one we currently have.
993 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
995 _mixdown_buffers.clear ();
996 _gain_buffers.clear ();
998 for (uint32_t n = 0; n < limit; ++n) {
999 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1000 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));