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