Fix broken whitespace. I'd apologize for the compile times if it was my fault :D
[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         int32_t nread;
273         float *ptr;
274         uint32_t real_cnt;
275         framepos_t file_cnt;
276
277         if (writable() && !_open) {
278                 /* file has not been opened yet - nothing written to it */
279                 memset (dst, 0, sizeof (Sample) * cnt);
280                 return cnt;
281         }
282
283         SNDFILE* sf = _descriptor->allocate ();
284
285         if (sf == 0) {
286                 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
287                 return 0;
288         }
289
290         if (start > _length) {
291
292                 /* read starts beyond end of data, just memset to zero */
293
294                 file_cnt = 0;
295
296         } else if (start + cnt > _length) {
297
298                 /* read ends beyond end of data, read some, memset the rest */
299
300                 file_cnt = _length - start;
301
302         } else {
303
304                 /* read is entirely within data */
305
306                 file_cnt = cnt;
307         }
308
309         if (file_cnt != cnt) {
310                 framepos_t delta = cnt - file_cnt;
311                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
312         }
313
314         if (file_cnt) {
315
316                 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
317                         char errbuf[256];
318                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
319                         error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
320                         _descriptor->release ();
321                         return 0;
322                 }
323
324                 if (_info.channels == 1) {
325                         framecnt_t ret = sf_read_float (sf, dst, file_cnt);
326                         _read_data_count = ret * sizeof(float);
327                         if (ret != file_cnt) {
328                                 char errbuf[256];
329                                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
330                                 error << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.val().substr (1), errbuf, _length) << endl;
331                         }
332                         _descriptor->release ();
333                         return ret;
334                 }
335         }
336
337         real_cnt = cnt * _info.channels;
338
339         Sample* interleave_buf = get_interleave_buffer (real_cnt);
340
341         nread = sf_read_float (sf, interleave_buf, real_cnt);
342         ptr = interleave_buf + _channel;
343         nread /= _info.channels;
344
345         /* stride through the interleaved data */
346
347         for (int32_t n = 0; n < nread; ++n) {
348                 dst[n] = *ptr;
349                 ptr += _info.channels;
350         }
351
352         _read_data_count = cnt * sizeof(float);
353
354         _descriptor->release ();
355         return nread;
356 }
357
358 framecnt_t
359 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
360 {
361         if (!_open && open()) {
362                 return 0; // failure
363         }
364
365         if (destructive()) {
366                 return destructive_write_unlocked (data, cnt);
367         } else {
368                 return nondestructive_write_unlocked (data, cnt);
369         }
370 }
371
372 framecnt_t
373 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
374 {
375         if (!writable()) {
376                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
377                 return 0;
378         }
379
380         if (_info.channels != 1) {
381                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
382                 /*NOTREACHED*/
383                 return 0;
384         }
385
386         framecnt_t oldlen;
387         int32_t frame_pos = _length;
388
389         if (write_float (data, frame_pos, cnt) != cnt) {
390                 return 0;
391         }
392
393         oldlen = _length;
394         update_length (oldlen, cnt);
395
396         if (_build_peakfiles) {
397                 compute_and_write_peaks (data, frame_pos, cnt, false, true);
398         }
399
400         _write_data_count = cnt;
401
402         return cnt;
403 }
404
405 framecnt_t
406 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
407 {
408         framepos_t old_file_pos;
409
410         if (!writable()) {
411                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
412                 return 0;
413         }
414
415         if (_capture_start && _capture_end) {
416
417                 /* start and end of capture both occur within the data we are writing,
418                    so do both crossfades.
419                 */
420
421                 _capture_start = false;
422                 _capture_end = false;
423
424                 /* move to the correct location place */
425                 file_pos = capture_start_frame - _timeline_position;
426
427                 // split cnt in half
428                 framecnt_t subcnt = cnt / 2;
429                 framecnt_t ofilepos = file_pos;
430
431                 // fade in
432                 if (crossfade (data, subcnt, 1) != subcnt) {
433                         return 0;
434                 }
435
436                 file_pos += subcnt;
437                 Sample * tmpdata = data + subcnt;
438
439                 // fade out
440                 subcnt = cnt - subcnt;
441                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
442                         return 0;
443                 }
444
445                 file_pos = ofilepos; // adjusted below
446
447         } else if (_capture_start) {
448
449                 /* start of capture both occur within the data we are writing,
450                    so do the fade in
451                 */
452
453                 _capture_start = false;
454                 _capture_end = false;
455
456                 /* move to the correct location place */
457                 file_pos = capture_start_frame - _timeline_position;
458
459                 if (crossfade (data, cnt, 1) != cnt) {
460                         return 0;
461                 }
462
463         } else if (_capture_end) {
464
465                 /* end of capture both occur within the data we are writing,
466                    so do the fade out
467                 */
468
469                 _capture_start = false;
470                 _capture_end = false;
471
472                 if (crossfade (data, cnt, 0) != cnt) {
473                         return 0;
474                 }
475
476         } else {
477
478                 /* in the middle of recording */
479
480                 if (write_float (data, file_pos, cnt) != cnt) {
481                         return 0;
482                 }
483         }
484
485         old_file_pos = file_pos;
486         update_length (file_pos, cnt);
487
488         if (_build_peakfiles) {
489                 compute_and_write_peaks (data, file_pos, cnt, false, true);
490         }
491
492         file_pos += cnt;
493
494         return cnt;
495 }
496
497 int
498 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
499 {
500         set_timeline_position (when);
501
502         if (_flags & Broadcast) {
503                 if (setup_broadcast_info (when, now, tnow)) {
504                         return -1;
505                 }
506         }
507
508         return flush_header ();
509 }
510
511 int
512 SndFileSource::flush_header ()
513 {
514         if (!writable()) {
515                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
516                 return -1;
517         }
518
519         if (!_open) {
520                 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
521                 return -1;
522         }
523
524         SNDFILE* sf = _descriptor->allocate ();
525         if (sf == 0) {
526                 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
527                 return -1;
528         }
529
530         int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
531         _descriptor->release ();
532
533         return r;
534 }
535
536 int
537 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
538 {
539         if (!writable()) {
540                 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
541                 return -1;
542         }
543
544         if (!_open) {
545                 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
546                 return -1;
547         }
548
549         if (!(_flags & Broadcast)) {
550                 return 0;
551         }
552
553         _broadcast_info->set_originator_ref_from_session (_session);
554         _broadcast_info->set_origination_time (&now);
555
556         /* now update header position taking header offset into account */
557
558         set_header_timeline_position ();
559
560         SNDFILE* sf = _descriptor->allocate ();
561
562         if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
563                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
564                                            _path, _broadcast_info->get_error())
565                       << endmsg;
566                 _flags = Flag (_flags & ~Broadcast);
567                 delete _broadcast_info;
568                 _broadcast_info = 0;
569         }
570
571         _descriptor->release ();
572         return 0;
573 }
574
575 void
576 SndFileSource::set_header_timeline_position ()
577 {
578         if (!(_flags & Broadcast)) {
579                 return;
580         }
581
582         _broadcast_info->set_time_reference (_timeline_position);
583
584         SNDFILE* sf = _descriptor->allocate ();
585
586         if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
587                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
588                                            _path, _broadcast_info->get_error())
589                       << endmsg;
590                 _flags = Flag (_flags & ~Broadcast);
591                 delete _broadcast_info;
592                 _broadcast_info = 0;
593         }
594
595         _descriptor->release ();
596 }
597
598 framecnt_t
599 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
600 {
601         SNDFILE* sf = _descriptor->allocate ();
602
603         if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
604                 char errbuf[256];
605                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
606                 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
607                 _descriptor->release ();
608                 return 0;
609         }
610
611         if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
612                 _descriptor->release ();
613                 return 0;
614         }
615
616         _descriptor->release ();
617         return cnt;
618 }
619
620 framepos_t
621 SndFileSource::natural_position() const
622 {
623         return _timeline_position;
624 }
625
626 bool
627 SndFileSource::set_destructive (bool yn)
628 {
629         if (yn) {
630                 _flags = Flag (_flags | Writable | Destructive);
631                 if (!xfade_buf) {
632                         xfade_buf = new Sample[xfade_frames];
633                 }
634                 clear_capture_marks ();
635                 _timeline_position = header_position_offset;
636         } else {
637                 _flags = Flag (_flags & ~Destructive);
638                 _timeline_position = 0;
639                 /* leave xfade buf alone in case we need it again later */
640         }
641
642         return true;
643 }
644
645 void
646 SndFileSource::clear_capture_marks ()
647 {
648         _capture_start = false;
649         _capture_end = false;
650 }
651
652 /** @param pos Capture start position in session frames */
653 void
654 SndFileSource::mark_capture_start (framepos_t pos)
655 {
656         if (destructive()) {
657                 if (pos < _timeline_position) {
658                         _capture_start = false;
659                 } else {
660                         _capture_start = true;
661                         capture_start_frame = pos;
662                 }
663         }
664 }
665
666 void
667 SndFileSource::mark_capture_end()
668 {
669         if (destructive()) {
670                 _capture_end = true;
671         }
672 }
673
674 framecnt_t
675 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
676 {
677         framecnt_t xfade = min (xfade_frames, cnt);
678         framecnt_t nofade = cnt - xfade;
679         Sample* fade_data = 0;
680         framepos_t fade_position = 0; // in frames
681         ssize_t retval;
682         framecnt_t file_cnt;
683
684         if (fade_in) {
685                 fade_position = file_pos;
686                 fade_data = data;
687         } else {
688                 fade_position = file_pos + nofade;
689                 fade_data = data + nofade;
690         }
691
692         if (fade_position > _length) {
693
694                 /* read starts beyond end of data, just memset to zero */
695
696                 file_cnt = 0;
697
698         } else if (fade_position + xfade > _length) {
699
700                 /* read ends beyond end of data, read some, memset the rest */
701
702                 file_cnt = _length - fade_position;
703
704         } else {
705
706                 /* read is entirely within data */
707
708                 file_cnt = xfade;
709         }
710
711         if (file_cnt) {
712
713                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
714                         if (retval >= 0 && errno == EAGAIN) {
715                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
716                                  * short or no data there */
717                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
718                         } else {
719                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
720                                 return 0;
721                         }
722                 }
723         }
724
725         if (file_cnt != xfade) {
726                 framecnt_t delta = xfade - file_cnt;
727                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
728         }
729
730         if (nofade && !fade_in) {
731                 if (write_float (data, file_pos, nofade) != nofade) {
732                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
733                         return 0;
734                 }
735         }
736
737         if (xfade == xfade_frames) {
738
739                 framecnt_t n;
740
741                 /* use the standard xfade curve */
742
743                 if (fade_in) {
744
745                         /* fade new material in */
746
747                         for (n = 0; n < xfade; ++n) {
748                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
749                         }
750
751                 } else {
752
753
754                         /* fade new material out */
755
756                         for (n = 0; n < xfade; ++n) {
757                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
758                         }
759                 }
760
761         } else if (xfade < xfade_frames) {
762
763                 gain_t in[xfade];
764                 gain_t out[xfade];
765
766                 /* short xfade, compute custom curve */
767
768                 compute_equal_power_fades (xfade, in, out);
769
770                 for (framecnt_t n = 0; n < xfade; ++n) {
771                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
772                 }
773
774         } else if (xfade) {
775
776                 /* long xfade length, has to be computed across several calls */
777
778         }
779
780         if (xfade) {
781                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
782                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
783                         return 0;
784                 }
785         }
786
787         if (fade_in && nofade) {
788                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
789                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
790                         return 0;
791                 }
792         }
793
794         return cnt;
795 }
796
797 framepos_t
798 SndFileSource::last_capture_start_frame () const
799 {
800         if (destructive()) {
801                 return capture_start_frame;
802         } else {
803                 return 0;
804         }
805 }
806
807 void
808 SndFileSource::handle_header_position_change ()
809 {
810         if (destructive()) {
811                 if ( _length != 0 ) {
812                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
813                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
814                 } else if (writable()) {
815                         _timeline_position = header_position_offset;
816                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
817                 }
818         }
819 }
820
821 void
822 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
823 {
824         /* This static method is assumed to have been called by the Session
825            before any DFS's are created.
826         */
827
828         xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
829
830         delete [] out_coefficient;
831         delete [] in_coefficient;
832
833         out_coefficient = new gain_t[xfade_frames];
834         in_coefficient = new gain_t[xfade_frames];
835
836         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
837 }
838
839 void
840 SndFileSource::set_timeline_position (framepos_t pos)
841 {
842         // destructive track timeline postion does not change
843         // except at instantion or when header_position_offset
844         // (session start) changes
845
846         if (!destructive()) {
847                 AudioFileSource::set_timeline_position (pos);
848         }
849 }
850
851 int
852 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
853 {
854         SNDFILE *sf;
855         SF_INFO sf_info;
856         BroadcastInfo binfo;
857
858         sf_info.format = 0; // libsndfile says to clear this before sf_open().
859
860         if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
861                 char errbuf[256];
862                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
863                 return false;
864         }
865
866         info.samplerate  = sf_info.samplerate;
867         info.channels    = sf_info.channels;
868         info.length      = sf_info.frames;
869
870         string major = sndfile_major_format(sf_info.format);
871         string minor = sndfile_minor_format(sf_info.format);
872
873         if (major.length() + minor.length() < 16) { /* arbitrary */
874                 info.format_name = string_compose("%1/%2", major, minor);
875         } else {
876                 info.format_name = string_compose("%1\n%2", major, minor);
877         }
878
879         info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
880
881         sf_close (sf);
882
883         return true;
884 }
885
886 bool
887 SndFileSource::one_of_several_channels () const
888 {
889         return _info.channels > 1;
890 }
891
892 bool
893 SndFileSource::clamped_at_unity () const
894 {
895         int const type = _info.format & SF_FORMAT_TYPEMASK;
896         int const sub = _info.format & SF_FORMAT_SUBMASK;
897         /* XXX: this may not be the full list of formats that are unclamped */
898         return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
899 }
900
901 void
902 SndFileSource::file_closed ()
903 {
904         /* stupid libsndfile updated the headers on close,
905            so touch the peakfile if it exists and has data
906            to make sure its time is as new as the audio
907            file.
908         */
909
910         touch_peakfile ();
911 }
912
913 void
914 SndFileSource::set_path (const string& p)
915 {
916         FileSource::set_path (p);
917
918         if (_descriptor) {
919                 _descriptor->set_path (_path);
920         }
921 }