merge with master.
[ardour.git] / libs / ardour / sndfilesource.cc
1 /*
2     Copyright (C) 2006 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 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <cstring>
25 #include <cerrno>
26 #include <climits>
27 #include <cstdarg>
28
29 #include <sys/stat.h>
30
31 #ifdef PLATFORM_WINDOWS
32 #include <glibmm/convert.h>
33 #endif
34 #include <glibmm/fileutils.h>
35 #include <glibmm/miscutils.h>
36
37 #include "ardour/sndfilesource.h"
38 #include "ardour/sndfile_helpers.h"
39 #include "ardour/utils.h"
40 #include "ardour/session.h"
41
42 #include "i18n.h"
43
44 using namespace std;
45 using namespace ARDOUR;
46 using namespace PBD;
47 using std::string;
48
49 gain_t* SndFileSource::out_coefficient = 0;
50 gain_t* SndFileSource::in_coefficient = 0;
51 framecnt_t SndFileSource::xfade_frames = 64;
52 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
53                 Source::Writable |
54                 Source::Removable |
55                 Source::RemovableIfEmpty |
56                 Source::CanRename );
57
58 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
59         : Source(s, node)
60         , AudioFileSource (s, node)
61         , _descriptor (0)
62         , _broadcast_info (0)
63         , _capture_start (false)
64         , _capture_end (false)
65         , file_pos (0)
66         , xfade_buf (0)
67 {
68         init_sndfile ();
69
70         assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
71         existence_check ();
72
73         if (open()) {
74                 throw failed_constructor ();
75         }
76 }
77
78 /** Constructor for existing external-to-session files.
79     Files created this way are never writable or removable 
80 */
81 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
82         : Source(s, DataType::AUDIO, path, flags)
83           /* note that the origin of an external file is itself */
84         , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
85         , _descriptor (0)
86         , _broadcast_info (0)
87         , _capture_start (false)
88         , _capture_end (false)
89         , file_pos (0)
90         , xfade_buf (0)
91 {
92         _channel = chn;
93
94         init_sndfile ();
95
96         assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
97         existence_check ();
98
99         if (open()) {
100                 throw failed_constructor ();
101         }
102 }
103
104 /** This constructor is used to construct new internal-to-session files, 
105     not open existing ones. 
106 */
107 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
108                               SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
109         : Source(s, DataType::AUDIO, path, flags)
110         , AudioFileSource (s, path, origin, flags, sfmt, hf)
111         , _descriptor (0)
112         , _broadcast_info (0)
113         , _capture_start (false)
114         , _capture_end (false)
115         , file_pos (0)
116         , xfade_buf (0)
117 {
118         int fmt = 0;
119
120         init_sndfile ();
121
122         assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
123         existence_check ();
124
125         _file_is_new = true;
126
127         switch (hf) {
128         case CAF:
129                 fmt = SF_FORMAT_CAF;
130                 _flags = Flag (_flags & ~Broadcast);
131                 break;
132
133         case AIFF:
134                 fmt = SF_FORMAT_AIFF;
135                 _flags = Flag (_flags & ~Broadcast);
136                 break;
137
138         case BWF:
139                 fmt = SF_FORMAT_WAV;
140                 _flags = Flag (_flags | Broadcast);
141                 break;
142
143         case WAVE:
144                 fmt = SF_FORMAT_WAV;
145                 _flags = Flag (_flags & ~Broadcast);
146                 break;
147
148         case WAVE64:
149                 fmt = SF_FORMAT_W64;
150                 _flags = Flag (_flags & ~Broadcast);
151                 break;
152
153         default:
154                 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
155                 /*NOTREACHED*/
156                 break;
157
158         }
159
160         switch (sfmt) {
161         case FormatFloat:
162                 fmt |= SF_FORMAT_FLOAT;
163                 break;
164
165         case FormatInt24:
166                 fmt |= SF_FORMAT_PCM_24;
167                 break;
168
169         case FormatInt16:
170                 fmt |= SF_FORMAT_PCM_16;
171                 break;
172         }
173
174         _info.channels = 1;
175         _info.samplerate = rate;
176         _info.format = fmt;
177
178         if (_flags & Destructive) {
179                 if (open()) {
180                         throw failed_constructor();
181                 }
182         } else {
183                 /* normal mode: do not open the file here - do that in write_unlocked() as needed
184                  */
185         }
186 }
187
188 /** Constructor to be called for recovering files being used for
189  * capture. They are in-session, they already exist, they should not
190  * be writable. They are an odd hybrid (from a constructor point of
191  * view) of the previous two constructors.
192  */
193 SndFileSource::SndFileSource (Session& s, const string& path, int chn)
194         : Source (s, DataType::AUDIO, path, Flag (0))
195           /* the final boolean argument is not used, its value is irrelevant. see audiofilesource.h for explanation */
196         , AudioFileSource (s, path, Flag (0))
197         , _descriptor (0)
198         , _broadcast_info (0)
199         , _capture_start (false)
200         , _capture_end (false)
201         , file_pos (0)
202         , xfade_buf (0)
203 {
204         _channel = chn;
205
206         init_sndfile ();
207
208         assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
209         existence_check ();
210
211         if (open()) {
212                 throw failed_constructor ();
213         }
214 }
215
216 void
217 SndFileSource::init_sndfile ()
218 {
219         /* although libsndfile says we don't need to set this,
220            valgrind and source code shows us that we do.
221         */
222
223         memset (&_info, 0, sizeof(_info));
224
225         if (destructive()) {
226                 xfade_buf = new Sample[xfade_frames];
227                 _timeline_position = header_position_offset;
228         }
229
230         AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
231 }
232
233 int
234 SndFileSource::open ()
235 {
236         string path_to_open;
237
238 #ifdef PLATFORM_WINDOWS
239         path_to_open = Glib::locale_from_utf8(_path);
240 #else
241         path_to_open = _path;
242 #endif
243
244         _descriptor = new SndFileDescriptor (path_to_open.c_str(), writable(), &_info);
245         _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
246         SNDFILE* sf = _descriptor->allocate ();
247
248         if (sf == 0) {
249                 char errbuf[1024];
250                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
251 #ifndef HAVE_COREAUDIO
252                 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
253                    so we don't want to see this message.
254                 */
255
256                 cerr << "failed to open " << path_to_open << " with name " << _name << endl;
257
258                 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
259                                         path_to_open, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
260 #endif
261                 return -1;
262         }
263
264         if (_channel >= _info.channels) {
265 #ifndef HAVE_COREAUDIO
266                 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
267 #endif
268                 delete _descriptor;
269                 _descriptor = 0;
270                 return -1;
271         }
272
273         _length = _info.frames;
274
275         if (!_broadcast_info) {
276                 _broadcast_info = new BroadcastInfo;
277         }
278
279         bool bwf_info_exists = _broadcast_info->load_from_file (sf);
280
281         if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
282                 /* newly created files will not have a BWF header at this point in time.
283                  * Import will have called Source::set_timeline_position() if one exists
284                  * in the original. */
285                 header_position_offset = _timeline_position;
286         }
287
288         /* Set our timeline position to either the time reference from a BWF header or the current
289            start of the session.
290         */
291         set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
292
293         if (_length != 0 && !bwf_info_exists) {
294                 delete _broadcast_info;
295                 _broadcast_info = 0;
296                 _flags = Flag (_flags & ~Broadcast);
297         } 
298
299         /* Set the broadcast flag if the BWF info is already there. We need
300          * this when recovering or using existing files.
301          */
302         
303         if (bwf_info_exists) {
304                 _flags = Flag (_flags | Broadcast);
305         }
306
307         if (writable()) {
308                 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
309
310                 if (_flags & Broadcast) {
311
312                         if (!_broadcast_info) {
313                                 _broadcast_info = new BroadcastInfo;
314                         }
315
316                         _broadcast_info->set_from_session (_session, header_position_offset);
317                         _broadcast_info->set_description (string_compose ("BWF %1", _name));
318
319                         if (!_broadcast_info->write_to_file (sf)) {
320                                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
321                                                          path_to_open, _broadcast_info->get_error())
322                                       << endmsg;
323                                 _flags = Flag (_flags & ~Broadcast);
324                                 delete _broadcast_info;
325                                 _broadcast_info = 0;
326                         }
327                 }
328         }
329
330         _descriptor->release ();
331         _open = true;
332         return 0;
333 }
334
335 SndFileSource::~SndFileSource ()
336 {
337         delete _descriptor;
338         delete _broadcast_info;
339         delete [] xfade_buf;
340 }
341
342 float
343 SndFileSource::sample_rate () const
344 {
345         return _info.samplerate;
346 }
347
348 framecnt_t
349 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
350 {
351         assert (cnt >= 0);
352         
353         int32_t nread;
354         float *ptr;
355         uint32_t real_cnt;
356         framepos_t file_cnt;
357
358         if (writable() && !_open) {
359                 /* file has not been opened yet - nothing written to it */
360                 memset (dst, 0, sizeof (Sample) * cnt);
361                 return cnt;
362         }
363
364         SNDFILE* sf = _descriptor->allocate ();
365
366         if (sf == 0) {
367                 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
368                 return 0;
369         }
370
371         if (start > _length) {
372
373                 /* read starts beyond end of data, just memset to zero */
374
375                 file_cnt = 0;
376
377         } else if (start + cnt > _length) {
378
379                 /* read ends beyond end of data, read some, memset the rest */
380
381                 file_cnt = _length - start;
382
383         } else {
384
385                 /* read is entirely within data */
386
387                 file_cnt = cnt;
388         }
389
390         assert (file_cnt >= 0);
391
392         if (file_cnt != cnt) {
393                 framepos_t delta = cnt - file_cnt;
394                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
395         }
396
397         if (file_cnt) {
398
399                 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
400                         char errbuf[256];
401                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
402                         error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
403                         _descriptor->release ();
404                         return 0;
405                 }
406
407                 if (_info.channels == 1) {
408                         framecnt_t ret = sf_read_float (sf, dst, file_cnt);
409                         if (ret != file_cnt) {
410                                 char errbuf[256];
411                                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
412                                 error << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5, ret was %6)"), start, file_cnt, _name.val().substr (1), errbuf, _length, ret) << endl;
413                         }
414                         _descriptor->release ();
415                         return ret;
416                 }
417         }
418
419         real_cnt = cnt * _info.channels;
420
421         Sample* interleave_buf = get_interleave_buffer (real_cnt);
422
423         nread = sf_read_float (sf, interleave_buf, real_cnt);
424         ptr = interleave_buf + _channel;
425         nread /= _info.channels;
426
427         /* stride through the interleaved data */
428
429         for (int32_t n = 0; n < nread; ++n) {
430                 dst[n] = *ptr;
431                 ptr += _info.channels;
432         }
433
434         _descriptor->release ();
435         return nread;
436 }
437
438 framecnt_t
439 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
440 {
441         if (!_open && open()) {
442                 return 0; // failure
443         }
444
445         if (destructive()) {
446                 return destructive_write_unlocked (data, cnt);
447         } else {
448                 return nondestructive_write_unlocked (data, cnt);
449         }
450 }
451
452 framecnt_t
453 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
454 {
455         if (!writable()) {
456                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
457                 return 0;
458         }
459
460         if (_info.channels != 1) {
461                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
462                 /*NOTREACHED*/
463                 return 0;
464         }
465
466         int32_t frame_pos = _length;
467
468         if (write_float (data, frame_pos, cnt) != cnt) {
469                 return 0;
470         }
471
472         update_length (_length + cnt);
473
474         if (_build_peakfiles) {
475                 compute_and_write_peaks (data, frame_pos, cnt, false, true);
476         }
477
478         return cnt;
479 }
480
481 framecnt_t
482 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
483 {
484         if (!writable()) {
485                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
486                 return 0;
487         }
488
489         if (_capture_start && _capture_end) {
490
491                 /* start and end of capture both occur within the data we are writing,
492                    so do both crossfades.
493                 */
494
495                 _capture_start = false;
496                 _capture_end = false;
497
498                 /* move to the correct location place */
499                 file_pos = capture_start_frame - _timeline_position;
500
501                 // split cnt in half
502                 framecnt_t subcnt = cnt / 2;
503                 framecnt_t ofilepos = file_pos;
504
505                 // fade in
506                 if (crossfade (data, subcnt, 1) != subcnt) {
507                         return 0;
508                 }
509
510                 file_pos += subcnt;
511                 Sample * tmpdata = data + subcnt;
512
513                 // fade out
514                 subcnt = cnt - subcnt;
515                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
516                         return 0;
517                 }
518
519                 file_pos = ofilepos; // adjusted below
520
521         } else if (_capture_start) {
522
523                 /* start of capture both occur within the data we are writing,
524                    so do the fade in
525                 */
526
527                 _capture_start = false;
528                 _capture_end = false;
529
530                 /* move to the correct location place */
531                 file_pos = capture_start_frame - _timeline_position;
532
533                 if (crossfade (data, cnt, 1) != cnt) {
534                         return 0;
535                 }
536
537         } else if (_capture_end) {
538
539                 /* end of capture both occur within the data we are writing,
540                    so do the fade out
541                 */
542
543                 _capture_start = false;
544                 _capture_end = false;
545
546                 if (crossfade (data, cnt, 0) != cnt) {
547                         return 0;
548                 }
549
550         } else {
551
552                 /* in the middle of recording */
553
554                 if (write_float (data, file_pos, cnt) != cnt) {
555                         return 0;
556                 }
557         }
558
559         update_length (file_pos + cnt);
560
561         if (_build_peakfiles) {
562                 compute_and_write_peaks (data, file_pos, cnt, false, true);
563         }
564
565         file_pos += cnt;
566
567         return cnt;
568 }
569
570 int
571 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
572 {
573         set_timeline_position (when);
574
575         if (_flags & Broadcast) {
576                 if (setup_broadcast_info (when, now, tnow)) {
577                         return -1;
578                 }
579         }
580
581         return flush_header ();
582 }
583
584 int
585 SndFileSource::flush_header ()
586 {
587         if (!writable()) {
588                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
589                 return -1;
590         }
591
592         if (!_open) {
593                 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
594                 return -1;
595         }
596
597         SNDFILE* sf = _descriptor->allocate ();
598         if (sf == 0) {
599                 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
600                 return -1;
601         }
602
603         int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
604         _descriptor->release ();
605
606         return r;
607 }
608
609 void
610 SndFileSource::flush ()
611 {
612         if (!_open) {
613                 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
614                 return;
615         }
616
617         if (!writable()) {
618                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
619                 return;
620         }
621
622         SNDFILE* sf = _descriptor->allocate ();
623         if (sf == 0) {
624                 error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
625                 return;
626         }
627
628         // Hopefully everything OK
629         sf_write_sync (sf);
630         _descriptor->release ();
631 }
632
633 int
634 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
635 {
636         if (!writable()) {
637                 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
638                 return -1;
639         }
640
641         if (!_open) {
642                 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
643                 return -1;
644         }
645
646         if (!(_flags & Broadcast)) {
647                 return 0;
648         }
649
650         _broadcast_info->set_originator_ref_from_session (_session);
651         _broadcast_info->set_origination_time (&now);
652
653         /* now update header position taking header offset into account */
654
655         set_header_timeline_position ();
656
657         SNDFILE* sf = _descriptor->allocate ();
658
659         if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
660                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
661                                            _path, _broadcast_info->get_error())
662                       << endmsg;
663                 _flags = Flag (_flags & ~Broadcast);
664                 delete _broadcast_info;
665                 _broadcast_info = 0;
666         }
667
668         _descriptor->release ();
669         return 0;
670 }
671
672 void
673 SndFileSource::set_header_timeline_position ()
674 {
675         if (!(_flags & Broadcast)) {
676                 return;
677         }
678
679         _broadcast_info->set_time_reference (_timeline_position);
680
681         SNDFILE* sf = _descriptor->allocate ();
682         
683         if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
684                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
685                                            _path, _broadcast_info->get_error())
686                       << endmsg;
687                 _flags = Flag (_flags & ~Broadcast);
688                 delete _broadcast_info;
689                 _broadcast_info = 0;
690         }
691
692         _descriptor->release ();
693 }
694
695 framecnt_t
696 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
697 {
698         SNDFILE* sf = _descriptor->allocate ();
699
700         if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
701                 char errbuf[256];
702                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
703                 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
704                 _descriptor->release ();
705                 return 0;
706         }
707
708         if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
709                 _descriptor->release ();
710                 return 0;
711         }
712
713         _descriptor->release ();
714         return cnt;
715 }
716
717 framepos_t
718 SndFileSource::natural_position() const
719 {
720         return _timeline_position;
721 }
722
723 bool
724 SndFileSource::set_destructive (bool yn)
725 {
726         if (yn) {
727                 _flags = Flag (_flags | Writable | Destructive);
728                 if (!xfade_buf) {
729                         xfade_buf = new Sample[xfade_frames];
730                 }
731                 clear_capture_marks ();
732                 _timeline_position = header_position_offset;
733         } else {
734                 _flags = Flag (_flags & ~Destructive);
735                 _timeline_position = 0;
736                 /* leave xfade buf alone in case we need it again later */
737         }
738
739         return true;
740 }
741
742 void
743 SndFileSource::clear_capture_marks ()
744 {
745         _capture_start = false;
746         _capture_end = false;
747 }
748
749 /** @param pos Capture start position in session frames */
750 void
751 SndFileSource::mark_capture_start (framepos_t pos)
752 {
753         if (destructive()) {
754                 if (pos < _timeline_position) {
755                         _capture_start = false;
756                 } else {
757                         _capture_start = true;
758                         capture_start_frame = pos;
759                 }
760         }
761 }
762
763 void
764 SndFileSource::mark_capture_end()
765 {
766         if (destructive()) {
767                 _capture_end = true;
768         }
769 }
770
771 framecnt_t
772 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
773 {
774         framecnt_t xfade = min (xfade_frames, cnt);
775         framecnt_t nofade = cnt - xfade;
776         Sample* fade_data = 0;
777         framepos_t fade_position = 0; // in frames
778         ssize_t retval;
779         framecnt_t file_cnt;
780
781         if (fade_in) {
782                 fade_position = file_pos;
783                 fade_data = data;
784         } else {
785                 fade_position = file_pos + nofade;
786                 fade_data = data + nofade;
787         }
788
789         if (fade_position > _length) {
790
791                 /* read starts beyond end of data, just memset to zero */
792
793                 file_cnt = 0;
794
795         } else if (fade_position + xfade > _length) {
796
797                 /* read ends beyond end of data, read some, memset the rest */
798
799                 file_cnt = _length - fade_position;
800
801         } else {
802
803                 /* read is entirely within data */
804
805                 file_cnt = xfade;
806         }
807
808         if (file_cnt) {
809
810                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
811                         if (retval >= 0 && errno == EAGAIN) {
812                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
813                                  * short or no data there */
814                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
815                         } else {
816                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
817                                 return 0;
818                         }
819                 }
820         }
821
822         if (file_cnt != xfade) {
823                 framecnt_t delta = xfade - file_cnt;
824                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
825         }
826
827         if (nofade && !fade_in) {
828                 if (write_float (data, file_pos, nofade) != nofade) {
829                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
830                         return 0;
831                 }
832         }
833
834         if (xfade == xfade_frames) {
835
836                 framecnt_t n;
837
838                 /* use the standard xfade curve */
839
840                 if (fade_in) {
841
842                         /* fade new material in */
843
844                         for (n = 0; n < xfade; ++n) {
845                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
846                         }
847
848                 } else {
849
850
851                         /* fade new material out */
852
853                         for (n = 0; n < xfade; ++n) {
854                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
855                         }
856                 }
857
858         } else if (xfade < xfade_frames) {
859
860                 std::vector<gain_t> in(xfade);
861                 std::vector<gain_t> out(xfade);
862
863                 /* short xfade, compute custom curve */
864
865                 compute_equal_power_fades (xfade, &in[0], &out[0]);
866
867                 for (framecnt_t n = 0; n < xfade; ++n) {
868                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
869                 }
870
871         } else if (xfade) {
872
873                 /* long xfade length, has to be computed across several calls */
874
875         }
876
877         if (xfade) {
878                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
879                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
880                         return 0;
881                 }
882         }
883
884         if (fade_in && nofade) {
885                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
886                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
887                         return 0;
888                 }
889         }
890
891         return cnt;
892 }
893
894 framepos_t
895 SndFileSource::last_capture_start_frame () const
896 {
897         if (destructive()) {
898                 return capture_start_frame;
899         } else {
900                 return 0;
901         }
902 }
903
904 void
905 SndFileSource::handle_header_position_change ()
906 {
907         if (destructive()) {
908                 if ( _length != 0 ) {
909                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
910                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
911                 } else if (writable()) {
912                         _timeline_position = header_position_offset;
913                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
914                 }
915         }
916 }
917
918 void
919 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
920 {
921         /* This static method is assumed to have been called by the Session
922            before any DFS's are created.
923         */
924
925         xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
926
927         delete [] out_coefficient;
928         delete [] in_coefficient;
929
930         out_coefficient = new gain_t[xfade_frames];
931         in_coefficient = new gain_t[xfade_frames];
932
933         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
934 }
935
936 void
937 SndFileSource::set_timeline_position (framepos_t pos)
938 {
939         // destructive track timeline postion does not change
940         // except at instantion or when header_position_offset
941         // (session start) changes
942
943         if (!destructive()) {
944                 AudioFileSource::set_timeline_position (pos);
945         }
946 }
947
948 int
949 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
950 {
951         SNDFILE *sf;
952         SF_INFO sf_info;
953         BroadcastInfo binfo;
954
955         sf_info.format = 0; // libsndfile says to clear this before sf_open().
956
957         if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
958                 char errbuf[256];
959                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
960                 return false;
961         }
962
963         info.samplerate  = sf_info.samplerate;
964         info.channels    = sf_info.channels;
965         info.length      = sf_info.frames;
966
967         string major = sndfile_major_format(sf_info.format);
968         string minor = sndfile_minor_format(sf_info.format);
969
970         if (major.length() + minor.length() < 16) { /* arbitrary */
971                 info.format_name = string_compose("%1/%2", major, minor);
972         } else {
973                 info.format_name = string_compose("%1\n%2", major, minor);
974         }
975
976         info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
977
978         sf_close (sf);
979
980         return true;
981 }
982
983 bool
984 SndFileSource::one_of_several_channels () const
985 {
986         return _info.channels > 1;
987 }
988
989 bool
990 SndFileSource::clamped_at_unity () const
991 {
992         int const type = _info.format & SF_FORMAT_TYPEMASK;
993         int const sub = _info.format & SF_FORMAT_SUBMASK;
994         /* XXX: this may not be the full list of formats that are unclamped */
995         return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
996 }
997
998 void
999 SndFileSource::file_closed ()
1000 {
1001         /* stupid libsndfile updated the headers on close,
1002            so touch the peakfile if it exists and has data
1003            to make sure its time is as new as the audio
1004            file.
1005         */
1006
1007         touch_peakfile ();
1008 }
1009
1010 void
1011 SndFileSource::set_path (const string& p)
1012 {
1013         FileSource::set_path (p);
1014
1015         if (_descriptor) {
1016                 _descriptor->set_path (_path);
1017         }
1018 }