2 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3 * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2008-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2012-2018 Robin Gareus <robin@gareus.org>
7 * Copyright (C) 2013-2015 John Emmas <john@creativepost.co.uk>
8 * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "libardour-config.h"
38 #include "pbd/gstdio_compat.h"
40 #include <glibmm/convert.h>
41 #include <glibmm/fileutils.h>
42 #include <glibmm/miscutils.h>
44 #include "ardour/runtime_functions.h"
45 #include "ardour/sndfilesource.h"
46 #include "ardour/sndfile_helpers.h"
47 #include "ardour/utils.h"
48 #include "ardour/session.h"
53 using namespace ARDOUR;
57 gain_t* SndFileSource::out_coefficient = 0;
58 gain_t* SndFileSource::in_coefficient = 0;
59 samplecnt_t SndFileSource::xfade_samples = 64;
60 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
63 Source::RemovableIfEmpty |
66 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
68 , AudioFileSource (s, node)
71 , _capture_start (false)
72 , _capture_end (false)
78 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
82 throw failed_constructor ();
86 /** Constructor for existing external-to-session files.
87 Files created this way are never writable or removable
89 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
90 : Source(s, DataType::AUDIO, path, flags)
91 /* note that the origin of an external file is itself */
92 , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
95 , _capture_start (false)
96 , _capture_end (false)
104 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
108 throw failed_constructor ();
112 /** This constructor is used to construct new internal-to-session files,
113 not open existing ones.
115 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
116 SampleFormat sfmt, HeaderFormat hf, samplecnt_t rate, Flag flags)
117 : Source(s, DataType::AUDIO, path, flags)
118 , AudioFileSource (s, path, origin, flags, sfmt, hf)
120 , _broadcast_info (0)
121 , _capture_start (false)
122 , _capture_end (false)
130 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
138 _flags = Flag (_flags & ~Broadcast);
142 fmt = SF_FORMAT_FLAC;
143 if (sfmt == FormatFloat) {
146 _flags = Flag (_flags & ~Broadcast);
147 _flags = Flag (_flags & ~Destructive); // XXX or force WAV if destructive?
151 fmt = SF_FORMAT_AIFF;
152 _flags = Flag (_flags & ~Broadcast);
157 _flags = Flag (_flags | Broadcast);
162 _flags = Flag (_flags & ~Broadcast);
167 _flags = Flag (_flags & ~Broadcast);
171 fmt = SF_FORMAT_RF64;
172 _flags = Flag (_flags & ~Broadcast);
173 _flags = Flag (_flags | RF64_RIFF);
177 fmt = SF_FORMAT_RF64;
178 _flags = Flag (_flags | Broadcast);
179 _flags = Flag (_flags | RF64_RIFF);
183 fmt = SF_FORMAT_RF64;
184 _flags = Flag (_flags & ~Broadcast);
188 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
189 abort(); /*NOTREACHED*/
196 fmt |= SF_FORMAT_FLOAT;
200 fmt |= SF_FORMAT_PCM_24;
204 fmt |= SF_FORMAT_PCM_16;
209 _info.samplerate = rate;
212 if (_flags & Destructive) {
214 throw failed_constructor();
217 /* normal mode: do not open the file here - do that in {read,write}_unlocked() as needed
222 /** Constructor to be called for recovering files being used for
223 * capture. They are in-session, they already exist, they should not
224 * be writable. They are an odd hybrid (from a constructor point of
225 * view) of the previous two constructors.
227 SndFileSource::SndFileSource (Session& s, const string& path, int chn)
228 : Source (s, DataType::AUDIO, path, Flag (0))
229 /* the final boolean argument is not used, its value is irrelevant. see audiofilesource.h for explanation */
230 , AudioFileSource (s, path, Flag (0))
232 , _broadcast_info (0)
233 , _capture_start (false)
234 , _capture_end (false)
242 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
246 throw failed_constructor ();
250 /** Constructor to losslessly compress existing source to flac */
251 SndFileSource::SndFileSource (Session& s, const AudioFileSource& other, const string& path, bool use16bits, Progress* progress)
252 : Source(s, DataType::AUDIO, path, Flag ((other.flags () | default_writable_flags | NoPeakFile) & ~RF64_RIFF))
253 , AudioFileSource (s, path, "", Flag ((other.flags () | default_writable_flags | NoPeakFile) & ~RF64_RIFF), /*unused*/ FormatFloat, /*unused*/ WAVE64)
255 , _broadcast_info (0)
256 , _capture_start (false)
257 , _capture_end (false)
261 if (other.readable_length () == 0) {
262 throw failed_constructor();
265 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
273 _info.samplerate = other.sample_rate ();
274 _info.format = SF_FORMAT_FLAC | (use16bits ? SF_FORMAT_PCM_16 : SF_FORMAT_PCM_24);
276 /* flac is either read or write -- never both,
277 * so we need to special-case ::open () */
278 #ifdef PLATFORM_WINDOWS
279 int fd = g_open (_path.c_str(), O_CREAT | O_RDWR, 0644);
281 int fd = ::open (_path.c_str(), O_CREAT | O_RDWR, 0644);
284 throw failed_constructor();
287 _sndfile = sf_open_fd (fd, SFM_WRITE, &_info, true);
290 throw failed_constructor();
294 /* setting flac compression quality above the default does not produce a significant size
295 * improvement (not for large raw recordings anyway, the_CLA tests 2017-10-02, >> 250MB files,
296 * ~1% smaller), but does have a significant encoding speed penalty.
298 * We still may expose this as option someday though, perhaps for opposite reason: "fast encoding"
300 double flac_quality = 1; // libsndfile uses range 0..1 (mapped to flac 0..8), default is (5/8)
301 if (sf_command (_sndfile, SFC_SET_COMPRESSION_LEVEL, &flac_quality, sizeof (double)) != SF_TRUE) {
303 sf_error_str (_sndfile, errbuf, sizeof (errbuf) - 1);
304 error << string_compose (_("Cannot set flac compression level: %1"), errbuf) << endmsg;
313 /* normalize before converting to fixed point, calc gain factor */
314 samplecnt_t len = other.read (buf, off, 8192, other.channel ());
316 peak = compute_peak (buf, len, peak);
318 len = other.read (buf, off, 8192, other.channel ());
320 progress->set_progress (0.5f * (float) off / other.readable_length ());
331 len = other.read (buf, off, 8192, other.channel ());
334 for (samplecnt_t i = 0; i < len; ++i) {
340 len = other.read (buf, off, 8192, other.channel ());
342 progress->set_progress (0.5f + 0.5f * (float) off / other.readable_length ());
348 SndFileSource::init_sndfile ()
350 /* although libsndfile says we don't need to set this,
351 valgrind and source code shows us that we do.
354 memset (&_info, 0, sizeof(_info));
357 xfade_buf = new Sample[xfade_samples];
358 _natural_position = header_position_offset;
361 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
365 SndFileSource::close ()
375 SndFileSource::open ()
381 // We really only want to use g_open for all platforms but because of this
382 // method(SndfileSource::open), the compiler(or at least GCC) is confused
383 // because g_open will expand to "open" on non-POSIX systems and needs the
384 // global namespace qualifer. The problem is since since C99 ::g_open will
385 // apparently expand to ":: open"
386 #ifdef PLATFORM_WINDOWS
387 int fd = g_open (_path.c_str(), writable() ? O_CREAT | O_RDWR : O_RDONLY, writable() ? 0644 : 0444);
389 int fd = ::open (_path.c_str(), writable() ? O_CREAT | O_RDWR : O_RDONLY, writable() ? 0644 : 0444);
393 error << string_compose (
394 _ ("SndFileSource: cannot open file \"%1\" for %2"),
396 (writable () ? "read+write" : "reading")) << endmsg;
400 if ((_info.format & SF_FORMAT_TYPEMASK ) == SF_FORMAT_FLAC) {
401 assert (!destructive());
402 _sndfile = sf_open_fd (fd, writable () ? SFM_WRITE : SFM_READ, &_info, true);
404 _sndfile = sf_open_fd (fd, writable() ? SFM_RDWR : SFM_READ, &_info, true);
409 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
410 #ifndef HAVE_COREAUDIO
411 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
412 so we don't want to see this message.
415 cerr << "failed to open " << _path << " with name " << _name << endl;
417 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
418 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
423 if (_channel >= _info.channels) {
424 #ifndef HAVE_COREAUDIO
425 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
432 _length = _info.frames;
434 #ifdef HAVE_RF64_RIFF
435 if (_file_is_new && _length == 0 && writable()) {
436 if (_flags & RF64_RIFF) {
437 if (sf_command (_sndfile, SFC_RF64_AUTO_DOWNGRADE, 0, 0) != SF_TRUE) {
439 sf_error_str (_sndfile, errbuf, sizeof (errbuf) - 1);
440 error << string_compose (_("Cannot mark RF64 audio file for automatic downgrade to WAV: %1"), errbuf)
447 if (!_broadcast_info) {
448 _broadcast_info = new BroadcastInfo;
451 bool bwf_info_exists = _broadcast_info->load_from_file (_sndfile);
453 if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
454 /* newly created files will not have a BWF header at this point in time.
455 * Import will have called Source::set_natural_position() if one exists
456 * in the original. */
457 header_position_offset = _natural_position;
461 /* Set our timeline position to either the time reference from a BWF header or the current
462 start of the session.
464 set_natural_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
466 /* If a BWF header exists, set our _natural_position from it */
467 if (bwf_info_exists) {
468 set_natural_position (_broadcast_info->get_time_reference());
472 if (_length != 0 && !bwf_info_exists) {
473 delete _broadcast_info;
475 _flags = Flag (_flags & ~Broadcast);
478 /* Set the broadcast flag if the BWF info is already there. We need
479 * this when recovering or using existing files.
482 if (bwf_info_exists) {
483 _flags = Flag (_flags | Broadcast);
487 sf_command (_sndfile, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
489 if (_flags & Broadcast) {
491 if (!_broadcast_info) {
492 _broadcast_info = new BroadcastInfo;
495 _broadcast_info->set_from_session (_session, header_position_offset);
496 _broadcast_info->set_description (string_compose ("BWF %1", _name));
498 if (!_broadcast_info->write_to_file (_sndfile)) {
499 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
500 _path, _broadcast_info->get_error())
502 _flags = Flag (_flags & ~Broadcast);
503 delete _broadcast_info;
512 SndFileSource::~SndFileSource ()
515 delete _broadcast_info;
520 SndFileSource::sample_rate () const
522 return _info.samplerate;
526 SndFileSource::read_unlocked (Sample *dst, samplepos_t start, samplecnt_t cnt) const
532 samplecnt_t real_cnt;
533 samplepos_t file_cnt;
535 if (writable() && !_sndfile) {
536 /* file has not been opened yet - nothing written to it */
537 memset (dst, 0, sizeof (Sample) * cnt);
541 if (const_cast<SndFileSource*>(this)->open()) {
542 error << string_compose (_("could not open file %1 for reading."), _path) << endmsg;
546 if (start > _length) {
548 /* read starts beyond end of data, just memset to zero */
552 } else if (start + cnt > _length) {
554 /* read ends beyond end of data, read some, memset the rest */
556 file_cnt = _length - start;
560 /* read is entirely within data */
565 assert (file_cnt >= 0);
567 if (file_cnt != cnt) {
568 samplepos_t delta = cnt - file_cnt;
569 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
574 if (sf_seek (_sndfile, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
576 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
577 error << string_compose(_("SndFileSource: could not seek to sample %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
581 if (_info.channels == 1) {
582 samplecnt_t ret = sf_read_float (_sndfile, dst, file_cnt);
583 if (ret != file_cnt) {
585 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
586 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;
589 for (samplecnt_t i = 0; i < ret; ++i) {
597 real_cnt = cnt * _info.channels;
599 Sample* interleave_buf = get_interleave_buffer (real_cnt);
601 nread = sf_read_float (_sndfile, interleave_buf, real_cnt);
602 ptr = interleave_buf + _channel;
603 nread /= _info.channels;
605 /* stride through the interleaved data */
608 for (samplecnt_t n = 0; n < nread; ++n) {
609 dst[n] = *ptr * _gain;
610 ptr += _info.channels;
613 for (samplecnt_t n = 0; n < nread; ++n) {
615 ptr += _info.channels;
623 SndFileSource::write_unlocked (Sample *data, samplecnt_t cnt)
630 return destructive_write_unlocked (data, cnt);
632 return nondestructive_write_unlocked (data, cnt);
637 SndFileSource::nondestructive_write_unlocked (Sample *data, samplecnt_t cnt)
640 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
644 if (_info.channels != 1) {
645 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
646 abort(); /*NOTREACHED*/
650 samplepos_t sample_pos = _length;
652 if (write_float (data, sample_pos, cnt) != cnt) {
656 update_length (_length + cnt);
658 if (_build_peakfiles) {
659 compute_and_write_peaks (data, sample_pos, cnt, true, true);
666 SndFileSource::destructive_write_unlocked (Sample* data, samplecnt_t cnt)
669 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
673 if (_capture_start && _capture_end) {
675 /* start and end of capture both occur within the data we are writing,
676 so do both crossfades.
679 _capture_start = false;
680 _capture_end = false;
682 /* move to the correct location place */
683 file_pos = capture_start_sample - _natural_position;
686 samplecnt_t subcnt = cnt / 2;
687 samplecnt_t ofilepos = file_pos;
690 if (crossfade (data, subcnt, 1) != subcnt) {
695 Sample * tmpdata = data + subcnt;
698 subcnt = cnt - subcnt;
699 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
703 file_pos = ofilepos; // adjusted below
705 } else if (_capture_start) {
707 /* start of capture both occur within the data we are writing,
711 _capture_start = false;
712 _capture_end = false;
714 /* move to the correct location place */
715 file_pos = capture_start_sample - _natural_position;
717 if (crossfade (data, cnt, 1) != cnt) {
721 } else if (_capture_end) {
723 /* end of capture both occur within the data we are writing,
727 _capture_start = false;
728 _capture_end = false;
730 if (crossfade (data, cnt, 0) != cnt) {
736 /* in the middle of recording */
738 if (write_float (data, file_pos, cnt) != cnt) {
743 update_length (file_pos + cnt);
745 if (_build_peakfiles) {
746 compute_and_write_peaks (data, file_pos, cnt, true, true);
755 SndFileSource::update_header (samplepos_t when, struct tm& now, time_t tnow)
757 set_natural_position (when);
759 if (_flags & Broadcast) {
760 if (setup_broadcast_info (when, now, tnow)) {
765 return flush_header ();
769 SndFileSource::flush_header ()
772 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
777 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
781 int const r = sf_command (_sndfile, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
787 SndFileSource::flush ()
790 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
795 error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
799 // Hopefully everything OK
800 sf_write_sync (_sndfile);
804 SndFileSource::setup_broadcast_info (samplepos_t /*when*/, struct tm& now, time_t /*tnow*/)
807 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
812 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
816 if (!(_flags & Broadcast) || !_broadcast_info) {
820 _broadcast_info->set_originator_ref_from_session (_session);
821 _broadcast_info->set_origination_time (&now);
823 /* now update header position taking header offset into account */
825 set_header_natural_position ();
831 SndFileSource::set_header_natural_position ()
833 if (!(_flags & Broadcast)) {
836 assert (_broadcast_info);
838 _broadcast_info->set_time_reference (_natural_position);
840 if (_sndfile == 0 || !_broadcast_info->write_to_file (_sndfile)) {
841 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
842 _path, _broadcast_info->get_error())
844 _flags = Flag (_flags & ~Broadcast);
845 delete _broadcast_info;
851 SndFileSource::write_float (Sample* data, samplepos_t sample_pos, samplecnt_t cnt)
853 if ((_info.format & SF_FORMAT_TYPEMASK ) == SF_FORMAT_FLAC) {
854 assert (_length == sample_pos);
856 else if (_sndfile == 0 || sf_seek (_sndfile, sample_pos, SEEK_SET|SFM_WRITE) < 0) {
858 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
859 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, sample_pos, errbuf) << endmsg;
863 if (sf_writef_float (_sndfile, data, cnt) != (ssize_t) cnt) {
871 SndFileSource::clear_capture_marks ()
873 _capture_start = false;
874 _capture_end = false;
877 /** @param pos Capture start position in session samples */
879 SndFileSource::mark_capture_start (samplepos_t pos)
882 if (pos < _natural_position) {
883 _capture_start = false;
885 _capture_start = true;
886 capture_start_sample = pos;
892 SndFileSource::mark_capture_end()
900 SndFileSource::crossfade (Sample* data, samplecnt_t cnt, int fade_in)
902 samplecnt_t xfade = min (xfade_samples, cnt);
903 samplecnt_t nofade = cnt - xfade;
904 Sample* fade_data = 0;
905 samplepos_t fade_position = 0; // in samples
907 samplecnt_t file_cnt;
910 fade_position = file_pos;
913 fade_position = file_pos + nofade;
914 fade_data = data + nofade;
917 if (fade_position > _length) {
919 /* read starts beyond end of data, just memset to zero */
923 } else if (fade_position + xfade > _length) {
925 /* read ends beyond end of data, read some, memset the rest */
927 file_cnt = _length - fade_position;
931 /* read is entirely within data */
938 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
939 if (retval >= 0 && errno == EAGAIN) {
940 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
941 * short or no data there */
942 memset (xfade_buf, 0, xfade * sizeof(Sample));
944 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
950 if (file_cnt != xfade) {
951 samplecnt_t delta = xfade - file_cnt;
952 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
955 if (nofade && !fade_in) {
956 if (write_float (data, file_pos, nofade) != nofade) {
957 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
962 if (xfade == xfade_samples) {
966 /* use the standard xfade curve */
970 /* fade new material in */
972 for (n = 0; n < xfade; ++n) {
973 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
979 /* fade new material out */
981 for (n = 0; n < xfade; ++n) {
982 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
986 } else if (xfade < xfade_samples) {
988 std::vector<gain_t> in(xfade);
989 std::vector<gain_t> out(xfade);
991 /* short xfade, compute custom curve */
993 compute_equal_power_fades (xfade, &in[0], &out[0]);
995 for (samplecnt_t n = 0; n < xfade; ++n) {
996 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
1001 /* long xfade length, has to be computed across several calls */
1006 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
1007 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
1012 if (fade_in && nofade) {
1013 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
1014 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
1023 SndFileSource::last_capture_start_sample () const
1025 if (destructive()) {
1026 return capture_start_sample;
1033 SndFileSource::handle_header_position_change ()
1035 if (destructive()) {
1036 if ( _length != 0 ) {
1037 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
1038 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
1039 } else if (writable()) {
1040 _natural_position = header_position_offset;
1041 set_header_natural_position (); //this will get flushed if/when the file is recorded to
1047 SndFileSource::setup_standard_crossfades (Session const & s, samplecnt_t rate)
1049 /* This static method is assumed to have been called by the Session
1050 before any DFS's are created.
1053 xfade_samples = (samplecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
1055 delete [] out_coefficient;
1056 delete [] in_coefficient;
1058 out_coefficient = new gain_t[xfade_samples];
1059 in_coefficient = new gain_t[xfade_samples];
1061 compute_equal_power_fades (xfade_samples, in_coefficient, out_coefficient);
1065 SndFileSource::set_natural_position (samplepos_t pos)
1067 // destructive track timeline postion does not change
1068 // except at instantion or when header_position_offset
1069 // (session start) changes
1071 if (!destructive()) {
1072 AudioFileSource::set_natural_position (pos);
1077 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
1081 BroadcastInfo binfo;
1083 sf_info.format = 0; // libsndfile says to clear this before sf_open().
1085 if (path.empty() || Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
1089 #ifdef PLATFORM_WINDOWS
1090 int fd = g_open (path.c_str(), O_RDONLY, 0444);
1092 int fd = ::open (path.c_str(), O_RDONLY, 0444);
1096 error << string_compose ( _("SndFileSource: cannot open file \"%1\" for reading"), path)
1100 if ((sf = sf_open_fd (fd, SFM_READ, &sf_info, true)) == 0) {
1102 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
1106 info.samplerate = sf_info.samplerate;
1107 info.channels = sf_info.channels;
1108 info.length = sf_info.frames;
1110 string major = sndfile_major_format(sf_info.format);
1111 string minor = sndfile_minor_format(sf_info.format);
1113 if (major.length() + minor.length() < 16) { /* arbitrary */
1114 info.format_name = string_compose("%1/%2", major, minor);
1116 info.format_name = string_compose("%1\n%2", major, minor);
1119 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
1127 SndFileSource::one_of_several_channels () const
1129 return _info.channels > 1;
1133 SndFileSource::clamped_at_unity () const
1135 int const type = _info.format & SF_FORMAT_TYPEMASK;
1136 int const sub = _info.format & SF_FORMAT_SUBMASK;
1137 /* XXX: this may not be the full list of formats that are unclamped */
1138 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
1142 SndFileSource::file_closed ()
1144 /* stupid libsndfile updated the headers on close,
1145 so touch the peakfile if it exists and has data
1146 to make sure its time is as new as the audio
1154 SndFileSource::set_path (const string& p)
1156 FileSource::set_path (p);