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