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 nframes_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 ustring& path, int chn, Flag flags)
71 : Source(s, DataType::AUDIO, path, flags)
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 ustring& path,
85 SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
86 : Source(s, DataType::AUDIO, path, flags)
87 , AudioFileSource (s, path, 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;
147 throw failed_constructor();
150 if (writable() && (_flags & Broadcast)) {
152 if (!_broadcast_info) {
153 _broadcast_info = new BroadcastInfo;
156 _broadcast_info->set_from_session (s, header_position_offset);
157 _broadcast_info->set_description (string_compose ("BWF %1", _name));
159 if (!_broadcast_info->write_to_file (sf)) {
160 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
161 _path, _broadcast_info->get_error())
163 _flags = Flag (_flags & ~Broadcast);
164 delete _broadcast_info;
171 SndFileSource::init_sndfile ()
175 // lets try to keep the object initalizations here at the top
180 /* although libsndfile says we don't need to set this,
181 valgrind and source code shows us that we do.
184 memset (&_info, 0, sizeof(_info));
186 _capture_start = false;
187 _capture_end = false;
191 xfade_buf = new Sample[xfade_frames];
192 _timeline_position = header_position_offset;
195 AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
199 SndFileSource::open ()
201 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
203 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
204 #ifndef HAVE_COREAUDIO
205 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
206 so we don't want to see this message.
209 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
210 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
215 if (_channel >= _info.channels) {
216 #ifndef HAVE_COREAUDIO
217 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
224 _length = _info.frames;
226 if (!_broadcast_info) {
227 _broadcast_info = new BroadcastInfo;
230 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
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);
247 SndFileSource::~SndFileSource ()
255 /* stupid libsndfile updated the headers on close,
256 so touch the peakfile if it exists and has data
257 to make sure its time is as new as the audio
264 delete _broadcast_info;
269 SndFileSource::sample_rate () const
271 return _info.samplerate;
275 SndFileSource::read_unlocked (Sample *dst, sframes_t start, nframes_t cnt) const
282 if (start > _length) {
284 /* read starts beyond end of data, just memset to zero */
288 } else if (start + cnt > _length) {
290 /* read ends beyond end of data, read some, memset the rest */
292 file_cnt = _length - start;
296 /* read is entirely within data */
301 if (file_cnt != cnt) {
302 nframes_t delta = cnt - file_cnt;
303 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
308 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
310 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
311 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
315 if (_info.channels == 1) {
316 nframes_t ret = sf_read_float (sf, dst, file_cnt);
317 _read_data_count = ret * sizeof(float);
318 if (ret != file_cnt) {
320 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
321 cerr << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.substr (1), errbuf, _length) << endl;
327 real_cnt = cnt * _info.channels;
329 Sample* interleave_buf = get_interleave_buffer (real_cnt);
331 nread = sf_read_float (sf, interleave_buf, real_cnt);
332 ptr = interleave_buf + _channel;
333 nread /= _info.channels;
335 /* stride through the interleaved data */
337 for (int32_t n = 0; n < nread; ++n) {
339 ptr += _info.channels;
342 _read_data_count = cnt * sizeof(float);
348 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
351 return destructive_write_unlocked (data, cnt);
353 return nondestructive_write_unlocked (data, cnt);
358 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
361 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
365 if (_info.channels != 1) {
366 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
372 int32_t frame_pos = _length;
374 if (write_float (data, frame_pos, cnt) != cnt) {
379 update_length (oldlen, cnt);
381 if (_build_peakfiles) {
382 compute_and_write_peaks (data, frame_pos, cnt, false, true);
385 _write_data_count = cnt;
391 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
393 nframes_t old_file_pos;
396 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
400 if (_capture_start && _capture_end) {
402 /* start and end of capture both occur within the data we are writing,
403 so do both crossfades.
406 _capture_start = false;
407 _capture_end = false;
409 /* move to the correct location place */
410 file_pos = capture_start_frame - _timeline_position;
413 nframes_t subcnt = cnt / 2;
414 nframes_t ofilepos = file_pos;
417 if (crossfade (data, subcnt, 1) != subcnt) {
422 Sample * tmpdata = data + subcnt;
425 subcnt = cnt - subcnt;
426 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
430 file_pos = ofilepos; // adjusted below
432 } else if (_capture_start) {
434 /* start of capture both occur within the data we are writing,
438 _capture_start = false;
439 _capture_end = false;
441 /* move to the correct location place */
442 file_pos = capture_start_frame - _timeline_position;
444 if (crossfade (data, cnt, 1) != cnt) {
448 } else if (_capture_end) {
450 /* end of capture both occur within the data we are writing,
454 _capture_start = false;
455 _capture_end = false;
457 if (crossfade (data, cnt, 0) != cnt) {
463 /* in the middle of recording */
465 if (write_float (data, file_pos, cnt) != cnt) {
470 old_file_pos = file_pos;
471 update_length (file_pos, cnt);
473 if (_build_peakfiles) {
474 compute_and_write_peaks (data, file_pos, cnt, false, true);
483 SndFileSource::update_header (sframes_t when, struct tm& now, time_t tnow)
485 set_timeline_position (when);
487 if (_flags & Broadcast) {
488 if (setup_broadcast_info (when, now, tnow)) {
493 return flush_header ();
497 SndFileSource::flush_header ()
499 if (!writable() || (sf == 0)) {
500 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
503 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
507 SndFileSource::setup_broadcast_info (sframes_t /*when*/, struct tm& now, time_t /*tnow*/)
510 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
514 if (!(_flags & Broadcast)) {
518 _broadcast_info->set_originator_ref (_session);
519 _broadcast_info->set_origination_time (&now);
521 /* now update header position taking header offset into account */
523 set_header_timeline_position ();
525 if (!_broadcast_info->write_to_file (sf)) {
526 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
527 _path, _broadcast_info->get_error())
529 _flags = Flag (_flags & ~Broadcast);
530 delete _broadcast_info;
538 SndFileSource::set_header_timeline_position ()
540 if (!(_flags & Broadcast)) {
544 _broadcast_info->set_time_reference (_timeline_position);
546 if (!_broadcast_info->write_to_file (sf)) {
547 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
548 _path, _broadcast_info->get_error())
550 _flags = Flag (_flags & ~Broadcast);
551 delete _broadcast_info;
557 SndFileSource::write_float (Sample* data, sframes_t frame_pos, nframes_t cnt)
559 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
561 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
562 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
566 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
574 SndFileSource::natural_position() const
576 return _timeline_position;
580 SndFileSource::set_destructive (bool yn)
583 _flags = Flag (_flags | Destructive);
585 xfade_buf = new Sample[xfade_frames];
587 clear_capture_marks ();
588 _timeline_position = header_position_offset;
590 _flags = Flag (_flags & ~Destructive);
591 _timeline_position = 0;
592 /* leave xfade buf alone in case we need it again later */
599 SndFileSource::clear_capture_marks ()
601 _capture_start = false;
602 _capture_end = false;
606 SndFileSource::mark_capture_start (sframes_t pos)
609 if (pos < _timeline_position) {
610 _capture_start = false;
612 _capture_start = true;
613 capture_start_frame = pos;
619 SndFileSource::mark_capture_end()
627 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
629 nframes_t xfade = min (xfade_frames, cnt);
630 nframes_t nofade = cnt - xfade;
631 Sample* fade_data = 0;
632 nframes_t fade_position = 0; // in frames
637 fade_position = file_pos;
640 fade_position = file_pos + nofade;
641 fade_data = data + nofade;
644 if (fade_position > _length) {
646 /* read starts beyond end of data, just memset to zero */
650 } else if (fade_position + xfade > _length) {
652 /* read ends beyond end of data, read some, memset the rest */
654 file_cnt = _length - fade_position;
658 /* read is entirely within data */
665 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
666 if (retval >= 0 && errno == EAGAIN) {
667 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
668 * short or no data there */
669 memset (xfade_buf, 0, xfade * sizeof(Sample));
671 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
677 if (file_cnt != xfade) {
678 nframes_t delta = xfade - file_cnt;
679 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
682 if (nofade && !fade_in) {
683 if (write_float (data, file_pos, nofade) != nofade) {
684 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
689 if (xfade == xfade_frames) {
693 /* use the standard xfade curve */
697 /* fade new material in */
699 for (n = 0; n < xfade; ++n) {
700 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
706 /* fade new material out */
708 for (n = 0; n < xfade; ++n) {
709 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
713 } else if (xfade < xfade_frames) {
718 /* short xfade, compute custom curve */
720 compute_equal_power_fades (xfade, in, out);
722 for (nframes_t n = 0; n < xfade; ++n) {
723 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
728 /* long xfade length, has to be computed across several calls */
733 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
734 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
739 if (fade_in && nofade) {
740 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
741 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
750 SndFileSource::last_capture_start_frame () const
753 return capture_start_frame;
760 SndFileSource::handle_header_position_change ()
763 if ( _length != 0 ) {
764 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
765 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
766 } else if (writable()) {
767 _timeline_position = header_position_offset;
768 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
774 SndFileSource::setup_standard_crossfades (Session const & s, nframes_t rate)
776 /* This static method is assumed to have been called by the Session
777 before any DFS's are created.
780 xfade_frames = (nframes_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
782 delete [] out_coefficient;
783 delete [] in_coefficient;
785 out_coefficient = new gain_t[xfade_frames];
786 in_coefficient = new gain_t[xfade_frames];
788 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
792 SndFileSource::set_timeline_position (int64_t pos)
794 // destructive track timeline postion does not change
795 // except at instantion or when header_position_offset
796 // (session start) changes
798 if (!destructive()) {
799 AudioFileSource::set_timeline_position (pos);
804 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
810 sf_info.format = 0; // libsndfile says to clear this before sf_open().
812 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
814 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
818 info.samplerate = sf_info.samplerate;
819 info.channels = sf_info.channels;
820 info.length = sf_info.frames;
821 info.format_name = string_compose("Format: %1, %2",
822 sndfile_major_format(sf_info.format),
823 sndfile_minor_format(sf_info.format));
825 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
833 SndFileSource::one_of_several_channels () const
835 return _info.channels > 1;