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