2 Copyright (C) 2006 Paul Davis
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.
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.
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.
21 #include "libardour-config.h"
30 #include <sys/utsname.h>
33 #include <glibmm/miscutils.h>
35 #include "ardour/sndfilesource.h"
36 #include "ardour/sndfile_helpers.h"
37 #include "ardour/utils.h"
38 #include "ardour/version.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/session.h"
45 using namespace ARDOUR;
49 gain_t* SndFileSource::out_coefficient = 0;
50 gain_t* SndFileSource::in_coefficient = 0;
51 framecnt_t SndFileSource::xfade_frames = 64;
52 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
55 Source::RemovableIfEmpty |
58 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
60 , AudioFileSource (s, node)
65 throw failed_constructor ();
69 /** Files created this way are never writable or removable */
70 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
71 : Source(s, DataType::AUDIO, path, flags)
72 /* note that the origin of an external file is itself */
73 , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
80 throw failed_constructor ();
84 /** This constructor is used to construct new files, not open existing ones. */
85 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
86 SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
87 : Source(s, DataType::AUDIO, path, flags)
88 , AudioFileSource (s, path, origin, flags, sfmt, hf)
99 _flags = Flag (_flags & ~Broadcast);
103 fmt = SF_FORMAT_AIFF;
104 _flags = Flag (_flags & ~Broadcast);
109 _flags = Flag (_flags | Broadcast);
114 _flags = Flag (_flags & ~Broadcast);
119 _flags = Flag (_flags & ~Broadcast);
123 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
131 fmt |= SF_FORMAT_FLOAT;
135 fmt |= SF_FORMAT_PCM_24;
139 fmt |= SF_FORMAT_PCM_16;
144 _info.samplerate = rate;
147 /* do not open the file here - do that in write_unlocked() as needed
152 SndFileSource::init_sndfile ()
158 // lets try to keep the object initalizations here at the top
162 /* although libsndfile says we don't need to set this,
163 valgrind and source code shows us that we do.
166 memset (&_info, 0, sizeof(_info));
168 _capture_start = false;
169 _capture_end = false;
173 xfade_buf = new Sample[xfade_frames];
174 _timeline_position = header_position_offset;
177 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
181 SndFileSource::open ()
183 _descriptor = new SndFileDescriptor (_path, writable(), &_info);
184 _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
185 SNDFILE* sf = _descriptor->allocate ();
189 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
190 #ifndef HAVE_COREAUDIO
191 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
192 so we don't want to see this message.
195 cerr << "failed to open " << _path << " with name " << _name << endl;
197 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
198 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
203 if (_channel >= _info.channels) {
204 #ifndef HAVE_COREAUDIO
205 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
212 _length = _info.frames;
214 if (!_broadcast_info) {
215 _broadcast_info = new BroadcastInfo;
218 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
220 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
222 if (_length != 0 && !bwf_info_exists) {
223 delete _broadcast_info;
225 _flags = Flag (_flags & ~Broadcast);
229 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
231 if (_flags & Broadcast) {
233 if (!_broadcast_info) {
234 _broadcast_info = new BroadcastInfo;
237 _broadcast_info->set_from_session (_session, header_position_offset);
238 _broadcast_info->set_description (string_compose ("BWF %1", _name));
240 if (!_broadcast_info->write_to_file (sf)) {
241 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
242 _path, _broadcast_info->get_error())
244 _flags = Flag (_flags & ~Broadcast);
245 delete _broadcast_info;
251 _descriptor->release ();
256 SndFileSource::~SndFileSource ()
259 delete _broadcast_info;
264 SndFileSource::sample_rate () const
266 return _info.samplerate;
270 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
279 if (writable() && !_open) {
280 /* file has not been opened yet - nothing written to it */
281 memset (dst, 0, sizeof (Sample) * cnt);
285 SNDFILE* sf = _descriptor->allocate ();
288 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
292 if (start > _length) {
294 /* read starts beyond end of data, just memset to zero */
298 } else if (start + cnt > _length) {
300 /* read ends beyond end of data, read some, memset the rest */
302 file_cnt = _length - start;
306 /* read is entirely within data */
311 assert (file_cnt >= 0);
313 if (file_cnt != cnt) {
314 framepos_t delta = cnt - file_cnt;
315 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
320 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
322 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
323 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
324 _descriptor->release ();
328 if (_info.channels == 1) {
329 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
330 if (ret != file_cnt) {
332 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
333 error << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.val().substr (1), errbuf, _length) << endl;
335 _descriptor->release ();
340 real_cnt = cnt * _info.channels;
342 Sample* interleave_buf = get_interleave_buffer (real_cnt);
344 nread = sf_read_float (sf, interleave_buf, real_cnt);
345 ptr = interleave_buf + _channel;
346 nread /= _info.channels;
348 /* stride through the interleaved data */
350 for (int32_t n = 0; n < nread; ++n) {
352 ptr += _info.channels;
355 _descriptor->release ();
360 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
362 if (!_open && open()) {
367 return destructive_write_unlocked (data, cnt);
369 return nondestructive_write_unlocked (data, cnt);
374 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
377 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
381 if (_info.channels != 1) {
382 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
388 int32_t frame_pos = _length;
390 if (write_float (data, frame_pos, cnt) != cnt) {
395 update_length (oldlen, cnt);
397 if (_build_peakfiles) {
398 compute_and_write_peaks (data, frame_pos, cnt, false, true);
405 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
408 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
412 if (_capture_start && _capture_end) {
414 /* start and end of capture both occur within the data we are writing,
415 so do both crossfades.
418 _capture_start = false;
419 _capture_end = false;
421 /* move to the correct location place */
422 file_pos = capture_start_frame - _timeline_position;
425 framecnt_t subcnt = cnt / 2;
426 framecnt_t ofilepos = file_pos;
429 if (crossfade (data, subcnt, 1) != subcnt) {
434 Sample * tmpdata = data + subcnt;
437 subcnt = cnt - subcnt;
438 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
442 file_pos = ofilepos; // adjusted below
444 } else if (_capture_start) {
446 /* start of capture both occur within the data we are writing,
450 _capture_start = false;
451 _capture_end = false;
453 /* move to the correct location place */
454 file_pos = capture_start_frame - _timeline_position;
456 if (crossfade (data, cnt, 1) != cnt) {
460 } else if (_capture_end) {
462 /* end of capture both occur within the data we are writing,
466 _capture_start = false;
467 _capture_end = false;
469 if (crossfade (data, cnt, 0) != cnt) {
475 /* in the middle of recording */
477 if (write_float (data, file_pos, cnt) != cnt) {
482 update_length (file_pos, cnt);
484 if (_build_peakfiles) {
485 compute_and_write_peaks (data, file_pos, cnt, false, true);
494 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
496 set_timeline_position (when);
498 if (_flags & Broadcast) {
499 if (setup_broadcast_info (when, now, tnow)) {
504 return flush_header ();
508 SndFileSource::flush_header ()
511 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
516 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
520 SNDFILE* sf = _descriptor->allocate ();
522 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
526 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
527 _descriptor->release ();
533 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
536 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
541 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
545 if (!(_flags & Broadcast)) {
549 _broadcast_info->set_originator_ref_from_session (_session);
550 _broadcast_info->set_origination_time (&now);
552 /* now update header position taking header offset into account */
554 set_header_timeline_position ();
556 SNDFILE* sf = _descriptor->allocate ();
558 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
559 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
560 _path, _broadcast_info->get_error())
562 _flags = Flag (_flags & ~Broadcast);
563 delete _broadcast_info;
567 _descriptor->release ();
572 SndFileSource::set_header_timeline_position ()
574 if (!(_flags & Broadcast)) {
578 _broadcast_info->set_time_reference (_timeline_position);
580 SNDFILE* sf = _descriptor->allocate ();
582 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
583 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
584 _path, _broadcast_info->get_error())
586 _flags = Flag (_flags & ~Broadcast);
587 delete _broadcast_info;
591 _descriptor->release ();
595 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
597 SNDFILE* sf = _descriptor->allocate ();
599 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
601 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
602 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
603 _descriptor->release ();
607 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
608 _descriptor->release ();
612 _descriptor->release ();
617 SndFileSource::natural_position() const
619 return _timeline_position;
623 SndFileSource::set_destructive (bool yn)
626 _flags = Flag (_flags | Writable | Destructive);
628 xfade_buf = new Sample[xfade_frames];
630 clear_capture_marks ();
631 _timeline_position = header_position_offset;
633 _flags = Flag (_flags & ~Destructive);
634 _timeline_position = 0;
635 /* leave xfade buf alone in case we need it again later */
642 SndFileSource::clear_capture_marks ()
644 _capture_start = false;
645 _capture_end = false;
648 /** @param pos Capture start position in session frames */
650 SndFileSource::mark_capture_start (framepos_t pos)
653 if (pos < _timeline_position) {
654 _capture_start = false;
656 _capture_start = true;
657 capture_start_frame = pos;
663 SndFileSource::mark_capture_end()
671 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
673 framecnt_t xfade = min (xfade_frames, cnt);
674 framecnt_t nofade = cnt - xfade;
675 Sample* fade_data = 0;
676 framepos_t fade_position = 0; // in frames
681 fade_position = file_pos;
684 fade_position = file_pos + nofade;
685 fade_data = data + nofade;
688 if (fade_position > _length) {
690 /* read starts beyond end of data, just memset to zero */
694 } else if (fade_position + xfade > _length) {
696 /* read ends beyond end of data, read some, memset the rest */
698 file_cnt = _length - fade_position;
702 /* read is entirely within data */
709 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
710 if (retval >= 0 && errno == EAGAIN) {
711 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
712 * short or no data there */
713 memset (xfade_buf, 0, xfade * sizeof(Sample));
715 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
721 if (file_cnt != xfade) {
722 framecnt_t delta = xfade - file_cnt;
723 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
726 if (nofade && !fade_in) {
727 if (write_float (data, file_pos, nofade) != nofade) {
728 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
733 if (xfade == xfade_frames) {
737 /* use the standard xfade curve */
741 /* fade new material in */
743 for (n = 0; n < xfade; ++n) {
744 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
750 /* fade new material out */
752 for (n = 0; n < xfade; ++n) {
753 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
757 } else if (xfade < xfade_frames) {
762 /* short xfade, compute custom curve */
764 compute_equal_power_fades (xfade, in, out);
766 for (framecnt_t n = 0; n < xfade; ++n) {
767 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
772 /* long xfade length, has to be computed across several calls */
777 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
778 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
783 if (fade_in && nofade) {
784 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
785 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
794 SndFileSource::last_capture_start_frame () const
797 return capture_start_frame;
804 SndFileSource::handle_header_position_change ()
807 if ( _length != 0 ) {
808 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
809 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
810 } else if (writable()) {
811 _timeline_position = header_position_offset;
812 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
818 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
820 /* This static method is assumed to have been called by the Session
821 before any DFS's are created.
824 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
826 delete [] out_coefficient;
827 delete [] in_coefficient;
829 out_coefficient = new gain_t[xfade_frames];
830 in_coefficient = new gain_t[xfade_frames];
832 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
836 SndFileSource::set_timeline_position (framepos_t pos)
838 // destructive track timeline postion does not change
839 // except at instantion or when header_position_offset
840 // (session start) changes
842 if (!destructive()) {
843 AudioFileSource::set_timeline_position (pos);
848 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
854 sf_info.format = 0; // libsndfile says to clear this before sf_open().
856 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
858 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
862 info.samplerate = sf_info.samplerate;
863 info.channels = sf_info.channels;
864 info.length = sf_info.frames;
866 string major = sndfile_major_format(sf_info.format);
867 string minor = sndfile_minor_format(sf_info.format);
869 if (major.length() + minor.length() < 16) { /* arbitrary */
870 info.format_name = string_compose("%1/%2", major, minor);
872 info.format_name = string_compose("%1\n%2", major, minor);
875 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
883 SndFileSource::one_of_several_channels () const
885 return _info.channels > 1;
889 SndFileSource::clamped_at_unity () const
891 int const type = _info.format & SF_FORMAT_TYPEMASK;
892 int const sub = _info.format & SF_FORMAT_SUBMASK;
893 /* XXX: this may not be the full list of formats that are unclamped */
894 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
898 SndFileSource::file_closed ()
900 /* stupid libsndfile updated the headers on close,
901 so touch the peakfile if it exists and has data
902 to make sure its time is as new as the audio
910 SndFileSource::set_path (const string& p)
912 FileSource::set_path (p);
915 _descriptor->set_path (_path);