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 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, oldpath, newpath, strerror (errno)) << endmsg;
239 AudioSource::initialize_peakfile (const string& audio_path, const bool in_session)
243 _peakpath = construct_peak_filepath (audio_path, in_session);
245 if (!empty() && !Glib::file_test (_peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
246 string oldpeak = construct_peak_filepath (audio_path, in_session, true);
247 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Looking for old peak file %1 for Audio file %2\n", oldpeak, audio_path));
248 if (Glib::file_test (oldpeak.c_str(), Glib::FILE_TEST_EXISTS)) {
249 // TODO use hard-link if possible
250 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Copy old peakfile %1 to %2\n", oldpeak, _peakpath));
251 PBD::copy_file (oldpeak, _peakpath);
255 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Initialize Peakfile %1 for Audio file %2\n", _peakpath, audio_path));
257 if (g_stat (_peakpath.c_str(), &statbuf)) {
258 if (errno != ENOENT) {
259 /* it exists in the peaks dir, but there is some kind of error */
261 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), _peakpath) << endmsg;
265 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 does not exist\n", _peakpath));
267 _peaks_built = false;
271 /* we found it in the peaks dir, so check it out */
273 if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
274 DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", _peakpath));
275 _peaks_built = false;
277 // Check if the audio file has changed since the peakfile was built.
279 int err = g_stat (audio_path.c_str(), &stat_file);
283 /* no audio path - nested source or we can't
284 read it or ... whatever, use the peakfile as-is.
286 DEBUG_TRACE(DEBUG::Peaks, string_compose("Error when calling stat on Peakfile %1\n", _peakpath));
289 _peak_byte_max = statbuf.st_size;
293 /* allow 6 seconds slop on checking peak vs. file times because of various
297 if (stat_file.st_mtime > statbuf.st_mtime && (stat_file.st_mtime - statbuf.st_mtime > 6)) {
298 _peaks_built = false;
302 _peak_byte_max = statbuf.st_size;
308 if (!empty() && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
309 build_peaks_from_scratch ();
316 AudioSource::read (Sample *dst, framepos_t start, framecnt_t cnt, int /*channel*/) const
320 Glib::Threads::Mutex::Lock lm (_lock);
321 return read_unlocked (dst, start, cnt);
325 AudioSource::write (Sample *dst, framecnt_t cnt)
327 Glib::Threads::Mutex::Lock lm (_lock);
328 /* any write makes the file not removable */
329 _flags = Flag (_flags & ~Removable);
330 return write_unlocked (dst, cnt);
334 AudioSource::read_peaks (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt, double samples_per_visual_peak) const
336 return read_peaks_with_fpp (peaks, npeaks, start, cnt, samples_per_visual_peak, _FPP);
339 /** @param peaks Buffer to write peak data.
340 * @param npeaks Number of peaks to write.
344 AudioSource::read_peaks_with_fpp (PeakData *peaks, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
345 double samples_per_visual_peak, framecnt_t samples_per_file_peak) const
347 Glib::Threads::Mutex::Lock lm (_lock);
349 double expected_peaks;
350 PeakData::PeakDatum xmax;
351 PeakData::PeakDatum xmin;
353 #ifdef PLATFORM_WINDOWS
354 SYSTEM_INFO system_info;
355 GetSystemInfo (&system_info);
356 const int bufsize = system_info.dwAllocationGranularity;;
358 const int bufsize = sysconf(_SC_PAGESIZE);
360 framecnt_t read_npeaks = npeaks;
361 framecnt_t zero_fill = 0;
365 expected_peaks = (cnt / (double) samples_per_file_peak);
366 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
367 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2)"), _peakpath, strerror (errno)) << endmsg;
371 if (!_captured_for.empty()) {
373 /* _captured_for is only set after a capture pass is
374 * complete. so we know that capturing is finished for this
375 * file, and now we can check actual size of the peakfile is at
376 * least large enough for all the data in the audio file. if it
377 * is too short, assume that a crash or other error truncated
378 * it, and rebuild it from scratch.
380 * XXX this may not work for destructive recording, but we
381 * might decided to get rid of that anyway.
385 const off_t expected_file_size = (_length / (double) samples_per_file_peak) * sizeof (PeakData);
387 if (statbuf.st_size < expected_file_size) {
388 warning << string_compose (_("peak file %1 is truncated from %2 to %3"), _peakpath, expected_file_size, statbuf.st_size) << endmsg;
389 const_cast<AudioSource*>(this)->build_peaks_from_scratch ();
390 if (g_stat (_peakpath.c_str(), &statbuf) != 0) {
391 error << string_compose (_("Cannot open peakfile @ %1 for size check (%2) after rebuild"), _peakpath, strerror (errno)) << endmsg;
393 if (statbuf.st_size < expected_file_size) {
394 fatal << "peak file is still truncated after rebuild" << endmsg;
400 ScopedFileDescriptor sfd (g_open (_peakpath.c_str(), O_RDONLY, 0444));
403 error << string_compose (_("Cannot open peakfile @ %1 for reading (%2)"), _peakpath, strerror (errno)) << endmsg;
407 scale = npeaks/expected_peaks;
410 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"
411 , npeaks, start, cnt, _length, samples_per_visual_peak, expected_peaks, scale, peaks));
413 /* fix for near-end-of-file conditions */
415 if (cnt > _length - start) {
416 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
417 cnt = _length - start;
418 read_npeaks = min ((framecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
419 zero_fill = npeaks - read_npeaks;
420 expected_peaks = (cnt / (double) samples_per_file_peak);
421 scale = npeaks/expected_peaks;
424 // cerr << "actual npeaks = " << read_npeaks << " zf = " << zero_fill << endl;
428 DEBUG_TRACE (DEBUG::Peaks, "RAW DATA\n");
430 /* no scaling at all, just get the sample data and duplicate it for
431 both max and min peak values.
434 boost::scoped_array<Sample> raw_staging(new Sample[cnt]);
436 if (read_unlocked (raw_staging.get(), start, cnt) != cnt) {
437 error << _("cannot read sample data for unscaled peak computation") << endmsg;
441 for (framecnt_t i = 0; i < npeaks; ++i) {
442 peaks[i].max = raw_staging[i];
443 peaks[i].min = raw_staging[i];
450 off_t first_peak_byte = (start / samples_per_file_peak) * sizeof (PeakData);
451 size_t bytes_to_read = sizeof (PeakData) * read_npeaks;
452 /* open, read, close */
454 DEBUG_TRACE (DEBUG::Peaks, "DIRECT PEAKS\n");
456 off_t map_off = first_peak_byte;
457 off_t read_map_off = map_off & ~(bufsize - 1);
458 off_t map_delta = map_off - read_map_off;
459 size_t map_length = bytes_to_read + map_delta;
461 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < bytes_to_read)) {
462 peak_cache.reset (new PeakData[npeaks]);
464 #ifdef PLATFORM_WINDOWS
465 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
470 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
471 if (map_handle == NULL) {
472 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
476 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
477 if (view_handle == NULL) {
478 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
482 addr = (char*) view_handle;
484 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
486 err_flag = UnmapViewOfFile (view_handle);
487 err_flag = CloseHandle(map_handle);
489 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
493 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
494 if (addr == MAP_FAILED) {
495 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
499 memcpy ((void*)peak_cache.get(), (void*)(addr + map_delta), bytes_to_read);
500 munmap (addr, map_length);
503 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
507 _last_scale = samples_per_visual_peak;
508 _last_map_off = map_off;
509 _last_raw_map_length = bytes_to_read;
512 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
519 DEBUG_TRACE (DEBUG::Peaks, "DOWNSAMPLE\n");
523 - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
524 - less peaks than the peakfile holds for the same range
526 So, read a block into a staging area, and then downsample from there.
528 to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
531 const framecnt_t chunksize = (framecnt_t) expected_peaks; // we read all the peaks we need in one hit.
533 /* compute the rounded up frame position */
535 framepos_t current_stored_peak = (framepos_t) ceil (start / (double) samples_per_file_peak);
536 framepos_t next_visual_peak = (framepos_t) ceil (start / samples_per_visual_peak);
537 double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
538 framepos_t stored_peak_before_next_visual_peak = (framepos_t) next_visual_peak_frame / samples_per_file_peak;
539 framecnt_t nvisual_peaks = 0;
542 /* handle the case where the initial visual peak is on a pixel boundary */
544 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
546 /* open ... close during out: handling */
548 off_t map_off = (uint32_t) (ceil (start / (double) samples_per_file_peak)) * sizeof(PeakData);
549 off_t read_map_off = map_off & ~(bufsize - 1);
550 off_t map_delta = map_off - read_map_off;
551 size_t raw_map_length = chunksize * sizeof(PeakData);
552 size_t map_length = (chunksize * sizeof(PeakData)) + map_delta;
554 if (_first_run || (_last_scale != samples_per_visual_peak) || (_last_map_off != map_off) || (_last_raw_map_length < raw_map_length)) {
555 peak_cache.reset (new PeakData[npeaks]);
556 boost::scoped_array<PeakData> staging (new PeakData[chunksize]);
559 #ifdef PLATFORM_WINDOWS
560 HANDLE file_handle = (HANDLE) _get_osfhandle(int(sfd));
565 map_handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
566 if (map_handle == NULL) {
567 error << string_compose (_("map failed - could not create file mapping for peakfile %1."), _peakpath) << endmsg;
571 view_handle = MapViewOfFile(map_handle, FILE_MAP_READ, 0, read_map_off, map_length);
572 if (view_handle == NULL) {
573 error << string_compose (_("map failed - could not map peakfile %1."), _peakpath) << endmsg;
577 addr = (char *) view_handle;
579 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
581 err_flag = UnmapViewOfFile (view_handle);
582 err_flag = CloseHandle(map_handle);
584 error << string_compose (_("unmap failed - could not unmap peakfile %1."), _peakpath) << endmsg;
588 addr = (char*) mmap (0, map_length, PROT_READ, MAP_PRIVATE, sfd, read_map_off);
589 if (addr == MAP_FAILED) {
590 error << string_compose (_("map failed - could not mmap peakfile %1."), _peakpath) << endmsg;
594 memcpy ((void*)staging.get(), (void*)(addr + map_delta), raw_map_length);
595 munmap (addr, map_length);
597 while (nvisual_peaks < read_npeaks) {
602 while ((current_stored_peak <= stored_peak_before_next_visual_peak) && (i < chunksize)) {
604 xmax = max (xmax, staging[i].max);
605 xmin = min (xmin, staging[i].min);
607 ++current_stored_peak;
610 peak_cache[nvisual_peaks].max = xmax;
611 peak_cache[nvisual_peaks].min = xmin;
613 next_visual_peak_frame = min ((double) start + cnt, (next_visual_peak_frame + samples_per_visual_peak));
614 stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / samples_per_file_peak;
618 cerr << "Zero fill end of peaks (@ " << read_npeaks << " with " << zero_fill << ")" << endl;
619 memset (&peak_cache[read_npeaks], 0, sizeof (PeakData) * zero_fill);
623 _last_scale = samples_per_visual_peak;
624 _last_map_off = map_off;
625 _last_raw_map_length = raw_map_length;
628 memcpy ((void*)peaks, (void*)peak_cache.get(), npeaks * sizeof(PeakData));
631 DEBUG_TRACE (DEBUG::Peaks, "UPSAMPLE\n");
635 - less frames-per-peak (more resolution)
636 - more peaks than stored in the Peakfile
638 So, fetch data from the raw source, and generate peak
642 framecnt_t frames_read = 0;
643 framepos_t current_frame = start;
645 framecnt_t nvisual_peaks = 0;
646 framecnt_t chunksize = (framecnt_t) min (cnt, (framecnt_t) 4096);
647 boost::scoped_array<Sample> raw_staging(new Sample[chunksize]);
649 framepos_t frame_pos = start;
650 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
651 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
652 double pixels_per_frame = 1.0 / samples_per_visual_peak;
657 while (nvisual_peaks < read_npeaks) {
659 if (i == frames_read) {
661 to_read = min (chunksize, (framecnt_t)(_length - current_frame));
663 if (current_frame >= _length) {
665 /* hmm, error condition - we've reached the end of the file
666 without generating all the peak data. cook up a zero-filled
667 data buffer and then use it. this is simpler than
668 adjusting zero_fill and read_npeaks and then breaking out of
672 memset (raw_staging.get(), 0, sizeof (Sample) * chunksize);
676 to_read = min (chunksize, (_length - current_frame));
679 if ((frames_read = read_unlocked (raw_staging.get(), current_frame, to_read)) == 0) {
680 error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
681 _name, to_read, current_frame, _length, strerror (errno))
690 xmax = max (xmax, raw_staging[i]);
691 xmin = min (xmin, raw_staging[i]);
694 pixel_pos += pixels_per_frame;
696 if (pixel_pos >= next_pixel_pos) {
698 peaks[nvisual_peaks].max = xmax;
699 peaks[nvisual_peaks].min = xmin;
704 next_pixel_pos = ceil (pixel_pos + 0.5);
709 memset (&peaks[read_npeaks], 0, sizeof (PeakData) * zero_fill);
713 DEBUG_TRACE (DEBUG::Peaks, "READPEAKS DONE\n");
718 AudioSource::build_peaks_from_scratch ()
720 const framecnt_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
722 DEBUG_TRACE (DEBUG::Peaks, "Building peaks from scratch\n");
727 /* hold lock while building peaks */
729 Glib::Threads::Mutex::Lock lp (_lock);
731 if (prepare_for_peakfile_writes ()) {
735 framecnt_t current_frame = 0;
736 framecnt_t cnt = _length;
738 _peaks_built = false;
739 boost::scoped_array<Sample> buf(new Sample[bufsize]);
743 framecnt_t frames_to_read = min (bufsize, cnt);
744 framecnt_t frames_read;
746 if ((frames_read = read_unlocked (buf.get(), current_frame, frames_to_read)) != frames_to_read) {
747 error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
748 done_with_peakfile_writes (false);
752 lp.release(); // allow butler to refill buffers
754 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
755 cerr << "peak file creation interrupted: " << _name << endmsg;
757 done_with_peakfile_writes (false);
761 if (compute_and_write_peaks (buf.get(), current_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::close_peakfile ()
794 Glib::Threads::Mutex::Lock lp (_lock);
795 if (_peakfile_fd >= 0) {
796 close (_peakfile_fd);
799 if (!_peakpath.empty()) {
800 ::g_unlink (_peakpath.c_str());
802 _peaks_built = false;
807 AudioSource::prepare_for_peakfile_writes ()
809 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
813 if ((_peakfile_fd = g_open (_peakpath.c_str(), O_CREAT|O_RDWR, 0664)) < 0) {
814 error << string_compose(_("AudioSource: cannot open _peakpath (c) \"%1\" (%2)"), _peakpath, strerror (errno)) << endmsg;
821 AudioSource::done_with_peakfile_writes (bool done)
823 if (_session.deletion_in_progress() || _session.peaks_cleanup_in_progres()) {
825 close (_peakfile_fd);
831 if (peak_leftover_cnt) {
832 compute_and_write_peaks (0, 0, 0, true, false, _FPP);
836 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
838 PeaksReady (); /* EMIT SIGNAL */
841 close (_peakfile_fd);
845 /** @param first_frame Offset from the source start of the first frame to
846 * process. _lock MUST be held by caller.
849 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
850 bool force, bool intermediate_peaks_ready)
852 return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
856 AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
857 bool force, bool intermediate_peaks_ready, framecnt_t fpp)
860 uint32_t peaks_computed;
861 framepos_t current_frame;
862 framecnt_t frames_done;
863 const size_t blocksize = (128 * 1024);
864 off_t first_peak_byte;
865 boost::scoped_array<Sample> buf2;
867 if (_peakfile_fd < 0) {
868 if (prepare_for_peakfile_writes ()) {
874 if (peak_leftover_cnt) {
876 if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
878 /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
879 and we have leftovers. flush a single peak (since the leftovers
880 never represent more than that, and restart.
885 x.min = peak_leftovers[0];
886 x.max = peak_leftovers[0];
888 off_t byte = (peak_leftover_frame / fpp) * sizeof (PeakData);
890 off_t offset = lseek (_peakfile_fd, byte, SEEK_SET);
892 if (offset != byte) {
893 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
897 if (::write (_peakfile_fd, &x, sizeof (PeakData)) != sizeof (PeakData)) {
898 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
902 _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
905 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
906 PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
907 if (intermediate_peaks_ready) {
908 PeaksReady (); /* EMIT SIGNAL */
912 /* left overs are done */
914 peak_leftover_cnt = 0;
918 /* else ... had leftovers, but they immediately preceed the new data, so just
919 merge them and compute.
922 /* make a new contiguous buffer containing leftovers and the new stuff */
924 to_do = cnt + peak_leftover_cnt;
925 buf2.reset(new Sample[to_do]);
928 memcpy (buf2.get(), peak_leftovers, peak_leftover_cnt * sizeof (Sample));
931 memcpy (buf2.get()+peak_leftover_cnt, buf, cnt * sizeof (Sample));
933 /* no more leftovers */
934 peak_leftover_cnt = 0;
936 /* use the temporary buffer */
939 /* make sure that when we write into the peakfile, we startup where we left off */
941 first_frame = peak_leftover_frame;
947 boost::scoped_array<PeakData> peakbuf(new PeakData[(to_do/fpp)+1]);
949 current_frame = first_frame;
954 /* if some frames were passed in (i.e. we're not flushing leftovers)
955 and there are less than fpp to do, save them till
959 if (force && (to_do < fpp)) {
960 /* keep the left overs around for next time */
962 if (peak_leftover_size < to_do) {
963 delete [] peak_leftovers;
964 peak_leftovers = new Sample[to_do];
965 peak_leftover_size = to_do;
967 memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
968 peak_leftover_cnt = to_do;
969 peak_leftover_frame = current_frame;
976 framecnt_t this_time = min (fpp, to_do);
978 peakbuf[peaks_computed].max = buf[0];
979 peakbuf[peaks_computed].min = buf[0];
981 ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
986 frames_done += this_time;
987 current_frame += this_time;
990 first_peak_byte = (first_frame / fpp) * sizeof (PeakData);
992 if (can_truncate_peaks()) {
994 /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
995 the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
996 it does not cause single-extent allocation even for peakfiles of
997 less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
1000 off_t endpos = lseek (_peakfile_fd, 0, SEEK_END);
1001 off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
1003 if (endpos < target_length) {
1004 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1005 if (ftruncate (_peakfile_fd, target_length)) {
1006 /* error doesn't actually matter so continue on without testing */
1012 off_t offset = lseek(_peakfile_fd, first_peak_byte, SEEK_SET);
1014 if (offset != first_peak_byte) {
1015 error << string_compose(_("%1: could not seek in peak file data (%2)"), _name, strerror (errno)) << endmsg;
1019 ssize_t bytes_to_write = sizeof (PeakData) * peaks_computed;
1021 ssize_t bytes_written = ::write (_peakfile_fd, peakbuf.get(), bytes_to_write);
1023 if (bytes_written != bytes_to_write) {
1024 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
1028 _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + bytes_to_write));
1031 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1032 PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
1033 if (intermediate_peaks_ready) {
1034 PeaksReady (); /* EMIT SIGNAL */
1042 AudioSource::truncate_peakfile ()
1044 if (_peakfile_fd < 0) {
1045 error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
1050 /* truncate the peakfile down to its natural length if necessary */
1052 off_t end = lseek (_peakfile_fd, 0, SEEK_END);
1054 if (end > _peak_byte_max) {
1055 DEBUG_TRACE(DEBUG::Peaks, string_compose ("Truncating Peakfile %1\n", _peakpath));
1056 if (ftruncate (_peakfile_fd, _peak_byte_max)) {
1057 error << string_compose (_("could not truncate peakfile %1 to %2 (error: %3)"),
1058 _peakpath, _peak_byte_max, errno) << endmsg;
1064 AudioSource::available_peaks (double zoom_factor) const
1066 if (zoom_factor < _FPP) {
1067 return length(_timeline_position); // peak data will come from the audio file
1070 /* peak data comes from peakfile, but the filesize might not represent
1071 the valid data due to ftruncate optimizations, so use _peak_byte_max state.
1072 XXX - there might be some atomicity issues here, we should probably add a lock,
1073 but _peak_byte_max only monotonically increases after initialization.
1076 off_t end = _peak_byte_max;
1078 return (end/sizeof(PeakData)) * _FPP;
1082 AudioSource::mark_streaming_write_completed (const Lock& lock)
1084 Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
1087 PeaksReady (); /* EMIT SIGNAL */
1092 AudioSource::allocate_working_buffers (framecnt_t framerate)
1094 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1097 /* Note: we don't need any buffers allocated until
1098 a level 1 audiosource is created, at which
1099 time we'll call ::ensure_buffers_for_level()
1100 with the right value and do the right thing.
1103 if (!_mixdown_buffers.empty()) {
1104 ensure_buffers_for_level_locked ( _mixdown_buffers.size(), framerate);
1109 AudioSource::ensure_buffers_for_level (uint32_t level, framecnt_t frame_rate)
1111 Glib::Threads::Mutex::Lock lm (_level_buffer_lock);
1112 ensure_buffers_for_level_locked (level, frame_rate);
1116 AudioSource::ensure_buffers_for_level_locked (uint32_t level, framecnt_t frame_rate)
1118 framecnt_t nframes = (framecnt_t) floor (Config->get_audio_playback_buffer_seconds() * frame_rate);
1120 /* this may be called because either "level" or "frame_rate" have
1121 * changed. and it may be called with "level" smaller than the current
1122 * number of buffers, because a new compound region has been created at
1123 * a more shallow level than the deepest one we currently have.
1126 uint32_t limit = max ((size_t) level, _mixdown_buffers.size());
1128 _mixdown_buffers.clear ();
1129 _gain_buffers.clear ();
1131 for (uint32_t n = 0; n < limit; ++n) {
1132 _mixdown_buffers.push_back (boost::shared_array<Sample> (new Sample[nframes]));
1133 _gain_buffers.push_back (boost::shared_array<gain_t> (new gain_t[nframes]));