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"
38 #include "pbd/pthread_utils.h"
40 #include "ardour/audiosource.h"
41 #include "ardour/audio_diskstream.h"
42 #include "ardour/cycle_timer.h"
43 #include "ardour/session.h"
44 #include "ardour/transient_detector.h"
45 #include "ardour/runtime_functions.h"
50 using namespace ARDOUR;
53 Glib::StaticMutex AudioSource::_level_buffer_lock = GLIBMM_STATIC_MUTEX_INIT;
54 vector<boost::shared_ptr<Sample> > AudioSource::_mixdown_buffers;
55 vector<boost::shared_ptr<gain_t> > AudioSource::_gain_buffers;
56 size_t AudioSource::_working_buffers_size = 0;
57 bool AudioSource::_build_missing_peakfiles = false;
59 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
60 bool AudioSource::_build_peakfiles = false;
64 AudioSource::AudioSource (Session& s, string name)
65 : Source (s, DataType::AUDIO, name)
70 _peakfile_descriptor = 0;
72 _write_data_count = 0;
73 peak_leftover_cnt = 0;
74 peak_leftover_size = 0;
78 AudioSource::AudioSource (Session& s, const XMLNode& node)
85 _peakfile_descriptor = 0;
87 _write_data_count = 0;
88 peak_leftover_cnt = 0;
89 peak_leftover_size = 0;
92 if (set_state (node, Stateful::loading_state_version)) {
93 throw failed_constructor();
97 AudioSource::~AudioSource ()
99 /* shouldn't happen but make sure we don't leak file descriptors anyway */
101 if (peak_leftover_cnt) {
102 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
105 delete _peakfile_descriptor;
106 delete [] peak_leftovers;
110 AudioSource::get_state ()
112 XMLNode& node (Source::get_state());
114 if (_captured_for.length()) {
115 node.add_property ("captured-for", _captured_for);
122 AudioSource::set_state (const XMLNode& node, int /*version*/)
124 const XMLProperty* prop;
126 if ((prop = node.property ("captured-for")) != 0) {
127 _captured_for = prop->value();
134 AudioSource::empty () const
140 AudioSource::length (framepos_t /*pos*/) const
146 AudioSource::update_length (framepos_t pos, framecnt_t cnt)
148 if (pos + cnt > _length) {
154 /***********************************************************************
156 ***********************************************************************/
158 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
159 * things are set up so that doThisWhenReady is called when the peaks are ready.
160 * A new PBD::ScopedConnection is created for the associated connection and written to
161 * *connect_here_if_not.
163 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
164 * @param connect_here_if_not Address to write new ScopedConnection to.
165 * @param event_loop Event loop for doThisWhenReady to be called in.
168 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
171 Glib::Mutex::Lock lm (_peaks_ready_lock);
173 if (!(ret = _peaks_built)) {
174 *connect_here_if_not = new ScopedConnection;
175 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
182 AudioSource::touch_peakfile ()
186 if (stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
192 tbuf.actime = statbuf.st_atime;
193 tbuf.modtime = time ((time_t) 0);
195 utime (peakpath.c_str(), &tbuf);
199 AudioSource::rename_peakfile (string newpath)
201 /* caller must hold _lock */
203 string oldpath = peakpath;
205 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
206 if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
207 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
218 AudioSource::initialize_peakfile (bool newfile, string audio_path)
222 peakpath = peak_path (audio_path);
224 /* if the peak file should be there, but isn't .... */
226 if (!newfile && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
227 peakpath = find_broken_peakfile (peakpath, audio_path);
230 if (stat (peakpath.c_str(), &statbuf)) {
231 if (errno != ENOENT) {
232 /* it exists in the peaks dir, but there is some kind of error */
234 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
238 /* peakfile does not exist */
240 _peaks_built = false;
244 /* we found it in the peaks dir, so check it out */
246 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
248 _peaks_built = false;
250 // Check if the audio file has changed since the peakfile was built.
251 struct stat stat_file;
252 int err = stat (audio_path.c_str(), &stat_file);
256 /* no audio path - nested source or we can't
257 read it or ... whatever, use the peakfile as-is.
261 _peak_byte_max = statbuf.st_size;
265 /* allow 6 seconds slop on checking peak vs. file times because of various
269 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
270 _peaks_built = false;
274 _peak_byte_max = statbuf.st_size;
280 if (!newfile && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
281 build_peaks_from_scratch ();
288 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
292 Glib::Mutex::Lock lm (_lock);
293 return read_unlocked (dst, start, cnt);
297 AudioSource::write (Sample *dst, framecnt_t cnt)
299 Glib::Mutex::Lock lm (_lock);
300 /* any write makes the fill not removable */
301 _flags = Flag (_flags & ~Removable);
302 return write_unlocked (dst, cnt);
306 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
308 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
311 /** @param peaks Buffer to write peak data.
312 * @param npeaks Number of peaks to write.
316 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
317 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
319 Glib::Mutex::Lock lm (_lock);
321 double expected_peaks;
322 PeakData::PeakDatum xmax;
323 PeakData::PeakDatum xmin;
326 framecnt_t zero_fill = 0;
328 PeakData* staging = 0;
329 Sample* raw_staging = 0;
331 FdFileDescriptor* peakfile_descriptor = new FdFileDescriptor (peakpath, false, 0664);
332 int peakfile_fd = -1;
334 expected_peaks = (cnt / (double) samples_per_file_peak);
335 scale = npeaks/expected_peaks;
337 #undef DEBUG_READ_PEAKS
338 #ifdef DEBUG_READ_PEAKS
339 cerr << "======>RP: npeaks = " << npeaks
340 << " start = " << start
342 << " len = " << _length
343 << " samples_per_visual_peak =" << samples_per_visual_peak
344 << " expected was " << expected_peaks << " ... scale = " << scale
345 << " PD ptr = " << peaks
350 /* fix for near-end-of-file conditions */
352 if (cnt > _length - start) {
353 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << 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 #ifdef DEBUG_READ_PEAKS
365 cerr << "RAW DATA\n";
367 /* no scaling at all, just get the sample data and duplicate it for
368 both max and min peak values.
371 Sample* raw_staging = new Sample[cnt];
373 if (read_unlocked (raw_staging, start, cnt) != cnt) {
374 error << _("cannot read sample data for unscaled peak computation") << endmsg;
378 for (framecnt_t i = 0; i < npeaks; ++i) {
379 peaks[i].max = raw_staging[i];
380 peaks[i].min = raw_staging[i];
383 delete peakfile_descriptor;
384 delete [] raw_staging;
390 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
392 /* open, read, close */
394 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
395 error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
396 delete peakfile_descriptor;
400 #ifdef DEBUG_READ_PEAKS
401 cerr << "DIRECT PEAKS\n";
404 nread = ::pread (peakfile_fd, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
405 delete peakfile_descriptor;
407 if (nread != sizeof (PeakData) * npeaks) {
408 cerr << "AudioSource["
410 << "]: cannot read peaks from peakfile! (read only "
420 delete peakfile_descriptor;
425 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
428 delete peakfile_descriptor;
437 #ifdef DEBUG_READ_PEAKS
438 cerr << "DOWNSAMPLE\n";
442 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
443 - less peaks than the peakfile holds for the same range
445 So, read a block into a staging area, and then downsample from there.
447 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
450 const framecnt_t chunksize = (framecnt_t) min (expected_peaks, 65536.0);
452 staging = new PeakData[chunksize];
454 /* compute the rounded up frame position */
456 framepos_t current_frame = start;
457 framepos_t current_stored_peak = (framepos_t) ceil (current_frame / (double) samples_per_file_peak);
458 framepos_t next_visual_peak = (framepos_t) ceil (current_frame / samples_per_visual_peak);
459 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
460 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
461 framecnt_t nvisual_peaks = 0;
462 framecnt_t stored_peaks_read = 0;
465 /* handle the case where the initial visual peak is on a pixel boundary */
467 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
469 /* open ... close during out: handling */
471 if ((peakfile_fd = peakfile_descriptor->allocate ()) < 0) {
472 error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
473 delete peakfile_descriptor;
478 while (nvisual_peaks < npeaks) {
480 if (i == stored_peaks_read) {
482 uint32_t start_byte = current_stored_peak * sizeof(PeakData);
483 tnp = min ((framecnt_t)(_length/samples_per_file_peak - current_stored_peak), (framecnt_t) expected_peaks);
484 to_read = min (chunksize, tnp);
486 #ifdef DEBUG_READ_PEAKS
487 cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
490 if ((nread = ::pread (peakfile_fd, staging, sizeof (PeakData) * to_read, start_byte))
491 != sizeof (PeakData) * to_read) {
493 off_t fend = lseek (peakfile_fd, 0, SEEK_END);
495 cerr << "AudioSource["
497 << "]: cannot read peak data from peakfile ("
498 << (nread / sizeof(PeakData))
499 << " peaks instead of "
504 << " at start_byte = " << start_byte
505 << " _length = " << _length << " versus len = " << fend
506 << " expected maxpeaks = " << (_length - current_frame)/samples_per_file_peak
507 << " npeaks was " << npeaks
513 stored_peaks_read = nread / sizeof(PeakData);
519 while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
521 xmax = max (xmax, staging[i].max);
522 xmin = min (xmin, staging[i].min);
524 ++current_stored_peak;
528 peaks[nvisual_peaks].max = xmax;
529 peaks[nvisual_peaks].min = xmin;
533 //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
534 next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
535 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
539 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
546 #ifdef DEBUG_READ_PEAKS
547 cerr << "UPSAMPLE\n";
551 - less frames-per-peak (more resolution)
552 - more peaks than stored in the Peakfile
554 So, fetch data from the raw source, and generate peak
558 framecnt_t frames_read = 0;
559 framepos_t current_frame = start;
561 framecnt_t nvisual_peaks = 0;
562 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
563 raw_staging = new Sample[chunksize];
565 framepos_t frame_pos = start;
566 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
567 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
568 double pixels_per_frame = 1.0 / samples_per_visual_peak;
573 while (nvisual_peaks < npeaks) {
575 if (i == frames_read) {
577 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
579 if (current_frame >= _length) {
581 /* hmm, error condition - we've reached the end of the file
582 without generating all the peak data. cook up a zero-filled
583 data buffer and then use it. this is simpler than
584 adjusting zero_fill and npeaks and then breaking out of
588 memset (raw_staging, 0, sizeof (Sample) * chunksize);
592 to_read = min (chunksize, (_length - current_frame));
595 if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
596 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
597 _name, to_read, current_frame, _length, strerror (errno))
606 xmax = max (xmax, raw_staging[i]);
607 xmin = min (xmin, raw_staging[i]);
610 pixel_pos += pixels_per_frame;
612 if (pixel_pos >= next_pixel_pos) {
614 peaks[nvisual_peaks].max = xmax;
615 peaks[nvisual_peaks].min = xmin;
620 next_pixel_pos = ceil (pixel_pos + 0.5);
625 memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
632 delete peakfile_descriptor;
635 delete [] raw_staging;
637 #ifdef DEBUG_READ_PEAKS
644 #undef DEBUG_PEAK_BUILD
647 AudioSource::build_peaks_from_scratch ()
651 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
656 /* hold lock while building peaks */
658 Glib::Mutex::Lock lp (_lock);
660 if (prepare_for_peakfile_writes ()) {
664 framecnt_t current_frame = 0;
665 framecnt_t cnt = _length;
667 _peaks_built = false;
668 buf = new Sample[bufsize];
672 framecnt_t frames_to_read = min (bufsize, cnt);
673 framecnt_t frames_read;
675 if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
676 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
677 done_with_peakfile_writes (false);
681 if (compute_and_write_peaks (buf, current_frame, frames_read, true, false, _FPP)) {
685 current_frame += frames_read;
694 done_with_peakfile_writes ((cnt == 0));
702 unlink (peakpath.c_str());
711 AudioSource::prepare_for_peakfile_writes ()
713 _peakfile_descriptor = new FdFileDescriptor (peakpath, true, 0664);
714 if ((_peakfile_fd = _peakfile_descriptor->allocate()) < 0) {
715 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
722 AudioSource::done_with_peakfile_writes (bool done)
724 if (peak_leftover_cnt) {
725 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
729 Glib::Mutex::Lock lm (_peaks_ready_lock);
731 PeaksReady (); /* EMIT SIGNAL */
734 delete _peakfile_descriptor;
735 _peakfile_descriptor = 0;
738 /** @param first_frame Offset from the source start of the first frame to process */
740 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
741 bool force, bool intermediate_peaks_ready)
743 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
747 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
748 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
752 uint32_t peaks_computed;
753 PeakData* peakbuf = 0;
755 framepos_t current_frame;
756 framecnt_t frames_done;
757 const size_t blocksize = (128 * 1024);
758 off_t first_peak_byte;
760 if (_peakfile_descriptor == 0) {
761 prepare_for_peakfile_writes ();
765 if (peak_leftover_cnt) {
767 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
769 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
770 and we have leftovers. flush a single peak (since the leftovers
771 never represent more than that, and restart.
776 x.min = peak_leftovers[0];
777 x.max = peak_leftovers[0];
779 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
781 if (::pwrite (_peakfile_fd, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
782 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
786 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
789 Glib::Mutex::Lock lm (_peaks_ready_lock);
790 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
791 if (intermediate_peaks_ready) {
792 PeaksReady (); /* EMIT SIGNAL */
796 /* left overs are done */
798 peak_leftover_cnt = 0;
802 /* else ... had leftovers, but they immediately preceed the new data, so just
803 merge them and compute.
806 /* make a new contiguous buffer containing leftovers and the new stuff */
808 to_do = cnt + peak_leftover_cnt;
809 buf2 = new Sample[to_do];
812 memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
815 memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
817 /* no more leftovers */
818 peak_leftover_cnt = 0;
820 /* use the temporary buffer */
823 /* make sure that when we write into the peakfile, we startup where we left off */
825 first_frame = peak_leftover_frame;
831 peakbuf = new PeakData[(to_do/fpp)+1];
833 current_frame = first_frame;
838 /* if some frames were passed in (i.e. we're not flushing leftovers)
839 and there are less than fpp to do, save them till
843 if (force && (to_do < fpp)) {
844 /* keep the left overs around for next time */
846 if (peak_leftover_size < to_do) {
847 delete [] peak_leftovers;
848 peak_leftovers = new Sample[to_do];
849 peak_leftover_size = to_do;
851 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
852 peak_leftover_cnt = to_do;
853 peak_leftover_frame = current_frame;
860 framecnt_t this_time = min (fpp, to_do);
862 peakbuf[peaks_computed].max = buf[0];
863 peakbuf[peaks_computed].min = buf[0];
865 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
870 frames_done += this_time;
871 current_frame += this_time;
874 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
876 if (can_truncate_peaks()) {
878 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
879 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
880 it does not cause single-extent allocation even for peakfiles of
881 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
884 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
885 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
887 if (endpos < target_length) {
888 (void) ftruncate (_peakfile_fd, target_length);
889 /* error doesn't actually matter though, so continue on without testing */
893 if (::pwrite (_peakfile_fd, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
894 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
898 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
901 Glib::Mutex::Lock lm (_peaks_ready_lock);
902 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
903 if (intermediate_peaks_ready) {
904 PeaksReady (); /* EMIT SIGNAL */
918 AudioSource::truncate_peakfile ()
920 if (_peakfile_descriptor == 0) {
921 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
926 /* truncate the peakfile down to its natural length if necessary */
928 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
930 if (end > _peak_byte_max) {
931 (void) ftruncate (_peakfile_fd, _peak_byte_max);
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::dec_read_data_count (framecnt_t cnt)
956 uint32_t val = cnt * sizeof (Sample);
958 if (val < _read_data_count) {
959 _read_data_count -= val;
961 _read_data_count = 0;
966 AudioSource::mark_streaming_write_completed ()
968 Glib::Mutex::Lock lm (_peaks_ready_lock);
971 PeaksReady (); /* EMIT SIGNAL */
976 AudioSource::allocate_working_buffers (framecnt_t framerate)
978 Glib::Mutex::Lock lm (_level_buffer_lock);
981 /* Note: we don't need any buffers allocated until
982 a level 1 audiosource is created, at which
983 time we'll call ::ensure_buffers_for_level()
984 with the right value and do the right thing.
987 if (!_mixdown_buffers.empty()) {
988 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
993 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
995 Glib::Mutex::Lock lm (_level_buffer_lock);
996 ensure_buffers_for_level_locked (level, frame_rate);
1000 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1002 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1004 _mixdown_buffers.clear ();
1005 _gain_buffers.clear ();
1007 while (_mixdown_buffers.size() < level) {
1008 _mixdown_buffers.push_back (boost::shared_ptr<Sample> (new Sample[nframes]));
1009 _gain_buffers.push_back (boost::shared_ptr<gain_t> (new gain_t[nframes]));