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