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/session.h"
43 using namespace ARDOUR;
47 gain_t* SndFileSource::out_coefficient = 0;
48 gain_t* SndFileSource::in_coefficient = 0;
49 framecnt_t SndFileSource::xfade_frames = 64;
50 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
53 Source::RemovableIfEmpty |
56 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
58 , AudioFileSource (s, node)
63 throw failed_constructor ();
67 /** Files created this way are never writable or removable */
68 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
69 : Source(s, DataType::AUDIO, path, flags)
70 /* note that the origin of an external file is itself */
71 , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
78 throw failed_constructor ();
82 /** This constructor is used to construct new files, not open existing ones. */
83 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
84 SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
85 : Source(s, DataType::AUDIO, path, flags)
86 , AudioFileSource (s, path, origin, flags, sfmt, hf)
97 _flags = Flag (_flags & ~Broadcast);
101 fmt = SF_FORMAT_AIFF;
102 _flags = Flag (_flags & ~Broadcast);
107 _flags = Flag (_flags | Broadcast);
112 _flags = Flag (_flags & ~Broadcast);
117 _flags = Flag (_flags & ~Broadcast);
121 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
129 fmt |= SF_FORMAT_FLOAT;
133 fmt |= SF_FORMAT_PCM_24;
137 fmt |= SF_FORMAT_PCM_16;
142 _info.samplerate = rate;
145 if (_flags & Destructive) {
147 throw failed_constructor();
150 /* normal mode: do not open the file here - do that in write_unlocked() as needed
156 SndFileSource::init_sndfile ()
162 // lets try to keep the object initalizations here at the top
166 /* although libsndfile says we don't need to set this,
167 valgrind and source code shows us that we do.
170 memset (&_info, 0, sizeof(_info));
172 _capture_start = false;
173 _capture_end = false;
177 xfade_buf = new Sample[xfade_frames];
178 _timeline_position = header_position_offset;
181 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
185 SndFileSource::open ()
187 _descriptor = new SndFileDescriptor (_path, writable(), &_info);
188 _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
189 SNDFILE* sf = _descriptor->allocate ();
193 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
194 #ifndef HAVE_COREAUDIO
195 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
196 so we don't want to see this message.
199 cerr << "failed to open " << _path << " with name " << _name << endl;
201 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
202 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
207 if (_channel >= _info.channels) {
208 #ifndef HAVE_COREAUDIO
209 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
216 _length = _info.frames;
218 if (!_broadcast_info) {
219 _broadcast_info = new BroadcastInfo;
222 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
224 if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
225 /* newly created files will not have a BWF header at this point in time.
226 * Import will have called Source::set_timeline_position() if one exists
227 * in the original. */
228 header_position_offset = _timeline_position;
231 /* Set our timeline position to either the time reference from a BWF header or the current
232 start of the session.
234 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
236 if (_length != 0 && !bwf_info_exists) {
237 delete _broadcast_info;
239 _flags = Flag (_flags & ~Broadcast);
243 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
245 if (_flags & Broadcast) {
247 if (!_broadcast_info) {
248 _broadcast_info = new BroadcastInfo;
251 _broadcast_info->set_from_session (_session, header_position_offset);
252 _broadcast_info->set_description (string_compose ("BWF %1", _name));
254 if (!_broadcast_info->write_to_file (sf)) {
255 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
256 _path, _broadcast_info->get_error())
258 _flags = Flag (_flags & ~Broadcast);
259 delete _broadcast_info;
265 _descriptor->release ();
270 SndFileSource::~SndFileSource ()
273 delete _broadcast_info;
278 SndFileSource::sample_rate () const
280 return _info.samplerate;
284 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
293 if (writable() && !_open) {
294 /* file has not been opened yet - nothing written to it */
295 memset (dst, 0, sizeof (Sample) * cnt);
299 SNDFILE* sf = _descriptor->allocate ();
302 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
306 if (start > _length) {
308 /* read starts beyond end of data, just memset to zero */
312 } else if (start + cnt > _length) {
314 /* read ends beyond end of data, read some, memset the rest */
316 file_cnt = _length - start;
320 /* read is entirely within data */
325 assert (file_cnt >= 0);
327 if (file_cnt != cnt) {
328 framepos_t delta = cnt - file_cnt;
329 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
334 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
336 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
337 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
338 _descriptor->release ();
342 if (_info.channels == 1) {
343 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
344 if (ret != file_cnt) {
346 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
347 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;
349 _descriptor->release ();
354 real_cnt = cnt * _info.channels;
356 Sample* interleave_buf = get_interleave_buffer (real_cnt);
358 nread = sf_read_float (sf, interleave_buf, real_cnt);
359 ptr = interleave_buf + _channel;
360 nread /= _info.channels;
362 /* stride through the interleaved data */
364 for (int32_t n = 0; n < nread; ++n) {
366 ptr += _info.channels;
369 _descriptor->release ();
374 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
376 if (!_open && open()) {
381 return destructive_write_unlocked (data, cnt);
383 return nondestructive_write_unlocked (data, cnt);
388 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
391 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
395 if (_info.channels != 1) {
396 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
401 int32_t frame_pos = _length;
403 if (write_float (data, frame_pos, cnt) != cnt) {
407 update_length (_length + cnt);
409 if (_build_peakfiles) {
410 compute_and_write_peaks (data, frame_pos, cnt, false, true);
417 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
420 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
424 if (_capture_start && _capture_end) {
426 /* start and end of capture both occur within the data we are writing,
427 so do both crossfades.
430 _capture_start = false;
431 _capture_end = false;
433 /* move to the correct location place */
434 file_pos = capture_start_frame - _timeline_position;
437 framecnt_t subcnt = cnt / 2;
438 framecnt_t ofilepos = file_pos;
441 if (crossfade (data, subcnt, 1) != subcnt) {
446 Sample * tmpdata = data + subcnt;
449 subcnt = cnt - subcnt;
450 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
454 file_pos = ofilepos; // adjusted below
456 } else if (_capture_start) {
458 /* start of capture both occur within the data we are writing,
462 _capture_start = false;
463 _capture_end = false;
465 /* move to the correct location place */
466 file_pos = capture_start_frame - _timeline_position;
468 if (crossfade (data, cnt, 1) != cnt) {
472 } else if (_capture_end) {
474 /* end of capture both occur within the data we are writing,
478 _capture_start = false;
479 _capture_end = false;
481 if (crossfade (data, cnt, 0) != cnt) {
487 /* in the middle of recording */
489 if (write_float (data, file_pos, cnt) != cnt) {
494 update_length (file_pos + cnt);
496 if (_build_peakfiles) {
497 compute_and_write_peaks (data, file_pos, cnt, false, true);
506 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
508 set_timeline_position (when);
510 if (_flags & Broadcast) {
511 if (setup_broadcast_info (when, now, tnow)) {
516 return flush_header ();
520 SndFileSource::flush_header ()
523 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
528 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
532 SNDFILE* sf = _descriptor->allocate ();
534 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
538 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
539 _descriptor->release ();
545 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
548 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
553 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
557 if (!(_flags & Broadcast)) {
561 _broadcast_info->set_originator_ref_from_session (_session);
562 _broadcast_info->set_origination_time (&now);
564 /* now update header position taking header offset into account */
566 set_header_timeline_position ();
568 SNDFILE* sf = _descriptor->allocate ();
570 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
571 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
572 _path, _broadcast_info->get_error())
574 _flags = Flag (_flags & ~Broadcast);
575 delete _broadcast_info;
579 _descriptor->release ();
584 SndFileSource::set_header_timeline_position ()
586 if (!(_flags & Broadcast)) {
590 _broadcast_info->set_time_reference (_timeline_position);
592 SNDFILE* sf = _descriptor->allocate ();
594 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
595 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
596 _path, _broadcast_info->get_error())
598 _flags = Flag (_flags & ~Broadcast);
599 delete _broadcast_info;
603 _descriptor->release ();
607 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
609 SNDFILE* sf = _descriptor->allocate ();
611 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
613 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
614 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
615 _descriptor->release ();
619 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
620 _descriptor->release ();
624 _descriptor->release ();
629 SndFileSource::natural_position() const
631 return _timeline_position;
635 SndFileSource::set_destructive (bool yn)
638 _flags = Flag (_flags | Writable | Destructive);
640 xfade_buf = new Sample[xfade_frames];
642 clear_capture_marks ();
643 _timeline_position = header_position_offset;
645 _flags = Flag (_flags & ~Destructive);
646 _timeline_position = 0;
647 /* leave xfade buf alone in case we need it again later */
654 SndFileSource::clear_capture_marks ()
656 _capture_start = false;
657 _capture_end = false;
660 /** @param pos Capture start position in session frames */
662 SndFileSource::mark_capture_start (framepos_t pos)
665 if (pos < _timeline_position) {
666 _capture_start = false;
668 _capture_start = true;
669 capture_start_frame = pos;
675 SndFileSource::mark_capture_end()
683 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
685 framecnt_t xfade = min (xfade_frames, cnt);
686 framecnt_t nofade = cnt - xfade;
687 Sample* fade_data = 0;
688 framepos_t fade_position = 0; // in frames
693 fade_position = file_pos;
696 fade_position = file_pos + nofade;
697 fade_data = data + nofade;
700 if (fade_position > _length) {
702 /* read starts beyond end of data, just memset to zero */
706 } else if (fade_position + xfade > _length) {
708 /* read ends beyond end of data, read some, memset the rest */
710 file_cnt = _length - fade_position;
714 /* read is entirely within data */
721 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
722 if (retval >= 0 && errno == EAGAIN) {
723 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
724 * short or no data there */
725 memset (xfade_buf, 0, xfade * sizeof(Sample));
727 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
733 if (file_cnt != xfade) {
734 framecnt_t delta = xfade - file_cnt;
735 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
738 if (nofade && !fade_in) {
739 if (write_float (data, file_pos, nofade) != nofade) {
740 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
745 if (xfade == xfade_frames) {
749 /* use the standard xfade curve */
753 /* fade new material in */
755 for (n = 0; n < xfade; ++n) {
756 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
762 /* fade new material out */
764 for (n = 0; n < xfade; ++n) {
765 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
769 } else if (xfade < xfade_frames) {
774 /* short xfade, compute custom curve */
776 compute_equal_power_fades (xfade, in, out);
778 for (framecnt_t n = 0; n < xfade; ++n) {
779 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
784 /* long xfade length, has to be computed across several calls */
789 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
790 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
795 if (fade_in && nofade) {
796 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
797 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
806 SndFileSource::last_capture_start_frame () const
809 return capture_start_frame;
816 SndFileSource::handle_header_position_change ()
819 if ( _length != 0 ) {
820 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
821 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
822 } else if (writable()) {
823 _timeline_position = header_position_offset;
824 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
830 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
832 /* This static method is assumed to have been called by the Session
833 before any DFS's are created.
836 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
838 delete [] out_coefficient;
839 delete [] in_coefficient;
841 out_coefficient = new gain_t[xfade_frames];
842 in_coefficient = new gain_t[xfade_frames];
844 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
848 SndFileSource::set_timeline_position (framepos_t pos)
850 // destructive track timeline postion does not change
851 // except at instantion or when header_position_offset
852 // (session start) changes
854 if (!destructive()) {
855 AudioFileSource::set_timeline_position (pos);
860 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
866 sf_info.format = 0; // libsndfile says to clear this before sf_open().
868 if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
870 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
874 info.samplerate = sf_info.samplerate;
875 info.channels = sf_info.channels;
876 info.length = sf_info.frames;
878 string major = sndfile_major_format(sf_info.format);
879 string minor = sndfile_minor_format(sf_info.format);
881 if (major.length() + minor.length() < 16) { /* arbitrary */
882 info.format_name = string_compose("%1/%2", major, minor);
884 info.format_name = string_compose("%1\n%2", major, minor);
887 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
895 SndFileSource::one_of_several_channels () const
897 return _info.channels > 1;
901 SndFileSource::clamped_at_unity () const
903 int const type = _info.format & SF_FORMAT_TYPEMASK;
904 int const sub = _info.format & SF_FORMAT_SUBMASK;
905 /* XXX: this may not be the full list of formats that are unclamped */
906 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
910 SndFileSource::file_closed ()
912 /* stupid libsndfile updated the headers on close,
913 so touch the peakfile if it exists and has data
914 to make sure its time is as new as the audio
922 SndFileSource::set_path (const string& p)
924 FileSource::set_path (p);
927 _descriptor->set_path (_path);