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