don't popup import progress window until we give import a chance to fail first; sndfi...
[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 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 void 
182 SndFileSource::init ()
183 {
184         ustring file;
185
186         // lets try to keep the object initalizations here at the top
187         xfade_buf = 0;
188         sf = 0;
189         _broadcast_info = 0;
190
191         if (is_embedded()) {
192                 _name = _path;
193         } else {
194                 _name = Glib::path_get_basename (_path);
195         }
196
197         /* although libsndfile says we don't need to set this,
198            valgrind and source code shows us that we do.
199         */
200
201         memset (&_info, 0, sizeof(_info));
202
203         _capture_start = false;
204         _capture_end = false;
205         file_pos = 0;
206
207         if (destructive()) {    
208                 xfade_buf = new Sample[xfade_frames];
209                 timeline_position = header_position_offset;
210         }
211
212         AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
213 }
214
215 int
216 SndFileSource::open ()
217 {
218         if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
219                 char errbuf[256];
220                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
221 #ifndef HAVE_COREAUDIO
222                 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
223                    so we don't want to see this message.
224                 */
225
226                 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"), 
227                                         _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
228 #endif
229                 return -1;
230         }
231
232         if (_channel >= _info.channels) {
233 #ifndef HAVE_COREAUDIO
234                 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
235 #endif
236                 sf_close (sf);
237                 sf = 0;
238                 return -1;
239         }
240
241         _length = _info.frames;
242
243         _broadcast_info = new SF_BROADCAST_INFO;
244         memset (_broadcast_info, 0, sizeof (*_broadcast_info));
245         
246         bool timecode_info_exists;
247
248         set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
249
250         if (_length != 0 && !timecode_info_exists) {
251                 delete _broadcast_info;
252                 _broadcast_info = 0;
253                 _flags = Flag (_flags & ~Broadcast);
254         }
255
256         if (writable()) {
257                 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
258         }
259
260         return 0;
261 }
262
263 SndFileSource::~SndFileSource ()
264 {
265         GoingAway (); /* EMIT SIGNAL */
266
267         if (sf) {
268                 sf_close (sf);
269                 sf = 0;
270
271                 /* stupid libsndfile updated the headers on close,
272                    so touch the peakfile if it exists and has data
273                    to make sure its time is as new as the audio
274                    file.
275                 */
276
277                 touch_peakfile ();
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 != cnt) {
323                 nframes_t delta = cnt - file_cnt;
324                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
325         }
326
327         if (file_cnt) {
328
329                 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
330                         char errbuf[256];
331                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
332                         error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
333                         return 0;
334                 }
335                 
336                 if (_info.channels == 1) {
337                         nframes_t ret = sf_read_float (sf, dst, file_cnt);
338                         _read_data_count = cnt * sizeof(float);
339                         return ret;
340                 }
341         }
342
343         real_cnt = cnt * _info.channels;
344
345         Sample* interleave_buf = get_interleave_buffer (real_cnt);
346         
347         nread = sf_read_float (sf, interleave_buf, real_cnt);
348         ptr = interleave_buf + _channel;
349         nread /= _info.channels;
350         
351         /* stride through the interleaved data */
352         
353         for (int32_t n = 0; n < nread; ++n) {
354                 dst[n] = *ptr;
355                 ptr += _info.channels;
356         }
357
358         _read_data_count = cnt * sizeof(float);
359                 
360         return nread;
361 }
362
363 nframes_t 
364 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
365 {
366         if (destructive()) {
367                 return destructive_write_unlocked (data, cnt);
368         } else {
369                 return nondestructive_write_unlocked (data, cnt);
370         }
371 }
372
373 nframes_t 
374 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
375 {
376         if (!writable()) {
377                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
378                 return 0;
379         }
380
381         if (_info.channels != 1) {
382                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
383                 /*NOTREACHED*/
384                 return 0;
385         }
386         
387         nframes_t oldlen;
388         int32_t frame_pos = _length;
389
390         if (write_float (data, frame_pos, cnt) != cnt) {
391                 return 0;
392         }
393
394         oldlen = _length;
395         update_length (oldlen, cnt);
396
397         if (_build_peakfiles) {
398                 compute_and_write_peaks (data, frame_pos, cnt, false, true);
399         }
400
401         _write_data_count = cnt;
402         
403         return cnt;
404 }
405
406 nframes_t
407 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
408 {
409         nframes_t old_file_pos;
410
411         if (!writable()) {
412                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
413                 return 0;
414         }
415
416         if (_capture_start && _capture_end) {
417
418                 /* start and end of capture both occur within the data we are writing,
419                    so do both crossfades.
420                 */
421
422                 _capture_start = false;
423                 _capture_end = false;
424                 
425                 /* move to the correct location place */
426                 file_pos = capture_start_frame - timeline_position;
427                 
428                 // split cnt in half
429                 nframes_t subcnt = cnt / 2;
430                 nframes_t ofilepos = file_pos;
431                 
432                 // fade in
433                 if (crossfade (data, subcnt, 1) != subcnt) {
434                         return 0;
435                 }
436                 
437                 file_pos += subcnt;
438                 Sample * tmpdata = data + subcnt;
439                 
440                 // fade out
441                 subcnt = cnt - subcnt;
442                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
443                         return 0;
444                 }
445                 
446                 file_pos = ofilepos; // adjusted below
447
448         } else if (_capture_start) {
449
450                 /* start of capture both occur within the data we are writing,
451                    so do the fade in
452                 */
453
454                 _capture_start = false;
455                 _capture_end = false;
456                 
457                 /* move to the correct location place */
458                 file_pos = capture_start_frame - timeline_position;
459
460                 if (crossfade (data, cnt, 1) != cnt) {
461                         return 0;
462                 }
463                 
464         } else if (_capture_end) {
465
466                 /* end of capture both occur within the data we are writing,
467                    so do the fade out
468                 */
469
470                 _capture_start = false;
471                 _capture_end = false;
472                 
473                 if (crossfade (data, cnt, 0) != cnt) {
474                         return 0;
475                 }
476
477         } else {
478
479                 /* in the middle of recording */
480
481                 if (write_float (data, file_pos, cnt) != cnt) {
482                         return 0;
483                 }
484         }
485
486         old_file_pos = file_pos;
487         update_length (file_pos, cnt);
488
489         if (_build_peakfiles) {
490                 compute_and_write_peaks (data, file_pos, cnt, false, true);
491         }
492
493         file_pos += cnt;
494         
495         return cnt;
496 }
497
498 int
499 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
500 {       
501         set_timeline_position (when);
502
503         if (_flags & Broadcast) {
504                 if (setup_broadcast_info (when, now, tnow)) {
505                         return -1;
506                 }
507         } 
508
509         return flush_header ();
510 }
511
512 int
513 SndFileSource::flush_header ()
514 {
515         if (!writable() || (sf == 0)) {
516                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
517                 return -1;
518         }
519         return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
520 }
521
522 int
523 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
524 {
525         if (!writable()) {
526                 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
527                 return -1;
528         }
529
530         if (!(_flags & Broadcast)) {
531                 return 0;
532         }
533
534         /* random code is 9 digits */
535         
536         int random_code = random() % 999999999;
537         
538         snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
539                   Config->get_bwf_country_code().c_str(),
540                   Config->get_bwf_organization_code().c_str(),
541                   bwf_serial_number,
542                   now.tm_hour,
543                   now.tm_min,
544                   now.tm_sec,
545                   random_code);
546         
547         snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
548                   1900 + now.tm_year,
549                   now.tm_mon,
550                   now.tm_mday);
551         
552         snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
553                   now.tm_hour,
554                   now.tm_min,
555                   now.tm_sec);
556
557         /* now update header position taking header offset into account */
558         
559         set_header_timeline_position ();
560
561         if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
562                 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
563                 _flags = Flag (_flags & ~Broadcast);
564                 delete _broadcast_info;
565                 _broadcast_info = 0;
566                 return -1;
567         }
568
569         return 0;
570 }
571
572 void
573 SndFileSource::set_header_timeline_position ()
574 {
575         if (!(_flags & Broadcast)) {
576                 return;
577         }
578
579        _broadcast_info->time_reference_high = (timeline_position >> 32);
580        _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
581
582         if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
583                 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
584                 _flags = Flag (_flags & ~Broadcast);
585                 delete _broadcast_info;
586                 _broadcast_info = 0;
587         }
588 }
589
590 nframes_t
591 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
592 {
593         if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
594                 char errbuf[256];
595                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
596                 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
597                 return 0;
598         }
599         
600         if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
601                 return 0;
602         }
603         
604         return cnt;
605 }
606
607 nframes_t
608 SndFileSource::natural_position() const
609 {
610         return timeline_position;
611 }
612
613 bool
614 SndFileSource::set_destructive (bool yn)
615 {
616         if (yn) {
617                 _flags = Flag (_flags | Destructive);
618                 if (!xfade_buf) {
619                         xfade_buf = new Sample[xfade_frames];
620                 }
621                 clear_capture_marks ();
622                 timeline_position = header_position_offset;
623         } else {
624                 _flags = Flag (_flags & ~Destructive);
625                 timeline_position = 0;
626                 /* leave xfade buf alone in case we need it again later */
627         }
628
629         return true;
630 }
631
632 void
633 SndFileSource::clear_capture_marks ()
634 {
635         _capture_start = false;
636         _capture_end = false;
637 }       
638
639 void
640 SndFileSource::mark_capture_start (nframes_t pos)
641 {
642         if (destructive()) {
643                 if (pos < timeline_position) {
644                         _capture_start = false;
645                 } else {
646                         _capture_start = true;
647                         capture_start_frame = pos;
648                 }
649         }
650 }
651
652 void
653 SndFileSource::mark_capture_end()
654 {
655         if (destructive()) {
656                 _capture_end = true;
657         }
658 }
659
660 nframes_t
661 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
662 {
663         nframes_t xfade = min (xfade_frames, cnt);
664         nframes_t nofade = cnt - xfade;
665         Sample* fade_data = 0;
666         nframes_t fade_position = 0; // in frames
667         ssize_t retval;
668         nframes_t file_cnt;
669
670         if (fade_in) {
671                 fade_position = file_pos;
672                 fade_data = data;
673         } else {
674                 fade_position = file_pos + nofade;
675                 fade_data = data + nofade;
676         }
677
678         if (fade_position > _length) {
679                 
680                 /* read starts beyond end of data, just memset to zero */
681                 
682                 file_cnt = 0;
683
684         } else if (fade_position + xfade > _length) {
685                 
686                 /* read ends beyond end of data, read some, memset the rest */
687                 
688                 file_cnt = _length - fade_position;
689
690         } else {
691                 
692                 /* read is entirely within data */
693
694                 file_cnt = xfade;
695         }
696
697         if (file_cnt) {
698                 
699                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
700                         if (retval >= 0 && errno == EAGAIN) {
701                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
702                                  * short or no data there */
703                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
704                         } else {
705                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
706                                 return 0;
707                         }
708                 }
709         } 
710
711         if (file_cnt != xfade) {
712                 nframes_t delta = xfade - file_cnt;
713                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
714         }
715         
716         if (nofade && !fade_in) {
717                 if (write_float (data, file_pos, nofade) != nofade) {
718                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
719                         return 0;
720                 }
721         }
722
723         if (xfade == xfade_frames) {
724
725                 nframes_t n;
726
727                 /* use the standard xfade curve */
728                 
729                 if (fade_in) {
730
731                         /* fade new material in */
732                         
733                         for (n = 0; n < xfade; ++n) {
734                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
735                         }
736
737                 } else {
738
739
740                         /* fade new material out */
741                         
742                         for (n = 0; n < xfade; ++n) {
743                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
744                         }
745                 }
746
747         } else if (xfade < xfade_frames) {
748
749                 gain_t in[xfade];
750                 gain_t out[xfade];
751
752                 /* short xfade, compute custom curve */
753
754                 compute_equal_power_fades (xfade, in, out);
755
756                 for (nframes_t n = 0; n < xfade; ++n) {
757                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);                
758                 }
759
760         } else if (xfade) {
761
762                 /* long xfade length, has to be computed across several calls */
763
764         }
765
766         if (xfade) {
767                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
768                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
769                         return 0;
770                 }
771         }
772         
773         if (fade_in && nofade) {
774                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
775                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
776                         return 0;
777                 }
778         }
779
780         return cnt;
781 }
782
783 nframes_t
784 SndFileSource::last_capture_start_frame () const
785 {
786         if (destructive()) {
787                 return capture_start_frame;
788         } else {
789                 return 0;
790         }
791 }
792
793 void
794 SndFileSource::handle_header_position_change ()
795 {
796         if (destructive()) {
797                 if ( _length != 0 ) {
798                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
799                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
800                 } else if (writable()) {
801                         timeline_position = header_position_offset;
802                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
803                 }
804         }
805 }
806
807 void
808 SndFileSource::setup_standard_crossfades (nframes_t rate)
809 {
810         /* This static method is assumed to have been called by the Session
811            before any DFS's are created.
812         */
813
814         xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
815
816         if (out_coefficient) {
817                 delete [] out_coefficient;
818         }
819
820         if (in_coefficient) {
821                 delete [] in_coefficient;
822         }
823
824         out_coefficient = new gain_t[xfade_frames];
825         in_coefficient = new gain_t[xfade_frames];
826
827         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
828 }
829
830 void
831 SndFileSource::set_timeline_position (int64_t pos)
832 {
833         // destructive track timeline postion does not change
834         // except at instantion or when header_position_offset 
835         // (session start) changes
836
837         if (!destructive()) {
838                 AudioFileSource::set_timeline_position (pos);
839         } 
840 }
841
842 int
843 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
844 {
845         SNDFILE *sf;
846         SF_INFO sf_info;
847         SF_BROADCAST_INFO binfo;
848         bool timecode_exists;
849
850         sf_info.format = 0; // libsndfile says to clear this before sf_open().
851
852         if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { 
853                 char errbuf[256];
854                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
855                 return false;
856         }
857
858         info.samplerate  = sf_info.samplerate;
859         info.channels    = sf_info.channels;
860         info.length      = sf_info.frames;
861         info.format_name = string_compose("%1\n%2",
862                                            sndfile_major_format(sf_info.format),
863                                            sndfile_minor_format(sf_info.format));
864
865         memset (&binfo, 0, sizeof (binfo));
866         info.timecode  = get_timecode_info (sf, &binfo, timecode_exists);
867
868         if (!timecode_exists) {
869                 info.timecode = 0;
870         }
871         
872         sf_close (sf);
873
874         return true;
875 }
876
877 int64_t
878 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
879 {
880         if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
881                 exists = false;
882                 return (header_position_offset);
883         } 
884         
885         /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
886            of the time reference.
887         */
888         
889         exists = true;
890         int64_t ret = (uint32_t) binfo->time_reference_high;
891         ret <<= 32;
892         ret |= (uint32_t) binfo->time_reference_low;
893         return ret;
894 }
895
896 bool
897 SndFileSource::one_of_several_channels () const
898 {
899         return _info.channels > 1;
900 }
901