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"
31 #include <glibmm/miscutils.h>
33 #include "ardour/sndfilesource.h"
34 #include "ardour/sndfile_helpers.h"
35 #include "ardour/utils.h"
36 #include "ardour/session.h"
41 using namespace ARDOUR;
45 gain_t* SndFileSource::out_coefficient = 0;
46 gain_t* SndFileSource::in_coefficient = 0;
47 framecnt_t SndFileSource::xfade_frames = 64;
48 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
51 Source::RemovableIfEmpty |
54 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
56 , AudioFileSource (s, node)
61 throw failed_constructor ();
65 /** Files created this way are never writable or removable */
66 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
67 : Source(s, DataType::AUDIO, path, flags)
68 /* note that the origin of an external file is itself */
69 , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
76 throw failed_constructor ();
80 /** This constructor is used to construct new files, not open existing ones. */
81 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
82 SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
83 : Source(s, DataType::AUDIO, path, flags)
84 , AudioFileSource (s, path, origin, flags, sfmt, hf)
95 _flags = Flag (_flags & ~Broadcast);
100 _flags = Flag (_flags & ~Broadcast);
105 _flags = Flag (_flags | Broadcast);
110 _flags = Flag (_flags & ~Broadcast);
115 _flags = Flag (_flags & ~Broadcast);
119 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
127 fmt |= SF_FORMAT_FLOAT;
131 fmt |= SF_FORMAT_PCM_24;
135 fmt |= SF_FORMAT_PCM_16;
140 _info.samplerate = rate;
143 if (_flags & Destructive) {
145 throw failed_constructor();
148 /* normal mode: do not open the file here - do that in write_unlocked() as needed
154 SndFileSource::init_sndfile ()
160 // lets try to keep the object initalizations here at the top
164 /* although libsndfile says we don't need to set this,
165 valgrind and source code shows us that we do.
168 memset (&_info, 0, sizeof(_info));
170 _capture_start = false;
171 _capture_end = false;
175 xfade_buf = new Sample[xfade_frames];
176 _timeline_position = header_position_offset;
179 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
183 SndFileSource::open ()
185 _descriptor = new SndFileDescriptor (_path, writable(), &_info);
186 _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
187 SNDFILE* sf = _descriptor->allocate ();
191 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
192 #ifndef HAVE_COREAUDIO
193 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
194 so we don't want to see this message.
197 cerr << "failed to open " << _path << " with name " << _name << endl;
199 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
200 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
205 if (_channel >= _info.channels) {
206 #ifndef HAVE_COREAUDIO
207 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
214 _length = _info.frames;
216 if (!_broadcast_info) {
217 _broadcast_info = new BroadcastInfo;
220 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
222 if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
223 /* newly created files will not have a BWF header at this point in time.
224 * Import will have called Source::set_timeline_position() if one exists
225 * in the original. */
226 header_position_offset = _timeline_position;
229 /* Set our timeline position to either the time reference from a BWF header or the current
230 start of the session.
232 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
234 if (_length != 0 && !bwf_info_exists) {
235 delete _broadcast_info;
237 _flags = Flag (_flags & ~Broadcast);
241 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
243 if (_flags & Broadcast) {
245 if (!_broadcast_info) {
246 _broadcast_info = new BroadcastInfo;
249 _broadcast_info->set_from_session (_session, header_position_offset);
250 _broadcast_info->set_description (string_compose ("BWF %1", _name));
252 if (!_broadcast_info->write_to_file (sf)) {
253 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
254 _path, _broadcast_info->get_error())
256 _flags = Flag (_flags & ~Broadcast);
257 delete _broadcast_info;
263 _descriptor->release ();
268 SndFileSource::~SndFileSource ()
271 delete _broadcast_info;
276 SndFileSource::sample_rate () const
278 return _info.samplerate;
282 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
291 if (writable() && !_open) {
292 /* file has not been opened yet - nothing written to it */
293 memset (dst, 0, sizeof (Sample) * cnt);
297 SNDFILE* sf = _descriptor->allocate ();
300 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
304 if (start > _length) {
306 /* read starts beyond end of data, just memset to zero */
310 } else if (start + cnt > _length) {
312 /* read ends beyond end of data, read some, memset the rest */
314 file_cnt = _length - start;
318 /* read is entirely within data */
323 assert (file_cnt >= 0);
325 if (file_cnt != cnt) {
326 framepos_t delta = cnt - file_cnt;
327 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
332 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
334 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
335 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
336 _descriptor->release ();
340 if (_info.channels == 1) {
341 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
342 if (ret != file_cnt) {
344 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
345 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;
347 _descriptor->release ();
352 real_cnt = cnt * _info.channels;
354 Sample* interleave_buf = get_interleave_buffer (real_cnt);
356 nread = sf_read_float (sf, interleave_buf, real_cnt);
357 ptr = interleave_buf + _channel;
358 nread /= _info.channels;
360 /* stride through the interleaved data */
362 for (int32_t n = 0; n < nread; ++n) {
364 ptr += _info.channels;
367 _descriptor->release ();
372 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
374 if (!_open && open()) {
379 return destructive_write_unlocked (data, cnt);
381 return nondestructive_write_unlocked (data, cnt);
386 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
389 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
393 if (_info.channels != 1) {
394 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
399 int32_t frame_pos = _length;
401 if (write_float (data, frame_pos, cnt) != cnt) {
405 update_length (_length + cnt);
407 if (_build_peakfiles) {
408 compute_and_write_peaks (data, frame_pos, cnt, false, true);
415 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
418 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
422 if (_capture_start && _capture_end) {
424 /* start and end of capture both occur within the data we are writing,
425 so do both crossfades.
428 _capture_start = false;
429 _capture_end = false;
431 /* move to the correct location place */
432 file_pos = capture_start_frame - _timeline_position;
435 framecnt_t subcnt = cnt / 2;
436 framecnt_t ofilepos = file_pos;
439 if (crossfade (data, subcnt, 1) != subcnt) {
444 Sample * tmpdata = data + subcnt;
447 subcnt = cnt - subcnt;
448 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
452 file_pos = ofilepos; // adjusted below
454 } else if (_capture_start) {
456 /* start of capture both occur within the data we are writing,
460 _capture_start = false;
461 _capture_end = false;
463 /* move to the correct location place */
464 file_pos = capture_start_frame - _timeline_position;
466 if (crossfade (data, cnt, 1) != cnt) {
470 } else if (_capture_end) {
472 /* end of capture both occur within the data we are writing,
476 _capture_start = false;
477 _capture_end = false;
479 if (crossfade (data, cnt, 0) != cnt) {
485 /* in the middle of recording */
487 if (write_float (data, file_pos, cnt) != cnt) {
492 update_length (file_pos + cnt);
494 if (_build_peakfiles) {
495 compute_and_write_peaks (data, file_pos, cnt, false, true);
504 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
506 set_timeline_position (when);
508 if (_flags & Broadcast) {
509 if (setup_broadcast_info (when, now, tnow)) {
514 return flush_header ();
518 SndFileSource::flush_header ()
521 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
526 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
530 SNDFILE* sf = _descriptor->allocate ();
532 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
536 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
537 _descriptor->release ();
543 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
546 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
551 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
555 if (!(_flags & Broadcast)) {
559 _broadcast_info->set_originator_ref_from_session (_session);
560 _broadcast_info->set_origination_time (&now);
562 /* now update header position taking header offset into account */
564 set_header_timeline_position ();
566 SNDFILE* sf = _descriptor->allocate ();
568 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
569 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
570 _path, _broadcast_info->get_error())
572 _flags = Flag (_flags & ~Broadcast);
573 delete _broadcast_info;
577 _descriptor->release ();
582 SndFileSource::set_header_timeline_position ()
584 if (!(_flags & Broadcast)) {
588 _broadcast_info->set_time_reference (_timeline_position);
590 SNDFILE* sf = _descriptor->allocate ();
592 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
593 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
594 _path, _broadcast_info->get_error())
596 _flags = Flag (_flags & ~Broadcast);
597 delete _broadcast_info;
601 _descriptor->release ();
605 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
607 SNDFILE* sf = _descriptor->allocate ();
609 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
611 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
612 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
613 _descriptor->release ();
617 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
618 _descriptor->release ();
622 _descriptor->release ();
627 SndFileSource::natural_position() const
629 return _timeline_position;
633 SndFileSource::set_destructive (bool yn)
636 _flags = Flag (_flags | Writable | Destructive);
638 xfade_buf = new Sample[xfade_frames];
640 clear_capture_marks ();
641 _timeline_position = header_position_offset;
643 _flags = Flag (_flags & ~Destructive);
644 _timeline_position = 0;
645 /* leave xfade buf alone in case we need it again later */
652 SndFileSource::clear_capture_marks ()
654 _capture_start = false;
655 _capture_end = false;
658 /** @param pos Capture start position in session frames */
660 SndFileSource::mark_capture_start (framepos_t pos)
663 if (pos < _timeline_position) {
664 _capture_start = false;
666 _capture_start = true;
667 capture_start_frame = pos;
673 SndFileSource::mark_capture_end()
681 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
683 framecnt_t xfade = min (xfade_frames, cnt);
684 framecnt_t nofade = cnt - xfade;
685 Sample* fade_data = 0;
686 framepos_t fade_position = 0; // in frames
691 fade_position = file_pos;
694 fade_position = file_pos + nofade;
695 fade_data = data + nofade;
698 if (fade_position > _length) {
700 /* read starts beyond end of data, just memset to zero */
704 } else if (fade_position + xfade > _length) {
706 /* read ends beyond end of data, read some, memset the rest */
708 file_cnt = _length - fade_position;
712 /* read is entirely within data */
719 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
720 if (retval >= 0 && errno == EAGAIN) {
721 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
722 * short or no data there */
723 memset (xfade_buf, 0, xfade * sizeof(Sample));
725 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
731 if (file_cnt != xfade) {
732 framecnt_t delta = xfade - file_cnt;
733 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
736 if (nofade && !fade_in) {
737 if (write_float (data, file_pos, nofade) != nofade) {
738 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
743 if (xfade == xfade_frames) {
747 /* use the standard xfade curve */
751 /* fade new material in */
753 for (n = 0; n < xfade; ++n) {
754 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
760 /* fade new material out */
762 for (n = 0; n < xfade; ++n) {
763 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
767 } else if (xfade < xfade_frames) {
772 /* short xfade, compute custom curve */
774 compute_equal_power_fades (xfade, in, out);
776 for (framecnt_t n = 0; n < xfade; ++n) {
777 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
782 /* long xfade length, has to be computed across several calls */
787 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
788 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
793 if (fade_in && nofade) {
794 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
795 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
804 SndFileSource::last_capture_start_frame () const
807 return capture_start_frame;
814 SndFileSource::handle_header_position_change ()
817 if ( _length != 0 ) {
818 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
819 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
820 } else if (writable()) {
821 _timeline_position = header_position_offset;
822 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
828 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
830 /* This static method is assumed to have been called by the Session
831 before any DFS's are created.
834 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
836 delete [] out_coefficient;
837 delete [] in_coefficient;
839 out_coefficient = new gain_t[xfade_frames];
840 in_coefficient = new gain_t[xfade_frames];
842 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
846 SndFileSource::set_timeline_position (framepos_t pos)
848 // destructive track timeline postion does not change
849 // except at instantion or when header_position_offset
850 // (session start) changes
852 if (!destructive()) {
853 AudioFileSource::set_timeline_position (pos);
858 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
864 sf_info.format = 0; // libsndfile says to clear this before sf_open().
866 if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
868 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
872 info.samplerate = sf_info.samplerate;
873 info.channels = sf_info.channels;
874 info.length = sf_info.frames;
876 string major = sndfile_major_format(sf_info.format);
877 string minor = sndfile_minor_format(sf_info.format);
879 if (major.length() + minor.length() < 16) { /* arbitrary */
880 info.format_name = string_compose("%1/%2", major, minor);
882 info.format_name = string_compose("%1\n%2", major, minor);
885 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
893 SndFileSource::one_of_several_channels () const
895 return _info.channels > 1;
899 SndFileSource::clamped_at_unity () const
901 int const type = _info.format & SF_FORMAT_TYPEMASK;
902 int const sub = _info.format & SF_FORMAT_SUBMASK;
903 /* XXX: this may not be the full list of formats that are unclamped */
904 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
908 SndFileSource::file_closed ()
910 /* stupid libsndfile updated the headers on close,
911 so touch the peakfile if it exists and has data
912 to make sure its time is as new as the audio
920 SndFileSource::set_path (const string& p)
922 FileSource::set_path (p);
925 _descriptor->set_path (_path);