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