fixed compiler complaints from last commit
[ardour.git] / libs / ardour / audiosource.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
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.
8
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.
13
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.
17
18     $Id: source.cc 404 2006-03-17 17:39:21Z pauld $
19 */
20
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <poll.h>
25 #include <float.h>
26 #include <utime.h>
27 #include <cerrno>
28 #include <ctime>
29 #include <cmath>
30 #include <iomanip>
31 #include <algorithm>
32 #include <vector>
33
34 #include <pbd/xml++.h>
35 #include <pbd/pthread_utils.h>
36
37 #include <ardour/audiosource.h>
38 #include <ardour/cycle_timer.h>
39
40 #include "i18n.h"
41
42 using namespace std;
43 using namespace ARDOUR;
44 using namespace PBD;
45
46 pthread_t                    AudioSource::peak_thread;
47 bool                         AudioSource::have_peak_thread = false;
48 vector<boost::shared_ptr<AudioSource> > AudioSource::pending_peak_sources;
49 Glib::Mutex*                 AudioSource::pending_peak_sources_lock = 0;
50 int                          AudioSource::peak_request_pipe[2];
51
52 bool AudioSource::_build_missing_peakfiles = false;
53 bool AudioSource::_build_peakfiles = false;
54
55 AudioSource::AudioSource (Session& s, string name)
56         : Source (s, name)
57 {
58         if (pending_peak_sources_lock == 0) {
59                 pending_peak_sources_lock = new Glib::Mutex;
60         }
61
62         _peaks_built = false;
63         _peak_byte_max = 0;
64         next_peak_clear_should_notify = true;
65         _read_data_count = 0;
66         _write_data_count = 0;
67 }
68
69 AudioSource::AudioSource (Session& s, const XMLNode& node) 
70         : Source (s, node)
71 {
72         if (pending_peak_sources_lock == 0) {
73                 pending_peak_sources_lock = new Glib::Mutex;
74         }
75
76         _peaks_built = false;
77         _peak_byte_max = 0;
78         next_peak_clear_should_notify = true;
79         _read_data_count = 0;
80         _write_data_count = 0;
81
82         if (set_state (node)) {
83                 throw failed_constructor();
84         }
85 }
86
87 AudioSource::~AudioSource ()
88 {
89 }
90
91 XMLNode&
92 AudioSource::get_state ()
93 {
94         XMLNode& node (Source::get_state());
95
96         if (_captured_for.length()) {
97                 node.add_property ("captured-for", _captured_for);
98         }
99
100         return node;
101 }
102
103 int
104 AudioSource::set_state (const XMLNode& node)
105 {
106         const XMLProperty* prop;
107
108         Source::set_state (node);
109
110         if ((prop = node.property ("captured-for")) != 0) {
111                 _captured_for = prop->value();
112         }
113
114         return 0;
115 }
116
117 /***********************************************************************
118   PEAK FILE STUFF
119  ***********************************************************************/
120
121 void*
122 AudioSource::peak_thread_work (void* arg)
123 {
124         PBD::ThreadCreated (pthread_self(), X_("Peak"));
125         struct pollfd pfd[1];
126
127         if (pending_peak_sources_lock == 0) {
128                 pending_peak_sources_lock = new Glib::Mutex;
129         }
130
131         Glib::Mutex::Lock lm (*pending_peak_sources_lock);
132
133         while (true) {
134
135                 pfd[0].fd = peak_request_pipe[0];
136                 pfd[0].events = POLLIN|POLLERR|POLLHUP;
137
138                 pending_peak_sources_lock->unlock ();
139
140                 if (poll (pfd, 1, -1) < 0) {
141
142                         if (errno == EINTR) {
143                                 pending_peak_sources_lock->lock ();
144                                 continue;
145                         }
146                         
147                         error << string_compose (_("poll on peak request pipe failed (%1)"),
148                                           strerror (errno))
149                               << endmsg;
150                         break;
151                 }
152
153                 if (pfd[0].revents & ~POLLIN) {
154                         error << _("Error on peak thread request pipe") << endmsg;
155                         break;
156                 }
157
158                 if (pfd[0].revents & POLLIN) {
159
160                         char req;
161                         
162                         /* empty the pipe of all current requests */
163
164                         while (1) {
165                                 size_t nread = ::read (peak_request_pipe[0], &req, sizeof (req));
166
167                                 if (nread == 1) {
168                                         switch ((PeakRequest::Type) req) {
169                                         
170                                         case PeakRequest::Build:
171                                                 break;
172                                                 
173                                         case PeakRequest::Quit:
174                                                 pthread_exit_pbd (0);
175                                                 /*NOTREACHED*/
176                                                 break;
177                                                 
178                                         default:
179                                                 break;
180                                         }
181
182                                 } else if (nread == 0) {
183                                         break;
184                                 } else if (errno == EAGAIN) {
185                                         break;
186                                 } else {
187                                         fatal << _("Error reading from peak request pipe") << endmsg;
188                                         /*NOTREACHED*/
189                                 }
190                         }
191                 }
192
193                 pending_peak_sources_lock->lock ();
194
195                 while (!pending_peak_sources.empty()) {
196
197                         boost::shared_ptr<AudioSource> s = pending_peak_sources.front();
198                         pending_peak_sources.erase (pending_peak_sources.begin());
199                         
200                         pending_peak_sources_lock->unlock ();
201                         s->build_peaks();
202                         pending_peak_sources_lock->lock ();
203                 }
204         }
205
206         pthread_exit_pbd (0);
207         /*NOTREACHED*/
208         return 0;
209 }
210
211 int
212 AudioSource::start_peak_thread ()
213 {
214         if (!_build_peakfiles) {
215                 return 0;
216         }
217
218         if (pipe (peak_request_pipe)) {
219                 error << string_compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg;
220                 return -1;
221         }
222
223         if (fcntl (peak_request_pipe[0], F_SETFL, O_NONBLOCK)) {
224                 error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
225                 return -1;
226         }
227
228         if (fcntl (peak_request_pipe[1], F_SETFL, O_NONBLOCK)) {
229                 error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
230                 return -1;
231         }
232
233         if (pthread_create_and_store ("peak file builder", &peak_thread, 0, peak_thread_work, 0)) {
234                 error << _("AudioSource: could not create peak thread") << endmsg;
235                 return -1;
236         }
237
238         have_peak_thread = true;
239         return 0;
240 }
241
242 void
243 AudioSource::stop_peak_thread ()
244 {
245         if (!have_peak_thread) {
246                 return;
247         }
248
249         void* status;
250
251         char c = (char) PeakRequest::Quit;
252         ::write (peak_request_pipe[1], &c, 1);
253         pthread_join (peak_thread, &status);
254 }
255
256 void 
257 AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source, bool notify)
258 {
259         if (have_peak_thread) {
260                 
261                 Glib::Mutex::Lock lm (*pending_peak_sources_lock);
262                 
263                 source->next_peak_clear_should_notify = notify;
264                 
265                 if (find (pending_peak_sources.begin(),
266                           pending_peak_sources.end(),
267                           source) == pending_peak_sources.end()) {
268                         pending_peak_sources.push_back (source);
269                 }
270
271                 char c = (char) PeakRequest::Build;
272                 ::write (peak_request_pipe[1], &c, 1);
273         }
274 }
275
276 void AudioSource::clear_queue_for_peaks ()
277 {
278         /* this is done to cancel a group of running peak builds */
279         if (have_peak_thread) {
280                 Glib::Mutex::Lock lm (*pending_peak_sources_lock);
281                 pending_peak_sources.clear ();
282         }
283 }
284
285
286 bool
287 AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
288 {
289         bool ret;
290         Glib::Mutex::Lock lm (_lock);
291
292         /* check to see if the peak data is ready. if not
293            connect the slot while still holding the lock.
294         */
295
296         if (!(ret = _peaks_built)) {
297                 conn = PeaksReady.connect (the_slot);
298         }
299
300         return ret;
301 }
302
303 void
304 AudioSource::touch_peakfile ()
305 {
306         struct stat statbuf;
307
308         if (stat (peakpath.c_str(), &statbuf) != 0 || statbuf.st_size == 0) {
309                 return;
310         }
311         
312         struct utimbuf tbuf;
313         
314         tbuf.actime = statbuf.st_atime;
315         tbuf.modtime = time ((time_t) 0);
316         
317         utime (peakpath.c_str(), &tbuf);
318 }
319
320 int
321 AudioSource::rename_peakfile (string newpath)
322 {
323         /* caller must hold _lock */
324
325         string oldpath = peakpath;
326
327         if (access (oldpath.c_str(), F_OK) == 0) {
328                 if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
329                         error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg;
330                         return -1;
331                 }
332         }
333
334         peakpath = newpath;
335
336         return 0;
337 }
338
339 int
340 AudioSource::initialize_peakfile (bool newfile, string audio_path)
341 {
342         struct stat statbuf;
343
344         peakpath = peak_path (audio_path);
345
346         /* Nasty band-aid for older sessions that were created before we
347            used libsndfile for all audio files.
348         */
349         
350         if (!newfile && access (peakpath.c_str(), R_OK) != 0) {
351                 string str = old_peak_path (audio_path);
352                 if (access (str.c_str(), R_OK) == 0) {
353                         peakpath = str;
354                 }
355         }
356
357         if (newfile) {
358
359                 if (!_build_peakfiles) {
360                         return 0;
361                 }
362
363                 _peaks_built = false;
364
365         } else {
366
367                 if (stat (peakpath.c_str(), &statbuf)) {
368                         if (errno != ENOENT) {
369                                 /* it exists in the peaks dir, but there is some kind of error */
370                                 
371                                 error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg;
372                                 return -1;
373                         }
374                         
375                         _peaks_built = false;
376
377                 } else {
378                         
379                         /* we found it in the peaks dir, so check it out */
380
381                         if (statbuf.st_size == 0) {
382                                 _peaks_built = false;
383                         } else {
384                                 // Check if the audio file has changed since the peakfile was built.
385                                 struct stat stat_file;
386                                 int err = stat (audio_path.c_str(), &stat_file);
387                                 
388                                 if (!err && stat_file.st_mtime > statbuf.st_mtime){
389                                         _peaks_built = false;
390                                         _peak_byte_max = 0;
391                                 } else {
392                                         _peaks_built = true;
393                                         _peak_byte_max = statbuf.st_size;
394                                 }
395                         }
396                 }
397         }
398
399         if (!newfile && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) {
400                 build_peaks_from_scratch ();
401         } 
402         
403         return 0;
404 }
405
406 nframes_t
407 AudioSource::read (Sample *dst, nframes_t start, nframes_t cnt) const
408 {
409         Glib::Mutex::Lock lm (_lock);
410         return read_unlocked (dst, start, cnt);
411 }
412
413 nframes_t
414 AudioSource::write (Sample *dst, nframes_t cnt)
415 {
416         Glib::Mutex::Lock lm (_lock);
417         return write_unlocked (dst, cnt);
418 }
419
420 int 
421 AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_visual_peak) const
422 {
423         Glib::Mutex::Lock lm (_lock);
424         double scale;
425         double expected_peaks;
426         PeakData::PeakDatum xmax;
427         PeakData::PeakDatum xmin;
428         int32_t to_read;
429         uint32_t nread;
430         nframes_t zero_fill = 0;
431         int ret = -1;
432         PeakData* staging = 0;
433         Sample* raw_staging = 0;
434         int peakfile = -1;
435
436         expected_peaks = (cnt / (double) frames_per_peak);
437         scale = npeaks/expected_peaks;
438
439 #undef DEBUG_READ_PEAKS
440 #ifdef DEBUG_READ_PEAKS
441         cerr << "======>RP: npeaks = " << npeaks 
442              << " start = " << start 
443              << " cnt = " << cnt 
444              << " len = " << _length 
445              << "   samples_per_visual_peak =" << samples_per_visual_peak 
446              << " expected was " << expected_peaks << " ... scale = " << scale
447              << " PD ptr = " << peaks
448              <<endl;
449         
450 #endif
451
452         /* fix for near-end-of-file conditions */
453
454         if (cnt > _length - start) {
455                 // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << endl;
456                 cnt = _length - start;
457                 nframes_t old = npeaks;
458                 npeaks = min ((nframes_t) floor (cnt / samples_per_visual_peak), npeaks);
459                 zero_fill = old - npeaks;
460         }
461
462         // cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl;
463         
464         if (npeaks == cnt) {
465
466 #ifdef DEBUG_READ_PEAKS
467                 cerr << "RAW DATA\n";
468 #endif          
469                 /* no scaling at all, just get the sample data and duplicate it for
470                    both max and min peak values.
471                 */
472
473                 Sample* raw_staging = new Sample[cnt];
474                 
475                 if (read_unlocked (raw_staging, start, cnt) != cnt) {
476                         error << _("cannot read sample data for unscaled peak computation") << endmsg;
477                         return -1;
478                 }
479
480                 for (nframes_t i = 0; i < npeaks; ++i) {
481                         peaks[i].max = raw_staging[i];
482                         peaks[i].min = raw_staging[i];
483                 }
484
485                 delete [] raw_staging;
486                 return 0;
487         }
488
489         if (scale == 1.0) {
490
491                 off_t first_peak_byte = (start / frames_per_peak) * sizeof (PeakData);
492
493                 /* open, read, close */
494
495                 if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
496                         error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
497                         return -1;
498                 }
499
500 #ifdef DEBUG_READ_PEAKS
501                 cerr << "DIRECT PEAKS\n";
502 #endif
503                 
504                 nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
505                 close (peakfile);
506
507                 if (nread != sizeof (PeakData) * npeaks) {
508                         cerr << "AudioSource["
509                              << _name
510                              << "]: cannot read peaks from peakfile! (read only " 
511                              << nread
512                              << " not " 
513                              << npeaks
514                               << "at sample " 
515                              << start
516                              << " = byte "
517                              << first_peak_byte
518                              << ')'
519                              << endl;
520                         return -1;
521                 }
522
523                 if (zero_fill) {
524                         memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
525                 }
526
527                 return 0;
528         }
529
530
531         nframes_t tnp;
532
533         if (scale < 1.0) {
534
535 #ifdef DEBUG_READ_PEAKS
536                 cerr << "DOWNSAMPLE\n";
537 #endif          
538                 /* the caller wants:
539
540                     - more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
541                     - less peaks than the peakfile holds for the same range
542
543                     So, read a block into a staging area, and then downsample from there.
544
545                     to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks  
546                 */
547
548                 const uint32_t chunksize = (uint32_t) min (expected_peaks, 65536.0);
549                 
550                 staging = new PeakData[chunksize];
551                 
552                 /* compute the rounded up frame position  */
553         
554                 nframes_t current_frame = start;
555                 nframes_t current_stored_peak = (nframes_t) ceil (current_frame / (double) frames_per_peak);
556                 uint32_t       next_visual_peak  = (uint32_t) ceil (current_frame / samples_per_visual_peak);
557                 double         next_visual_peak_frame = next_visual_peak * samples_per_visual_peak;
558                 uint32_t       stored_peak_before_next_visual_peak = (nframes_t) next_visual_peak_frame / frames_per_peak;
559                 uint32_t       nvisual_peaks = 0;
560                 uint32_t       stored_peaks_read = 0;
561                 uint32_t       i = 0;
562
563                 /* handle the case where the initial visual peak is on a pixel boundary */
564
565                 current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak);
566
567                 /* open ... close during out: handling */
568
569                 if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
570                         error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
571                         return 0;
572                 }
573
574                 while (nvisual_peaks < npeaks) {
575
576                         if (i == stored_peaks_read) {
577
578                                 uint32_t       start_byte = current_stored_peak * sizeof(PeakData);
579                                 tnp = min ((_length/frames_per_peak - current_stored_peak), (nframes_t) expected_peaks);
580                                 to_read = min (chunksize, tnp);
581                                 
582 #ifdef DEBUG_READ_PEAKS
583                                 cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
584 #endif
585                                 
586                                 if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte))
587                                     != sizeof (PeakData) * to_read) {
588
589                                         off_t fend = lseek (peakfile, 0, SEEK_END);
590                                         
591                                         cerr << "AudioSource["
592                                              << _name
593                                              << "]: cannot read peak data from peakfile ("
594                                              << (nread / sizeof(PeakData))
595                                              << " peaks instead of "
596                                              << to_read
597                                              << ") ("
598                                              << strerror (errno)
599                                              << ')'
600                                              << " at start_byte = " << start_byte 
601                                              << " _length = " << _length << " versus len = " << fend
602                                              << " expected maxpeaks = " << (_length - current_frame)/frames_per_peak
603                                              << " npeaks was " << npeaks
604                                              << endl;
605                                         goto out;
606                                 }
607                                 
608                                 i = 0;
609                                 stored_peaks_read = nread / sizeof(PeakData);
610                         }
611                         
612                         xmax = -1.0;
613                         xmin = 1.0;
614
615                         while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) {
616
617                                 xmax = max (xmax, staging[i].max);
618                                 xmin = min (xmin, staging[i].min);
619                                 ++i;
620                                 ++current_stored_peak;
621                                 --expected_peaks;
622                         }
623
624                         peaks[nvisual_peaks].max = xmax;
625                         peaks[nvisual_peaks].min = xmin;
626                         ++nvisual_peaks;
627                         ++next_visual_peak;
628
629                         //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) );
630                         next_visual_peak_frame =  min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) );
631                         stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / frames_per_peak; 
632                 }
633
634                 if (zero_fill) {
635                         memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
636                 }
637                 
638                 ret = 0;
639
640         } else {
641                 
642 #ifdef DEBUG_READ_PEAKS
643                 cerr << "UPSAMPLE\n";
644 #endif
645                 /* the caller wants 
646
647                      - less frames-per-peak (more resolution)
648                      - more peaks than stored in the Peakfile
649
650                    So, fetch data from the raw source, and generate peak
651                    data on the fly.
652                 */
653
654                 nframes_t frames_read = 0;
655                 nframes_t current_frame = start;
656                 nframes_t i = 0;
657                 nframes_t nvisual_peaks = 0;
658                 nframes_t chunksize = (nframes_t) min (cnt, (nframes_t) 4096);
659                 raw_staging = new Sample[chunksize];
660                 
661                 nframes_t frame_pos = start;
662                 double pixel_pos = floor (frame_pos / samples_per_visual_peak);
663                 double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak);
664                 double pixels_per_frame = 1.0 / samples_per_visual_peak;
665
666                 xmin = 1.0;
667                 xmax = -1.0;
668
669                 while (nvisual_peaks < npeaks) {
670
671                         if (i == frames_read) {
672                                 
673                                 to_read = min (chunksize, (_length - current_frame));
674
675                                 if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
676                                         error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3")
677                                                          , _name, to_read, current_frame) 
678                                               << endmsg;
679                                         goto out;
680                                 }
681
682                                 i = 0;
683                         }
684                         
685                         xmax = max (xmax, raw_staging[i]);
686                         xmin = min (xmin, raw_staging[i]);
687                         ++i;
688                         ++current_frame;
689                         pixel_pos += pixels_per_frame;
690
691                         if (pixel_pos >= next_pixel_pos) {
692
693                                 peaks[nvisual_peaks].max = xmax;
694                                 peaks[nvisual_peaks].min = xmin;
695                                 ++nvisual_peaks;
696                                 xmin = 1.0;
697                                 xmax = -1.0;
698
699                                 next_pixel_pos = ceil (pixel_pos + 0.5);
700                         }
701                 }
702                 
703                 if (zero_fill) {
704                         memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill);
705                 }
706
707                 ret = 0;
708         }
709
710   out:
711         if (peakfile >= 0) {
712                 close (peakfile);
713         }
714
715         if (staging) {
716                 delete [] staging;
717         } 
718
719         if (raw_staging) {
720                 delete [] raw_staging;
721         }
722
723 #ifdef DEBUG_READ_PEAKS
724         cerr << "RP DONE\n";
725 #endif
726
727         return ret;
728 }
729
730 #undef DEBUG_PEAK_BUILD
731
732 int
733 AudioSource::build_peaks ()
734 {
735         vector<PeakBuildRecord*> built;
736         int status = -1;
737         bool pr_signal = false;
738         list<PeakBuildRecord*> copy;
739
740         {
741                 Glib::Mutex::Lock lm (_lock);
742                 copy = pending_peak_builds;
743                 pending_peak_builds.clear ();
744         }
745                 
746 #ifdef DEBUG_PEAK_BUILD
747         cerr << "build peaks with " << copy.size() << " requests pending\n";
748 #endif          
749
750         for (list<PeakBuildRecord *>::iterator i = copy.begin(); i != copy.end(); ++i) {
751                 
752                 if ((status = do_build_peak ((*i)->frame, (*i)->cnt)) != 0) { 
753                         unlink (peakpath.c_str());
754                         break;
755                 }
756                 built.push_back (new PeakBuildRecord (*(*i)));
757                 delete *i;
758         }
759
760         { 
761                 Glib::Mutex::Lock lm (_lock);
762
763                 if (status == 0) {
764                         _peaks_built = true;
765                         
766                         if (next_peak_clear_should_notify) {
767                                 next_peak_clear_should_notify = false;
768                                 pr_signal = true;
769                         }
770                 }
771         }
772
773         if (status == 0) {
774                 for (vector<PeakBuildRecord *>::iterator i = built.begin(); i != built.end(); ++i) {
775                         PeakRangeReady ((*i)->frame, (*i)->cnt); /* EMIT SIGNAL */
776                         delete *i;
777                 }
778
779                 if (pr_signal) {
780                         truncate_peakfile();
781                         PeaksReady (); /* EMIT SIGNAL */
782                 }
783         }
784
785         return status;
786 }
787
788 int
789 AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt)
790 {
791         nframes_t current_frame;
792         Sample buf[frames_per_peak];
793         Sample xmin, xmax;
794         uint32_t  peaki;
795         PeakData* peakbuf;
796         nframes_t frames_read;
797         nframes_t frames_to_read;
798         off_t first_peak_byte;
799         int peakfile = -1;
800         int ret = -1;
801         off_t target_length;
802         off_t endpos;
803
804 #ifdef DEBUG_PEAK_BUILD
805         cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl;
806 #endif
807
808         first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
809
810 #ifdef DEBUG_PEAK_BUILD
811         cerr << "seeking to " << first_peak_byte << " before writing new peak data\n";
812 #endif
813
814         current_frame = first_frame;
815         peakbuf = new PeakData[(cnt/frames_per_peak)+1];
816         peaki = 0;
817
818         if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
819                 error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
820                 return -1;
821         }
822         
823         while (cnt) {
824
825                 frames_to_read = min (frames_per_peak, cnt);
826
827                 /* lock for every read */
828
829                 if ((frames_read = read (buf, current_frame, frames_to_read)) != frames_to_read) {
830                         error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
831                         goto out;
832                 }
833
834                 xmin = buf[0];
835                 xmax = buf[0];
836
837                 for (nframes_t n = 1; n < frames_read; ++n) {
838                         xmax = max (xmax, buf[n]);
839                         xmin = min (xmin, buf[n]);
840
841 //                      if (current_frame < frames_read) {
842 //                              cerr << "sample = " << buf[n] << " max = " << xmax << " min = " << xmin << " max of 2 = " << max (xmax, buf[n]) << endl;
843 //                      }
844                 }
845
846                 peakbuf[peaki].max = xmax;
847                 peakbuf[peaki].min = xmin;
848                 peaki++;
849
850                 current_frame += frames_read;
851                 cnt -= frames_read;
852         }
853
854 #define BLOCKSIZE (128 * 1024)
855
856         /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
857            the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
858            it does not cause single-extent allocation even for peakfiles of 
859            less than BLOCKSIZE bytes.  only call ftruncate if we'll make the file larger.
860         */
861         endpos = lseek (peakfile, 0, SEEK_END);
862                 
863         target_length = BLOCKSIZE * ((first_peak_byte + BLOCKSIZE + 1) / BLOCKSIZE);
864
865         if (endpos < target_length) {
866                 // XXX - we really shouldn't be doing this for destructive source peaks
867                 ftruncate (peakfile, target_length);
868                 //cerr << "do build TRUNC: " << peakpath << "  " << target_length << endl;
869
870                 /* error doesn't actually matter though, so continue on without testing */
871         }
872
873         if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) {
874                 error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
875                 goto out;
876         }
877
878         _peak_byte_max = max(_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaki));
879
880         ret = 0;
881
882   out:
883         delete [] peakbuf;
884         if (peakfile >= 0) {
885                 close (peakfile);
886         }
887         return ret;
888 }
889
890 void
891 AudioSource::build_peaks_from_scratch ()
892 {
893         Glib::Mutex::Lock lp (_lock);
894
895         next_peak_clear_should_notify = true;
896         pending_peak_builds.push_back (new PeakBuildRecord (0, _length));
897         queue_for_peaks (shared_from_this(), true);
898 }
899
900 void
901 AudioSource::truncate_peakfile ()
902 {
903         int peakfile = -1;
904
905         /* truncate the peakfile down to its natural length if necessary */
906
907         if ((peakfile = ::open (peakpath.c_str(), O_RDWR)) >= 0) {
908                 off_t end = lseek (peakfile, 0, SEEK_END);
909                 
910                 if (end > _peak_byte_max) {
911                         ftruncate(peakfile, _peak_byte_max);
912                         //cerr << "truncated " << peakpath << " to " << _peak_byte_max << " bytes" << endl;
913                 }
914                 else {
915                         //cerr << "NOT truncated " << peakpath << " to " << _peak_byte_max << " end " << end << endl;
916                 }
917                 close (peakfile);
918         }
919 }
920
921 bool
922 AudioSource::file_changed (string path)
923 {
924         struct stat stat_file;
925         struct stat stat_peak;
926
927         int e1 = stat (path.c_str(), &stat_file);
928         int e2 = stat (peak_path(path).c_str(), &stat_peak);
929         
930         if (!e1 && !e2 && stat_file.st_mtime > stat_peak.st_mtime){
931                 return true;
932         } else {
933                 return false;
934         }
935 }
936
937 nframes_t
938 AudioSource::available_peaks (double zoom_factor) const
939 {
940         off_t end;
941
942         if (zoom_factor < frames_per_peak) {
943                 return length(); // peak data will come from the audio file
944         } 
945         
946         /* peak data comes from peakfile, but the filesize might not represent
947            the valid data due to ftruncate optimizations, so use _peak_byte_max state.
948            XXX - there might be some atomicity issues here, we should probably add a lock,
949            but _peak_byte_max only monotonically increases after initialization.
950         */
951
952         end = _peak_byte_max;
953
954         return (end/sizeof(PeakData)) * frames_per_peak;
955 }
956
957 void
958 AudioSource::update_length (nframes_t pos, nframes_t cnt)
959 {
960         if (pos + cnt > _length) {
961                 _length = pos+cnt;
962         }
963 }
964