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/convert.h>
51 #include <glibmm/fileutils.h>
52 #include <glibmm/miscutils.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"
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, 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 const XMLProperty* 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, Glib::locale_from_utf8(oldpath), Glib::locale_from_utf8(newpath), strerror (errno)) << endmsg;
239 AudioSource::initialize_peakfile (string audio_path)
243 peakpath = peak_path (audio_path);
245 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", Glib::locale_from_utf8(peakpath), Glib::locale_from_utf8(audio_path)));
247 /* if the peak file should be there, but isn't .... */
249 if (!empty() && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
250 peakpath = find_broken_peakfile (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\""), Glib::locale_from_utf8(peakpath)) << endmsg;
261 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 does not exist\n", Glib::locale_from_utf8(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", Glib::locale_from_utf8(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", Glib::locale_from_utf8(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, framepos_t start, framecnt_t cnt, int /*channel*/) const
316 Glib::Threads::Mutex::Lock lm (_lock);
317 return read_unlocked (dst, start, cnt);
321 AudioSource::write (Sample *dst, framecnt_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, framecnt_t npeaks, framepos_t start, framecnt_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, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
341 double samples_per_visual_peak, framecnt_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 framecnt_t read_npeaks = npeaks;
357 framecnt_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)"), Glib::locale_from_utf8(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"), Glib::locale_from_utf8(peakpath), expected_file_size, statbuf.st_size) << endmsg;
385 const_cast<AudioSource*>(this)->build_peaks_from_scratch ();
386 if (g_stat (peakpath.c_str(), &statbuf) != 0) {
387 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2) after rebuild"), Glib::locale_from_utf8(peakpath), strerror (errno)) << endmsg;
389 if (statbuf.st_size < expected_file_size) {
390 fatal << "peak file is still truncated after rebuild" << endmsg;
396 ScopedFileDescriptor sfd (::open (Glib::locale_from_utf8 (peakpath).c_str(), O_RDONLY));
399 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), Glib::locale_from_utf8(peakpath), strerror (errno)) << endmsg;
403 scale = npeaks/expected_peaks;
406 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"
407 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
409 /* fix for near-end-of-file conditions */
411 if (cnt > _length - start) {
412 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
413 cnt = _length - start;
414 read_npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
415 zero_fill = npeaks - read_npeaks;
416 expected_peaks = (cnt / (double) samples_per_file_peak);
417 scale = npeaks/expected_peaks;
420 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
424 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
426 /* no scaling at all, just get the sample data and duplicate it for
427 both max and min peak values.
430 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
432 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
433 error << _("cannot read sample data for unscaled peak computation") << endmsg;
437 for (framecnt_t i = 0; i < npeaks; ++i) {
438 peaks[i].max = raw_staging[i];
439 peaks[i].min = raw_staging[i];
446 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
447 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
448 /* open, read, close */
450 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
452 off_t map_off = first_peak_byte;
453 off_t read_map_off = map_off & ~(bufsize - 1);
454 off_t map_delta = map_off - read_map_off;
455 size_t map_length = bytes_to_read + map_delta;
457 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
458 peak_cache.reset (new PeakData[npeaks]);
460 #ifdef PLATFORM_WINDOWS
461 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
466 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
467 if (map_handle == NULL) {
468 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), Glib::locale_from_utf8(peakpath)) << endmsg;
472 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
473 if (view_handle == NULL) {
474 error << string_compose (_("map failed - could not map peakfile %1."), Glib::locale_from_utf8(peakpath)) << endmsg;
478 addr = (char*) view_handle;
480 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
482 err_flag = UnmapViewOfFile (view_handle);
483 err_flag = CloseHandle(map_handle);
485 error << string_compose (_("unmap failed - could not unmap peakfile %1."), Glib::locale_from_utf8(peakpath)) << endmsg;
489 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
490 if (addr == MAP_FAILED) {
491 error << string_compose (_("map failed - could not mmap peakfile %1."), peakpath) << endmsg;
495 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
496 munmap (addr, map_length);
499 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
503 _last_scale = samples_per_visual_peak;
504 _last_map_off = map_off;
505 _last_raw_map_length = bytes_to_read;
508 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
515 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
519 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
520 - less peaks than the peakfile holds for the same range
522 So, read a block into a staging area, and then downsample from there.
524 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
527 const framecnt_t chunksize = (framecnt_t) expected_peaks; // we read all the peaks we need in one hit.
529 /* compute the rounded up frame position */
531 framepos_t current_stored_peak = (framepos_t) ceil (start / (double) samples_per_file_peak);
532 framepos_t next_visual_peak = (framepos_t) ceil (start / samples_per_visual_peak);
533 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
534 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
535 framecnt_t nvisual_peaks = 0;
538 /* handle the case where the initial visual peak is on a pixel boundary */
540 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
542 /* open ... close during out: handling */
544 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
545 off_t read_map_off = map_off & ~(bufsize - 1);
546 off_t map_delta = map_off - read_map_off;
547 size_t raw_map_length = chunksize * sizeof(PeakData);
548 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
550 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
551 peak_cache.reset (new PeakData[npeaks]);
552 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
555 #ifdef PLATFORM_WINDOWS
556 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
561 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
562 if (map_handle == NULL) {
563 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), Glib::locale_from_utf8(peakpath)) << endmsg;
567 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
568 if (view_handle == NULL) {
569 error << string_compose (_("map failed - could not map peakfile %1."), Glib::locale_from_utf8(peakpath)) << endmsg;
573 addr = (char *) view_handle;
575 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
577 err_flag = UnmapViewOfFile (view_handle);
578 err_flag = CloseHandle(map_handle);
580 error << string_compose (_("unmap failed - could not unmap peakfile %1."), Glib::locale_from_utf8(peakpath)) << endmsg;
584 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
585 if (addr == MAP_FAILED) {
586 error << string_compose (_("map failed - could not mmap peakfile %1."), peakpath) << endmsg;
590 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
591 munmap (addr, map_length);
593 while (nvisual_peaks < read_npeaks) {
598 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
600 xmax = max (xmax, staging[i].max);
601 xmin = min (xmin, staging[i].min);
603 ++current_stored_peak;
606 peak_cache[nvisual_peaks].max = xmax;
607 peak_cache[nvisual_peaks].min = xmin;
609 next_visual_peak_frame = min ((double) start + cnt, (next_visual_peak_frame + samples_per_visual_peak));
610 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
614 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
615 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
619 _last_scale = samples_per_visual_peak;
620 _last_map_off = map_off;
621 _last_raw_map_length = raw_map_length;
624 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
627 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
631 - less frames-per-peak (more resolution)
632 - more peaks than stored in the Peakfile
634 So, fetch data from the raw source, and generate peak
638 framecnt_t frames_read = 0;
639 framepos_t current_frame = start;
641 framecnt_t nvisual_peaks = 0;
642 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
643 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
645 framepos_t frame_pos = start;
646 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
647 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
648 double pixels_per_frame = 1.0 / samples_per_visual_peak;
653 while (nvisual_peaks < read_npeaks) {
655 if (i == frames_read) {
657 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
659 if (current_frame >= _length) {
661 /* hmm, error condition - we've reached the end of the file
662 without generating all the peak data. cook up a zero-filled
663 data buffer and then use it. this is simpler than
664 adjusting zero_fill and read_npeaks and then breaking out of
668 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
672 to_read = min (chunksize, (_length - current_frame));
675 if ((frames_read = read_unlocked (raw_staging.get(), current_frame, to_read)) == 0) {
676 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
677 _name, to_read, current_frame, _length, strerror (errno))
686 xmax = max (xmax, raw_staging[i]);
687 xmin = min (xmin, raw_staging[i]);
690 pixel_pos += pixels_per_frame;
692 if (pixel_pos >= next_pixel_pos) {
694 peaks[nvisual_peaks].max = xmax;
695 peaks[nvisual_peaks].min = xmin;
700 next_pixel_pos = ceil (pixel_pos + 0.5);
705 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
709 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
714 AudioSource::build_peaks_from_scratch ()
716 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
718 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
723 /* hold lock while building peaks */
725 Glib::Threads::Mutex::Lock lp (_lock);
727 if (prepare_for_peakfile_writes ()) {
731 framecnt_t current_frame = 0;
732 framecnt_t cnt = _length;
734 _peaks_built = false;
735 boost::scoped_array<Sample> buf(new Sample[bufsize]);
739 framecnt_t frames_to_read = min (bufsize, cnt);
740 framecnt_t frames_read;
742 if ((frames_read = read_unlocked (buf.get(), current_frame, frames_to_read)) != frames_to_read) {
743 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
744 done_with_peakfile_writes (false);
748 if (compute_and_write_peaks (buf.get(), current_frame, frames_read, true, false, _FPP)) {
752 current_frame += frames_read;
761 done_with_peakfile_writes ((cnt == 0));
769 DEBUG_TRACE (DEBUG::Peaks, string_compose("Could not write peak data, attempting to remove peakfile %1\n", Glib::locale_from_utf8(peakpath)));
770 ::g_unlink (peakpath.c_str());
777 AudioSource::prepare_for_peakfile_writes ()
779 if ((_peakfile_fd = open (Glib::locale_from_utf8 (peakpath).c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
780 error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), Glib::locale_from_utf8(peakpath), strerror (errno)) << endmsg;
787 AudioSource::done_with_peakfile_writes (bool done)
789 if (peak_leftover_cnt) {
790 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
794 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
796 PeaksReady (); /* EMIT SIGNAL */
799 close (_peakfile_fd);
803 /** @param first_frame Offset from the source start of the first frame to
804 * process. _lock MUST be held by caller.
807 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
808 bool force, bool intermediate_peaks_ready)
810 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
814 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
815 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
818 uint32_t peaks_computed;
819 framepos_t current_frame;
820 framecnt_t frames_done;
821 const size_t blocksize = (128 * 1024);
822 off_t first_peak_byte;
823 boost::scoped_array<Sample> buf2;
825 if (_peakfile_fd < 0) {
826 if (prepare_for_peakfile_writes ()) {
832 if (peak_leftover_cnt) {
834 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
836 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
837 and we have leftovers. flush a single peak (since the leftovers
838 never represent more than that, and restart.
843 x.min = peak_leftovers[0];
844 x.max = peak_leftovers[0];
846 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
848 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
850 if (offset != byte) {
851 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
855 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
856 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
860 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
863 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
864 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
865 if (intermediate_peaks_ready) {
866 PeaksReady (); /* EMIT SIGNAL */
870 /* left overs are done */
872 peak_leftover_cnt = 0;
876 /* else ... had leftovers, but they immediately preceed the new data, so just
877 merge them and compute.
880 /* make a new contiguous buffer containing leftovers and the new stuff */
882 to_do = cnt + peak_leftover_cnt;
883 buf2.reset(new Sample[to_do]);
886 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
889 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
891 /* no more leftovers */
892 peak_leftover_cnt = 0;
894 /* use the temporary buffer */
897 /* make sure that when we write into the peakfile, we startup where we left off */
899 first_frame = peak_leftover_frame;
905 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
907 current_frame = first_frame;
912 /* if some frames were passed in (i.e. we're not flushing leftovers)
913 and there are less than fpp to do, save them till
917 if (force && (to_do < fpp)) {
918 /* keep the left overs around for next time */
920 if (peak_leftover_size < to_do) {
921 delete [] peak_leftovers;
922 peak_leftovers = new Sample[to_do];
923 peak_leftover_size = to_do;
925 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
926 peak_leftover_cnt = to_do;
927 peak_leftover_frame = current_frame;
934 framecnt_t this_time = min (fpp, to_do);
936 peakbuf[peaks_computed].max = buf[0];
937 peakbuf[peaks_computed].min = buf[0];
939 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
944 frames_done += this_time;
945 current_frame += this_time;
948 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
950 if (can_truncate_peaks()) {
952 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
953 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
954 it does not cause single-extent allocation even for peakfiles of
955 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
958 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
959 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
961 if (endpos < target_length) {
962 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", Glib::locale_from_utf8(peakpath)));
963 if (ftruncate (_peakfile_fd, target_length)) {
964 /* error doesn't actually matter so continue on without testing */
970 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
972 if (offset != first_peak_byte) {
973 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
977 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
979 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
981 if (bytes_written != bytes_to_write) {
982 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
986 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
989 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
990 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
991 if (intermediate_peaks_ready) {
992 PeaksReady (); /* EMIT SIGNAL */
1000 AudioSource::truncate_peakfile ()
1002 if (_peakfile_fd < 0) {
1003 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1008 /* truncate the peakfile down to its natural length if necessary */
1010 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1012 if (end > _peak_byte_max) {
1013 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", Glib::locale_from_utf8(peakpath)));
1014 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1015 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1016 Glib::locale_from_utf8(peakpath), _peak_byte_max, errno) << endmsg;
1022 AudioSource::available_peaks (double zoom_factor) const
1024 if (zoom_factor < _FPP) {
1025 return length(_timeline_position); // peak data will come from the audio file
1028 /* peak data comes from peakfile, but the filesize might not represent
1029 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1030 XXX - there might be some atomicity issues here, we should probably add a lock,
1031 but _peak_byte_max only monotonically increases after initialization.
1034 off_t end = _peak_byte_max;
1036 return (end/sizeof(PeakData)) * _FPP;
1040 AudioSource::mark_streaming_write_completed (const Lock& lock)
1042 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1045 PeaksReady (); /* EMIT SIGNAL */
1050 AudioSource::allocate_working_buffers (framecnt_t framerate)
1052 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1055 /* Note: we don't need any buffers allocated until
1056 a level 1 audiosource is created, at which
1057 time we'll call ::ensure_buffers_for_level()
1058 with the right value and do the right thing.
1061 if (!_mixdown_buffers.empty()) {
1062 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1067 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
1069 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1070 ensure_buffers_for_level_locked (level, frame_rate);
1074 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1076 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1078 /* this may be called because either "level" or "frame_rate" have
1079 * changed. and it may be called with "level" smaller than the current
1080 * number of buffers, because a new compound region has been created at
1081 * a more shallow level than the deepest one we currently have.
1084 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1086 _mixdown_buffers.clear ();
1087 _gain_buffers.clear ();
1089 for (uint32_t n = 0; n < limit; ++n) {
1090 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1091 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));