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