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