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 lm.release(); // build_peaks_from_scratch() takes _lock
391 const_cast<AudioSource*>(this)->build_peaks_from_scratch ();
393 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
394 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2) after rebuild"), _peakpath, strerror (errno)) << endmsg;
396 if (statbuf.st_size < expected_file_size) {
397 fatal << "peak file is still truncated after rebuild" << endmsg;
403 ScopedFileDescriptor sfd (g_open (_peakpath.c_str(), O_RDONLY, 0444));
406 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), _peakpath, strerror (errno)) << endmsg;
410 scale = npeaks/expected_peaks;
413 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"
414 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
416 /* fix for near-end-of-file conditions */
418 if (cnt > _length - start) {
419 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
420 cnt = _length - start;
421 read_npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
422 zero_fill = npeaks - read_npeaks;
423 expected_peaks = (cnt / (double) samples_per_file_peak);
424 scale = npeaks/expected_peaks;
427 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
431 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
433 /* no scaling at all, just get the sample data and duplicate it for
434 both max and min peak values.
437 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
439 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
440 error << _("cannot read sample data for unscaled peak computation") << endmsg;
444 for (framecnt_t i = 0; i < npeaks; ++i) {
445 peaks[i].max = raw_staging[i];
446 peaks[i].min = raw_staging[i];
453 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
454 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
455 /* open, read, close */
457 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
459 off_t map_off = first_peak_byte;
460 off_t read_map_off = map_off & ~(bufsize - 1);
461 off_t map_delta = map_off - read_map_off;
462 size_t map_length = bytes_to_read + map_delta;
464 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
465 peak_cache.reset (new PeakData[npeaks]);
467 #ifdef PLATFORM_WINDOWS
468 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
473 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
474 if (map_handle == NULL) {
475 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
479 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
480 if (view_handle == NULL) {
481 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
485 addr = (char*) view_handle;
487 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
489 err_flag = UnmapViewOfFile (view_handle);
490 err_flag = CloseHandle(map_handle);
492 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
496 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
497 if (addr == MAP_FAILED) {
498 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
502 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
503 munmap (addr, map_length);
506 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
510 _last_scale = samples_per_visual_peak;
511 _last_map_off = map_off;
512 _last_raw_map_length = bytes_to_read;
515 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
522 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
526 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
527 - less peaks than the peakfile holds for the same range
529 So, read a block into a staging area, and then downsample from there.
531 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
534 const framecnt_t chunksize = (framecnt_t) expected_peaks; // we read all the peaks we need in one hit.
536 /* compute the rounded up frame position */
538 framepos_t current_stored_peak = (framepos_t) ceil (start / (double) samples_per_file_peak);
539 framepos_t next_visual_peak = (framepos_t) ceil (start / samples_per_visual_peak);
540 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
541 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
542 framecnt_t nvisual_peaks = 0;
545 /* handle the case where the initial visual peak is on a pixel boundary */
547 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
549 /* open ... close during out: handling */
551 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
552 off_t read_map_off = map_off & ~(bufsize - 1);
553 off_t map_delta = map_off - read_map_off;
554 size_t raw_map_length = chunksize * sizeof(PeakData);
555 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
557 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
558 peak_cache.reset (new PeakData[npeaks]);
559 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
562 #ifdef PLATFORM_WINDOWS
563 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
568 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
569 if (map_handle == NULL) {
570 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
574 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
575 if (view_handle == NULL) {
576 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
580 addr = (char *) view_handle;
582 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
584 err_flag = UnmapViewOfFile (view_handle);
585 err_flag = CloseHandle(map_handle);
587 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
591 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
592 if (addr == MAP_FAILED) {
593 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
597 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
598 munmap (addr, map_length);
600 while (nvisual_peaks < read_npeaks) {
605 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
607 xmax = max (xmax, staging[i].max);
608 xmin = min (xmin, staging[i].min);
610 ++current_stored_peak;
613 peak_cache[nvisual_peaks].max = xmax;
614 peak_cache[nvisual_peaks].min = xmin;
616 next_visual_peak_frame = min ((double) start + cnt, (next_visual_peak_frame + samples_per_visual_peak));
617 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
621 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
622 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
626 _last_scale = samples_per_visual_peak;
627 _last_map_off = map_off;
628 _last_raw_map_length = raw_map_length;
631 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
634 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
638 - less frames-per-peak (more resolution)
639 - more peaks than stored in the Peakfile
641 So, fetch data from the raw source, and generate peak
645 framecnt_t frames_read = 0;
646 framepos_t current_frame = start;
648 framecnt_t nvisual_peaks = 0;
649 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
650 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
652 framepos_t frame_pos = start;
653 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
654 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
655 double pixels_per_frame = 1.0 / samples_per_visual_peak;
660 while (nvisual_peaks < read_npeaks) {
662 if (i == frames_read) {
664 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
666 if (current_frame >= _length) {
668 /* hmm, error condition - we've reached the end of the file
669 without generating all the peak data. cook up a zero-filled
670 data buffer and then use it. this is simpler than
671 adjusting zero_fill and read_npeaks and then breaking out of
675 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
679 to_read = min (chunksize, (_length - current_frame));
682 if ((frames_read = read_unlocked (raw_staging.get(), current_frame, to_read)) == 0) {
683 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
684 _name, to_read, current_frame, _length, strerror (errno))
693 xmax = max (xmax, raw_staging[i]);
694 xmin = min (xmin, raw_staging[i]);
697 pixel_pos += pixels_per_frame;
699 if (pixel_pos >= next_pixel_pos) {
701 peaks[nvisual_peaks].max = xmax;
702 peaks[nvisual_peaks].min = xmin;
707 next_pixel_pos = ceil (pixel_pos + 0.5);
712 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
716 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
721 AudioSource::build_peaks_from_scratch ()
723 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
725 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
730 /* hold lock while building peaks */
732 Glib::Threads::Mutex::Lock lp (_lock);
734 if (prepare_for_peakfile_writes ()) {
738 framecnt_t current_frame = 0;
739 framecnt_t cnt = _length;
741 _peaks_built = false;
742 boost::scoped_array<Sample> buf(new Sample[bufsize]);
746 framecnt_t frames_to_read = min (bufsize, cnt);
747 framecnt_t frames_read;
749 if ((frames_read = read_unlocked (buf.get(), current_frame, frames_to_read)) != frames_to_read) {
750 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
751 done_with_peakfile_writes (false);
755 lp.release(); // allow butler to refill buffers
757 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
758 cerr << "peak file creation interrupted: " << _name << endmsg;
760 done_with_peakfile_writes (false);
764 if (compute_and_write_peaks (buf.get(), current_frame, frames_read, true, false, _FPP)) {
768 current_frame += frames_read;
779 done_with_peakfile_writes ((cnt == 0));
787 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", _peakpath));
788 ::g_unlink (_peakpath.c_str());
795 AudioSource::close_peakfile ()
797 Glib::Threads::Mutex::Lock lp (_lock);
798 if (_peakfile_fd >= 0) {
799 close (_peakfile_fd);
802 if (!_peakpath.empty()) {
803 ::g_unlink (_peakpath.c_str());
805 _peaks_built = false;
810 AudioSource::prepare_for_peakfile_writes ()
812 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
816 if ((_peakfile_fd = g_open (_peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
817 error << string_compose(_("AudioSource: cannot open _peakpath (c) \"%1\" (%2)"), _peakpath, strerror (errno)) << endmsg;
824 AudioSource::done_with_peakfile_writes (bool done)
826 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
828 close (_peakfile_fd);
834 if (peak_leftover_cnt) {
835 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
839 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
841 PeaksReady (); /* EMIT SIGNAL */
844 close (_peakfile_fd);
848 /** @param first_frame Offset from the source start of the first frame to
849 * process. _lock MUST be held by caller.
852 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
853 bool force, bool intermediate_peaks_ready)
855 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
859 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
860 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
863 uint32_t peaks_computed;
864 framepos_t current_frame;
865 framecnt_t frames_done;
866 const size_t blocksize = (128 * 1024);
867 off_t first_peak_byte;
868 boost::scoped_array<Sample> buf2;
870 if (_peakfile_fd < 0) {
871 if (prepare_for_peakfile_writes ()) {
877 if (peak_leftover_cnt) {
879 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
881 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
882 and we have leftovers. flush a single peak (since the leftovers
883 never represent more than that, and restart.
888 x.min = peak_leftovers[0];
889 x.max = peak_leftovers[0];
891 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
893 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
895 if (offset != byte) {
896 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
900 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
901 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
905 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
908 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
909 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
910 if (intermediate_peaks_ready) {
911 PeaksReady (); /* EMIT SIGNAL */
915 /* left overs are done */
917 peak_leftover_cnt = 0;
921 /* else ... had leftovers, but they immediately preceed the new data, so just
922 merge them and compute.
925 /* make a new contiguous buffer containing leftovers and the new stuff */
927 to_do = cnt + peak_leftover_cnt;
928 buf2.reset(new Sample[to_do]);
931 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
934 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
936 /* no more leftovers */
937 peak_leftover_cnt = 0;
939 /* use the temporary buffer */
942 /* make sure that when we write into the peakfile, we startup where we left off */
944 first_frame = peak_leftover_frame;
950 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
952 current_frame = first_frame;
957 /* if some frames were passed in (i.e. we're not flushing leftovers)
958 and there are less than fpp to do, save them till
962 if (force && (to_do < fpp)) {
963 /* keep the left overs around for next time */
965 if (peak_leftover_size < to_do) {
966 delete [] peak_leftovers;
967 peak_leftovers = new Sample[to_do];
968 peak_leftover_size = to_do;
970 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
971 peak_leftover_cnt = to_do;
972 peak_leftover_frame = current_frame;
979 framecnt_t this_time = min (fpp, to_do);
981 peakbuf[peaks_computed].max = buf[0];
982 peakbuf[peaks_computed].min = buf[0];
984 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
989 frames_done += this_time;
990 current_frame += this_time;
993 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
995 if (can_truncate_peaks()) {
997 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
998 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
999 it does not cause single-extent allocation even for peakfiles of
1000 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
1003 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
1004 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
1006 if (endpos < target_length) {
1007 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1008 if (ftruncate (_peakfile_fd, target_length)) {
1009 /* error doesn't actually matter so continue on without testing */
1015 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
1017 if (offset != first_peak_byte) {
1018 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
1022 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
1024 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
1026 if (bytes_written != bytes_to_write) {
1027 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
1031 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
1034 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1035 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
1036 if (intermediate_peaks_ready) {
1037 PeaksReady (); /* EMIT SIGNAL */
1045 AudioSource::truncate_peakfile ()
1047 if (_peakfile_fd < 0) {
1048 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1053 /* truncate the peakfile down to its natural length if necessary */
1055 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1057 if (end > _peak_byte_max) {
1058 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1059 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1060 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1061 _peakpath, _peak_byte_max, errno) << endmsg;
1067 AudioSource::available_peaks (double zoom_factor) const
1069 if (zoom_factor < _FPP) {
1070 return length(_timeline_position); // peak data will come from the audio file
1073 /* peak data comes from peakfile, but the filesize might not represent
1074 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1075 XXX - there might be some atomicity issues here, we should probably add a lock,
1076 but _peak_byte_max only monotonically increases after initialization.
1079 off_t end = _peak_byte_max;
1081 return (end/sizeof(PeakData)) * _FPP;
1085 AudioSource::mark_streaming_write_completed (const Lock& lock)
1087 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1090 PeaksReady (); /* EMIT SIGNAL */
1095 AudioSource::allocate_working_buffers (framecnt_t framerate)
1097 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1100 /* Note: we don't need any buffers allocated until
1101 a level 1 audiosource is created, at which
1102 time we'll call ::ensure_buffers_for_level()
1103 with the right value and do the right thing.
1106 if (!_mixdown_buffers.empty()) {
1107 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1112 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
1114 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1115 ensure_buffers_for_level_locked (level, frame_rate);
1119 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1121 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1123 /* this may be called because either "level" or "frame_rate" have
1124 * changed. and it may be called with "level" smaller than the current
1125 * number of buffers, because a new compound region has been created at
1126 * a more shallow level than the deepest one we currently have.
1129 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1131 _mixdown_buffers.clear ();
1132 _gain_buffers.clear ();
1134 for (uint32_t n = 0; n < limit; ++n) {
1135 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1136 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));