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