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