Follow fluidsynth's API changes introduced with 2.0.0
[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 samplecnt_t SndFileSource::xfade_samples = 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, samplecnt_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 = 0;
254         init_sndfile ();
255
256         _file_is_new = true;
257
258         _info.channels = 1;
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 #if 0
280         /* setting flac compression quality above the default does not produce a significant size
281          * improvement (not for large raw recordings anyway, the_CLA tests 2017-10-02, >> 250MB files,
282          * ~1% smaller), but does have a significant encoding speed penalty.
283          *
284          * We still may expose this as option someday though, perhaps for opposite reason: "fast encoding"
285          */
286         double flac_quality = 1; // libsndfile uses range 0..1 (mapped to flac 0..8), default is (5/8)
287         if (sf_command (_sndfile, SFC_SET_COMPRESSION_LEVEL, &flac_quality, sizeof (double)) != SF_TRUE) {
288                 char errbuf[256];
289                 sf_error_str (_sndfile, errbuf, sizeof (errbuf) - 1);
290                 error << string_compose (_("Cannot set flac compression level: %1"), errbuf) << endmsg;
291         }
292 #endif
293
294         Sample buf[8192];
295         samplecnt_t off = 0;
296         float peak = 0;
297         float norm = 1.f;
298
299         /* normalize before converting to fixed point, calc gain factor */
300         samplecnt_t len = other.read (buf, off, 8192, other.channel ());
301         while (len > 0) {
302                 peak = compute_peak (buf, len, peak);
303                 off += len;
304                 len = other.read (buf, off, 8192, other.channel ());
305                 if (progress) {
306                         progress->set_progress (0.5f * (float) off / other.readable_length ());
307                 }
308         }
309
310         if (peak > 0) {
311                 _gain *= peak;
312                 norm = 1.f / peak;
313         }
314
315         /* copy file */
316         off = 0;
317         len = other.read (buf, off, 8192, other.channel ());
318         while (len > 0) {
319                 if (norm != 1.f) {
320                         for (samplecnt_t i = 0; i < len; ++i) {
321                                 buf[i] *= norm;
322                         }
323                 }
324                 write (buf, len);
325                 off += len;
326                 len = other.read (buf, off, 8192, other.channel ());
327                 if (progress) {
328                         progress->set_progress (0.5f + 0.5f * (float) off / other.readable_length ());
329                 }
330         }
331 }
332
333 void
334 SndFileSource::init_sndfile ()
335 {
336         /* although libsndfile says we don't need to set this,
337            valgrind and source code shows us that we do.
338         */
339
340         memset (&_info, 0, sizeof(_info));
341
342         if (destructive()) {
343                 xfade_buf = new Sample[xfade_samples];
344                 _timeline_position = header_position_offset;
345         }
346
347         AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
348 }
349
350 void
351 SndFileSource::close ()
352 {
353         if (_sndfile) {
354                 sf_close (_sndfile);
355                 _sndfile = 0;
356                 file_closed ();
357         }
358 }
359
360 int
361 SndFileSource::open ()
362 {
363         if (_sndfile) {
364                 return 0;
365         }
366
367 // We really only want to use g_open for all platforms but because of this
368 // method(SndfileSource::open), the compiler(or at least GCC) is confused
369 // because g_open will expand to "open" on non-POSIX systems and needs the
370 // global namespace qualifer. The problem is since since C99 ::g_open will
371 // apparently expand to ":: open"
372 #ifdef PLATFORM_WINDOWS
373         int fd = g_open (_path.c_str(), writable() ? O_CREAT | O_RDWR : O_RDONLY, writable() ? 0644 : 0444);
374 #else
375         int fd = ::open (_path.c_str(), writable() ? O_CREAT | O_RDWR : O_RDONLY, writable() ? 0644 : 0444);
376 #endif
377
378         if (fd == -1) {
379                 error << string_compose (
380                              _ ("SndFileSource: cannot open file \"%1\" for %2"),
381                              _path,
382                              (writable () ? "read+write" : "reading")) << endmsg;
383                 return -1;
384         }
385
386         if ((_info.format & SF_FORMAT_TYPEMASK ) == SF_FORMAT_FLAC) {
387                 assert (!writable());
388                 _sndfile = sf_open_fd (fd, SFM_READ, &_info, true);
389         } else {
390                 _sndfile = sf_open_fd (fd, writable() ? SFM_RDWR : SFM_READ, &_info, true);
391         }
392
393         if (_sndfile == 0) {
394                 char errbuf[1024];
395                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
396 #ifndef HAVE_COREAUDIO
397                 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
398                    so we don't want to see this message.
399                 */
400
401                 cerr << "failed to open " << _path << " with name " << _name << endl;
402
403                 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
404                                         _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
405 #endif
406                 return -1;
407         }
408
409         if (_channel >= _info.channels) {
410 #ifndef HAVE_COREAUDIO
411                 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
412 #endif
413                 sf_close (_sndfile);
414                 _sndfile = 0;
415                 return -1;
416         }
417
418         _length = _info.frames;
419
420 #ifdef HAVE_RF64_RIFF
421         if (_file_is_new && _length == 0 && writable()) {
422                 if (_flags & RF64_RIFF) {
423                         if (sf_command (_sndfile, SFC_RF64_AUTO_DOWNGRADE, 0, 0) != SF_TRUE) {
424                                 char errbuf[256];
425                                 sf_error_str (_sndfile, errbuf, sizeof (errbuf) - 1);
426                                 error << string_compose (_("Cannot mark RF64 audio file for automatic downgrade to WAV: %1"), errbuf)
427                                       << endmsg;
428                         }
429                 }
430         }
431 #endif
432
433         if (!_broadcast_info) {
434                 _broadcast_info = new BroadcastInfo;
435         }
436
437         bool bwf_info_exists = _broadcast_info->load_from_file (_sndfile);
438
439         if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
440                 /* newly created files will not have a BWF header at this point in time.
441                  * Import will have called Source::set_timeline_position() if one exists
442                  * in the original. */
443                 header_position_offset = _timeline_position;
444         }
445
446         /* Set our timeline position to either the time reference from a BWF header or the current
447            start of the session.
448         */
449         set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
450
451         if (_length != 0 && !bwf_info_exists) {
452                 delete _broadcast_info;
453                 _broadcast_info = 0;
454                 _flags = Flag (_flags & ~Broadcast);
455         }
456
457         /* Set the broadcast flag if the BWF info is already there. We need
458          * this when recovering or using existing files.
459          */
460
461         if (bwf_info_exists) {
462                 _flags = Flag (_flags | Broadcast);
463         }
464
465         if (writable()) {
466                 sf_command (_sndfile, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
467
468                 if (_flags & Broadcast) {
469
470                         if (!_broadcast_info) {
471                                 _broadcast_info = new BroadcastInfo;
472                         }
473
474                         _broadcast_info->set_from_session (_session, header_position_offset);
475                         _broadcast_info->set_description (string_compose ("BWF %1", _name));
476
477                         if (!_broadcast_info->write_to_file (_sndfile)) {
478                                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
479                                                          _path, _broadcast_info->get_error())
480                                       << endmsg;
481                                 _flags = Flag (_flags & ~Broadcast);
482                                 delete _broadcast_info;
483                                 _broadcast_info = 0;
484                         }
485                 }
486         }
487
488         return 0;
489 }
490
491 SndFileSource::~SndFileSource ()
492 {
493         close ();
494         delete _broadcast_info;
495         delete [] xfade_buf;
496 }
497
498 float
499 SndFileSource::sample_rate () const
500 {
501         return _info.samplerate;
502 }
503
504 samplecnt_t
505 SndFileSource::read_unlocked (Sample *dst, samplepos_t start, samplecnt_t cnt) const
506 {
507         assert (cnt >= 0);
508
509         samplecnt_t nread;
510         float *ptr;
511         samplecnt_t real_cnt;
512         samplepos_t file_cnt;
513
514         if (writable() && !_sndfile) {
515                 /* file has not been opened yet - nothing written to it */
516                 memset (dst, 0, sizeof (Sample) * cnt);
517                 return cnt;
518         }
519
520         if (const_cast<SndFileSource*>(this)->open()) {
521                 error << string_compose (_("could not open file %1 for reading."), _path) << endmsg;
522                 return 0;
523         }
524
525         if (start > _length) {
526
527                 /* read starts beyond end of data, just memset to zero */
528
529                 file_cnt = 0;
530
531         } else if (start + cnt > _length) {
532
533                 /* read ends beyond end of data, read some, memset the rest */
534
535                 file_cnt = _length - start;
536
537         } else {
538
539                 /* read is entirely within data */
540
541                 file_cnt = cnt;
542         }
543
544         assert (file_cnt >= 0);
545
546         if (file_cnt != cnt) {
547                 samplepos_t delta = cnt - file_cnt;
548                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
549         }
550
551         if (file_cnt) {
552
553                 if (sf_seek (_sndfile, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
554                         char errbuf[256];
555                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
556                         error << string_compose(_("SndFileSource: could not seek to sample %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
557                         return 0;
558                 }
559
560                 if (_info.channels == 1) {
561                         samplecnt_t ret = sf_read_float (_sndfile, dst, file_cnt);
562                         if (ret != file_cnt) {
563                                 char errbuf[256];
564                                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
565                                 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;
566                         }
567                         if (_gain != 1.f) {
568                                 for (samplecnt_t i = 0; i < ret; ++i) {
569                                         dst[i] *= _gain;
570                                 }
571                         }
572                         return ret;
573                 }
574         }
575
576         real_cnt = cnt * _info.channels;
577
578         Sample* interleave_buf = get_interleave_buffer (real_cnt);
579
580         nread = sf_read_float (_sndfile, interleave_buf, real_cnt);
581         ptr = interleave_buf + _channel;
582         nread /= _info.channels;
583
584         /* stride through the interleaved data */
585
586         if (_gain != 1.f) {
587                 for (samplecnt_t n = 0; n < nread; ++n) {
588                         dst[n] = *ptr * _gain;
589                         ptr += _info.channels;
590                 }
591         } else {
592                 for (samplecnt_t n = 0; n < nread; ++n) {
593                         dst[n] = *ptr;
594                         ptr += _info.channels;
595                 }
596         }
597
598         return nread;
599 }
600
601 samplecnt_t
602 SndFileSource::write_unlocked (Sample *data, samplecnt_t cnt)
603 {
604         if (open()) {
605                 return 0; // failure
606         }
607
608         if (destructive()) {
609                 return destructive_write_unlocked (data, cnt);
610         } else {
611                 return nondestructive_write_unlocked (data, cnt);
612         }
613 }
614
615 samplecnt_t
616 SndFileSource::nondestructive_write_unlocked (Sample *data, samplecnt_t cnt)
617 {
618         if (!writable()) {
619                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
620                 return 0;
621         }
622
623         if (_info.channels != 1) {
624                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
625                 abort(); /*NOTREACHED*/
626                 return 0;
627         }
628
629         samplepos_t sample_pos = _length;
630
631         if (write_float (data, sample_pos, cnt) != cnt) {
632                 return 0;
633         }
634
635         update_length (_length + cnt);
636
637         if (_build_peakfiles) {
638                 compute_and_write_peaks (data, sample_pos, cnt, true, true);
639         }
640
641         return cnt;
642 }
643
644 samplecnt_t
645 SndFileSource::destructive_write_unlocked (Sample* data, samplecnt_t cnt)
646 {
647         if (!writable()) {
648                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
649                 return 0;
650         }
651
652         if (_capture_start && _capture_end) {
653
654                 /* start and end of capture both occur within the data we are writing,
655                    so do both crossfades.
656                 */
657
658                 _capture_start = false;
659                 _capture_end = false;
660
661                 /* move to the correct location place */
662                 file_pos = capture_start_sample - _timeline_position;
663
664                 // split cnt in half
665                 samplecnt_t subcnt = cnt / 2;
666                 samplecnt_t ofilepos = file_pos;
667
668                 // fade in
669                 if (crossfade (data, subcnt, 1) != subcnt) {
670                         return 0;
671                 }
672
673                 file_pos += subcnt;
674                 Sample * tmpdata = data + subcnt;
675
676                 // fade out
677                 subcnt = cnt - subcnt;
678                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
679                         return 0;
680                 }
681
682                 file_pos = ofilepos; // adjusted below
683
684         } else if (_capture_start) {
685
686                 /* start of capture both occur within the data we are writing,
687                    so do the fade in
688                 */
689
690                 _capture_start = false;
691                 _capture_end = false;
692
693                 /* move to the correct location place */
694                 file_pos = capture_start_sample - _timeline_position;
695
696                 if (crossfade (data, cnt, 1) != cnt) {
697                         return 0;
698                 }
699
700         } else if (_capture_end) {
701
702                 /* end of capture both occur within the data we are writing,
703                    so do the fade out
704                 */
705
706                 _capture_start = false;
707                 _capture_end = false;
708
709                 if (crossfade (data, cnt, 0) != cnt) {
710                         return 0;
711                 }
712
713         } else {
714
715                 /* in the middle of recording */
716
717                 if (write_float (data, file_pos, cnt) != cnt) {
718                         return 0;
719                 }
720         }
721
722         update_length (file_pos + cnt);
723
724         if (_build_peakfiles) {
725                 compute_and_write_peaks (data, file_pos, cnt, true, true);
726         }
727
728         file_pos += cnt;
729
730         return cnt;
731 }
732
733 int
734 SndFileSource::update_header (samplepos_t when, struct tm& now, time_t tnow)
735 {
736         set_timeline_position (when);
737
738         if (_flags & Broadcast) {
739                 if (setup_broadcast_info (when, now, tnow)) {
740                         return -1;
741                 }
742         }
743
744         return flush_header ();
745 }
746
747 int
748 SndFileSource::flush_header ()
749 {
750         if (!writable()) {
751                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
752                 return -1;
753         }
754
755         if (_sndfile == 0) {
756                 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
757                 return -1;
758         }
759
760         int const r = sf_command (_sndfile, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
761
762         return r;
763 }
764
765 void
766 SndFileSource::flush ()
767 {
768         if (!writable()) {
769                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
770                 return;
771         }
772
773         if (_sndfile == 0) {
774                 error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
775                 return;
776         }
777
778         // Hopefully everything OK
779         sf_write_sync (_sndfile);
780 }
781
782 int
783 SndFileSource::setup_broadcast_info (samplepos_t /*when*/, struct tm& now, time_t /*tnow*/)
784 {
785         if (!writable()) {
786                 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
787                 return -1;
788         }
789
790         if (!_sndfile) {
791                 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
792                 return -1;
793         }
794
795         if (!(_flags & Broadcast) || !_broadcast_info) {
796                 return 0;
797         }
798
799         _broadcast_info->set_originator_ref_from_session (_session);
800         _broadcast_info->set_origination_time (&now);
801
802         /* now update header position taking header offset into account */
803
804         set_header_timeline_position ();
805
806         return 0;
807 }
808
809 void
810 SndFileSource::set_header_timeline_position ()
811 {
812         if (!(_flags & Broadcast)) {
813                 return;
814         }
815         assert (_broadcast_info);
816
817         _broadcast_info->set_time_reference (_timeline_position);
818
819         if (_sndfile == 0 || !_broadcast_info->write_to_file (_sndfile)) {
820                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
821                                            _path, _broadcast_info->get_error())
822                       << endmsg;
823                 _flags = Flag (_flags & ~Broadcast);
824                 delete _broadcast_info;
825                 _broadcast_info = 0;
826         }
827 }
828
829 samplecnt_t
830 SndFileSource::write_float (Sample* data, samplepos_t sample_pos, samplecnt_t cnt)
831 {
832         if ((_info.format & SF_FORMAT_TYPEMASK ) == SF_FORMAT_FLAC) {
833                 assert (_length == sample_pos);
834         }
835         else if (_sndfile == 0 || sf_seek (_sndfile, sample_pos, SEEK_SET|SFM_WRITE) < 0) {
836                 char errbuf[256];
837                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
838                 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, sample_pos, errbuf) << endmsg;
839                 return 0;
840         }
841
842         if (sf_writef_float (_sndfile, data, cnt) != (ssize_t) cnt) {
843                 return 0;
844         }
845
846         return cnt;
847 }
848
849 samplepos_t
850 SndFileSource::natural_position() const
851 {
852         return _timeline_position;
853 }
854
855 void
856 SndFileSource::clear_capture_marks ()
857 {
858         _capture_start = false;
859         _capture_end = false;
860 }
861
862 /** @param pos Capture start position in session samples */
863 void
864 SndFileSource::mark_capture_start (samplepos_t pos)
865 {
866         if (destructive()) {
867                 if (pos < _timeline_position) {
868                         _capture_start = false;
869                 } else {
870                         _capture_start = true;
871                         capture_start_sample = pos;
872                 }
873         }
874 }
875
876 void
877 SndFileSource::mark_capture_end()
878 {
879         if (destructive()) {
880                 _capture_end = true;
881         }
882 }
883
884 samplecnt_t
885 SndFileSource::crossfade (Sample* data, samplecnt_t cnt, int fade_in)
886 {
887         samplecnt_t xfade = min (xfade_samples, cnt);
888         samplecnt_t nofade = cnt - xfade;
889         Sample* fade_data = 0;
890         samplepos_t fade_position = 0; // in samples
891         ssize_t retval;
892         samplecnt_t file_cnt;
893
894         if (fade_in) {
895                 fade_position = file_pos;
896                 fade_data = data;
897         } else {
898                 fade_position = file_pos + nofade;
899                 fade_data = data + nofade;
900         }
901
902         if (fade_position > _length) {
903
904                 /* read starts beyond end of data, just memset to zero */
905
906                 file_cnt = 0;
907
908         } else if (fade_position + xfade > _length) {
909
910                 /* read ends beyond end of data, read some, memset the rest */
911
912                 file_cnt = _length - fade_position;
913
914         } else {
915
916                 /* read is entirely within data */
917
918                 file_cnt = xfade;
919         }
920
921         if (file_cnt) {
922
923                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
924                         if (retval >= 0 && errno == EAGAIN) {
925                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
926                                  * short or no data there */
927                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
928                         } else {
929                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
930                                 return 0;
931                         }
932                 }
933         }
934
935         if (file_cnt != xfade) {
936                 samplecnt_t delta = xfade - file_cnt;
937                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
938         }
939
940         if (nofade && !fade_in) {
941                 if (write_float (data, file_pos, nofade) != nofade) {
942                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
943                         return 0;
944                 }
945         }
946
947         if (xfade == xfade_samples) {
948
949                 samplecnt_t n;
950
951                 /* use the standard xfade curve */
952
953                 if (fade_in) {
954
955                         /* fade new material in */
956
957                         for (n = 0; n < xfade; ++n) {
958                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
959                         }
960
961                 } else {
962
963
964                         /* fade new material out */
965
966                         for (n = 0; n < xfade; ++n) {
967                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
968                         }
969                 }
970
971         } else if (xfade < xfade_samples) {
972
973                 std::vector<gain_t> in(xfade);
974                 std::vector<gain_t> out(xfade);
975
976                 /* short xfade, compute custom curve */
977
978                 compute_equal_power_fades (xfade, &in[0], &out[0]);
979
980                 for (samplecnt_t n = 0; n < xfade; ++n) {
981                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
982                 }
983
984         } else if (xfade) {
985
986                 /* long xfade length, has to be computed across several calls */
987
988         }
989
990         if (xfade) {
991                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
992                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
993                         return 0;
994                 }
995         }
996
997         if (fade_in && nofade) {
998                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
999                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
1000                         return 0;
1001                 }
1002         }
1003
1004         return cnt;
1005 }
1006
1007 samplepos_t
1008 SndFileSource::last_capture_start_sample () const
1009 {
1010         if (destructive()) {
1011                 return capture_start_sample;
1012         } else {
1013                 return 0;
1014         }
1015 }
1016
1017 void
1018 SndFileSource::handle_header_position_change ()
1019 {
1020         if (destructive()) {
1021                 if ( _length != 0 ) {
1022                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
1023                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
1024                 } else if (writable()) {
1025                         _timeline_position = header_position_offset;
1026                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
1027                 }
1028         }
1029 }
1030
1031 void
1032 SndFileSource::setup_standard_crossfades (Session const & s, samplecnt_t rate)
1033 {
1034         /* This static method is assumed to have been called by the Session
1035            before any DFS's are created.
1036         */
1037
1038         xfade_samples = (samplecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
1039
1040         delete [] out_coefficient;
1041         delete [] in_coefficient;
1042
1043         out_coefficient = new gain_t[xfade_samples];
1044         in_coefficient = new gain_t[xfade_samples];
1045
1046         compute_equal_power_fades (xfade_samples, in_coefficient, out_coefficient);
1047 }
1048
1049 void
1050 SndFileSource::set_timeline_position (samplepos_t pos)
1051 {
1052         // destructive track timeline postion does not change
1053         // except at instantion or when header_position_offset
1054         // (session start) changes
1055
1056         if (!destructive()) {
1057                 AudioFileSource::set_timeline_position (pos);
1058         }
1059 }
1060
1061 int
1062 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
1063 {
1064         SNDFILE *sf;
1065         SF_INFO sf_info;
1066         BroadcastInfo binfo;
1067
1068         sf_info.format = 0; // libsndfile says to clear this before sf_open().
1069
1070         if (path.empty() || Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
1071                 return false;
1072         }
1073
1074 #ifdef PLATFORM_WINDOWS
1075         int fd = g_open (path.c_str(), O_RDONLY, 0444);
1076 #else
1077         int fd = ::open (path.c_str(), O_RDONLY, 0444);
1078 #endif
1079
1080         if (fd == -1) {
1081                 error << string_compose ( _("SndFileSource: cannot open file \"%1\" for reading"), path)
1082                       << endmsg;
1083                 return false;
1084         }
1085         if ((sf = sf_open_fd (fd, SFM_READ, &sf_info, true)) == 0) {
1086                 char errbuf[1024];
1087                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
1088                 return false;
1089         }
1090
1091         info.samplerate  = sf_info.samplerate;
1092         info.channels    = sf_info.channels;
1093         info.length      = sf_info.frames;
1094
1095         string major = sndfile_major_format(sf_info.format);
1096         string minor = sndfile_minor_format(sf_info.format);
1097
1098         if (major.length() + minor.length() < 16) { /* arbitrary */
1099                 info.format_name = string_compose("%1/%2", major, minor);
1100         } else {
1101                 info.format_name = string_compose("%1\n%2", major, minor);
1102         }
1103
1104         info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
1105
1106         sf_close (sf);
1107
1108         return true;
1109 }
1110
1111 bool
1112 SndFileSource::one_of_several_channels () const
1113 {
1114         return _info.channels > 1;
1115 }
1116
1117 bool
1118 SndFileSource::clamped_at_unity () const
1119 {
1120         int const type = _info.format & SF_FORMAT_TYPEMASK;
1121         int const sub = _info.format & SF_FORMAT_SUBMASK;
1122         /* XXX: this may not be the full list of formats that are unclamped */
1123         return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
1124 }
1125
1126 void
1127 SndFileSource::file_closed ()
1128 {
1129         /* stupid libsndfile updated the headers on close,
1130            so touch the peakfile if it exists and has data
1131            to make sure its time is as new as the audio
1132            file.
1133         */
1134
1135         touch_peakfile ();
1136 }
1137
1138 void
1139 SndFileSource::set_path (const string& p)
1140 {
1141         FileSource::set_path (p);
1142 }
1143