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 if (_flags & Destructive) {
149 throw failed_constructor();
152 /* normal mode: do not open the file here - do that in write_unlocked() as needed
158 SndFileSource::init_sndfile ()
164 // lets try to keep the object initalizations here at the top
168 /* although libsndfile says we don't need to set this,
169 valgrind and source code shows us that we do.
172 memset (&_info, 0, sizeof(_info));
174 _capture_start = false;
175 _capture_end = false;
179 xfade_buf = new Sample[xfade_frames];
180 _timeline_position = header_position_offset;
183 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
187 SndFileSource::open ()
189 _descriptor = new SndFileDescriptor (_path, writable(), &_info);
190 _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
191 SNDFILE* sf = _descriptor->allocate ();
195 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
196 #ifndef HAVE_COREAUDIO
197 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
198 so we don't want to see this message.
201 cerr << "failed to open " << _path << " with name " << _name << endl;
203 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
204 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
209 if (_channel >= _info.channels) {
210 #ifndef HAVE_COREAUDIO
211 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
218 _length = _info.frames;
220 if (!_broadcast_info) {
221 _broadcast_info = new BroadcastInfo;
224 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
226 /* Set our timeline position to either the time reference from a BWF header or the current
227 start of the session.
229 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
231 if (_length != 0 && !bwf_info_exists) {
232 delete _broadcast_info;
234 _flags = Flag (_flags & ~Broadcast);
238 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
240 if (_flags & Broadcast) {
242 if (!_broadcast_info) {
243 _broadcast_info = new BroadcastInfo;
246 _broadcast_info->set_from_session (_session, header_position_offset);
247 _broadcast_info->set_description (string_compose ("BWF %1", _name));
249 if (!_broadcast_info->write_to_file (sf)) {
250 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
251 _path, _broadcast_info->get_error())
253 _flags = Flag (_flags & ~Broadcast);
254 delete _broadcast_info;
260 _descriptor->release ();
265 SndFileSource::~SndFileSource ()
268 delete _broadcast_info;
273 SndFileSource::sample_rate () const
275 return _info.samplerate;
279 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
288 if (writable() && !_open) {
289 /* file has not been opened yet - nothing written to it */
290 memset (dst, 0, sizeof (Sample) * cnt);
294 SNDFILE* sf = _descriptor->allocate ();
297 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
301 if (start > _length) {
303 /* read starts beyond end of data, just memset to zero */
307 } else if (start + cnt > _length) {
309 /* read ends beyond end of data, read some, memset the rest */
311 file_cnt = _length - start;
315 /* read is entirely within data */
320 assert (file_cnt >= 0);
322 if (file_cnt != cnt) {
323 framepos_t delta = cnt - file_cnt;
324 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
329 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
331 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
332 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
333 _descriptor->release ();
337 if (_info.channels == 1) {
338 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
339 if (ret != file_cnt) {
341 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
342 error << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.val().substr (1), errbuf, _length) << endl;
344 _descriptor->release ();
349 real_cnt = cnt * _info.channels;
351 Sample* interleave_buf = get_interleave_buffer (real_cnt);
353 nread = sf_read_float (sf, interleave_buf, real_cnt);
354 ptr = interleave_buf + _channel;
355 nread /= _info.channels;
357 /* stride through the interleaved data */
359 for (int32_t n = 0; n < nread; ++n) {
361 ptr += _info.channels;
364 _descriptor->release ();
369 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
371 if (!_open && open()) {
376 return destructive_write_unlocked (data, cnt);
378 return nondestructive_write_unlocked (data, cnt);
383 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
386 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
390 if (_info.channels != 1) {
391 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
397 int32_t frame_pos = _length;
399 if (write_float (data, frame_pos, cnt) != cnt) {
404 update_length (oldlen, cnt);
406 if (_build_peakfiles) {
407 compute_and_write_peaks (data, frame_pos, cnt, false, true);
414 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
417 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
421 if (_capture_start && _capture_end) {
423 /* start and end of capture both occur within the data we are writing,
424 so do both crossfades.
427 _capture_start = false;
428 _capture_end = false;
430 /* move to the correct location place */
431 file_pos = capture_start_frame - _timeline_position;
434 framecnt_t subcnt = cnt / 2;
435 framecnt_t ofilepos = file_pos;
438 if (crossfade (data, subcnt, 1) != subcnt) {
443 Sample * tmpdata = data + subcnt;
446 subcnt = cnt - subcnt;
447 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
451 file_pos = ofilepos; // adjusted below
453 } else if (_capture_start) {
455 /* start of capture both occur within the data we are writing,
459 _capture_start = false;
460 _capture_end = false;
462 /* move to the correct location place */
463 file_pos = capture_start_frame - _timeline_position;
465 if (crossfade (data, cnt, 1) != cnt) {
469 } else if (_capture_end) {
471 /* end of capture both occur within the data we are writing,
475 _capture_start = false;
476 _capture_end = false;
478 if (crossfade (data, cnt, 0) != cnt) {
484 /* in the middle of recording */
486 if (write_float (data, file_pos, cnt) != cnt) {
491 update_length (file_pos, cnt);
493 if (_build_peakfiles) {
494 compute_and_write_peaks (data, file_pos, cnt, false, true);
503 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
505 set_timeline_position (when);
507 if (_flags & Broadcast) {
508 if (setup_broadcast_info (when, now, tnow)) {
513 return flush_header ();
517 SndFileSource::flush_header ()
520 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
525 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
529 SNDFILE* sf = _descriptor->allocate ();
531 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
535 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
536 _descriptor->release ();
542 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
545 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
550 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
554 if (!(_flags & Broadcast)) {
558 _broadcast_info->set_originator_ref_from_session (_session);
559 _broadcast_info->set_origination_time (&now);
561 /* now update header position taking header offset into account */
563 set_header_timeline_position ();
565 SNDFILE* sf = _descriptor->allocate ();
567 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
568 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
569 _path, _broadcast_info->get_error())
571 _flags = Flag (_flags & ~Broadcast);
572 delete _broadcast_info;
576 _descriptor->release ();
581 SndFileSource::set_header_timeline_position ()
583 if (!(_flags & Broadcast)) {
587 _broadcast_info->set_time_reference (_timeline_position);
589 SNDFILE* sf = _descriptor->allocate ();
591 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
592 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
593 _path, _broadcast_info->get_error())
595 _flags = Flag (_flags & ~Broadcast);
596 delete _broadcast_info;
600 _descriptor->release ();
604 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
606 SNDFILE* sf = _descriptor->allocate ();
608 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
610 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
611 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
612 _descriptor->release ();
616 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
617 _descriptor->release ();
621 _descriptor->release ();
626 SndFileSource::natural_position() const
628 return _timeline_position;
632 SndFileSource::set_destructive (bool yn)
635 _flags = Flag (_flags | Writable | Destructive);
637 xfade_buf = new Sample[xfade_frames];
639 clear_capture_marks ();
640 _timeline_position = header_position_offset;
642 _flags = Flag (_flags & ~Destructive);
643 _timeline_position = 0;
644 /* leave xfade buf alone in case we need it again later */
651 SndFileSource::clear_capture_marks ()
653 _capture_start = false;
654 _capture_end = false;
657 /** @param pos Capture start position in session frames */
659 SndFileSource::mark_capture_start (framepos_t pos)
662 if (pos < _timeline_position) {
663 _capture_start = false;
665 _capture_start = true;
666 capture_start_frame = pos;
672 SndFileSource::mark_capture_end()
680 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
682 framecnt_t xfade = min (xfade_frames, cnt);
683 framecnt_t nofade = cnt - xfade;
684 Sample* fade_data = 0;
685 framepos_t fade_position = 0; // in frames
690 fade_position = file_pos;
693 fade_position = file_pos + nofade;
694 fade_data = data + nofade;
697 if (fade_position > _length) {
699 /* read starts beyond end of data, just memset to zero */
703 } else if (fade_position + xfade > _length) {
705 /* read ends beyond end of data, read some, memset the rest */
707 file_cnt = _length - fade_position;
711 /* read is entirely within data */
718 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
719 if (retval >= 0 && errno == EAGAIN) {
720 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
721 * short or no data there */
722 memset (xfade_buf, 0, xfade * sizeof(Sample));
724 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
730 if (file_cnt != xfade) {
731 framecnt_t delta = xfade - file_cnt;
732 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
735 if (nofade && !fade_in) {
736 if (write_float (data, file_pos, nofade) != nofade) {
737 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
742 if (xfade == xfade_frames) {
746 /* use the standard xfade curve */
750 /* fade new material in */
752 for (n = 0; n < xfade; ++n) {
753 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
759 /* fade new material out */
761 for (n = 0; n < xfade; ++n) {
762 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
766 } else if (xfade < xfade_frames) {
771 /* short xfade, compute custom curve */
773 compute_equal_power_fades (xfade, in, out);
775 for (framecnt_t n = 0; n < xfade; ++n) {
776 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
781 /* long xfade length, has to be computed across several calls */
786 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
787 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
792 if (fade_in && nofade) {
793 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
794 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
803 SndFileSource::last_capture_start_frame () const
806 return capture_start_frame;
813 SndFileSource::handle_header_position_change ()
816 if ( _length != 0 ) {
817 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
818 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
819 } else if (writable()) {
820 _timeline_position = header_position_offset;
821 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
827 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
829 /* This static method is assumed to have been called by the Session
830 before any DFS's are created.
833 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
835 delete [] out_coefficient;
836 delete [] in_coefficient;
838 out_coefficient = new gain_t[xfade_frames];
839 in_coefficient = new gain_t[xfade_frames];
841 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
845 SndFileSource::set_timeline_position (framepos_t pos)
847 // destructive track timeline postion does not change
848 // except at instantion or when header_position_offset
849 // (session start) changes
851 if (!destructive()) {
852 AudioFileSource::set_timeline_position (pos);
857 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
863 sf_info.format = 0; // libsndfile says to clear this before sf_open().
865 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
867 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
871 info.samplerate = sf_info.samplerate;
872 info.channels = sf_info.channels;
873 info.length = sf_info.frames;
875 string major = sndfile_major_format(sf_info.format);
876 string minor = sndfile_minor_format(sf_info.format);
878 if (major.length() + minor.length() < 16) { /* arbitrary */
879 info.format_name = string_compose("%1/%2", major, minor);
881 info.format_name = string_compose("%1\n%2", major, minor);
884 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
892 SndFileSource::one_of_several_channels () const
894 return _info.channels > 1;
898 SndFileSource::clamped_at_unity () const
900 int const type = _info.format & SF_FORMAT_TYPEMASK;
901 int const sub = _info.format & SF_FORMAT_SUBMASK;
902 /* XXX: this may not be the full list of formats that are unclamped */
903 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
907 SndFileSource::file_closed ()
909 /* stupid libsndfile updated the headers on close,
910 so touch the peakfile if it exists and has data
911 to make sure its time is as new as the audio
919 SndFileSource::set_path (const string& p)
921 FileSource::set_path (p);
924 _descriptor->set_path (_path);