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