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 /** Files created this way are never writable or removable */
69 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
70 : Source(s, DataType::AUDIO, path, flags)
71 /* note that the origin of an external file is itself */
72 , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
79 throw failed_constructor ();
83 /** This constructor is used to construct new files, not open existing ones. */
84 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
85 SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
86 : Source(s, DataType::AUDIO, path, flags)
87 , AudioFileSource (s, path, origin, flags, sfmt, hf)
98 _flags = Flag (_flags & ~Broadcast);
102 fmt = SF_FORMAT_AIFF;
103 _flags = Flag (_flags & ~Broadcast);
108 _flags = Flag (_flags | Broadcast);
113 _flags = Flag (_flags & ~Broadcast);
118 _flags = Flag (_flags & ~Broadcast);
122 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
130 fmt |= SF_FORMAT_FLOAT;
134 fmt |= SF_FORMAT_PCM_24;
138 fmt |= SF_FORMAT_PCM_16;
143 _info.samplerate = rate;
146 if (_flags & Destructive) {
148 throw failed_constructor();
151 /* normal mode: do not open the file here - do that in write_unlocked() as needed
157 SndFileSource::init_sndfile ()
163 // lets try to keep the object initalizations here at the top
167 /* although libsndfile says we don't need to set this,
168 valgrind and source code shows us that we do.
171 memset (&_info, 0, sizeof(_info));
173 _capture_start = false;
174 _capture_end = false;
178 xfade_buf = new Sample[xfade_frames];
179 _timeline_position = header_position_offset;
182 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
186 SndFileSource::open ()
190 #ifdef PLATFORM_WINDOWS
191 path_to_open = Glib::locale_from_utf8(_path);
193 path_to_open = _path;
196 _descriptor = new SndFileDescriptor (path_to_open.c_str(), writable(), &_info);
197 _descriptor->Closed.connect_same_thread (file_manager_connection, boost::bind (&SndFileSource::file_closed, this));
198 SNDFILE* sf = _descriptor->allocate ();
202 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
203 #ifndef HAVE_COREAUDIO
204 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
205 so we don't want to see this message.
208 cerr << "failed to open " << path_to_open << " with name " << _name << endl;
210 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
211 path_to_open, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
216 if (_channel >= _info.channels) {
217 #ifndef HAVE_COREAUDIO
218 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
225 _length = _info.frames;
227 if (!_broadcast_info) {
228 _broadcast_info = new BroadcastInfo;
231 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
233 if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
234 /* newly created files will not have a BWF header at this point in time.
235 * Import will have called Source::set_timeline_position() if one exists
236 * in the original. */
237 header_position_offset = _timeline_position;
240 /* Set our timeline position to either the time reference from a BWF header or the current
241 start of the session.
243 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
245 if (_length != 0 && !bwf_info_exists) {
246 delete _broadcast_info;
248 _flags = Flag (_flags & ~Broadcast);
252 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
254 if (_flags & Broadcast) {
256 if (!_broadcast_info) {
257 _broadcast_info = new BroadcastInfo;
260 _broadcast_info->set_from_session (_session, header_position_offset);
261 _broadcast_info->set_description (string_compose ("BWF %1", _name));
263 if (!_broadcast_info->write_to_file (sf)) {
264 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
265 path_to_open, _broadcast_info->get_error())
267 _flags = Flag (_flags & ~Broadcast);
268 delete _broadcast_info;
274 _descriptor->release ();
279 SndFileSource::~SndFileSource ()
282 delete _broadcast_info;
287 SndFileSource::sample_rate () const
289 return _info.samplerate;
293 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
302 if (writable() && !_open) {
303 /* file has not been opened yet - nothing written to it */
304 memset (dst, 0, sizeof (Sample) * cnt);
308 SNDFILE* sf = _descriptor->allocate ();
311 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
315 if (start > _length) {
317 /* read starts beyond end of data, just memset to zero */
321 } else if (start + cnt > _length) {
323 /* read ends beyond end of data, read some, memset the rest */
325 file_cnt = _length - start;
329 /* read is entirely within data */
334 assert (file_cnt >= 0);
336 if (file_cnt != cnt) {
337 framepos_t delta = cnt - file_cnt;
338 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
343 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
345 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
346 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
347 _descriptor->release ();
351 if (_info.channels == 1) {
352 framecnt_t ret = sf_read_float (sf, dst, file_cnt);
353 if (ret != file_cnt) {
355 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
356 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;
358 _descriptor->release ();
363 real_cnt = cnt * _info.channels;
365 Sample* interleave_buf = get_interleave_buffer (real_cnt);
367 nread = sf_read_float (sf, interleave_buf, real_cnt);
368 ptr = interleave_buf + _channel;
369 nread /= _info.channels;
371 /* stride through the interleaved data */
373 for (int32_t n = 0; n < nread; ++n) {
375 ptr += _info.channels;
378 _descriptor->release ();
383 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
385 if (!_open && open()) {
390 return destructive_write_unlocked (data, cnt);
392 return nondestructive_write_unlocked (data, cnt);
397 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
400 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
404 if (_info.channels != 1) {
405 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
410 int32_t frame_pos = _length;
412 if (write_float (data, frame_pos, cnt) != cnt) {
416 update_length (_length + cnt);
418 if (_build_peakfiles) {
419 compute_and_write_peaks (data, frame_pos, cnt, false, true);
426 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
429 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
433 if (_capture_start && _capture_end) {
435 /* start and end of capture both occur within the data we are writing,
436 so do both crossfades.
439 _capture_start = false;
440 _capture_end = false;
442 /* move to the correct location place */
443 file_pos = capture_start_frame - _timeline_position;
446 framecnt_t subcnt = cnt / 2;
447 framecnt_t ofilepos = file_pos;
450 if (crossfade (data, subcnt, 1) != subcnt) {
455 Sample * tmpdata = data + subcnt;
458 subcnt = cnt - subcnt;
459 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
463 file_pos = ofilepos; // adjusted below
465 } else if (_capture_start) {
467 /* start of capture both occur within the data we are writing,
471 _capture_start = false;
472 _capture_end = false;
474 /* move to the correct location place */
475 file_pos = capture_start_frame - _timeline_position;
477 if (crossfade (data, cnt, 1) != cnt) {
481 } else if (_capture_end) {
483 /* end of capture both occur within the data we are writing,
487 _capture_start = false;
488 _capture_end = false;
490 if (crossfade (data, cnt, 0) != cnt) {
496 /* in the middle of recording */
498 if (write_float (data, file_pos, cnt) != cnt) {
503 update_length (file_pos + cnt);
505 if (_build_peakfiles) {
506 compute_and_write_peaks (data, file_pos, cnt, false, true);
515 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
517 set_timeline_position (when);
519 if (_flags & Broadcast) {
520 if (setup_broadcast_info (when, now, tnow)) {
525 return flush_header ();
529 SndFileSource::flush_header ()
532 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
537 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
541 SNDFILE* sf = _descriptor->allocate ();
543 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
547 int const r = sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
548 _descriptor->release ();
554 SndFileSource::flush ()
557 warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
562 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
566 SNDFILE* sf = _descriptor->allocate ();
568 error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
572 // Hopefully everything OK
574 _descriptor->release ();
578 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
581 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
586 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
590 if (!(_flags & Broadcast)) {
594 _broadcast_info->set_originator_ref_from_session (_session);
595 _broadcast_info->set_origination_time (&now);
597 /* now update header position taking header offset into account */
599 set_header_timeline_position ();
601 SNDFILE* sf = _descriptor->allocate ();
603 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
604 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
605 _path, _broadcast_info->get_error())
607 _flags = Flag (_flags & ~Broadcast);
608 delete _broadcast_info;
612 _descriptor->release ();
617 SndFileSource::set_header_timeline_position ()
619 if (!(_flags & Broadcast)) {
623 _broadcast_info->set_time_reference (_timeline_position);
625 SNDFILE* sf = _descriptor->allocate ();
627 if (sf == 0 || !_broadcast_info->write_to_file (sf)) {
628 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
629 _path, _broadcast_info->get_error())
631 _flags = Flag (_flags & ~Broadcast);
632 delete _broadcast_info;
636 _descriptor->release ();
640 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
642 SNDFILE* sf = _descriptor->allocate ();
644 if (sf == 0 || sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
646 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
647 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
648 _descriptor->release ();
652 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
653 _descriptor->release ();
657 _descriptor->release ();
662 SndFileSource::natural_position() const
664 return _timeline_position;
668 SndFileSource::set_destructive (bool yn)
671 _flags = Flag (_flags | Writable | Destructive);
673 xfade_buf = new Sample[xfade_frames];
675 clear_capture_marks ();
676 _timeline_position = header_position_offset;
678 _flags = Flag (_flags & ~Destructive);
679 _timeline_position = 0;
680 /* leave xfade buf alone in case we need it again later */
687 SndFileSource::clear_capture_marks ()
689 _capture_start = false;
690 _capture_end = false;
693 /** @param pos Capture start position in session frames */
695 SndFileSource::mark_capture_start (framepos_t pos)
698 if (pos < _timeline_position) {
699 _capture_start = false;
701 _capture_start = true;
702 capture_start_frame = pos;
708 SndFileSource::mark_capture_end()
716 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
718 framecnt_t xfade = min (xfade_frames, cnt);
719 framecnt_t nofade = cnt - xfade;
720 Sample* fade_data = 0;
721 framepos_t fade_position = 0; // in frames
726 fade_position = file_pos;
729 fade_position = file_pos + nofade;
730 fade_data = data + nofade;
733 if (fade_position > _length) {
735 /* read starts beyond end of data, just memset to zero */
739 } else if (fade_position + xfade > _length) {
741 /* read ends beyond end of data, read some, memset the rest */
743 file_cnt = _length - fade_position;
747 /* read is entirely within data */
754 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
755 if (retval >= 0 && errno == EAGAIN) {
756 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
757 * short or no data there */
758 memset (xfade_buf, 0, xfade * sizeof(Sample));
760 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
766 if (file_cnt != xfade) {
767 framecnt_t delta = xfade - file_cnt;
768 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
771 if (nofade && !fade_in) {
772 if (write_float (data, file_pos, nofade) != nofade) {
773 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
778 if (xfade == xfade_frames) {
782 /* use the standard xfade curve */
786 /* fade new material in */
788 for (n = 0; n < xfade; ++n) {
789 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
795 /* fade new material out */
797 for (n = 0; n < xfade; ++n) {
798 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
802 } else if (xfade < xfade_frames) {
804 std::vector<gain_t> in(xfade);
805 std::vector<gain_t> out(xfade);
807 /* short xfade, compute custom curve */
809 compute_equal_power_fades (xfade, &in[0], &out[0]);
811 for (framecnt_t n = 0; n < xfade; ++n) {
812 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
817 /* long xfade length, has to be computed across several calls */
822 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
823 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
828 if (fade_in && nofade) {
829 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
830 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
839 SndFileSource::last_capture_start_frame () const
842 return capture_start_frame;
849 SndFileSource::handle_header_position_change ()
852 if ( _length != 0 ) {
853 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
854 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
855 } else if (writable()) {
856 _timeline_position = header_position_offset;
857 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
863 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
865 /* This static method is assumed to have been called by the Session
866 before any DFS's are created.
869 xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
871 delete [] out_coefficient;
872 delete [] in_coefficient;
874 out_coefficient = new gain_t[xfade_frames];
875 in_coefficient = new gain_t[xfade_frames];
877 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
881 SndFileSource::set_timeline_position (framepos_t pos)
883 // destructive track timeline postion does not change
884 // except at instantion or when header_position_offset
885 // (session start) changes
887 if (!destructive()) {
888 AudioFileSource::set_timeline_position (pos);
893 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
899 sf_info.format = 0; // libsndfile says to clear this before sf_open().
901 if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
903 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
907 info.samplerate = sf_info.samplerate;
908 info.channels = sf_info.channels;
909 info.length = sf_info.frames;
911 string major = sndfile_major_format(sf_info.format);
912 string minor = sndfile_minor_format(sf_info.format);
914 if (major.length() + minor.length() < 16) { /* arbitrary */
915 info.format_name = string_compose("%1/%2", major, minor);
917 info.format_name = string_compose("%1\n%2", major, minor);
920 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
928 SndFileSource::one_of_several_channels () const
930 return _info.channels > 1;
934 SndFileSource::clamped_at_unity () const
936 int const type = _info.format & SF_FORMAT_TYPEMASK;
937 int const sub = _info.format & SF_FORMAT_SUBMASK;
938 /* XXX: this may not be the full list of formats that are unclamped */
939 return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
943 SndFileSource::file_closed ()
945 /* stupid libsndfile updated the headers on close,
946 so touch the peakfile if it exists and has data
947 to make sure its time is as new as the audio
955 SndFileSource::set_path (const string& p)
957 FileSource::set_path (p);
960 _descriptor->set_path (_path);