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>
36 #ifdef PLATFORM_WINDOWS
45 #include "pbd/gstdio_compat.h"
47 #include <boost/scoped_ptr.hpp>
49 #include <glibmm/fileutils.h>
50 #include <glibmm/miscutils.h>
52 #include "pbd/file_utils.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"
59 #include "ardour/session.h"
63 #include "ardour/debug.h"
66 using namespace ARDOUR;
69 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
70 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
71 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
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, const 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.set_property ("captured-for", _captured_for);
143 AudioSource::set_state (const XMLNode& node, int /*version*/)
145 node.get_property ("captured-for", _captured_for);
150 AudioSource::empty () const
156 AudioSource::length (samplepos_t /*pos*/) const
162 AudioSource::update_length (samplecnt_t len)
170 /***********************************************************************
172 ***********************************************************************/
174 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
175 * things are set up so that doThisWhenReady is called when the peaks are ready.
176 * A new PBD::ScopedConnection is created for the associated connection and written to
177 * *connect_here_if_not.
179 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
180 * @param connect_here_if_not Address to write new ScopedConnection to.
181 * @param event_loop Event loop for doThisWhenReady to be called in.
184 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
187 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
189 if (!(ret = _peaks_built)) {
190 *connect_here_if_not = new ScopedConnection;
191 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
198 AudioSource::touch_peakfile ()
202 if (g_stat (_peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
208 tbuf.actime = statbuf.st_atime;
209 tbuf.modtime = time ((time_t*) 0);
211 g_utime (_peakpath.c_str(), &tbuf);
215 AudioSource::rename_peakfile (string newpath)
217 /* caller must hold _lock */
219 string oldpath = _peakpath;
221 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
222 if (g_rename (oldpath.c_str(), newpath.c_str()) != 0) {
223 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
234 AudioSource::initialize_peakfile (const string& audio_path, const bool in_session)
236 Glib::Threads::Mutex::Lock lm (_initialize_peaks_lock);
239 _peakpath = construct_peak_filepath (audio_path, in_session);
241 if (!empty() && !Glib::file_test (_peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
242 string oldpeak = construct_peak_filepath (audio_path, in_session, true);
243 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Looking for old peak file %1 for Audio file %2\n", oldpeak, audio_path));
244 if (Glib::file_test (oldpeak.c_str(), Glib::FILE_TEST_EXISTS)) {
245 // TODO use hard-link if possible
246 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Copy old peakfile %1 to %2\n", oldpeak, _peakpath));
247 PBD::copy_file (oldpeak, _peakpath);
251 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", _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.
275 int err = g_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, samplepos_t start, samplecnt_t cnt, int /*channel*/) const
316 Glib::Threads::Mutex::Lock lm (_lock);
317 return read_unlocked (dst, start, cnt);
321 AudioSource::write (Sample *dst, samplecnt_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, samplecnt_t npeaks, samplepos_t start, samplecnt_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, samplecnt_t npeaks, samplepos_t start, samplecnt_t cnt,
341 double samples_per_visual_peak, samplecnt_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 samplecnt_t read_npeaks = npeaks;
357 samplecnt_t zero_fill = 0;
361 expected_peaks = (cnt / (double) samples_per_file_peak);
362 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
363 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2)"), _peakpath, strerror (errno)) << endmsg;
367 if (!_captured_for.empty()) {
369 /* _captured_for is only set after a capture pass is
370 * complete. so we know that capturing is finished for this
371 * file, and now we can check actual size of the peakfile is at
372 * least large enough for all the data in the audio file. if it
373 * is too short, assume that a crash or other error truncated
374 * it, and rebuild it from scratch.
376 * XXX this may not work for destructive recording, but we
377 * might decided to get rid of that anyway.
381 const off_t expected_file_size = (_length / (double) samples_per_file_peak) * sizeof (PeakData);
383 if (statbuf.st_size < expected_file_size) {
384 warning << string_compose (_("peak file %1 is truncated from %2 to %3"), _peakpath, expected_file_size, statbuf.st_size) << endmsg;
385 lm.release(); // build_peaks_from_scratch() takes _lock
386 const_cast<AudioSource*>(this)->build_peaks_from_scratch ();
388 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
389 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2) after rebuild"), _peakpath, strerror (errno)) << endmsg;
391 if (statbuf.st_size < expected_file_size) {
392 fatal << "peak file is still truncated after rebuild" << endmsg;
398 ScopedFileDescriptor sfd (g_open (_peakpath.c_str(), O_RDONLY, 0444));
401 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), _peakpath, strerror (errno)) << endmsg;
405 scale = npeaks/expected_peaks;
408 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"
409 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
411 /* fix for near-end-of-file conditions */
413 if (cnt > _length - start) {
414 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
415 cnt = _length - start;
416 read_npeaks = min ((samplecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
417 zero_fill = npeaks - read_npeaks;
418 expected_peaks = (cnt / (double) samples_per_file_peak);
419 scale = npeaks/expected_peaks;
422 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
426 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
428 /* no scaling at all, just get the sample data and duplicate it for
429 both max and min peak values.
432 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
434 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
435 error << _("cannot read sample data for unscaled peak computation") << endmsg;
439 for (samplecnt_t i = 0; i < npeaks; ++i) {
440 peaks[i].max = raw_staging[i];
441 peaks[i].min = raw_staging[i];
448 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
449 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
450 /* open, read, close */
452 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
454 off_t map_off = first_peak_byte;
455 off_t read_map_off = map_off & ~(bufsize - 1);
456 off_t map_delta = map_off - read_map_off;
457 size_t map_length = bytes_to_read + map_delta;
459 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
460 peak_cache.reset (new PeakData[npeaks]);
462 #ifdef PLATFORM_WINDOWS
463 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
468 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
469 if (map_handle == NULL) {
470 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
474 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
475 if (view_handle == NULL) {
476 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
480 addr = (char*) view_handle;
482 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
484 err_flag = UnmapViewOfFile (view_handle);
485 err_flag = CloseHandle(map_handle);
487 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
491 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
492 if (addr == MAP_FAILED) {
493 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
497 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
498 munmap (addr, map_length);
501 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
505 _last_scale = samples_per_visual_peak;
506 _last_map_off = map_off;
507 _last_raw_map_length = bytes_to_read;
510 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
517 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
521 - more samples-per-peak (lower resolution) than the peakfile, or to put it another way,
522 - less peaks than the peakfile holds for the same range
524 So, read a block into a staging area, and then downsample from there.
526 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
529 const samplecnt_t chunksize = (samplecnt_t) expected_peaks; // we read all the peaks we need in one hit.
531 /* compute the rounded up sample position */
533 samplepos_t current_stored_peak = (samplepos_t) ceil (start / (double) samples_per_file_peak);
534 samplepos_t next_visual_peak = (samplepos_t) ceil (start / samples_per_visual_peak);
535 double next_visual_peak_sample = next_visual_peak * samples_per_visual_peak;
536 samplepos_t stored_peak_before_next_visual_peak = (samplepos_t) next_visual_peak_sample / samples_per_file_peak;
537 samplecnt_t nvisual_peaks = 0;
540 /* handle the case where the initial visual peak is on a pixel boundary */
542 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
544 /* open ... close during out: handling */
546 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
547 off_t read_map_off = map_off & ~(bufsize - 1);
548 off_t map_delta = map_off - read_map_off;
549 size_t raw_map_length = chunksize * sizeof(PeakData);
550 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
552 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
553 peak_cache.reset (new PeakData[npeaks]);
554 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
557 #ifdef PLATFORM_WINDOWS
558 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
563 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
564 if (map_handle == NULL) {
565 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
569 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
570 if (view_handle == NULL) {
571 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
575 addr = (char *) view_handle;
577 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
579 err_flag = UnmapViewOfFile (view_handle);
580 err_flag = CloseHandle(map_handle);
582 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
586 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
587 if (addr == MAP_FAILED) {
588 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
592 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
593 munmap (addr, map_length);
595 while (nvisual_peaks < read_npeaks) {
600 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
602 xmax = max (xmax, staging[i].max);
603 xmin = min (xmin, staging[i].min);
605 ++current_stored_peak;
608 peak_cache[nvisual_peaks].max = xmax;
609 peak_cache[nvisual_peaks].min = xmin;
611 next_visual_peak_sample = min ((double) start + cnt, (next_visual_peak_sample + samples_per_visual_peak));
612 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_sample / samples_per_file_peak;
616 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
617 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
621 _last_scale = samples_per_visual_peak;
622 _last_map_off = map_off;
623 _last_raw_map_length = raw_map_length;
626 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
629 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
633 - less samples-per-peak (more resolution)
634 - more peaks than stored in the Peakfile
636 So, fetch data from the raw source, and generate peak
640 samplecnt_t samples_read = 0;
641 samplepos_t current_sample = start;
643 samplecnt_t nvisual_peaks = 0;
644 samplecnt_t chunksize = (samplecnt_t) min (cnt, (samplecnt_t) 4096);
645 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
647 samplepos_t sample_pos = start;
648 double pixel_pos = floor (sample_pos / samples_per_visual_peak);
649 double next_pixel_pos = ceil (sample_pos / samples_per_visual_peak);
650 double pixels_per_sample = 1.0 / samples_per_visual_peak;
655 while (nvisual_peaks < read_npeaks) {
657 if (i == samples_read) {
659 to_read = min (chunksize, (samplecnt_t)(_length - current_sample));
661 if (current_sample >= _length) {
663 /* hmm, error condition - we've reached the end of the file
664 without generating all the peak data. cook up a zero-filled
665 data buffer and then use it. this is simpler than
666 adjusting zero_fill and read_npeaks and then breaking out of
670 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
674 to_read = min (chunksize, (_length - current_sample));
677 if ((samples_read = read_unlocked (raw_staging.get(), current_sample, to_read)) == 0) {
678 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
679 _name, to_read, current_sample, _length, strerror (errno))
688 xmax = max (xmax, raw_staging[i]);
689 xmin = min (xmin, raw_staging[i]);
692 pixel_pos += pixels_per_sample;
694 if (pixel_pos >= next_pixel_pos) {
696 peaks[nvisual_peaks].max = xmax;
697 peaks[nvisual_peaks].min = xmin;
702 next_pixel_pos = ceil (pixel_pos + 0.5);
707 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
711 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
716 AudioSource::build_peaks_from_scratch ()
718 const samplecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
720 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
725 /* hold lock while building peaks */
727 Glib::Threads::Mutex::Lock lp (_lock);
729 if (prepare_for_peakfile_writes ()) {
733 samplecnt_t current_sample = 0;
734 samplecnt_t cnt = _length;
736 _peaks_built = false;
737 boost::scoped_array<Sample> buf(new Sample[bufsize]);
741 samplecnt_t samples_to_read = min (bufsize, cnt);
742 samplecnt_t samples_read;
744 if ((samples_read = read_unlocked (buf.get(), current_sample, samples_to_read)) != samples_to_read) {
745 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
746 done_with_peakfile_writes (false);
750 lp.release(); // allow butler to refill buffers
752 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
753 cerr << "peak file creation interrupted: " << _name << endmsg;
755 done_with_peakfile_writes (false);
759 if (compute_and_write_peaks (buf.get(), current_sample, samples_read, true, false, _FPP)) {
763 current_sample += samples_read;
774 done_with_peakfile_writes ((cnt == 0));
782 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", _peakpath));
783 ::g_unlink (_peakpath.c_str());
790 AudioSource::close_peakfile ()
792 Glib::Threads::Mutex::Lock lp (_lock);
793 if (_peakfile_fd >= 0) {
794 close (_peakfile_fd);
797 if (!_peakpath.empty()) {
798 ::g_unlink (_peakpath.c_str());
800 _peaks_built = false;
805 AudioSource::prepare_for_peakfile_writes ()
807 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
811 if ((_peakfile_fd = g_open (_peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
812 error << string_compose(_("AudioSource: cannot open _peakpath (c) \"%1\" (%2)"), _peakpath, strerror (errno)) << endmsg;
819 AudioSource::done_with_peakfile_writes (bool done)
821 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
823 close (_peakfile_fd);
829 if (peak_leftover_cnt) {
830 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
834 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
836 PeaksReady (); /* EMIT SIGNAL */
839 close (_peakfile_fd);
843 /** @param first_sample Offset from the source start of the first sample to
844 * process. _lock MUST be held by caller.
847 AudioSource::compute_and_write_peaks (Sample* buf, samplecnt_t first_sample, samplecnt_t cnt,
848 bool force, bool intermediate_peaks_ready)
850 return compute_and_write_peaks (buf, first_sample, cnt, force, intermediate_peaks_ready, _FPP);
854 AudioSource::compute_and_write_peaks (Sample* buf, samplecnt_t first_sample, samplecnt_t cnt,
855 bool force, bool intermediate_peaks_ready, samplecnt_t fpp)
858 uint32_t peaks_computed;
859 samplepos_t current_sample;
860 samplecnt_t samples_done;
861 const size_t blocksize = (128 * 1024);
862 off_t first_peak_byte;
863 boost::scoped_array<Sample> buf2;
865 if (_peakfile_fd < 0) {
866 if (prepare_for_peakfile_writes ()) {
872 if (peak_leftover_cnt) {
874 if (first_sample != peak_leftover_sample + peak_leftover_cnt) {
876 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
877 and we have leftovers. flush a single peak (since the leftovers
878 never represent more than that, and restart.
883 x.min = peak_leftovers[0];
884 x.max = peak_leftovers[0];
886 off_t byte = (peak_leftover_sample / fpp) * sizeof (PeakData);
888 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
890 if (offset != byte) {
891 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
895 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
896 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
900 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
903 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
904 PeakRangeReady (peak_leftover_sample, peak_leftover_cnt); /* EMIT SIGNAL */
905 if (intermediate_peaks_ready) {
906 PeaksReady (); /* EMIT SIGNAL */
910 /* left overs are done */
912 peak_leftover_cnt = 0;
916 /* else ... had leftovers, but they immediately preceed the new data, so just
917 merge them and compute.
920 /* make a new contiguous buffer containing leftovers and the new stuff */
922 to_do = cnt + peak_leftover_cnt;
923 buf2.reset(new Sample[to_do]);
926 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
929 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
931 /* no more leftovers */
932 peak_leftover_cnt = 0;
934 /* use the temporary buffer */
937 /* make sure that when we write into the peakfile, we startup where we left off */
939 first_sample = peak_leftover_sample;
945 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
947 current_sample = first_sample;
952 /* if some samples were passed in (i.e. we're not flushing leftovers)
953 and there are less than fpp to do, save them till
957 if (force && (to_do < fpp)) {
958 /* keep the left overs around for next time */
960 if (peak_leftover_size < to_do) {
961 delete [] peak_leftovers;
962 peak_leftovers = new Sample[to_do];
963 peak_leftover_size = to_do;
965 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
966 peak_leftover_cnt = to_do;
967 peak_leftover_sample = current_sample;
974 samplecnt_t this_time = min (fpp, to_do);
976 peakbuf[peaks_computed].max = buf[0];
977 peakbuf[peaks_computed].min = buf[0];
979 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
984 samples_done += this_time;
985 current_sample += this_time;
988 first_peak_byte = (first_sample / fpp) * sizeof (PeakData);
990 if (can_truncate_peaks()) {
992 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
993 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
994 it does not cause single-extent allocation even for peakfiles of
995 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
998 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
999 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
1001 if (endpos < target_length) {
1002 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1003 if (ftruncate (_peakfile_fd, target_length)) {
1004 /* error doesn't actually matter so continue on without testing */
1010 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
1012 if (offset != first_peak_byte) {
1013 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
1017 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
1019 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
1021 if (bytes_written != bytes_to_write) {
1022 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
1026 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
1029 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1030 PeakRangeReady (first_sample, samples_done); /* EMIT SIGNAL */
1031 if (intermediate_peaks_ready) {
1032 PeaksReady (); /* EMIT SIGNAL */
1040 AudioSource::truncate_peakfile ()
1042 if (_peakfile_fd < 0) {
1043 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1048 /* truncate the peakfile down to its natural length if necessary */
1050 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1052 if (end > _peak_byte_max) {
1053 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1054 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1055 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1056 _peakpath, _peak_byte_max, errno) << endmsg;
1062 AudioSource::available_peaks (double zoom_factor) const
1064 if (zoom_factor < _FPP) {
1065 return length(_timeline_position); // peak data will come from the audio file
1068 /* peak data comes from peakfile, but the filesize might not represent
1069 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1070 XXX - there might be some atomicity issues here, we should probably add a lock,
1071 but _peak_byte_max only monotonically increases after initialization.
1074 off_t end = _peak_byte_max;
1076 return (end/sizeof(PeakData)) * _FPP;
1080 AudioSource::mark_streaming_write_completed (const Lock& lock)
1082 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1085 PeaksReady (); /* EMIT SIGNAL */
1090 AudioSource::allocate_working_buffers (samplecnt_t framerate)
1092 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1095 /* Note: we don't need any buffers allocated until
1096 a level 1 audiosource is created, at which
1097 time we'll call ::ensure_buffers_for_level()
1098 with the right value and do the right thing.
1101 if (!_mixdown_buffers.empty()) {
1102 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1107 AudioSource::ensure_buffers_for_level (uint32_t level, samplecnt_t sample_rate)
1109 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1110 ensure_buffers_for_level_locked (level, sample_rate);
1114 AudioSource::ensure_buffers_for_level_locked (uint32_t level, samplecnt_t sample_rate)
1116 samplecnt_t nframes = (samplecnt_t) floor (Config->get_audio_playback_buffer_seconds() * sample_rate);
1118 /* this may be called because either "level" or "sample_rate" have
1119 * changed. and it may be called with "level" smaller than the current
1120 * number of buffers, because a new compound region has been created at
1121 * a more shallow level than the deepest one we currently have.
1124 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1126 _mixdown_buffers.clear ();
1127 _gain_buffers.clear ();
1129 for (uint32_t n = 0; n < limit; ++n) {
1130 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1131 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));