2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sys/utime.h>
37 #ifdef PLATFORM_WINDOWS
46 #include <glib/gstdio.h>
48 #include <boost/scoped_ptr.hpp>
50 #include <glibmm/fileutils.h>
51 #include <glibmm/miscutils.h>
53 #include "pbd/file_utils.h"
54 #include "pbd/scoped_file_descriptor.h"
55 #include "pbd/xml++.h"
57 #include "ardour/audiosource.h"
58 #include "ardour/rc_configuration.h"
59 #include "ardour/runtime_functions.h"
60 #include "ardour/session.h"
64 #include "ardour/debug.h"
67 using namespace ARDOUR;
70 Glib::Threads::Mutex AudioSource::_level_buffer_lock;
71 vector<boost::shared_array<Sample> > AudioSource::_mixdown_buffers;
72 vector<boost::shared_array<gain_t> > AudioSource::_gain_buffers;
73 bool AudioSource::_build_missing_peakfiles = false;
75 /** true if we want peakfiles (e.g. if we are displaying a GUI) */
76 bool AudioSource::_build_peakfiles = false;
80 AudioSource::AudioSource (Session& s, const string& name)
81 : Source (s, DataType::AUDIO, name)
84 , _peaks_built (false)
86 , peak_leftover_cnt (0)
87 , peak_leftover_size (0)
92 , _last_raw_map_length (0)
96 AudioSource::AudioSource (Session& s, const XMLNode& node)
100 , _peaks_built (false)
102 , peak_leftover_cnt (0)
103 , peak_leftover_size (0)
108 , _last_raw_map_length (0)
110 if (set_state (node, Stateful::loading_state_version)) {
111 throw failed_constructor();
115 AudioSource::~AudioSource ()
117 /* shouldn't happen but make sure we don't leak file descriptors anyway */
119 if (peak_leftover_cnt) {
120 cerr << "AudioSource destroyed with leftover peak data pending" << endl;
123 if ((-1) != _peakfile_fd) {
124 close (_peakfile_fd);
128 delete [] peak_leftovers;
132 AudioSource::get_state ()
134 XMLNode& node (Source::get_state());
136 if (_captured_for.length()) {
137 node.add_property ("captured-for", _captured_for);
144 AudioSource::set_state (const XMLNode& node, int /*version*/)
146 const XMLProperty* prop;
148 if ((prop = node.property ("captured-for")) != 0) {
149 _captured_for = prop->value();
156 AudioSource::empty () const
162 AudioSource::length (framepos_t /*pos*/) const
168 AudioSource::update_length (framecnt_t len)
176 /***********************************************************************
178 ***********************************************************************/
180 /** Checks to see if peaks are ready. If so, we return true. If not, we return false, and
181 * things are set up so that doThisWhenReady is called when the peaks are ready.
182 * A new PBD::ScopedConnection is created for the associated connection and written to
183 * *connect_here_if_not.
185 * @param doThisWhenReady Function to call when peaks are ready (if they are not already).
186 * @param connect_here_if_not Address to write new ScopedConnection to.
187 * @param event_loop Event loop for doThisWhenReady to be called in.
190 AudioSource::peaks_ready (boost::function<void()> doThisWhenReady, ScopedConnection** connect_here_if_not, EventLoop* event_loop) const
193 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
195 if (!(ret = _peaks_built)) {
196 *connect_here_if_not = new ScopedConnection;
197 PeaksReady.connect (**connect_here_if_not, MISSING_INVALIDATOR, doThisWhenReady, event_loop);
204 AudioSource::touch_peakfile ()
208 if (g_stat (_peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
214 tbuf.actime = statbuf.st_atime;
215 tbuf.modtime = time ((time_t*) 0);
217 g_utime (_peakpath.c_str(), &tbuf);
221 AudioSource::rename_peakfile (string newpath)
223 /* caller must hold _lock */
225 string oldpath = _peakpath;
227 if (Glib::file_test (oldpath, Glib::FILE_TEST_EXISTS)) {
228 if (g_rename (oldpath.c_str(), newpath.c_str()) != 0) {
229 error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
240 AudioSource::initialize_peakfile (const string& audio_path, const bool in_session)
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()) {
756 cerr << "peak file creation interrupted: " << _name << endmsg;
757 done_with_peakfile_writes (false);
761 if (compute_and_write_peaks (buf.get(), current_frame, frames_read, true, false, _FPP)) {
765 current_frame += frames_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::prepare_for_peakfile_writes ()
794 if ((_peakfile_fd = g_open (_peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
795 error << string_compose(_("AudioSource: cannot open _peakpath (c) \"%1\" (%2)"), _peakpath, strerror (errno)) << endmsg;
802 AudioSource::done_with_peakfile_writes (bool done)
804 if (peak_leftover_cnt) {
805 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
809 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
811 PeaksReady (); /* EMIT SIGNAL */
814 close (_peakfile_fd);
818 /** @param first_frame Offset from the source start of the first frame to
819 * process. _lock MUST be held by caller.
822 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
823 bool force, bool intermediate_peaks_ready)
825 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
829 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
830 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
833 uint32_t peaks_computed;
834 framepos_t current_frame;
835 framecnt_t frames_done;
836 const size_t blocksize = (128 * 1024);
837 off_t first_peak_byte;
838 boost::scoped_array<Sample> buf2;
840 if (_peakfile_fd < 0) {
841 if (prepare_for_peakfile_writes ()) {
847 if (peak_leftover_cnt) {
849 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
851 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
852 and we have leftovers. flush a single peak (since the leftovers
853 never represent more than that, and restart.
858 x.min = peak_leftovers[0];
859 x.max = peak_leftovers[0];
861 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
863 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
865 if (offset != byte) {
866 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
870 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
871 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
875 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
878 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
879 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
880 if (intermediate_peaks_ready) {
881 PeaksReady (); /* EMIT SIGNAL */
885 /* left overs are done */
887 peak_leftover_cnt = 0;
891 /* else ... had leftovers, but they immediately preceed the new data, so just
892 merge them and compute.
895 /* make a new contiguous buffer containing leftovers and the new stuff */
897 to_do = cnt + peak_leftover_cnt;
898 buf2.reset(new Sample[to_do]);
901 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
904 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
906 /* no more leftovers */
907 peak_leftover_cnt = 0;
909 /* use the temporary buffer */
912 /* make sure that when we write into the peakfile, we startup where we left off */
914 first_frame = peak_leftover_frame;
920 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
922 current_frame = first_frame;
927 /* if some frames were passed in (i.e. we're not flushing leftovers)
928 and there are less than fpp to do, save them till
932 if (force && (to_do < fpp)) {
933 /* keep the left overs around for next time */
935 if (peak_leftover_size < to_do) {
936 delete [] peak_leftovers;
937 peak_leftovers = new Sample[to_do];
938 peak_leftover_size = to_do;
940 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
941 peak_leftover_cnt = to_do;
942 peak_leftover_frame = current_frame;
949 framecnt_t this_time = min (fpp, to_do);
951 peakbuf[peaks_computed].max = buf[0];
952 peakbuf[peaks_computed].min = buf[0];
954 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
959 frames_done += this_time;
960 current_frame += this_time;
963 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
965 if (can_truncate_peaks()) {
967 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
968 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
969 it does not cause single-extent allocation even for peakfiles of
970 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
973 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
974 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
976 if (endpos < target_length) {
977 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
978 if (ftruncate (_peakfile_fd, target_length)) {
979 /* error doesn't actually matter so continue on without testing */
985 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
987 if (offset != first_peak_byte) {
988 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
992 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
994 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
996 if (bytes_written != bytes_to_write) {
997 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
1001 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
1004 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1005 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
1006 if (intermediate_peaks_ready) {
1007 PeaksReady (); /* EMIT SIGNAL */
1015 AudioSource::truncate_peakfile ()
1017 if (_peakfile_fd < 0) {
1018 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1023 /* truncate the peakfile down to its natural length if necessary */
1025 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1027 if (end > _peak_byte_max) {
1028 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1029 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1030 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1031 _peakpath, _peak_byte_max, errno) << endmsg;
1037 AudioSource::available_peaks (double zoom_factor) const
1039 if (zoom_factor < _FPP) {
1040 return length(_timeline_position); // peak data will come from the audio file
1043 /* peak data comes from peakfile, but the filesize might not represent
1044 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1045 XXX - there might be some atomicity issues here, we should probably add a lock,
1046 but _peak_byte_max only monotonically increases after initialization.
1049 off_t end = _peak_byte_max;
1051 return (end/sizeof(PeakData)) * _FPP;
1055 AudioSource::mark_streaming_write_completed (const Lock& lock)
1057 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1060 PeaksReady (); /* EMIT SIGNAL */
1065 AudioSource::allocate_working_buffers (framecnt_t framerate)
1067 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1070 /* Note: we don't need any buffers allocated until
1071 a level 1 audiosource is created, at which
1072 time we'll call ::ensure_buffers_for_level()
1073 with the right value and do the right thing.
1076 if (!_mixdown_buffers.empty()) {
1077 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1082 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
1084 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1085 ensure_buffers_for_level_locked (level, frame_rate);
1089 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1091 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1093 /* this may be called because either "level" or "frame_rate" have
1094 * changed. and it may be called with "level" smaller than the current
1095 * number of buffers, because a new compound region has been created at
1096 * a more shallow level than the deepest one we currently have.
1099 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1101 _mixdown_buffers.clear ();
1102 _gain_buffers.clear ();
1104 for (uint32_t n = 0; n < limit; ++n) {
1105 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1106 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));