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 #ifdef PLATFORM_WINDOWS
32 #include <glibmm/convert.h>
34 #include <glibmm/miscutils.h>
36 #include "ardour/sndfilesource.h"
37 #include "ardour/sndfile_helpers.h"
38 #include "ardour/utils.h"
39 #include "ardour/session.h"
44 using namespace ARDOUR;
48 gain_t* SndFileSource::out_coefficient = 0;
49 gain_t* SndFileSource::in_coefficient = 0;
50 framecnt_t SndFileSource::xfade_frames = 64;
51 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
54 Source::RemovableIfEmpty |
57 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
59 , AudioFileSource (s, node)
64 throw failed_constructor ();
68 /** Constructor for existing external-to-session files.
69 Files created this way are never writable or removable
71 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
72 : Source(s, DataType::AUDIO, path, flags)
73 /* note that the origin of an external file is itself */
74 , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
81 throw failed_constructor ();
85 /** This constructor is used to construct new internal-to-session files,
86 not open existing ones.
88 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
89 SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
90 : Source(s, DataType::AUDIO, path, flags)
91 , AudioFileSource (s, path, origin, flags, sfmt, hf)
102 _flags = Flag (_flags & ~Broadcast);
106 fmt = SF_FORMAT_AIFF;
107 _flags = Flag (_flags & ~Broadcast);
112 _flags = Flag (_flags | Broadcast);
117 _flags = Flag (_flags & ~Broadcast);
122 _flags = Flag (_flags & ~Broadcast);
126 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
134 fmt |= SF_FORMAT_FLOAT;
138 fmt |= SF_FORMAT_PCM_24;
142 fmt |= SF_FORMAT_PCM_16;
147 _info.samplerate = rate;
150 if (_flags & Destructive) {
152 throw failed_constructor();
155 /* normal mode: do not open the file here - do that in write_unlocked() as needed
161 SndFileSource::init_sndfile ()
167 // lets try to keep the object initalizations here at the top
171 /* although libsndfile says we don't need to set this,
172 valgrind and source code shows us that we do.
175 memset (&_info, 0, sizeof(_info));
177 _capture_start = false;
178 _capture_end = false;
182 xfade_buf = new Sample[xfade_frames];
183 _timeline_position = header_position_offset;
186 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
190 SndFileSource::open ()
194 #ifdef PLATFORM_WINDOWS
195 path_to_open = Glib::locale_from_utf8(_path);
197 path_to_open = _path;
200 _descriptor = new SndFileDescriptor (path_to_open.c_str(), writable(), &_info);
201 _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
202 SNDFILE* sf = _descriptor->allocate ();
206 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
207 #ifndef HAVE_COREAUDIO
208 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
209 so we don't want to see this message.
212 cerr << "failed to open " << path_to_open << " with name " << _name << endl;
214 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
215 path_to_open, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
220 if (_channel >= _info.channels) {
221 #ifndef HAVE_COREAUDIO
222 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
229 _length = _info.frames;
231 if (!_broadcast_info) {
232 _broadcast_info = new BroadcastInfo;
235 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
237 if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
238 /* newly created files will not have a BWF header at this point in time.
239 * Import will have called Source::set_timeline_position() if one exists
240 * in the original. */
241 header_position_offset = _timeline_position;
244 /* Set our timeline position to either the time reference from a BWF header or the current
245 start of the session.
247 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
249 if (_length != 0 && !bwf_info_exists) {
250 delete _broadcast_info;
252 _flags = Flag (_flags & ~Broadcast);
256 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
258 if (_flags & Broadcast) {
260 if (!_broadcast_info) {
261 _broadcast_info = new BroadcastInfo;
264 _broadcast_info->set_from_session (_session, header_position_offset);
265 _broadcast_info->set_description (string_compose ("BWF %1", _name));
267 if (!_broadcast_info->write_to_file (sf)) {
268 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
269 path_to_open, _broadcast_info->get_error())
271 _flags = Flag (_flags & ~Broadcast);
272 delete _broadcast_info;
278 _descriptor->release ();
283 SndFileSource::~SndFileSource ()
286 delete _broadcast_info;
291 SndFileSource::sample_rate () const
293 return _info.samplerate;
297 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
306 if (writable() && !_open) {
307 /* file has not been opened yet - nothing written to it */
308 memset (dst, 0, sizeof (Sample) * cnt);
312 SNDFILE* sf = _descriptor->allocate ();
315 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
319 if (start > _length) {
321 /* read starts beyond end of data, just memset to zero */
325 } else if (start + cnt > _length) {
327 /* read ends beyond end of data, read some, memset the rest */
329 file_cnt = _length - start;
333 /* read is entirely within data */
338 assert (file_cnt >= 0);
340 if (file_cnt != cnt) {
341 framepos_t delta = cnt - file_cnt;
342 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
347 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
349 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
350 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
351 _descriptor->release ();
355 if (_info.channels == 1) {
356 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
357 if (ret != file_cnt) {
359 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
360 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;
362 _descriptor->release ();
367 real_cnt = cnt * _info.channels;
369 Sample* interleave_buf = get_interleave_buffer (real_cnt);
371 nread = sf_read_float (sf, interleave_buf, real_cnt);
372 ptr = interleave_buf + _channel;
373 nread /= _info.channels;
375 /* stride through the interleaved data */
377 for (int32_t n = 0; n < nread; ++n) {
379 ptr += _info.channels;
382 _descriptor->release ();
387 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
389 if (!_open && open()) {
394 return destructive_write_unlocked (data, cnt);
396 return nondestructive_write_unlocked (data, cnt);
401 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
404 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
408 if (_info.channels != 1) {
409 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
414 int32_t frame_pos = _length;
416 if (write_float (data, frame_pos, cnt) != cnt) {
420 update_length (_length + cnt);
422 if (_build_peakfiles) {
423 compute_and_write_peaks (data, frame_pos, cnt, false, true);
430 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
433 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
437 if (_capture_start && _capture_end) {
439 /* start and end of capture both occur within the data we are writing,
440 so do both crossfades.
443 _capture_start = false;
444 _capture_end = false;
446 /* move to the correct location place */
447 file_pos = capture_start_frame - _timeline_position;
450 framecnt_t subcnt = cnt / 2;
451 framecnt_t ofilepos = file_pos;
454 if (crossfade (data, subcnt, 1) != subcnt) {
459 Sample * tmpdata = data + subcnt;
462 subcnt = cnt - subcnt;
463 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
467 file_pos = ofilepos; // adjusted below
469 } else if (_capture_start) {
471 /* start of capture both occur within the data we are writing,
475 _capture_start = false;
476 _capture_end = false;
478 /* move to the correct location place */
479 file_pos = capture_start_frame - _timeline_position;
481 if (crossfade (data, cnt, 1) != cnt) {
485 } else if (_capture_end) {
487 /* end of capture both occur within the data we are writing,
491 _capture_start = false;
492 _capture_end = false;
494 if (crossfade (data, cnt, 0) != cnt) {
500 /* in the middle of recording */
502 if (write_float (data, file_pos, cnt) != cnt) {
507 update_length (file_pos + cnt);
509 if (_build_peakfiles) {
510 compute_and_write_peaks (data, file_pos, cnt, false, true);
519 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
521 set_timeline_position (when);
523 if (_flags & Broadcast) {
524 if (setup_broadcast_info (when, now, tnow)) {
529 return flush_header ();
533 SndFileSource::flush_header ()
536 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
541 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
545 SNDFILE* sf = _descriptor->allocate ();
547 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
551 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
552 _descriptor->release ();
558 SndFileSource::flush ()
561 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
566 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
570 SNDFILE* sf = _descriptor->allocate ();
572 error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
576 // Hopefully everything OK
578 _descriptor->release ();
582 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
585 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
590 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
594 if (!(_flags & Broadcast)) {
598 _broadcast_info->set_originator_ref_from_session (_session);
599 _broadcast_info->set_origination_time (&now);
601 /* now update header position taking header offset into account */
603 set_header_timeline_position ();
605 SNDFILE* sf = _descriptor->allocate ();
607 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
608 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
609 _path, _broadcast_info->get_error())
611 _flags = Flag (_flags & ~Broadcast);
612 delete _broadcast_info;
616 _descriptor->release ();
621 SndFileSource::set_header_timeline_position ()
623 if (!(_flags & Broadcast)) {
627 _broadcast_info->set_time_reference (_timeline_position);
629 SNDFILE* sf = _descriptor->allocate ();
631 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
632 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
633 _path, _broadcast_info->get_error())
635 _flags = Flag (_flags & ~Broadcast);
636 delete _broadcast_info;
640 _descriptor->release ();
644 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
646 SNDFILE* sf = _descriptor->allocate ();
648 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
650 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
651 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
652 _descriptor->release ();
656 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
657 _descriptor->release ();
661 _descriptor->release ();
666 SndFileSource::natural_position() const
668 return _timeline_position;
672 SndFileSource::set_destructive (bool yn)
675 _flags = Flag (_flags | Writable | Destructive);
677 xfade_buf = new Sample[xfade_frames];
679 clear_capture_marks ();
680 _timeline_position = header_position_offset;
682 _flags = Flag (_flags & ~Destructive);
683 _timeline_position = 0;
684 /* leave xfade buf alone in case we need it again later */
691 SndFileSource::clear_capture_marks ()
693 _capture_start = false;
694 _capture_end = false;
697 /** @param pos Capture start position in session frames */
699 SndFileSource::mark_capture_start (framepos_t pos)
702 if (pos < _timeline_position) {
703 _capture_start = false;
705 _capture_start = true;
706 capture_start_frame = pos;
712 SndFileSource::mark_capture_end()
720 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
722 framecnt_t xfade = min (xfade_frames, cnt);
723 framecnt_t nofade = cnt - xfade;
724 Sample* fade_data = 0;
725 framepos_t fade_position = 0; // in frames
730 fade_position = file_pos;
733 fade_position = file_pos + nofade;
734 fade_data = data + nofade;
737 if (fade_position > _length) {
739 /* read starts beyond end of data, just memset to zero */
743 } else if (fade_position + xfade > _length) {
745 /* read ends beyond end of data, read some, memset the rest */
747 file_cnt = _length - fade_position;
751 /* read is entirely within data */
758 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
759 if (retval >= 0 && errno == EAGAIN) {
760 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
761 * short or no data there */
762 memset (xfade_buf, 0, xfade * sizeof(Sample));
764 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
770 if (file_cnt != xfade) {
771 framecnt_t delta = xfade - file_cnt;
772 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
775 if (nofade && !fade_in) {
776 if (write_float (data, file_pos, nofade) != nofade) {
777 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
782 if (xfade == xfade_frames) {
786 /* use the standard xfade curve */
790 /* fade new material in */
792 for (n = 0; n < xfade; ++n) {
793 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
799 /* fade new material out */
801 for (n = 0; n < xfade; ++n) {
802 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
806 } else if (xfade < xfade_frames) {
808 std::vector<gain_t> in(xfade);
809 std::vector<gain_t> out(xfade);
811 /* short xfade, compute custom curve */
813 compute_equal_power_fades (xfade, &in[0], &out[0]);
815 for (framecnt_t n = 0; n < xfade; ++n) {
816 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
821 /* long xfade length, has to be computed across several calls */
826 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
827 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
832 if (fade_in && nofade) {
833 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
834 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
843 SndFileSource::last_capture_start_frame () const
846 return capture_start_frame;
853 SndFileSource::handle_header_position_change ()
856 if ( _length != 0 ) {
857 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
858 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
859 } else if (writable()) {
860 _timeline_position = header_position_offset;
861 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
867 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
869 /* This static method is assumed to have been called by the Session
870 before any DFS's are created.
873 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
875 delete [] out_coefficient;
876 delete [] in_coefficient;
878 out_coefficient = new gain_t[xfade_frames];
879 in_coefficient = new gain_t[xfade_frames];
881 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
885 SndFileSource::set_timeline_position (framepos_t pos)
887 // destructive track timeline postion does not change
888 // except at instantion or when header_position_offset
889 // (session start) changes
891 if (!destructive()) {
892 AudioFileSource::set_timeline_position (pos);
897 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
903 sf_info.format = 0; // libsndfile says to clear this before sf_open().
905 if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
907 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
911 info.samplerate = sf_info.samplerate;
912 info.channels = sf_info.channels;
913 info.length = sf_info.frames;
915 string major = sndfile_major_format(sf_info.format);
916 string minor = sndfile_minor_format(sf_info.format);
918 if (major.length() + minor.length() < 16) { /* arbitrary */
919 info.format_name = string_compose("%1/%2", major, minor);
921 info.format_name = string_compose("%1\n%2", major, minor);
924 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
932 SndFileSource::one_of_several_channels () const
934 return _info.channels > 1;
938 SndFileSource::clamped_at_unity () const
940 int const type = _info.format & SF_FORMAT_TYPEMASK;
941 int const sub = _info.format & SF_FORMAT_SUBMASK;
942 /* XXX: this may not be the full list of formats that are unclamped */
943 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
947 SndFileSource::file_closed ()
949 /* stupid libsndfile updated the headers on close,
950 so touch the peakfile if it exists and has data
951 to make sure its time is as new as the audio
959 SndFileSource::set_path (const string& p)
961 FileSource::set_path (p);
964 _descriptor->set_path (_path);