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