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