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