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 /* Set our timeline position to either the time reference from a BWF header or the current
225 start of the session.
227 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
229 if (_length != 0 && !bwf_info_exists) {
230 delete _broadcast_info;
232 _flags = Flag (_flags & ~Broadcast);
236 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
238 if (_flags & Broadcast) {
240 if (!_broadcast_info) {
241 _broadcast_info = new BroadcastInfo;
244 _broadcast_info->set_from_session (_session, header_position_offset);
245 _broadcast_info->set_description (string_compose ("BWF %1", _name));
247 if (!_broadcast_info->write_to_file (sf)) {
248 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
249 _path, _broadcast_info->get_error())
251 _flags = Flag (_flags & ~Broadcast);
252 delete _broadcast_info;
258 _descriptor->release ();
263 SndFileSource::~SndFileSource ()
266 delete _broadcast_info;
271 SndFileSource::sample_rate () const
273 return _info.samplerate;
277 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
286 if (writable() && !_open) {
287 /* file has not been opened yet - nothing written to it */
288 memset (dst, 0, sizeof (Sample) * cnt);
292 SNDFILE* sf = _descriptor->allocate ();
295 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
299 if (start > _length) {
301 /* read starts beyond end of data, just memset to zero */
305 } else if (start + cnt > _length) {
307 /* read ends beyond end of data, read some, memset the rest */
309 file_cnt = _length - start;
313 /* read is entirely within data */
318 assert (file_cnt >= 0);
320 if (file_cnt != cnt) {
321 framepos_t delta = cnt - file_cnt;
322 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
327 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
329 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
330 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
331 _descriptor->release ();
335 if (_info.channels == 1) {
336 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
337 if (ret != file_cnt) {
339 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
340 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;
342 _descriptor->release ();
347 real_cnt = cnt * _info.channels;
349 Sample* interleave_buf = get_interleave_buffer (real_cnt);
351 nread = sf_read_float (sf, interleave_buf, real_cnt);
352 ptr = interleave_buf + _channel;
353 nread /= _info.channels;
355 /* stride through the interleaved data */
357 for (int32_t n = 0; n < nread; ++n) {
359 ptr += _info.channels;
362 _descriptor->release ();
367 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
369 if (!_open && open()) {
374 return destructive_write_unlocked (data, cnt);
376 return nondestructive_write_unlocked (data, cnt);
381 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
384 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
388 if (_info.channels != 1) {
389 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
394 int32_t frame_pos = _length;
396 if (write_float (data, frame_pos, cnt) != cnt) {
400 update_length (_length + cnt);
402 if (_build_peakfiles) {
403 compute_and_write_peaks (data, frame_pos, cnt, false, true);
410 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
413 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
417 if (_capture_start && _capture_end) {
419 /* start and end of capture both occur within the data we are writing,
420 so do both crossfades.
423 _capture_start = false;
424 _capture_end = false;
426 /* move to the correct location place */
427 file_pos = capture_start_frame - _timeline_position;
430 framecnt_t subcnt = cnt / 2;
431 framecnt_t ofilepos = file_pos;
434 if (crossfade (data, subcnt, 1) != subcnt) {
439 Sample * tmpdata = data + subcnt;
442 subcnt = cnt - subcnt;
443 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
447 file_pos = ofilepos; // adjusted below
449 } else if (_capture_start) {
451 /* start of capture both occur within the data we are writing,
455 _capture_start = false;
456 _capture_end = false;
458 /* move to the correct location place */
459 file_pos = capture_start_frame - _timeline_position;
461 if (crossfade (data, cnt, 1) != cnt) {
465 } else if (_capture_end) {
467 /* end of capture both occur within the data we are writing,
471 _capture_start = false;
472 _capture_end = false;
474 if (crossfade (data, cnt, 0) != cnt) {
480 /* in the middle of recording */
482 if (write_float (data, file_pos, cnt) != cnt) {
487 update_length (file_pos + cnt);
489 if (_build_peakfiles) {
490 compute_and_write_peaks (data, file_pos, cnt, false, true);
499 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
501 set_timeline_position (when);
503 if (_flags & Broadcast) {
504 if (setup_broadcast_info (when, now, tnow)) {
509 return flush_header ();
513 SndFileSource::flush_header ()
516 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
521 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
525 SNDFILE* sf = _descriptor->allocate ();
527 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
531 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
532 _descriptor->release ();
538 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
541 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
546 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
550 if (!(_flags & Broadcast)) {
554 _broadcast_info->set_originator_ref_from_session (_session);
555 _broadcast_info->set_origination_time (&now);
557 /* now update header position taking header offset into account */
559 set_header_timeline_position ();
561 SNDFILE* sf = _descriptor->allocate ();
563 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
564 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
565 _path, _broadcast_info->get_error())
567 _flags = Flag (_flags & ~Broadcast);
568 delete _broadcast_info;
572 _descriptor->release ();
577 SndFileSource::set_header_timeline_position ()
579 if (!(_flags & Broadcast)) {
583 _broadcast_info->set_time_reference (_timeline_position);
585 SNDFILE* sf = _descriptor->allocate ();
587 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
588 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
589 _path, _broadcast_info->get_error())
591 _flags = Flag (_flags & ~Broadcast);
592 delete _broadcast_info;
596 _descriptor->release ();
600 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
602 SNDFILE* sf = _descriptor->allocate ();
604 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
606 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
607 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
608 _descriptor->release ();
612 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
613 _descriptor->release ();
617 _descriptor->release ();
622 SndFileSource::natural_position() const
624 return _timeline_position;
628 SndFileSource::set_destructive (bool yn)
631 _flags = Flag (_flags | Writable | Destructive);
633 xfade_buf = new Sample[xfade_frames];
635 clear_capture_marks ();
636 _timeline_position = header_position_offset;
638 _flags = Flag (_flags & ~Destructive);
639 _timeline_position = 0;
640 /* leave xfade buf alone in case we need it again later */
647 SndFileSource::clear_capture_marks ()
649 _capture_start = false;
650 _capture_end = false;
653 /** @param pos Capture start position in session frames */
655 SndFileSource::mark_capture_start (framepos_t pos)
658 if (pos < _timeline_position) {
659 _capture_start = false;
661 _capture_start = true;
662 capture_start_frame = pos;
668 SndFileSource::mark_capture_end()
676 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
678 framecnt_t xfade = min (xfade_frames, cnt);
679 framecnt_t nofade = cnt - xfade;
680 Sample* fade_data = 0;
681 framepos_t fade_position = 0; // in frames
686 fade_position = file_pos;
689 fade_position = file_pos + nofade;
690 fade_data = data + nofade;
693 if (fade_position > _length) {
695 /* read starts beyond end of data, just memset to zero */
699 } else if (fade_position + xfade > _length) {
701 /* read ends beyond end of data, read some, memset the rest */
703 file_cnt = _length - fade_position;
707 /* read is entirely within data */
714 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
715 if (retval >= 0 && errno == EAGAIN) {
716 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
717 * short or no data there */
718 memset (xfade_buf, 0, xfade * sizeof(Sample));
720 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
726 if (file_cnt != xfade) {
727 framecnt_t delta = xfade - file_cnt;
728 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
731 if (nofade && !fade_in) {
732 if (write_float (data, file_pos, nofade) != nofade) {
733 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
738 if (xfade == xfade_frames) {
742 /* use the standard xfade curve */
746 /* fade new material in */
748 for (n = 0; n < xfade; ++n) {
749 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
755 /* fade new material out */
757 for (n = 0; n < xfade; ++n) {
758 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
762 } else if (xfade < xfade_frames) {
767 /* short xfade, compute custom curve */
769 compute_equal_power_fades (xfade, in, out);
771 for (framecnt_t n = 0; n < xfade; ++n) {
772 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
777 /* long xfade length, has to be computed across several calls */
782 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
783 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
788 if (fade_in && nofade) {
789 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
790 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
799 SndFileSource::last_capture_start_frame () const
802 return capture_start_frame;
809 SndFileSource::handle_header_position_change ()
812 if ( _length != 0 ) {
813 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
814 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
815 } else if (writable()) {
816 _timeline_position = header_position_offset;
817 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
823 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
825 /* This static method is assumed to have been called by the Session
826 before any DFS's are created.
829 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
831 delete [] out_coefficient;
832 delete [] in_coefficient;
834 out_coefficient = new gain_t[xfade_frames];
835 in_coefficient = new gain_t[xfade_frames];
837 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
841 SndFileSource::set_timeline_position (framepos_t pos)
843 // destructive track timeline postion does not change
844 // except at instantion or when header_position_offset
845 // (session start) changes
847 if (!destructive()) {
848 AudioFileSource::set_timeline_position (pos);
853 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
859 sf_info.format = 0; // libsndfile says to clear this before sf_open().
861 if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
863 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
867 info.samplerate = sf_info.samplerate;
868 info.channels = sf_info.channels;
869 info.length = sf_info.frames;
871 string major = sndfile_major_format(sf_info.format);
872 string minor = sndfile_minor_format(sf_info.format);
874 if (major.length() + minor.length() < 16) { /* arbitrary */
875 info.format_name = string_compose("%1/%2", major, minor);
877 info.format_name = string_compose("%1\n%2", major, minor);
880 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
888 SndFileSource::one_of_several_channels () const
890 return _info.channels > 1;
894 SndFileSource::clamped_at_unity () const
896 int const type = _info.format & SF_FORMAT_TYPEMASK;
897 int const sub = _info.format & SF_FORMAT_SUBMASK;
898 /* XXX: this may not be the full list of formats that are unclamped */
899 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
903 SndFileSource::file_closed ()
905 /* stupid libsndfile updated the headers on close,
906 so touch the peakfile if it exists and has data
907 to make sure its time is as new as the audio
915 SndFileSource::set_path (const string& p)
917 FileSource::set_path (p);
920 _descriptor->set_path (_path);