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