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