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