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 + start > _length) {
414 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
415 cnt = std::max ((samplecnt_t)0, _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;
424 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
428 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
430 /* no scaling at all, just get the sample data and duplicate it for
431 both max and min peak values.
434 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
436 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
437 error << _("cannot read sample data for unscaled peak computation") << endmsg;
441 for (samplecnt_t i = 0; i < npeaks; ++i) {
442 peaks[i].max = raw_staging[i];
443 peaks[i].min = raw_staging[i];
450 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
451 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
452 /* open, read, close */
454 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
456 off_t map_off = first_peak_byte;
457 off_t read_map_off = map_off & ~(bufsize - 1);
458 off_t map_delta = map_off - read_map_off;
459 size_t map_length = bytes_to_read + map_delta;
461 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
462 peak_cache.reset (new PeakData[npeaks]);
464 #ifdef PLATFORM_WINDOWS
465 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
470 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
471 if (map_handle == NULL) {
472 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
476 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
477 if (view_handle == NULL) {
478 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
482 addr = (char*) view_handle;
484 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
486 err_flag = UnmapViewOfFile (view_handle);
487 err_flag = CloseHandle(map_handle);
489 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
493 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
494 if (addr == MAP_FAILED) {
495 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
499 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
500 munmap (addr, map_length);
503 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
507 _last_scale = samples_per_visual_peak;
508 _last_map_off = map_off;
509 _last_raw_map_length = bytes_to_read;
512 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
519 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
523 - more samples-per-peak (lower resolution) than the peakfile, or to put it another way,
524 - less peaks than the peakfile holds for the same range
526 So, read a block into a staging area, and then downsample from there.
528 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
531 const samplecnt_t chunksize = (samplecnt_t) expected_peaks; // we read all the peaks we need in one hit.
533 /* compute the rounded up sample position */
535 samplepos_t current_stored_peak = (samplepos_t) ceil (start / (double) samples_per_file_peak);
536 samplepos_t next_visual_peak = (samplepos_t) ceil (start / samples_per_visual_peak);
537 double next_visual_peak_sample = next_visual_peak * samples_per_visual_peak;
538 samplepos_t stored_peak_before_next_visual_peak = (samplepos_t) next_visual_peak_sample / samples_per_file_peak;
539 samplecnt_t nvisual_peaks = 0;
542 /* handle the case where the initial visual peak is on a pixel boundary */
544 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
546 /* open ... close during out: handling */
548 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
549 off_t read_map_off = map_off & ~(bufsize - 1);
550 off_t map_delta = map_off - read_map_off;
551 size_t raw_map_length = chunksize * sizeof(PeakData);
552 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
554 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
555 peak_cache.reset (new PeakData[npeaks]);
556 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
559 #ifdef PLATFORM_WINDOWS
560 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
565 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
566 if (map_handle == NULL) {
567 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
571 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
572 if (view_handle == NULL) {
573 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
577 addr = (char *) view_handle;
579 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
581 err_flag = UnmapViewOfFile (view_handle);
582 err_flag = CloseHandle(map_handle);
584 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
588 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
589 if (addr == MAP_FAILED) {
590 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
594 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
595 munmap (addr, map_length);
597 while (nvisual_peaks < read_npeaks) {
602 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
604 xmax = max (xmax, staging[i].max);
605 xmin = min (xmin, staging[i].min);
607 ++current_stored_peak;
610 peak_cache[nvisual_peaks].max = xmax;
611 peak_cache[nvisual_peaks].min = xmin;
613 next_visual_peak_sample = min ((double) start + cnt, (next_visual_peak_sample + samples_per_visual_peak));
614 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_sample / samples_per_file_peak;
618 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
619 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
623 _last_scale = samples_per_visual_peak;
624 _last_map_off = map_off;
625 _last_raw_map_length = raw_map_length;
628 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
631 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
635 - less samples-per-peak (more resolution)
636 - more peaks than stored in the Peakfile
638 So, fetch data from the raw source, and generate peak
642 samplecnt_t samples_read = 0;
643 samplepos_t current_sample = start;
645 samplecnt_t nvisual_peaks = 0;
646 samplecnt_t chunksize = (samplecnt_t) min (cnt, (samplecnt_t) 4096);
647 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
649 samplepos_t sample_pos = start;
650 double pixel_pos = floor (sample_pos / samples_per_visual_peak);
651 double next_pixel_pos = ceil (sample_pos / samples_per_visual_peak);
652 double pixels_per_sample = 1.0 / samples_per_visual_peak;
657 while (nvisual_peaks < read_npeaks) {
659 if (i == samples_read) {
661 to_read = min (chunksize, (samplecnt_t)(_length - current_sample));
663 if (current_sample >= _length) {
665 /* hmm, error condition - we've reached the end of the file
666 without generating all the peak data. cook up a zero-filled
667 data buffer and then use it. this is simpler than
668 adjusting zero_fill and read_npeaks and then breaking out of
672 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
676 to_read = min (chunksize, (_length - current_sample));
679 if ((samples_read = read_unlocked (raw_staging.get(), current_sample, to_read)) == 0) {
680 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
681 _name, to_read, current_sample, _length, strerror (errno))
690 xmax = max (xmax, raw_staging[i]);
691 xmin = min (xmin, raw_staging[i]);
694 pixel_pos += pixels_per_sample;
696 if (pixel_pos >= next_pixel_pos) {
698 peaks[nvisual_peaks].max = xmax;
699 peaks[nvisual_peaks].min = xmin;
704 next_pixel_pos = ceil (pixel_pos + 0.5);
709 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
713 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
718 AudioSource::build_peaks_from_scratch ()
720 const samplecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
722 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
727 /* hold lock while building peaks */
729 Glib::Threads::Mutex::Lock lp (_lock);
731 if (prepare_for_peakfile_writes ()) {
735 samplecnt_t current_sample = 0;
736 samplecnt_t cnt = _length;
738 _peaks_built = false;
739 boost::scoped_array<Sample> buf(new Sample[bufsize]);
743 samplecnt_t samples_to_read = min (bufsize, cnt);
744 samplecnt_t samples_read;
746 if ((samples_read = read_unlocked (buf.get(), current_sample, samples_to_read)) != samples_to_read) {
747 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
748 done_with_peakfile_writes (false);
752 lp.release(); // allow butler to refill buffers
754 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
755 cerr << "peak file creation interrupted: " << _name << endmsg;
757 done_with_peakfile_writes (false);
761 if (compute_and_write_peaks (buf.get(), current_sample, samples_read, true, false, _FPP)) {
765 current_sample += samples_read;
776 done_with_peakfile_writes ((cnt == 0));
784 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", _peakpath));
785 ::g_unlink (_peakpath.c_str());
792 AudioSource::close_peakfile ()
794 Glib::Threads::Mutex::Lock lp (_lock);
795 if (_peakfile_fd >= 0) {
796 close (_peakfile_fd);
799 if (!_peakpath.empty()) {
800 ::g_unlink (_peakpath.c_str());
802 _peaks_built = false;
807 AudioSource::prepare_for_peakfile_writes ()
809 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
813 if ((_peakfile_fd = g_open (_peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
814 error << string_compose(_("AudioSource: cannot open _peakpath (c) \"%1\" (%2)"), _peakpath, strerror (errno)) << endmsg;
821 AudioSource::done_with_peakfile_writes (bool done)
823 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
825 close (_peakfile_fd);
831 if (peak_leftover_cnt) {
832 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
836 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
838 PeaksReady (); /* EMIT SIGNAL */
841 close (_peakfile_fd);
845 /** @param first_sample Offset from the source start of the first sample to
846 * process. _lock MUST be held by caller.
849 AudioSource::compute_and_write_peaks (Sample* buf, samplecnt_t first_sample, samplecnt_t cnt,
850 bool force, bool intermediate_peaks_ready)
852 return compute_and_write_peaks (buf, first_sample, cnt, force, intermediate_peaks_ready, _FPP);
856 AudioSource::compute_and_write_peaks (Sample* buf, samplecnt_t first_sample, samplecnt_t cnt,
857 bool force, bool intermediate_peaks_ready, samplecnt_t fpp)
860 uint32_t peaks_computed;
861 samplepos_t current_sample;
862 samplecnt_t samples_done;
863 const size_t blocksize = (128 * 1024);
864 off_t first_peak_byte;
865 boost::scoped_array<Sample> buf2;
867 if (_peakfile_fd < 0) {
868 if (prepare_for_peakfile_writes ()) {
874 if (peak_leftover_cnt) {
876 if (first_sample != peak_leftover_sample + peak_leftover_cnt) {
878 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
879 and we have leftovers. flush a single peak (since the leftovers
880 never represent more than that, and restart.
885 x.min = peak_leftovers[0];
886 x.max = peak_leftovers[0];
888 off_t byte = (peak_leftover_sample / fpp) * sizeof (PeakData);
890 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
892 if (offset != byte) {
893 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
897 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
898 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
902 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
905 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
906 PeakRangeReady (peak_leftover_sample, peak_leftover_cnt); /* EMIT SIGNAL */
907 if (intermediate_peaks_ready) {
908 PeaksReady (); /* EMIT SIGNAL */
912 /* left overs are done */
914 peak_leftover_cnt = 0;
918 /* else ... had leftovers, but they immediately preceed the new data, so just
919 merge them and compute.
922 /* make a new contiguous buffer containing leftovers and the new stuff */
924 to_do = cnt + peak_leftover_cnt;
925 buf2.reset(new Sample[to_do]);
928 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
931 if (buf && cnt > 0) {
932 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
935 /* no more leftovers */
936 peak_leftover_cnt = 0;
938 /* use the temporary buffer */
941 /* make sure that when we write into the peakfile, we startup where we left off */
943 first_sample = peak_leftover_sample;
949 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
951 current_sample = first_sample;
956 /* if some samples were passed in (i.e. we're not flushing leftovers)
957 and there are less than fpp to do, save them till
961 if (force && (to_do < fpp)) {
962 /* keep the left overs around for next time */
964 if (peak_leftover_size < to_do) {
965 delete [] peak_leftovers;
966 peak_leftovers = new Sample[to_do];
967 peak_leftover_size = to_do;
969 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
970 peak_leftover_cnt = to_do;
971 peak_leftover_sample = current_sample;
978 samplecnt_t this_time = min (fpp, to_do);
980 peakbuf[peaks_computed].max = buf[0];
981 peakbuf[peaks_computed].min = buf[0];
983 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
988 samples_done += this_time;
989 current_sample += this_time;
992 first_peak_byte = (first_sample / fpp) * sizeof (PeakData);
994 if (can_truncate_peaks()) {
996 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
997 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
998 it does not cause single-extent allocation even for peakfiles of
999 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
1002 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
1003 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
1005 if (endpos < target_length) {
1006 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1007 if (ftruncate (_peakfile_fd, target_length)) {
1008 /* error doesn't actually matter so continue on without testing */
1014 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
1016 if (offset != first_peak_byte) {
1017 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
1021 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
1023 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
1025 if (bytes_written != bytes_to_write) {
1026 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
1030 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
1033 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1034 PeakRangeReady (first_sample, samples_done); /* EMIT SIGNAL */
1035 if (intermediate_peaks_ready) {
1036 PeaksReady (); /* EMIT SIGNAL */
1044 AudioSource::truncate_peakfile ()
1046 if (_peakfile_fd < 0) {
1047 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1052 /* truncate the peakfile down to its natural length if necessary */
1054 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1056 if (end > _peak_byte_max) {
1057 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1058 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1059 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1060 _peakpath, _peak_byte_max, errno) << endmsg;
1066 AudioSource::available_peaks (double zoom_factor) const
1068 if (zoom_factor < _FPP) {
1069 return length(_timeline_position); // peak data will come from the audio file
1072 /* peak data comes from peakfile, but the filesize might not represent
1073 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1074 XXX - there might be some atomicity issues here, we should probably add a lock,
1075 but _peak_byte_max only monotonically increases after initialization.
1078 off_t end = _peak_byte_max;
1080 return (end/sizeof(PeakData)) * _FPP;
1084 AudioSource::mark_streaming_write_completed (const Lock& lock)
1086 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1089 PeaksReady (); /* EMIT SIGNAL */
1094 AudioSource::allocate_working_buffers (samplecnt_t framerate)
1096 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1099 /* Note: we don't need any buffers allocated until
1100 a level 1 audiosource is created, at which
1101 time we'll call ::ensure_buffers_for_level()
1102 with the right value and do the right thing.
1105 if (!_mixdown_buffers.empty()) {
1106 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1111 AudioSource::ensure_buffers_for_level (uint32_t level, samplecnt_t sample_rate)
1113 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1114 ensure_buffers_for_level_locked (level, sample_rate);
1118 AudioSource::ensure_buffers_for_level_locked (uint32_t level, samplecnt_t sample_rate)
1120 samplecnt_t nframes = (samplecnt_t) floor (Config->get_audio_playback_buffer_seconds() * sample_rate);
1122 /* this may be called because either "level" or "sample_rate" have
1123 * changed. and it may be called with "level" smaller than the current
1124 * number of buffers, because a new compound region has been created at
1125 * a more shallow level than the deepest one we currently have.
1128 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1130 _mixdown_buffers.clear ();
1131 _gain_buffers.clear ();
1133 for (uint32_t n = 0; n < limit; ++n) {
1134 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1135 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));