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.
21 #include <sys/utime.h>
37 #ifdef PLATFORM_WINDOWS
46 #include <glib/gstdio.h>
48 #include <boost/scoped_ptr.hpp>
50 #include <glibmm/fileutils.h>
51 #include <glibmm/miscutils.h>
53 #include "pbd/scoped_file_descriptor.h"
54 #include "pbd/xml++.h"
56 #include "ardour/audiosource.h"
57 #include "ardour/rc_configuration.h"
58 #include "ardour/runtime_functions.h"
62 #include "ardour/debug.h"
65 using namespace ARDOUR;
68 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
69 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
70 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
71 size_t AudioSource::_working_buffers_size = 0;
72 bool AudioSource::_build_missing_peakfiles = false;
74 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
75 bool AudioSource::_build_peakfiles = false;
79 AudioSource::AudioSource (Session& s, string name)
80 : Source (s, DataType::AUDIO, name)
83 , _peaks_built (false)
85 , peak_leftover_cnt (0)
86 , peak_leftover_size (0)
91 , _last_raw_map_length (0)
95 AudioSource::AudioSource (Session& s, const XMLNode& node)
99 , _peaks_built (false)
101 , peak_leftover_cnt (0)
102 , peak_leftover_size (0)
107 , _last_raw_map_length (0)
109 if (set_state (node, Stateful::loading_state_version)) {
110 throw failed_constructor();
114 AudioSource::~AudioSource ()
116 /* shouldn't happen but make sure we don't leak file descriptors anyway */
118 if (peak_leftover_cnt) {
119 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
122 if ((-1) != _peakfile_fd) {
123 close (_peakfile_fd);
127 delete [] peak_leftovers;
131 AudioSource::get_state ()
133 XMLNode& node (Source::get_state());
135 if (_captured_for.length()) {
136 node.add_property ("captured-for", _captured_for);
143 AudioSource::set_state (const XMLNode& node, int /*version*/)
145 const XMLProperty* prop;
147 if ((prop = node.property ("captured-for")) != 0) {
148 _captured_for = prop->value();
155 AudioSource::empty () const
161 AudioSource::length (framepos_t /*pos*/) const
167 AudioSource::update_length (framecnt_t len)
175 /***********************************************************************
177 ***********************************************************************/
179 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
180 * things are set up so that doThisWhenReady is called when the peaks are ready.
181 * A new PBD::ScopedConnection is created for the associated connection and written to
182 * *connect_here_if_not.
184 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
185 * @param connect_here_if_not Address to write new ScopedConnection to.
186 * @param event_loop Event loop for doThisWhenReady to be called in.
189 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
192 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
194 if (!(ret = _peaks_built)) {
195 *connect_here_if_not = new ScopedConnection;
196 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
203 AudioSource::touch_peakfile ()
207 if (g_stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
213 tbuf.actime = statbuf.st_atime;
214 tbuf.modtime = time ((time_t*) 0);
216 g_utime (peakpath.c_str(), &tbuf);
220 AudioSource::rename_peakfile (string newpath)
222 /* caller must hold _lock */
224 string oldpath = peakpath;
226 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
227 if (g_rename (oldpath.c_str(), newpath.c_str()) != 0) {
228 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
239 AudioSource::initialize_peakfile (string audio_path)
243 peakpath = peak_path (audio_path);
245 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", peakpath, audio_path));
247 /* if the peak file should be there, but isn't .... */
249 if (!empty() && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
250 peakpath = find_broken_peakfile (peakpath, audio_path);
253 if (g_stat (peakpath.c_str(), &statbuf)) {
254 if (errno != ENOENT) {
255 /* it exists in the peaks dir, but there is some kind of error */
257 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
261 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 does not exist\n", peakpath));
263 _peaks_built = false;
267 /* we found it in the peaks dir, so check it out */
269 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
270 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", peakpath));
271 _peaks_built = false;
273 // Check if the audio file has changed since the peakfile was built.
274 struct stat stat_file;
275 int err = stat (audio_path.c_str(), &stat_file);
279 /* no audio path - nested source or we can't
280 read it or ... whatever, use the peakfile as-is.
282 DEBUG_TRACE(DEBUG::Peaks, string_compose("Error when calling stat on Peakfile %1\n", peakpath));
285 _peak_byte_max = statbuf.st_size;
289 /* allow 6 seconds slop on checking peak vs. file times because of various
293 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
294 _peaks_built = false;
298 _peak_byte_max = statbuf.st_size;
304 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
305 build_peaks_from_scratch ();
312 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
316 Glib::Threads::Mutex::Lock lm (_lock);
317 return read_unlocked (dst, start, cnt);
321 AudioSource::write (Sample *dst, framecnt_t cnt)
323 Glib::Threads::Mutex::Lock lm (_lock);
324 /* any write makes the file not removable */
325 _flags = Flag (_flags & ~Removable);
326 return write_unlocked (dst, cnt);
330 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
332 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
335 /** @param peaks Buffer to write peak data.
336 * @param npeaks Number of peaks to write.
340 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
341 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
343 Glib::Threads::Mutex::Lock lm (_lock);
345 double expected_peaks;
346 PeakData::PeakDatum xmax;
347 PeakData::PeakDatum xmin;
349 #ifdef PLATFORM_WINDOWS
350 SYSTEM_INFO system_info;
351 GetSystemInfo (&system_info);
352 const int bufsize = system_info.dwAllocationGranularity;;
354 const int bufsize = sysconf(_SC_PAGESIZE);
356 framecnt_t read_npeaks = npeaks;
357 framecnt_t zero_fill = 0;
359 ScopedFileDescriptor sfd (::open (peakpath.c_str(), O_RDONLY));
362 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), peakpath, strerror (errno)) << endmsg;
366 expected_peaks = (cnt / (double) samples_per_file_peak);
367 scale = npeaks/expected_peaks;
369 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"
370 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
372 /* fix for near-end-of-file conditions */
374 if (cnt > _length - start) {
375 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
376 cnt = _length - start;
377 read_npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
378 zero_fill = npeaks - read_npeaks;
381 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
385 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
387 /* no scaling at all, just get the sample data and duplicate it for
388 both max and min peak values.
391 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
393 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
394 error << _("cannot read sample data for unscaled peak computation") << endmsg;
398 for (framecnt_t i = 0; i < npeaks; ++i) {
399 peaks[i].max = raw_staging[i];
400 peaks[i].min = raw_staging[i];
407 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
408 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
409 /* open, read, close */
411 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
413 off_t map_off = first_peak_byte;
414 off_t read_map_off = map_off & ~(bufsize - 1);
415 off_t map_delta = map_off - read_map_off;
416 size_t map_length = bytes_to_read + map_delta;
418 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
419 peak_cache.reset (new PeakData[npeaks]);
421 #ifdef PLATFORM_WINDOWS
422 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
427 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
428 if (map_handle == NULL) {
429 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), peakpath) << endmsg;
433 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
434 if (view_handle == NULL) {
435 error << string_compose (_("map failed - could not map peakfile %1."), peakpath) << endmsg;
439 addr = (char*) view_handle;
441 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
443 err_flag = UnmapViewOfFile (view_handle);
444 err_flag = CloseHandle(map_handle);
446 error << string_compose (_("unmap failed - could not unmap peakfile %1."), peakpath) << endmsg;
450 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
451 if (addr == MAP_FAILED) {
452 error << string_compose (_("map failed - could not mmap peakfile %1."), peakpath) << endmsg;
456 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
457 munmap (addr, map_length);
460 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
464 _last_scale = samples_per_visual_peak;
465 _last_map_off = map_off;
466 _last_raw_map_length = bytes_to_read;
469 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
476 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
480 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
481 - less peaks than the peakfile holds for the same range
483 So, read a block into a staging area, and then downsample from there.
485 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
488 const framecnt_t chunksize = (framecnt_t) expected_peaks; // we read all the peaks we need in one hit.
490 /* compute the rounded up frame position */
492 framepos_t current_stored_peak = (framepos_t) ceil (start / (double) samples_per_file_peak);
493 framepos_t next_visual_peak = (framepos_t) ceil (start / samples_per_visual_peak);
494 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
495 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
496 framecnt_t nvisual_peaks = 0;
499 /* handle the case where the initial visual peak is on a pixel boundary */
501 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
503 /* open ... close during out: handling */
505 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
506 off_t read_map_off = map_off & ~(bufsize - 1);
507 off_t map_delta = map_off - read_map_off;
508 size_t raw_map_length = chunksize * sizeof(PeakData);
509 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
511 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
512 peak_cache.reset (new PeakData[npeaks]);
513 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
516 #ifdef PLATFORM_WINDOWS
517 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
522 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
523 if (map_handle == NULL) {
524 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), peakpath) << endmsg;
528 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
529 if (view_handle == NULL) {
530 error << string_compose (_("map failed - could not map peakfile %1."), peakpath) << endmsg;
534 addr = (char *) view_handle;
536 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
538 err_flag = UnmapViewOfFile (view_handle);
539 err_flag = CloseHandle(map_handle);
541 error << string_compose (_("unmap failed - could not unmap peakfile %1."), peakpath) << endmsg;
545 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
546 if (addr == MAP_FAILED) {
547 error << string_compose (_("map failed - could not mmap peakfile %1."), peakpath) << endmsg;
551 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
552 munmap (addr, map_length);
554 while (nvisual_peaks < read_npeaks) {
559 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
561 xmax = max (xmax, staging[i].max);
562 xmin = min (xmin, staging[i].min);
564 ++current_stored_peak;
567 peak_cache[nvisual_peaks].max = xmax;
568 peak_cache[nvisual_peaks].min = xmin;
570 next_visual_peak_frame = min ((double) start + cnt, (next_visual_peak_frame + samples_per_visual_peak));
571 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
575 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
576 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
580 _last_scale = samples_per_visual_peak;
581 _last_map_off = map_off;
582 _last_raw_map_length = raw_map_length;
585 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
588 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
592 - less frames-per-peak (more resolution)
593 - more peaks than stored in the Peakfile
595 So, fetch data from the raw source, and generate peak
599 framecnt_t frames_read = 0;
600 framepos_t current_frame = start;
602 framecnt_t nvisual_peaks = 0;
603 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
604 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
606 framepos_t frame_pos = start;
607 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
608 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
609 double pixels_per_frame = 1.0 / samples_per_visual_peak;
614 while (nvisual_peaks < read_npeaks) {
616 if (i == frames_read) {
618 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
620 if (current_frame >= _length) {
622 /* hmm, error condition - we've reached the end of the file
623 without generating all the peak data. cook up a zero-filled
624 data buffer and then use it. this is simpler than
625 adjusting zero_fill and read_npeaks and then breaking out of
629 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
633 to_read = min (chunksize, (_length - current_frame));
636 if ((frames_read = read_unlocked (raw_staging.get(), current_frame, to_read)) == 0) {
637 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
638 _name, to_read, current_frame, _length, strerror (errno))
647 xmax = max (xmax, raw_staging[i]);
648 xmin = min (xmin, raw_staging[i]);
651 pixel_pos += pixels_per_frame;
653 if (pixel_pos >= next_pixel_pos) {
655 peaks[nvisual_peaks].max = xmax;
656 peaks[nvisual_peaks].min = xmin;
661 next_pixel_pos = ceil (pixel_pos + 0.5);
666 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
670 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
675 AudioSource::build_peaks_from_scratch ()
677 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
679 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
684 /* hold lock while building peaks */
686 Glib::Threads::Mutex::Lock lp (_lock);
688 if (prepare_for_peakfile_writes ()) {
692 framecnt_t current_frame = 0;
693 framecnt_t cnt = _length;
695 _peaks_built = false;
696 boost::scoped_array<Sample> buf(new Sample[bufsize]);
700 framecnt_t frames_to_read = min (bufsize, cnt);
701 framecnt_t frames_read;
703 if ((frames_read = read_unlocked (buf.get(), current_frame, frames_to_read)) != frames_to_read) {
704 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
705 done_with_peakfile_writes (false);
709 if (compute_and_write_peaks (buf.get(), current_frame, frames_read, true, false, _FPP)) {
713 current_frame += frames_read;
722 done_with_peakfile_writes ((cnt == 0));
730 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", peakpath));
731 ::g_unlink (peakpath.c_str());
738 AudioSource::prepare_for_peakfile_writes ()
740 if ((_peakfile_fd = open (peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
741 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
748 AudioSource::done_with_peakfile_writes (bool done)
750 if (peak_leftover_cnt) {
751 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
755 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
757 PeaksReady (); /* EMIT SIGNAL */
760 close (_peakfile_fd);
764 /** @param first_frame Offset from the source start of the first frame to process */
766 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
767 bool force, bool intermediate_peaks_ready)
769 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
773 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
774 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
777 uint32_t peaks_computed;
778 framepos_t current_frame;
779 framecnt_t frames_done;
780 const size_t blocksize = (128 * 1024);
781 off_t first_peak_byte;
782 boost::scoped_array<Sample> buf2;
784 if (_peakfile_fd < 0) {
785 if (prepare_for_peakfile_writes ()) {
791 if (peak_leftover_cnt) {
793 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
795 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
796 and we have leftovers. flush a single peak (since the leftovers
797 never represent more than that, and restart.
802 x.min = peak_leftovers[0];
803 x.max = peak_leftovers[0];
805 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
807 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
809 if (offset != byte) {
810 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
814 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
815 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
819 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
822 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
823 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
824 if (intermediate_peaks_ready) {
825 PeaksReady (); /* EMIT SIGNAL */
829 /* left overs are done */
831 peak_leftover_cnt = 0;
835 /* else ... had leftovers, but they immediately preceed the new data, so just
836 merge them and compute.
839 /* make a new contiguous buffer containing leftovers and the new stuff */
841 to_do = cnt + peak_leftover_cnt;
842 buf2.reset(new Sample[to_do]);
845 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
848 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
850 /* no more leftovers */
851 peak_leftover_cnt = 0;
853 /* use the temporary buffer */
856 /* make sure that when we write into the peakfile, we startup where we left off */
858 first_frame = peak_leftover_frame;
864 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
866 current_frame = first_frame;
871 /* if some frames were passed in (i.e. we're not flushing leftovers)
872 and there are less than fpp to do, save them till
876 if (force && (to_do < fpp)) {
877 /* keep the left overs around for next time */
879 if (peak_leftover_size < to_do) {
880 delete [] peak_leftovers;
881 peak_leftovers = new Sample[to_do];
882 peak_leftover_size = to_do;
884 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
885 peak_leftover_cnt = to_do;
886 peak_leftover_frame = current_frame;
893 framecnt_t this_time = min (fpp, to_do);
895 peakbuf[peaks_computed].max = buf[0];
896 peakbuf[peaks_computed].min = buf[0];
898 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
903 frames_done += this_time;
904 current_frame += this_time;
907 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
909 if (can_truncate_peaks()) {
911 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
912 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
913 it does not cause single-extent allocation even for peakfiles of
914 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
917 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
918 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
920 if (endpos < target_length) {
921 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", peakpath));
922 if (ftruncate (_peakfile_fd, target_length)) {
923 /* error doesn't actually matter so continue on without testing */
929 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
931 if (offset != first_peak_byte) {
932 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
936 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
938 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
940 if (bytes_written != bytes_to_write) {
941 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
945 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
948 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
949 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
950 if (intermediate_peaks_ready) {
951 PeaksReady (); /* EMIT SIGNAL */
959 AudioSource::truncate_peakfile ()
961 if (_peakfile_fd < 0) {
962 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
967 /* truncate the peakfile down to its natural length if necessary */
969 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
971 if (end > _peak_byte_max) {
972 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", peakpath));
973 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
974 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
975 peakpath, _peak_byte_max, errno) << endmsg;
981 AudioSource::available_peaks (double zoom_factor) const
983 if (zoom_factor < _FPP) {
984 return length(_timeline_position); // peak data will come from the audio file
987 /* peak data comes from peakfile, but the filesize might not represent
988 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
989 XXX - there might be some atomicity issues here, we should probably add a lock,
990 but _peak_byte_max only monotonically increases after initialization.
993 off_t end = _peak_byte_max;
995 return (end/sizeof(PeakData)) * _FPP;
999 AudioSource::mark_streaming_write_completed (const Lock& lock)
1001 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1004 PeaksReady (); /* EMIT SIGNAL */
1009 AudioSource::allocate_working_buffers (framecnt_t framerate)
1011 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1014 /* Note: we don't need any buffers allocated until
1015 a level 1 audiosource is created, at which
1016 time we'll call ::ensure_buffers_for_level()
1017 with the right value and do the right thing.
1020 if (!_mixdown_buffers.empty()) {
1021 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1026 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
1028 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1029 ensure_buffers_for_level_locked (level, frame_rate);
1033 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1035 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1037 /* this may be called because either "level" or "frame_rate" have
1038 * changed. and it may be called with "level" smaller than the current
1039 * number of buffers, because a new compound region has been created at
1040 * a more shallow level than the deepest one we currently have.
1043 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1045 _mixdown_buffers.clear ();
1046 _gain_buffers.clear ();
1048 for (uint32_t n = 0; n < limit; ++n) {
1049 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1050 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));