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