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"
45 using namespace ARDOUR;
48 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
49 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
50 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
51 size_t AudioSource::_working_buffers_size = 0;
52 bool AudioSource::_build_missing_peakfiles = false;
54 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
55 bool AudioSource::_build_peakfiles = false;
59 AudioSource::AudioSource (Session& s, string name)
60 : Source (s, DataType::AUDIO, name)
65 _peakfile_descriptor = 0;
66 peak_leftover_cnt = 0;
67 peak_leftover_size = 0;
71 AudioSource::AudioSource (Session& s, const XMLNode& node)
78 _peakfile_descriptor = 0;
79 peak_leftover_cnt = 0;
80 peak_leftover_size = 0;
83 if (set_state (node, Stateful::loading_state_version)) {
84 throw failed_constructor();
88 AudioSource::~AudioSource ()
90 /* shouldn't happen but make sure we don't leak file descriptors anyway */
92 if (peak_leftover_cnt) {
93 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
96 delete _peakfile_descriptor;
97 delete [] peak_leftovers;
101 AudioSource::get_state ()
103 XMLNode& node (Source::get_state());
105 if (_captured_for.length()) {
106 node.add_property ("captured-for", _captured_for);
113 AudioSource::set_state (const XMLNode& node, int /*version*/)
115 const XMLProperty* prop;
117 if ((prop = node.property ("captured-for")) != 0) {
118 _captured_for = prop->value();
125 AudioSource::empty () const
131 AudioSource::length (framepos_t /*pos*/) const
137 AudioSource::update_length (framecnt_t len)
145 /***********************************************************************
147 ***********************************************************************/
149 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
150 * things are set up so that doThisWhenReady is called when the peaks are ready.
151 * A new PBD::ScopedConnection is created for the associated connection and written to
152 * *connect_here_if_not.
154 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
155 * @param connect_here_if_not Address to write new ScopedConnection to.
156 * @param event_loop Event loop for doThisWhenReady to be called in.
159 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
162 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
164 if (!(ret = _peaks_built)) {
165 *connect_here_if_not = new ScopedConnection;
166 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
173 AudioSource::touch_peakfile ()
177 if (stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
183 tbuf.actime = statbuf.st_atime;
184 tbuf.modtime = time ((time_t) 0);
186 utime (peakpath.c_str(), &tbuf);
190 AudioSource::rename_peakfile (string newpath)
192 /* caller must hold _lock */
194 string oldpath = peakpath;
196 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
197 if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
198 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
209 AudioSource::initialize_peakfile (string audio_path)
213 peakpath = peak_path (audio_path);
215 /* if the peak file should be there, but isn't .... */
217 if (!empty() && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
218 peakpath = find_broken_peakfile (peakpath, audio_path);
221 if (stat (peakpath.c_str(), &statbuf)) {
222 if (errno != ENOENT) {
223 /* it exists in the peaks dir, but there is some kind of error */
225 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
229 /* peakfile does not exist */
231 _peaks_built = false;
235 /* we found it in the peaks dir, so check it out */
237 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
239 _peaks_built = false;
241 // Check if the audio file has changed since the peakfile was built.
242 struct stat stat_file;
243 int err = stat (audio_path.c_str(), &stat_file);
247 /* no audio path - nested source or we can't
248 read it or ... whatever, use the peakfile as-is.
252 _peak_byte_max = statbuf.st_size;
256 /* allow 6 seconds slop on checking peak vs. file times because of various
260 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
261 _peaks_built = false;
265 _peak_byte_max = statbuf.st_size;
271 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
272 build_peaks_from_scratch ();
279 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
283 Glib::Threads::Mutex::Lock lm (_lock);
284 return read_unlocked (dst, start, cnt);
288 AudioSource::write (Sample *dst, framecnt_t cnt)
290 Glib::Threads::Mutex::Lock lm (_lock);
291 /* any write makes the fill not removable */
292 _flags = Flag (_flags & ~Removable);
293 return write_unlocked (dst, cnt);
297 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
299 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
302 /** @param peaks Buffer to write peak data.
303 * @param npeaks Number of peaks to write.
307 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
308 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
310 Glib::Threads::Mutex::Lock lm (_lock);
312 double expected_peaks;
313 PeakData::PeakDatum xmax;
314 PeakData::PeakDatum xmin;
317 framecnt_t zero_fill = 0;
319 PeakData* staging = 0;
320 Sample* raw_staging = 0;
322 FdFileDescriptor* peakfile_descriptor = new FdFileDescriptor (peakpath, false, 0664);
323 int peakfile_fd = -1;
325 expected_peaks = (cnt / (double) samples_per_file_peak);
326 scale = npeaks/expected_peaks;
328 #undef DEBUG_READ_PEAKS
329 #ifdef DEBUG_READ_PEAKS
330 cerr << "======>RP: npeaks = " << npeaks
331 << " start = " << start
333 << " len = " << _length
334 << " samples_per_visual_peak =" << samples_per_visual_peak
335 << " expected was " << expected_peaks << " ... scale = " << scale
336 << " PD ptr = " << peaks
341 /* fix for near-end-of-file conditions */
343 if (cnt > _length - start) {
344 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << endl;
345 cnt = _length - start;
346 framecnt_t old = npeaks;
347 npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
348 zero_fill = old - npeaks;
351 // cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl;
355 #ifdef DEBUG_READ_PEAKS
356 cerr << "RAW DATA\n";
358 /* no scaling at all, just get the sample data and duplicate it for
359 both max and min peak values.
362 Sample* raw_staging = new Sample[cnt];
364 if (read_unlocked (raw_staging, start, cnt) != cnt) {
365 error << _("cannot read sample data for unscaled peak computation") << endmsg;
369 for (framecnt_t i = 0; i < npeaks; ++i) {
370 peaks[i].max = raw_staging[i];
371 peaks[i].min = raw_staging[i];
374 delete peakfile_descriptor;
375 delete [] raw_staging;
381 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
383 /* open, read, close */
385 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
386 error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
387 delete peakfile_descriptor;
391 #ifdef DEBUG_READ_PEAKS
392 cerr << "DIRECT PEAKS\n";
396 nread = ::pread (peakfile_fd, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
399 if (nread != sizeof (PeakData) * npeaks) {
400 cerr << "AudioSource["
402 << "]: cannot read peaks from peakfile! (read only "
412 delete peakfile_descriptor;
417 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
420 delete peakfile_descriptor;
429 #ifdef DEBUG_READ_PEAKS
430 cerr << "DOWNSAMPLE\n";
434 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
435 - less peaks than the peakfile holds for the same range
437 So, read a block into a staging area, and then downsample from there.
439 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
442 const framecnt_t chunksize = (framecnt_t) min (expected_peaks, 65536.0);
444 staging = new PeakData[chunksize];
446 /* compute the rounded up frame position */
448 framepos_t current_frame = start;
449 framepos_t current_stored_peak = (framepos_t) ceil (current_frame / (double) samples_per_file_peak);
450 framepos_t next_visual_peak = (framepos_t) ceil (current_frame / samples_per_visual_peak);
451 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
452 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
453 framecnt_t nvisual_peaks = 0;
454 framecnt_t stored_peaks_read = 0;
457 /* handle the case where the initial visual peak is on a pixel boundary */
459 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
461 /* open ... close during out: handling */
463 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
464 error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
465 delete peakfile_descriptor;
470 while (nvisual_peaks < npeaks) {
472 if (i == stored_peaks_read) {
474 uint32_t start_byte = current_stored_peak * sizeof(PeakData);
475 tnp = min ((framecnt_t)(_length/samples_per_file_peak - current_stored_peak), (framecnt_t) expected_peaks);
476 to_read = min (chunksize, tnp);
478 #ifdef DEBUG_READ_PEAKS
479 cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
483 if ((nread = ::pread (peakfile_fd, staging, sizeof (PeakData) * to_read, start_byte))
484 != sizeof (PeakData) * to_read) {
486 off_t fend = lseek (peakfile_fd, 0, SEEK_END);
488 cerr << "AudioSource["
490 << "]: cannot read peak data from peakfile ("
491 << (nread / sizeof(PeakData))
492 << " peaks instead of "
497 << " at start_byte = " << start_byte
498 << " _length = " << _length << " versus len = " << fend
499 << " expected maxpeaks = " << (_length - current_frame)/samples_per_file_peak
500 << " npeaks was " << npeaks
506 stored_peaks_read = nread / sizeof(PeakData);
512 while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
514 xmax = max (xmax, staging[i].max);
515 xmin = min (xmin, staging[i].min);
517 ++current_stored_peak;
521 peaks[nvisual_peaks].max = xmax;
522 peaks[nvisual_peaks].min = xmin;
526 //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
527 next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
528 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
532 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
539 #ifdef DEBUG_READ_PEAKS
540 cerr << "UPSAMPLE\n";
544 - less frames-per-peak (more resolution)
545 - more peaks than stored in the Peakfile
547 So, fetch data from the raw source, and generate peak
551 framecnt_t frames_read = 0;
552 framepos_t current_frame = start;
554 framecnt_t nvisual_peaks = 0;
555 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
556 raw_staging = new Sample[chunksize];
558 framepos_t frame_pos = start;
559 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
560 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
561 double pixels_per_frame = 1.0 / samples_per_visual_peak;
566 while (nvisual_peaks < npeaks) {
568 if (i == frames_read) {
570 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
572 if (current_frame >= _length) {
574 /* hmm, error condition - we've reached the end of the file
575 without generating all the peak data. cook up a zero-filled
576 data buffer and then use it. this is simpler than
577 adjusting zero_fill and npeaks and then breaking out of
581 memset (raw_staging, 0, sizeof (Sample) * chunksize);
585 to_read = min (chunksize, (_length - current_frame));
588 if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
589 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
590 _name, to_read, current_frame, _length, strerror (errno))
599 xmax = max (xmax, raw_staging[i]);
600 xmin = min (xmin, raw_staging[i]);
603 pixel_pos += pixels_per_frame;
605 if (pixel_pos >= next_pixel_pos) {
607 peaks[nvisual_peaks].max = xmax;
608 peaks[nvisual_peaks].min = xmin;
613 next_pixel_pos = ceil (pixel_pos + 0.5);
618 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
625 delete peakfile_descriptor;
628 delete [] raw_staging;
630 #ifdef DEBUG_READ_PEAKS
637 #undef DEBUG_PEAK_BUILD
640 AudioSource::build_peaks_from_scratch ()
644 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
649 /* hold lock while building peaks */
651 Glib::Threads::Mutex::Lock lp (_lock);
653 if (prepare_for_peakfile_writes ()) {
657 framecnt_t current_frame = 0;
658 framecnt_t cnt = _length;
660 _peaks_built = false;
661 buf = new Sample[bufsize];
665 framecnt_t frames_to_read = min (bufsize, cnt);
666 framecnt_t frames_read;
668 if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
669 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
670 done_with_peakfile_writes (false);
674 if (compute_and_write_peaks (buf, current_frame, frames_read, true, false, _FPP)) {
678 current_frame += frames_read;
687 done_with_peakfile_writes ((cnt == 0));
695 unlink (peakpath.c_str());
704 AudioSource::prepare_for_peakfile_writes ()
706 _peakfile_descriptor = new FdFileDescriptor (peakpath, true, 0664);
707 if ((_peakfile_fd = _peakfile_descriptor->allocate()) < 0) {
708 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
715 AudioSource::done_with_peakfile_writes (bool done)
717 if (peak_leftover_cnt) {
718 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
722 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
724 PeaksReady (); /* EMIT SIGNAL */
727 delete _peakfile_descriptor;
728 _peakfile_descriptor = 0;
731 /** @param first_frame Offset from the source start of the first frame to process */
733 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
734 bool force, bool intermediate_peaks_ready)
736 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
740 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
741 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
745 uint32_t peaks_computed;
746 PeakData* peakbuf = 0;
748 framepos_t current_frame;
749 framecnt_t frames_done;
750 const size_t blocksize = (128 * 1024);
751 off_t first_peak_byte;
753 if (_peakfile_descriptor == 0) {
754 prepare_for_peakfile_writes ();
758 if (peak_leftover_cnt) {
760 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
762 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
763 and we have leftovers. flush a single peak (since the leftovers
764 never represent more than that, and restart.
769 x.min = peak_leftovers[0];
770 x.max = peak_leftovers[0];
772 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
775 if (::pwrite (_peakfile_fd, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
776 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
780 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
783 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
784 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
785 if (intermediate_peaks_ready) {
786 PeaksReady (); /* EMIT SIGNAL */
790 /* left overs are done */
792 peak_leftover_cnt = 0;
796 /* else ... had leftovers, but they immediately preceed the new data, so just
797 merge them and compute.
800 /* make a new contiguous buffer containing leftovers and the new stuff */
802 to_do = cnt + peak_leftover_cnt;
803 buf2 = new Sample[to_do];
806 memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
809 memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
811 /* no more leftovers */
812 peak_leftover_cnt = 0;
814 /* use the temporary buffer */
817 /* make sure that when we write into the peakfile, we startup where we left off */
819 first_frame = peak_leftover_frame;
825 peakbuf = new PeakData[(to_do/fpp)+1];
827 current_frame = first_frame;
832 /* if some frames were passed in (i.e. we're not flushing leftovers)
833 and there are less than fpp to do, save them till
837 if (force && (to_do < fpp)) {
838 /* keep the left overs around for next time */
840 if (peak_leftover_size < to_do) {
841 delete [] peak_leftovers;
842 peak_leftovers = new Sample[to_do];
843 peak_leftover_size = to_do;
845 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
846 peak_leftover_cnt = to_do;
847 peak_leftover_frame = current_frame;
854 framecnt_t this_time = min (fpp, to_do);
856 peakbuf[peaks_computed].max = buf[0];
857 peakbuf[peaks_computed].min = buf[0];
859 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
864 frames_done += this_time;
865 current_frame += this_time;
868 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
870 if (can_truncate_peaks()) {
872 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
873 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
874 it does not cause single-extent allocation even for peakfiles of
875 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
878 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
879 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
881 if (endpos < target_length) {
882 if (ftruncate (_peakfile_fd, target_length)) {
883 /* error doesn't actually matter so continue on without testing */
889 if (::pwrite (_peakfile_fd, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
890 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
895 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
898 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
899 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
900 if (intermediate_peaks_ready) {
901 PeaksReady (); /* EMIT SIGNAL */
915 AudioSource::truncate_peakfile ()
917 if (_peakfile_descriptor == 0) {
918 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
923 /* truncate the peakfile down to its natural length if necessary */
925 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
927 if (end > _peak_byte_max) {
928 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
929 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
930 peakpath, _peak_byte_max, errno) << endmsg;
936 AudioSource::available_peaks (double zoom_factor) const
938 if (zoom_factor < _FPP) {
939 return length(_timeline_position); // peak data will come from the audio file
942 /* peak data comes from peakfile, but the filesize might not represent
943 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
944 XXX - there might be some atomicity issues here, we should probably add a lock,
945 but _peak_byte_max only monotonically increases after initialization.
948 off_t end = _peak_byte_max;
950 return (end/sizeof(PeakData)) * _FPP;
954 AudioSource::mark_streaming_write_completed ()
956 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
959 PeaksReady (); /* EMIT SIGNAL */
964 AudioSource::allocate_working_buffers (framecnt_t framerate)
966 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
969 /* Note: we don't need any buffers allocated until
970 a level 1 audiosource is created, at which
971 time we'll call ::ensure_buffers_for_level()
972 with the right value and do the right thing.
975 if (!_mixdown_buffers.empty()) {
976 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
981 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
983 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
984 ensure_buffers_for_level_locked (level, frame_rate);
988 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
990 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
992 /* this may be called because either "level" or "frame_rate" have
993 * changed. and it may be called with "level" smaller than the current
994 * number of buffers, because a new compound region has been created at
995 * a more shallow level than the deepest one we currently have.
998 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1000 _mixdown_buffers.clear ();
1001 _gain_buffers.clear ();
1003 for (uint32_t n = 0; n < limit; ++n) {
1004 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1005 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));