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