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, bool embedded, int chn, Flag flags)
71 : Source(s, DataType::AUDIO, path, flags)
72 , AudioFileSource (s, path, embedded,
73 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 ustring& path, bool embedded,
86 SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
87 : Source(s, DataType::AUDIO, path, flags)
88 , AudioFileSource (s, path, embedded, 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;
148 throw failed_constructor();
151 if (writable() && (_flags & Broadcast)) {
153 if (!_broadcast_info) {
154 _broadcast_info = new BroadcastInfo;
157 _broadcast_info->set_from_session (s, header_position_offset);
158 _broadcast_info->set_description (string_compose ("BWF %1", _name));
160 if (!_broadcast_info->write_to_file (sf)) {
161 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
162 _path, _broadcast_info->get_error())
164 _flags = Flag (_flags & ~Broadcast);
165 delete _broadcast_info;
172 SndFileSource::init_sndfile ()
176 // lets try to keep the object initalizations here at the top
184 _name = Glib::path_get_basename (_path);
187 /* although libsndfile says we don't need to set this,
188 valgrind and source code shows us that we do.
191 memset (&_info, 0, sizeof(_info));
193 _capture_start = false;
194 _capture_end = false;
198 xfade_buf = new Sample[xfade_frames];
199 _timeline_position = header_position_offset;
202 AudioFileSource::HeaderPositionOffsetChanged.connect (
203 mem_fun (*this, &SndFileSource::handle_header_position_change));
207 SndFileSource::open ()
209 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
211 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
212 #ifndef HAVE_COREAUDIO
213 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
214 so we don't want to see this message.
217 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
218 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
223 if (_channel >= _info.channels) {
224 #ifndef HAVE_COREAUDIO
225 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
232 _length = _info.frames;
234 if (!_broadcast_info) {
235 _broadcast_info = new BroadcastInfo;
238 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
240 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
242 if (_length != 0 && !bwf_info_exists) {
243 delete _broadcast_info;
245 _flags = Flag (_flags & ~Broadcast);
249 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
255 SndFileSource::~SndFileSource ()
257 GoingAway (); /* EMIT SIGNAL */
263 /* stupid libsndfile updated the headers on close,
264 so touch the peakfile if it exists and has data
265 to make sure its time is as new as the audio
272 delete _broadcast_info;
277 SndFileSource::sample_rate () const
279 return _info.samplerate;
283 SndFileSource::read_unlocked (Sample *dst, sframes_t start, nframes_t cnt) const
290 if (start > _length) {
292 /* read starts beyond end of data, just memset to zero */
296 } else if (start + cnt > _length) {
298 /* read ends beyond end of data, read some, memset the rest */
300 file_cnt = _length - start;
304 /* read is entirely within data */
309 if (file_cnt != cnt) {
310 nframes_t delta = cnt - file_cnt;
311 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
316 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
318 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
319 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
323 if (_info.channels == 1) {
324 nframes_t ret = sf_read_float (sf, dst, file_cnt);
325 _read_data_count = ret * sizeof(float);
326 if (ret != file_cnt) {
328 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
329 cerr << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.substr (1), errbuf, _length) << endl;
335 real_cnt = cnt * _info.channels;
337 Sample* interleave_buf = get_interleave_buffer (real_cnt);
339 nread = sf_read_float (sf, interleave_buf, real_cnt);
340 ptr = interleave_buf + _channel;
341 nread /= _info.channels;
343 /* stride through the interleaved data */
345 for (int32_t n = 0; n < nread; ++n) {
347 ptr += _info.channels;
350 _read_data_count = cnt * sizeof(float);
356 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
359 return destructive_write_unlocked (data, cnt);
361 return nondestructive_write_unlocked (data, cnt);
366 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
369 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
373 if (_info.channels != 1) {
374 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
380 int32_t frame_pos = _length;
382 if (write_float (data, frame_pos, cnt) != cnt) {
387 update_length (oldlen, cnt);
389 if (_build_peakfiles) {
390 compute_and_write_peaks (data, frame_pos, cnt, false, true);
393 _write_data_count = cnt;
399 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
401 nframes_t old_file_pos;
404 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
408 if (_capture_start && _capture_end) {
410 /* start and end of capture both occur within the data we are writing,
411 so do both crossfades.
414 _capture_start = false;
415 _capture_end = false;
417 /* move to the correct location place */
418 file_pos = capture_start_frame - _timeline_position;
421 nframes_t subcnt = cnt / 2;
422 nframes_t ofilepos = file_pos;
425 if (crossfade (data, subcnt, 1) != subcnt) {
430 Sample * tmpdata = data + subcnt;
433 subcnt = cnt - subcnt;
434 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
438 file_pos = ofilepos; // adjusted below
440 } else if (_capture_start) {
442 /* start of capture both occur within the data we are writing,
446 _capture_start = false;
447 _capture_end = false;
449 /* move to the correct location place */
450 file_pos = capture_start_frame - _timeline_position;
452 if (crossfade (data, cnt, 1) != cnt) {
456 } else if (_capture_end) {
458 /* end of capture both occur within the data we are writing,
462 _capture_start = false;
463 _capture_end = false;
465 if (crossfade (data, cnt, 0) != cnt) {
471 /* in the middle of recording */
473 if (write_float (data, file_pos, cnt) != cnt) {
478 old_file_pos = file_pos;
479 update_length (file_pos, cnt);
481 if (_build_peakfiles) {
482 compute_and_write_peaks (data, file_pos, cnt, false, true);
491 SndFileSource::update_header (sframes_t when, struct tm& now, time_t tnow)
493 set_timeline_position (when);
495 if (_flags & Broadcast) {
496 if (setup_broadcast_info (when, now, tnow)) {
501 return flush_header ();
505 SndFileSource::flush_header ()
507 if (!writable() || (sf == 0)) {
508 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
511 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
515 SndFileSource::setup_broadcast_info (sframes_t /*when*/, struct tm& now, time_t /*tnow*/)
518 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
522 if (!(_flags & Broadcast)) {
526 _broadcast_info->set_originator_ref (_session);
527 _broadcast_info->set_origination_time (&now);
529 /* now update header position taking header offset into account */
531 set_header_timeline_position ();
533 if (!_broadcast_info->write_to_file (sf)) {
534 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
535 _path, _broadcast_info->get_error())
537 _flags = Flag (_flags & ~Broadcast);
538 delete _broadcast_info;
546 SndFileSource::set_header_timeline_position ()
548 if (!(_flags & Broadcast)) {
552 _broadcast_info->set_time_reference (_timeline_position);
554 if (!_broadcast_info->write_to_file (sf)) {
555 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
556 _path, _broadcast_info->get_error())
558 _flags = Flag (_flags & ~Broadcast);
559 delete _broadcast_info;
565 SndFileSource::write_float (Sample* data, sframes_t frame_pos, nframes_t cnt)
567 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
569 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
570 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
574 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
582 SndFileSource::natural_position() const
584 return _timeline_position;
588 SndFileSource::set_destructive (bool yn)
591 _flags = Flag (_flags | Destructive);
593 xfade_buf = new Sample[xfade_frames];
595 clear_capture_marks ();
596 _timeline_position = header_position_offset;
598 _flags = Flag (_flags & ~Destructive);
599 _timeline_position = 0;
600 /* leave xfade buf alone in case we need it again later */
607 SndFileSource::clear_capture_marks ()
609 _capture_start = false;
610 _capture_end = false;
614 SndFileSource::mark_capture_start (sframes_t pos)
617 if (pos < _timeline_position) {
618 _capture_start = false;
620 _capture_start = true;
621 capture_start_frame = pos;
627 SndFileSource::mark_capture_end()
635 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
637 nframes_t xfade = min (xfade_frames, cnt);
638 nframes_t nofade = cnt - xfade;
639 Sample* fade_data = 0;
640 nframes_t fade_position = 0; // in frames
645 fade_position = file_pos;
648 fade_position = file_pos + nofade;
649 fade_data = data + nofade;
652 if (fade_position > _length) {
654 /* read starts beyond end of data, just memset to zero */
658 } else if (fade_position + xfade > _length) {
660 /* read ends beyond end of data, read some, memset the rest */
662 file_cnt = _length - fade_position;
666 /* read is entirely within data */
673 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
674 if (retval >= 0 && errno == EAGAIN) {
675 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
676 * short or no data there */
677 memset (xfade_buf, 0, xfade * sizeof(Sample));
679 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
685 if (file_cnt != xfade) {
686 nframes_t delta = xfade - file_cnt;
687 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
690 if (nofade && !fade_in) {
691 if (write_float (data, file_pos, nofade) != nofade) {
692 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
697 if (xfade == xfade_frames) {
701 /* use the standard xfade curve */
705 /* fade new material in */
707 for (n = 0; n < xfade; ++n) {
708 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
714 /* fade new material out */
716 for (n = 0; n < xfade; ++n) {
717 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
721 } else if (xfade < xfade_frames) {
726 /* short xfade, compute custom curve */
728 compute_equal_power_fades (xfade, in, out);
730 for (nframes_t n = 0; n < xfade; ++n) {
731 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
736 /* long xfade length, has to be computed across several calls */
741 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
742 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
747 if (fade_in && nofade) {
748 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
749 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
758 SndFileSource::last_capture_start_frame () const
761 return capture_start_frame;
768 SndFileSource::handle_header_position_change ()
771 if ( _length != 0 ) {
772 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
773 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
774 } else if (writable()) {
775 _timeline_position = header_position_offset;
776 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
782 SndFileSource::setup_standard_crossfades (Session const & s, nframes_t rate)
784 /* This static method is assumed to have been called by the Session
785 before any DFS's are created.
788 xfade_frames = (nframes_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
790 delete [] out_coefficient;
791 delete [] in_coefficient;
793 out_coefficient = new gain_t[xfade_frames];
794 in_coefficient = new gain_t[xfade_frames];
796 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
800 SndFileSource::set_timeline_position (int64_t pos)
802 // destructive track timeline postion does not change
803 // except at instantion or when header_position_offset
804 // (session start) changes
806 if (!destructive()) {
807 AudioFileSource::set_timeline_position (pos);
812 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
818 sf_info.format = 0; // libsndfile says to clear this before sf_open().
820 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
822 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
826 info.samplerate = sf_info.samplerate;
827 info.channels = sf_info.channels;
828 info.length = sf_info.frames;
829 info.format_name = string_compose("Format: %1, %2",
830 sndfile_major_format(sf_info.format),
831 sndfile_minor_format(sf_info.format));
833 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
841 SndFileSource::one_of_several_channels () const
843 return _info.channels > 1;