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