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_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
228 if (_length != 0 && !bwf_info_exists) {
229 delete _broadcast_info;
231 _flags = Flag (_flags & ~Broadcast);
235 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
237 if (_flags & Broadcast) {
239 if (!_broadcast_info) {
240 _broadcast_info = new BroadcastInfo;
243 _broadcast_info->set_from_session (_session, header_position_offset);
244 _broadcast_info->set_description (string_compose ("BWF %1", _name));
246 if (!_broadcast_info->write_to_file (sf)) {
247 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
248 _path, _broadcast_info->get_error())
250 _flags = Flag (_flags & ~Broadcast);
251 delete _broadcast_info;
257 _descriptor->release ();
262 SndFileSource::~SndFileSource ()
265 delete _broadcast_info;
270 SndFileSource::sample_rate () const
272 return _info.samplerate;
276 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
285 if (writable() && !_open) {
286 /* file has not been opened yet - nothing written to it */
287 memset (dst, 0, sizeof (Sample) * cnt);
291 SNDFILE* sf = _descriptor->allocate ();
294 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
298 if (start > _length) {
300 /* read starts beyond end of data, just memset to zero */
304 } else if (start + cnt > _length) {
306 /* read ends beyond end of data, read some, memset the rest */
308 file_cnt = _length - start;
312 /* read is entirely within data */
317 assert (file_cnt >= 0);
319 if (file_cnt != cnt) {
320 framepos_t delta = cnt - file_cnt;
321 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
326 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
328 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
329 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
330 _descriptor->release ();
334 if (_info.channels == 1) {
335 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
336 if (ret != file_cnt) {
338 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
339 error << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.val().substr (1), errbuf, _length) << endl;
341 _descriptor->release ();
346 real_cnt = cnt * _info.channels;
348 Sample* interleave_buf = get_interleave_buffer (real_cnt);
350 nread = sf_read_float (sf, interleave_buf, real_cnt);
351 ptr = interleave_buf + _channel;
352 nread /= _info.channels;
354 /* stride through the interleaved data */
356 for (int32_t n = 0; n < nread; ++n) {
358 ptr += _info.channels;
361 _descriptor->release ();
366 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
368 if (!_open && open()) {
373 return destructive_write_unlocked (data, cnt);
375 return nondestructive_write_unlocked (data, cnt);
380 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
383 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
387 if (_info.channels != 1) {
388 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) {
401 update_length (oldlen, cnt);
403 if (_build_peakfiles) {
404 compute_and_write_peaks (data, frame_pos, cnt, false, true);
411 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
414 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
418 if (_capture_start && _capture_end) {
420 /* start and end of capture both occur within the data we are writing,
421 so do both crossfades.
424 _capture_start = false;
425 _capture_end = false;
427 /* move to the correct location place */
428 file_pos = capture_start_frame - _timeline_position;
431 framecnt_t subcnt = cnt / 2;
432 framecnt_t ofilepos = file_pos;
435 if (crossfade (data, subcnt, 1) != subcnt) {
440 Sample * tmpdata = data + subcnt;
443 subcnt = cnt - subcnt;
444 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
448 file_pos = ofilepos; // adjusted below
450 } else if (_capture_start) {
452 /* start of capture both occur within the data we are writing,
456 _capture_start = false;
457 _capture_end = false;
459 /* move to the correct location place */
460 file_pos = capture_start_frame - _timeline_position;
462 if (crossfade (data, cnt, 1) != cnt) {
466 } else if (_capture_end) {
468 /* end of capture both occur within the data we are writing,
472 _capture_start = false;
473 _capture_end = false;
475 if (crossfade (data, cnt, 0) != cnt) {
481 /* in the middle of recording */
483 if (write_float (data, file_pos, cnt) != cnt) {
488 update_length (file_pos, cnt);
490 if (_build_peakfiles) {
491 compute_and_write_peaks (data, file_pos, cnt, false, true);
500 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
502 set_timeline_position (when);
504 if (_flags & Broadcast) {
505 if (setup_broadcast_info (when, now, tnow)) {
510 return flush_header ();
514 SndFileSource::flush_header ()
517 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
522 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
526 SNDFILE* sf = _descriptor->allocate ();
528 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
532 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
533 _descriptor->release ();
539 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
542 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
547 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
551 if (!(_flags & Broadcast)) {
555 _broadcast_info->set_originator_ref_from_session (_session);
556 _broadcast_info->set_origination_time (&now);
558 /* now update header position taking header offset into account */
560 set_header_timeline_position ();
562 SNDFILE* sf = _descriptor->allocate ();
564 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
565 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
566 _path, _broadcast_info->get_error())
568 _flags = Flag (_flags & ~Broadcast);
569 delete _broadcast_info;
573 _descriptor->release ();
578 SndFileSource::set_header_timeline_position ()
580 if (!(_flags & Broadcast)) {
584 _broadcast_info->set_time_reference (_timeline_position);
586 SNDFILE* sf = _descriptor->allocate ();
588 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
589 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
590 _path, _broadcast_info->get_error())
592 _flags = Flag (_flags & ~Broadcast);
593 delete _broadcast_info;
597 _descriptor->release ();
601 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
603 SNDFILE* sf = _descriptor->allocate ();
605 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
607 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
608 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
609 _descriptor->release ();
613 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
614 _descriptor->release ();
618 _descriptor->release ();
623 SndFileSource::natural_position() const
625 return _timeline_position;
629 SndFileSource::set_destructive (bool yn)
632 _flags = Flag (_flags | Writable | Destructive);
634 xfade_buf = new Sample[xfade_frames];
636 clear_capture_marks ();
637 _timeline_position = header_position_offset;
639 _flags = Flag (_flags & ~Destructive);
640 _timeline_position = 0;
641 /* leave xfade buf alone in case we need it again later */
648 SndFileSource::clear_capture_marks ()
650 _capture_start = false;
651 _capture_end = false;
654 /** @param pos Capture start position in session frames */
656 SndFileSource::mark_capture_start (framepos_t pos)
659 if (pos < _timeline_position) {
660 _capture_start = false;
662 _capture_start = true;
663 capture_start_frame = pos;
669 SndFileSource::mark_capture_end()
677 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
679 framecnt_t xfade = min (xfade_frames, cnt);
680 framecnt_t nofade = cnt - xfade;
681 Sample* fade_data = 0;
682 framepos_t fade_position = 0; // in frames
687 fade_position = file_pos;
690 fade_position = file_pos + nofade;
691 fade_data = data + nofade;
694 if (fade_position > _length) {
696 /* read starts beyond end of data, just memset to zero */
700 } else if (fade_position + xfade > _length) {
702 /* read ends beyond end of data, read some, memset the rest */
704 file_cnt = _length - fade_position;
708 /* read is entirely within data */
715 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
716 if (retval >= 0 && errno == EAGAIN) {
717 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
718 * short or no data there */
719 memset (xfade_buf, 0, xfade * sizeof(Sample));
721 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
727 if (file_cnt != xfade) {
728 framecnt_t delta = xfade - file_cnt;
729 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
732 if (nofade && !fade_in) {
733 if (write_float (data, file_pos, nofade) != nofade) {
734 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
739 if (xfade == xfade_frames) {
743 /* use the standard xfade curve */
747 /* fade new material in */
749 for (n = 0; n < xfade; ++n) {
750 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
756 /* fade new material out */
758 for (n = 0; n < xfade; ++n) {
759 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
763 } else if (xfade < xfade_frames) {
768 /* short xfade, compute custom curve */
770 compute_equal_power_fades (xfade, in, out);
772 for (framecnt_t n = 0; n < xfade; ++n) {
773 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
778 /* long xfade length, has to be computed across several calls */
783 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
784 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
789 if (fade_in && nofade) {
790 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
791 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
800 SndFileSource::last_capture_start_frame () const
803 return capture_start_frame;
810 SndFileSource::handle_header_position_change ()
813 if ( _length != 0 ) {
814 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
815 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
816 } else if (writable()) {
817 _timeline_position = header_position_offset;
818 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
824 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
826 /* This static method is assumed to have been called by the Session
827 before any DFS's are created.
830 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
832 delete [] out_coefficient;
833 delete [] in_coefficient;
835 out_coefficient = new gain_t[xfade_frames];
836 in_coefficient = new gain_t[xfade_frames];
838 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
842 SndFileSource::set_timeline_position (framepos_t pos)
844 // destructive track timeline postion does not change
845 // except at instantion or when header_position_offset
846 // (session start) changes
848 if (!destructive()) {
849 AudioFileSource::set_timeline_position (pos);
854 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
860 sf_info.format = 0; // libsndfile says to clear this before sf_open().
862 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
864 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
868 info.samplerate = sf_info.samplerate;
869 info.channels = sf_info.channels;
870 info.length = sf_info.frames;
872 string major = sndfile_major_format(sf_info.format);
873 string minor = sndfile_minor_format(sf_info.format);
875 if (major.length() + minor.length() < 16) { /* arbitrary */
876 info.format_name = string_compose("%1/%2", major, minor);
878 info.format_name = string_compose("%1\n%2", major, minor);
881 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
889 SndFileSource::one_of_several_channels () const
891 return _info.channels > 1;
895 SndFileSource::clamped_at_unity () const
897 int const type = _info.format & SF_FORMAT_TYPEMASK;
898 int const sub = _info.format & SF_FORMAT_SUBMASK;
899 /* XXX: this may not be the full list of formats that are unclamped */
900 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
904 SndFileSource::file_closed ()
906 /* stupid libsndfile updated the headers on close,
907 so touch the peakfile if it exists and has data
908 to make sure its time is as new as the audio
916 SndFileSource::set_path (const string& p)
918 FileSource::set_path (p);
921 _descriptor->set_path (_path);