Non-numeric Properties are not automatable
[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 void
841 SndFileSource::clear_capture_marks ()
842 {
843         _capture_start = false;
844         _capture_end = false;
845 }
846
847 /** @param pos Capture start position in session frames */
848 void
849 SndFileSource::mark_capture_start (framepos_t pos)
850 {
851         if (destructive()) {
852                 if (pos < _timeline_position) {
853                         _capture_start = false;
854                 } else {
855                         _capture_start = true;
856                         capture_start_frame = pos;
857                 }
858         }
859 }
860
861 void
862 SndFileSource::mark_capture_end()
863 {
864         if (destructive()) {
865                 _capture_end = true;
866         }
867 }
868
869 framecnt_t
870 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
871 {
872         framecnt_t xfade = min (xfade_frames, cnt);
873         framecnt_t nofade = cnt - xfade;
874         Sample* fade_data = 0;
875         framepos_t fade_position = 0; // in frames
876         ssize_t retval;
877         framecnt_t file_cnt;
878
879         if (fade_in) {
880                 fade_position = file_pos;
881                 fade_data = data;
882         } else {
883                 fade_position = file_pos + nofade;
884                 fade_data = data + nofade;
885         }
886
887         if (fade_position > _length) {
888
889                 /* read starts beyond end of data, just memset to zero */
890
891                 file_cnt = 0;
892
893         } else if (fade_position + xfade > _length) {
894
895                 /* read ends beyond end of data, read some, memset the rest */
896
897                 file_cnt = _length - fade_position;
898
899         } else {
900
901                 /* read is entirely within data */
902
903                 file_cnt = xfade;
904         }
905
906         if (file_cnt) {
907
908                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
909                         if (retval >= 0 && errno == EAGAIN) {
910                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
911                                  * short or no data there */
912                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
913                         } else {
914                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
915                                 return 0;
916                         }
917                 }
918         }
919
920         if (file_cnt != xfade) {
921                 framecnt_t delta = xfade - file_cnt;
922                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
923         }
924
925         if (nofade && !fade_in) {
926                 if (write_float (data, file_pos, nofade) != nofade) {
927                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
928                         return 0;
929                 }
930         }
931
932         if (xfade == xfade_frames) {
933
934                 framecnt_t n;
935
936                 /* use the standard xfade curve */
937
938                 if (fade_in) {
939
940                         /* fade new material in */
941
942                         for (n = 0; n < xfade; ++n) {
943                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
944                         }
945
946                 } else {
947
948
949                         /* fade new material out */
950
951                         for (n = 0; n < xfade; ++n) {
952                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
953                         }
954                 }
955
956         } else if (xfade < xfade_frames) {
957
958                 std::vector<gain_t> in(xfade);
959                 std::vector<gain_t> out(xfade);
960
961                 /* short xfade, compute custom curve */
962
963                 compute_equal_power_fades (xfade, &in[0], &out[0]);
964
965                 for (framecnt_t n = 0; n < xfade; ++n) {
966                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
967                 }
968
969         } else if (xfade) {
970
971                 /* long xfade length, has to be computed across several calls */
972
973         }
974
975         if (xfade) {
976                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
977                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
978                         return 0;
979                 }
980         }
981
982         if (fade_in && nofade) {
983                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
984                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
985                         return 0;
986                 }
987         }
988
989         return cnt;
990 }
991
992 framepos_t
993 SndFileSource::last_capture_start_frame () const
994 {
995         if (destructive()) {
996                 return capture_start_frame;
997         } else {
998                 return 0;
999         }
1000 }
1001
1002 void
1003 SndFileSource::handle_header_position_change ()
1004 {
1005         if (destructive()) {
1006                 if ( _length != 0 ) {
1007                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
1008                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
1009                 } else if (writable()) {
1010                         _timeline_position = header_position_offset;
1011                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
1012                 }
1013         }
1014 }
1015
1016 void
1017 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
1018 {
1019         /* This static method is assumed to have been called by the Session
1020            before any DFS's are created.
1021         */
1022
1023         xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
1024
1025         delete [] out_coefficient;
1026         delete [] in_coefficient;
1027
1028         out_coefficient = new gain_t[xfade_frames];
1029         in_coefficient = new gain_t[xfade_frames];
1030
1031         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
1032 }
1033
1034 void
1035 SndFileSource::set_timeline_position (framepos_t pos)
1036 {
1037         // destructive track timeline postion does not change
1038         // except at instantion or when header_position_offset
1039         // (session start) changes
1040
1041         if (!destructive()) {
1042                 AudioFileSource::set_timeline_position (pos);
1043         }
1044 }
1045
1046 int
1047 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
1048 {
1049         SNDFILE *sf;
1050         SF_INFO sf_info;
1051         BroadcastInfo binfo;
1052
1053         sf_info.format = 0; // libsndfile says to clear this before sf_open().
1054
1055         if (path.empty() || Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
1056                 return false;
1057         }
1058
1059 #ifdef PLATFORM_WINDOWS
1060         int fd = g_open (path.c_str(), O_RDONLY, 0444);
1061 #else
1062         int fd = ::open (path.c_str(), O_RDONLY, 0444);
1063 #endif
1064
1065         if (fd == -1) {
1066                 error << string_compose ( _("SndFileSource: cannot open file \"%1\" for reading"), path)
1067                       << endmsg;
1068                 return false;
1069         }
1070         if ((sf = sf_open_fd (fd, SFM_READ, &sf_info, true)) == 0) {
1071                 char errbuf[1024];
1072                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
1073                 return false;
1074         }
1075
1076         info.samplerate  = sf_info.samplerate;
1077         info.channels    = sf_info.channels;
1078         info.length      = sf_info.frames;
1079
1080         string major = sndfile_major_format(sf_info.format);
1081         string minor = sndfile_minor_format(sf_info.format);
1082
1083         if (major.length() + minor.length() < 16) { /* arbitrary */
1084                 info.format_name = string_compose("%1/%2", major, minor);
1085         } else {
1086                 info.format_name = string_compose("%1\n%2", major, minor);
1087         }
1088
1089         info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
1090
1091         sf_close (sf);
1092
1093         return true;
1094 }
1095
1096 bool
1097 SndFileSource::one_of_several_channels () const
1098 {
1099         return _info.channels > 1;
1100 }
1101
1102 bool
1103 SndFileSource::clamped_at_unity () const
1104 {
1105         int const type = _info.format & SF_FORMAT_TYPEMASK;
1106         int const sub = _info.format & SF_FORMAT_SUBMASK;
1107         /* XXX: this may not be the full list of formats that are unclamped */
1108         return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
1109 }
1110
1111 void
1112 SndFileSource::file_closed ()
1113 {
1114         /* stupid libsndfile updated the headers on close,
1115            so touch the peakfile if it exists and has data
1116            to make sure its time is as new as the audio
1117            file.
1118         */
1119
1120         touch_peakfile ();
1121 }
1122
1123 void
1124 SndFileSource::set_path (const string& p)
1125 {
1126         FileSource::set_path (p);
1127 }
1128