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.add_property ("captured-for", _captured_for);
143 AudioSource::set_state (const XMLNode& node, int /*version*/)
145 XMLProperty const * 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 (const string& audio_path, const bool in_session)
241 Glib::Threads::Mutex::Lock lm (_initialize_peaks_lock);
244 _peakpath = construct_peak_filepath (audio_path, in_session);
246 if (!empty() && !Glib::file_test (_peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
247 string oldpeak = construct_peak_filepath (audio_path, in_session, true);
248 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Looking for old peak file %1 for Audio file %2\n", oldpeak, audio_path));
249 if (Glib::file_test (oldpeak.c_str(), Glib::FILE_TEST_EXISTS)) {
250 // TODO use hard-link if possible
251 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Copy old peakfile %1 to %2\n", oldpeak, _peakpath));
252 PBD::copy_file (oldpeak, _peakpath);
256 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", _peakpath, audio_path));
258 if (g_stat (_peakpath.c_str(), &statbuf)) {
259 if (errno != ENOENT) {
260 /* it exists in the peaks dir, but there is some kind of error */
262 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), _peakpath) << endmsg;
266 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 does not exist\n", _peakpath));
268 _peaks_built = false;
272 /* we found it in the peaks dir, so check it out */
274 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
275 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", _peakpath));
276 _peaks_built = false;
278 // Check if the audio file has changed since the peakfile was built.
280 int err = g_stat (audio_path.c_str(), &stat_file);
284 /* no audio path - nested source or we can't
285 read it or ... whatever, use the peakfile as-is.
287 DEBUG_TRACE(DEBUG::Peaks, string_compose("Error when calling stat on Peakfile %1\n", _peakpath));
290 _peak_byte_max = statbuf.st_size;
294 /* allow 6 seconds slop on checking peak vs. file times because of various
298 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
299 _peaks_built = false;
303 _peak_byte_max = statbuf.st_size;
309 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
310 build_peaks_from_scratch ();
317 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
321 Glib::Threads::Mutex::Lock lm (_lock);
322 return read_unlocked (dst, start, cnt);
326 AudioSource::write (Sample *dst, framecnt_t cnt)
328 Glib::Threads::Mutex::Lock lm (_lock);
329 /* any write makes the file not removable */
330 _flags = Flag (_flags & ~Removable);
331 return write_unlocked (dst, cnt);
335 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
337 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
340 /** @param peaks Buffer to write peak data.
341 * @param npeaks Number of peaks to write.
345 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
346 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
348 Glib::Threads::Mutex::Lock lm (_lock);
350 double expected_peaks;
351 PeakData::PeakDatum xmax;
352 PeakData::PeakDatum xmin;
354 #ifdef PLATFORM_WINDOWS
355 SYSTEM_INFO system_info;
356 GetSystemInfo (&system_info);
357 const int bufsize = system_info.dwAllocationGranularity;;
359 const int bufsize = sysconf(_SC_PAGESIZE);
361 framecnt_t read_npeaks = npeaks;
362 framecnt_t zero_fill = 0;
366 expected_peaks = (cnt / (double) samples_per_file_peak);
367 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
368 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2)"), _peakpath, strerror (errno)) << endmsg;
372 if (!_captured_for.empty()) {
374 /* _captured_for is only set after a capture pass is
375 * complete. so we know that capturing is finished for this
376 * file, and now we can check actual size of the peakfile is at
377 * least large enough for all the data in the audio file. if it
378 * is too short, assume that a crash or other error truncated
379 * it, and rebuild it from scratch.
381 * XXX this may not work for destructive recording, but we
382 * might decided to get rid of that anyway.
386 const off_t expected_file_size = (_length / (double) samples_per_file_peak) * sizeof (PeakData);
388 if (statbuf.st_size < expected_file_size) {
389 warning << string_compose (_("peak file %1 is truncated from %2 to %3"), _peakpath, expected_file_size, statbuf.st_size) << endmsg;
390 const_cast<AudioSource*>(this)->build_peaks_from_scratch ();
391 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
392 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2) after rebuild"), _peakpath, strerror (errno)) << endmsg;
394 if (statbuf.st_size < expected_file_size) {
395 fatal << "peak file is still truncated after rebuild" << endmsg;
401 ScopedFileDescriptor sfd (g_open (_peakpath.c_str(), O_RDONLY, 0444));
404 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), _peakpath, strerror (errno)) << endmsg;
408 scale = npeaks/expected_peaks;
411 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"
412 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
414 /* fix for near-end-of-file conditions */
416 if (cnt > _length - start) {
417 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
418 cnt = _length - start;
419 read_npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
420 zero_fill = npeaks - read_npeaks;
421 expected_peaks = (cnt / (double) samples_per_file_peak);
422 scale = npeaks/expected_peaks;
425 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
429 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
431 /* no scaling at all, just get the sample data and duplicate it for
432 both max and min peak values.
435 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
437 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
438 error << _("cannot read sample data for unscaled peak computation") << endmsg;
442 for (framecnt_t i = 0; i < npeaks; ++i) {
443 peaks[i].max = raw_staging[i];
444 peaks[i].min = raw_staging[i];
451 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
452 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
453 /* open, read, close */
455 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
457 off_t map_off = first_peak_byte;
458 off_t read_map_off = map_off & ~(bufsize - 1);
459 off_t map_delta = map_off - read_map_off;
460 size_t map_length = bytes_to_read + map_delta;
462 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
463 peak_cache.reset (new PeakData[npeaks]);
465 #ifdef PLATFORM_WINDOWS
466 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
471 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
472 if (map_handle == NULL) {
473 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
477 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
478 if (view_handle == NULL) {
479 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
483 addr = (char*) view_handle;
485 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
487 err_flag = UnmapViewOfFile (view_handle);
488 err_flag = CloseHandle(map_handle);
490 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
494 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
495 if (addr == MAP_FAILED) {
496 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
500 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
501 munmap (addr, map_length);
504 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
508 _last_scale = samples_per_visual_peak;
509 _last_map_off = map_off;
510 _last_raw_map_length = bytes_to_read;
513 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
520 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
524 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
525 - less peaks than the peakfile holds for the same range
527 So, read a block into a staging area, and then downsample from there.
529 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
532 const framecnt_t chunksize = (framecnt_t) expected_peaks; // we read all the peaks we need in one hit.
534 /* compute the rounded up frame position */
536 framepos_t current_stored_peak = (framepos_t) ceil (start / (double) samples_per_file_peak);
537 framepos_t next_visual_peak = (framepos_t) ceil (start / samples_per_visual_peak);
538 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
539 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
540 framecnt_t nvisual_peaks = 0;
543 /* handle the case where the initial visual peak is on a pixel boundary */
545 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
547 /* open ... close during out: handling */
549 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
550 off_t read_map_off = map_off & ~(bufsize - 1);
551 off_t map_delta = map_off - read_map_off;
552 size_t raw_map_length = chunksize * sizeof(PeakData);
553 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
555 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
556 peak_cache.reset (new PeakData[npeaks]);
557 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
560 #ifdef PLATFORM_WINDOWS
561 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
566 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
567 if (map_handle == NULL) {
568 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
572 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
573 if (view_handle == NULL) {
574 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
578 addr = (char *) view_handle;
580 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
582 err_flag = UnmapViewOfFile (view_handle);
583 err_flag = CloseHandle(map_handle);
585 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
589 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
590 if (addr == MAP_FAILED) {
591 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
595 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
596 munmap (addr, map_length);
598 while (nvisual_peaks < read_npeaks) {
603 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
605 xmax = max (xmax, staging[i].max);
606 xmin = min (xmin, staging[i].min);
608 ++current_stored_peak;
611 peak_cache[nvisual_peaks].max = xmax;
612 peak_cache[nvisual_peaks].min = xmin;
614 next_visual_peak_frame = min ((double) start + cnt, (next_visual_peak_frame + samples_per_visual_peak));
615 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
619 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
620 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
624 _last_scale = samples_per_visual_peak;
625 _last_map_off = map_off;
626 _last_raw_map_length = raw_map_length;
629 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
632 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
636 - less frames-per-peak (more resolution)
637 - more peaks than stored in the Peakfile
639 So, fetch data from the raw source, and generate peak
643 framecnt_t frames_read = 0;
644 framepos_t current_frame = start;
646 framecnt_t nvisual_peaks = 0;
647 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
648 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
650 framepos_t frame_pos = start;
651 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
652 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
653 double pixels_per_frame = 1.0 / samples_per_visual_peak;
658 while (nvisual_peaks < read_npeaks) {
660 if (i == frames_read) {
662 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
664 if (current_frame >= _length) {
666 /* hmm, error condition - we've reached the end of the file
667 without generating all the peak data. cook up a zero-filled
668 data buffer and then use it. this is simpler than
669 adjusting zero_fill and read_npeaks and then breaking out of
673 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
677 to_read = min (chunksize, (_length - current_frame));
680 if ((frames_read = read_unlocked (raw_staging.get(), current_frame, to_read)) == 0) {
681 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
682 _name, to_read, current_frame, _length, strerror (errno))
691 xmax = max (xmax, raw_staging[i]);
692 xmin = min (xmin, raw_staging[i]);
695 pixel_pos += pixels_per_frame;
697 if (pixel_pos >= next_pixel_pos) {
699 peaks[nvisual_peaks].max = xmax;
700 peaks[nvisual_peaks].min = xmin;
705 next_pixel_pos = ceil (pixel_pos + 0.5);
710 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
714 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
719 AudioSource::build_peaks_from_scratch ()
721 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
723 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
728 /* hold lock while building peaks */
730 Glib::Threads::Mutex::Lock lp (_lock);
732 if (prepare_for_peakfile_writes ()) {
736 framecnt_t current_frame = 0;
737 framecnt_t cnt = _length;
739 _peaks_built = false;
740 boost::scoped_array<Sample> buf(new Sample[bufsize]);
744 framecnt_t frames_to_read = min (bufsize, cnt);
745 framecnt_t frames_read;
747 if ((frames_read = read_unlocked (buf.get(), current_frame, frames_to_read)) != frames_to_read) {
748 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
749 done_with_peakfile_writes (false);
753 lp.release(); // allow butler to refill buffers
755 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
756 cerr << "peak file creation interrupted: " << _name << endmsg;
758 done_with_peakfile_writes (false);
762 if (compute_and_write_peaks (buf.get(), current_frame, frames_read, true, false, _FPP)) {
766 current_frame += frames_read;
777 done_with_peakfile_writes ((cnt == 0));
785 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", _peakpath));
786 ::g_unlink (_peakpath.c_str());
793 AudioSource::close_peakfile ()
795 Glib::Threads::Mutex::Lock lp (_lock);
796 if (_peakfile_fd >= 0) {
797 close (_peakfile_fd);
800 if (!_peakpath.empty()) {
801 ::g_unlink (_peakpath.c_str());
803 _peaks_built = false;
808 AudioSource::prepare_for_peakfile_writes ()
810 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
814 if ((_peakfile_fd = g_open (_peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
815 error << string_compose(_("AudioSource: cannot open _peakpath (c) \"%1\" (%2)"), _peakpath, strerror (errno)) << endmsg;
822 AudioSource::done_with_peakfile_writes (bool done)
824 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
826 close (_peakfile_fd);
832 if (peak_leftover_cnt) {
833 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
837 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
839 PeaksReady (); /* EMIT SIGNAL */
842 close (_peakfile_fd);
846 /** @param first_frame Offset from the source start of the first frame to
847 * process. _lock MUST be held by caller.
850 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
851 bool force, bool intermediate_peaks_ready)
853 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
857 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
858 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
861 uint32_t peaks_computed;
862 framepos_t current_frame;
863 framecnt_t frames_done;
864 const size_t blocksize = (128 * 1024);
865 off_t first_peak_byte;
866 boost::scoped_array<Sample> buf2;
868 if (_peakfile_fd < 0) {
869 if (prepare_for_peakfile_writes ()) {
875 if (peak_leftover_cnt) {
877 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
879 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
880 and we have leftovers. flush a single peak (since the leftovers
881 never represent more than that, and restart.
886 x.min = peak_leftovers[0];
887 x.max = peak_leftovers[0];
889 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
891 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
893 if (offset != byte) {
894 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
898 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
899 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
903 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
906 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
907 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
908 if (intermediate_peaks_ready) {
909 PeaksReady (); /* EMIT SIGNAL */
913 /* left overs are done */
915 peak_leftover_cnt = 0;
919 /* else ... had leftovers, but they immediately preceed the new data, so just
920 merge them and compute.
923 /* make a new contiguous buffer containing leftovers and the new stuff */
925 to_do = cnt + peak_leftover_cnt;
926 buf2.reset(new Sample[to_do]);
929 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
932 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
934 /* no more leftovers */
935 peak_leftover_cnt = 0;
937 /* use the temporary buffer */
940 /* make sure that when we write into the peakfile, we startup where we left off */
942 first_frame = peak_leftover_frame;
948 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
950 current_frame = first_frame;
955 /* if some frames were passed in (i.e. we're not flushing leftovers)
956 and there are less than fpp to do, save them till
960 if (force && (to_do < fpp)) {
961 /* keep the left overs around for next time */
963 if (peak_leftover_size < to_do) {
964 delete [] peak_leftovers;
965 peak_leftovers = new Sample[to_do];
966 peak_leftover_size = to_do;
968 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
969 peak_leftover_cnt = to_do;
970 peak_leftover_frame = current_frame;
977 framecnt_t this_time = min (fpp, to_do);
979 peakbuf[peaks_computed].max = buf[0];
980 peakbuf[peaks_computed].min = buf[0];
982 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
987 frames_done += this_time;
988 current_frame += this_time;
991 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
993 if (can_truncate_peaks()) {
995 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
996 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
997 it does not cause single-extent allocation even for peakfiles of
998 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
1001 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
1002 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
1004 if (endpos < target_length) {
1005 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1006 if (ftruncate (_peakfile_fd, target_length)) {
1007 /* error doesn't actually matter so continue on without testing */
1013 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
1015 if (offset != first_peak_byte) {
1016 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
1020 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
1022 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
1024 if (bytes_written != bytes_to_write) {
1025 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
1029 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
1032 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1033 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
1034 if (intermediate_peaks_ready) {
1035 PeaksReady (); /* EMIT SIGNAL */
1043 AudioSource::truncate_peakfile ()
1045 if (_peakfile_fd < 0) {
1046 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1051 /* truncate the peakfile down to its natural length if necessary */
1053 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1055 if (end > _peak_byte_max) {
1056 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1057 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1058 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1059 _peakpath, _peak_byte_max, errno) << endmsg;
1065 AudioSource::available_peaks (double zoom_factor) const
1067 if (zoom_factor < _FPP) {
1068 return length(_timeline_position); // peak data will come from the audio file
1071 /* peak data comes from peakfile, but the filesize might not represent
1072 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1073 XXX - there might be some atomicity issues here, we should probably add a lock,
1074 but _peak_byte_max only monotonically increases after initialization.
1077 off_t end = _peak_byte_max;
1079 return (end/sizeof(PeakData)) * _FPP;
1083 AudioSource::mark_streaming_write_completed (const Lock& lock)
1085 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1088 PeaksReady (); /* EMIT SIGNAL */
1093 AudioSource::allocate_working_buffers (framecnt_t framerate)
1095 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1098 /* Note: we don't need any buffers allocated until
1099 a level 1 audiosource is created, at which
1100 time we'll call ::ensure_buffers_for_level()
1101 with the right value and do the right thing.
1104 if (!_mixdown_buffers.empty()) {
1105 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1110 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
1112 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1113 ensure_buffers_for_level_locked (level, frame_rate);
1117 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1119 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1121 /* this may be called because either "level" or "frame_rate" have
1122 * changed. and it may be called with "level" smaller than the current
1123 * number of buffers, because a new compound region has been created at
1124 * a more shallow level than the deepest one we currently have.
1127 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1129 _mixdown_buffers.clear ();
1130 _gain_buffers.clear ();
1132 for (uint32_t n = 0; n < limit; ++n) {
1133 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1134 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));