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