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.
26 #include <sys/utsname.h>
29 #include <glibmm/miscutils.h>
31 #include "ardour/sndfilesource.h"
32 #include "ardour/sndfile_helpers.h"
33 #include "ardour/utils.h"
34 #include "ardour/version.h"
35 #include "ardour/rc_configuration.h"
36 #include "ardour/session.h"
41 using namespace ARDOUR;
45 gain_t* SndFileSource::out_coefficient = 0;
46 gain_t* SndFileSource::in_coefficient = 0;
47 nframes_t SndFileSource::xfade_frames = 64;
48 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
51 Source::RemovableIfEmpty |
54 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
56 , AudioFileSource (s, node)
61 throw failed_constructor ();
65 /** Files created this way are never writable or removable */
66 SndFileSource::SndFileSource (Session& s, const ustring& path, bool embedded, int chn, Flag flags)
67 : Source(s, DataType::AUDIO, path, flags)
68 , AudioFileSource (s, path, embedded,
69 Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
76 throw failed_constructor ();
80 /** This constructor is used to construct new files, not open existing ones. */
81 SndFileSource::SndFileSource (Session& s, const ustring& path, bool embedded,
82 SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
83 : Source(s, DataType::AUDIO, path, flags)
84 , AudioFileSource (s, path, embedded, flags, sfmt, hf)
95 _flags = Flag (_flags & ~Broadcast);
100 _flags = Flag (_flags & ~Broadcast);
105 _flags = Flag (_flags | Broadcast);
110 _flags = Flag (_flags & ~Broadcast);
115 _flags = Flag (_flags & ~Broadcast);
119 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
127 fmt |= SF_FORMAT_FLOAT;
131 fmt |= SF_FORMAT_PCM_24;
135 fmt |= SF_FORMAT_PCM_16;
140 _info.samplerate = rate;
144 throw failed_constructor();
147 if (writable() && (_flags & Broadcast)) {
149 if (!_broadcast_info) {
150 _broadcast_info = new BroadcastInfo;
153 _broadcast_info->set_from_session (s, header_position_offset);
154 _broadcast_info->set_description (string_compose ("BWF %1", _name));
156 if (!_broadcast_info->write_to_file (sf)) {
157 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
158 _path, _broadcast_info->get_error())
160 _flags = Flag (_flags & ~Broadcast);
161 delete _broadcast_info;
168 SndFileSource::init_sndfile ()
172 // lets try to keep the object initalizations here at the top
180 _name = Glib::path_get_basename (_path);
183 /* although libsndfile says we don't need to set this,
184 valgrind and source code shows us that we do.
187 memset (&_info, 0, sizeof(_info));
189 _capture_start = false;
190 _capture_end = false;
194 xfade_buf = new Sample[xfade_frames];
195 _timeline_position = header_position_offset;
198 AudioFileSource::HeaderPositionOffsetChanged.connect (
199 mem_fun (*this, &SndFileSource::handle_header_position_change));
203 SndFileSource::open ()
205 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
207 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
208 #ifndef HAVE_COREAUDIO
209 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
210 so we don't want to see this message.
213 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
214 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
219 if (_channel >= _info.channels) {
220 #ifndef HAVE_COREAUDIO
221 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
228 _length = _info.frames;
230 if (!_broadcast_info) {
231 _broadcast_info = new BroadcastInfo;
234 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
236 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
238 if (_length != 0 && !bwf_info_exists) {
239 delete _broadcast_info;
241 _flags = Flag (_flags & ~Broadcast);
245 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
251 SndFileSource::~SndFileSource ()
253 GoingAway (); /* EMIT SIGNAL */
259 /* stupid libsndfile updated the headers on close,
260 so touch the peakfile if it exists and has data
261 to make sure its time is as new as the audio
268 delete _broadcast_info;
273 SndFileSource::sample_rate () const
275 return _info.samplerate;
279 SndFileSource::read_unlocked (Sample *dst, sframes_t start, nframes_t cnt) const
286 if (start > _length) {
288 /* read starts beyond end of data, just memset to zero */
292 } else if (start + cnt > _length) {
294 /* read ends beyond end of data, read some, memset the rest */
296 file_cnt = _length - start;
300 /* read is entirely within data */
305 if (file_cnt != cnt) {
306 nframes_t delta = cnt - file_cnt;
307 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
312 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
314 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
315 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
319 if (_info.channels == 1) {
320 nframes_t ret = sf_read_float (sf, dst, file_cnt);
321 _read_data_count = ret * sizeof(float);
322 if (ret != file_cnt) {
324 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
325 cerr << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.substr (1), errbuf, _length) << endl;
331 real_cnt = cnt * _info.channels;
333 Sample* interleave_buf = get_interleave_buffer (real_cnt);
335 nread = sf_read_float (sf, interleave_buf, real_cnt);
336 ptr = interleave_buf + _channel;
337 nread /= _info.channels;
339 /* stride through the interleaved data */
341 for (int32_t n = 0; n < nread; ++n) {
343 ptr += _info.channels;
346 _read_data_count = cnt * sizeof(float);
352 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
355 return destructive_write_unlocked (data, cnt);
357 return nondestructive_write_unlocked (data, cnt);
362 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
365 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
369 if (_info.channels != 1) {
370 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
376 int32_t frame_pos = _length;
378 if (write_float (data, frame_pos, cnt) != cnt) {
383 update_length (oldlen, cnt);
385 if (_build_peakfiles) {
386 compute_and_write_peaks (data, frame_pos, cnt, false, true);
389 _write_data_count = cnt;
395 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
397 nframes_t old_file_pos;
400 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
404 if (_capture_start && _capture_end) {
406 /* start and end of capture both occur within the data we are writing,
407 so do both crossfades.
410 _capture_start = false;
411 _capture_end = false;
413 /* move to the correct location place */
414 file_pos = capture_start_frame - _timeline_position;
417 nframes_t subcnt = cnt / 2;
418 nframes_t ofilepos = file_pos;
421 if (crossfade (data, subcnt, 1) != subcnt) {
426 Sample * tmpdata = data + subcnt;
429 subcnt = cnt - subcnt;
430 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
434 file_pos = ofilepos; // adjusted below
436 } else if (_capture_start) {
438 /* start of capture both occur within the data we are writing,
442 _capture_start = false;
443 _capture_end = false;
445 /* move to the correct location place */
446 file_pos = capture_start_frame - _timeline_position;
448 if (crossfade (data, cnt, 1) != cnt) {
452 } else if (_capture_end) {
454 /* end of capture both occur within the data we are writing,
458 _capture_start = false;
459 _capture_end = false;
461 if (crossfade (data, cnt, 0) != cnt) {
467 /* in the middle of recording */
469 if (write_float (data, file_pos, cnt) != cnt) {
474 old_file_pos = file_pos;
475 update_length (file_pos, cnt);
477 if (_build_peakfiles) {
478 compute_and_write_peaks (data, file_pos, cnt, false, true);
487 SndFileSource::update_header (sframes_t when, struct tm& now, time_t tnow)
489 set_timeline_position (when);
491 if (_flags & Broadcast) {
492 if (setup_broadcast_info (when, now, tnow)) {
497 return flush_header ();
501 SndFileSource::flush_header ()
503 if (!writable() || (sf == 0)) {
504 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
507 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
511 SndFileSource::setup_broadcast_info (sframes_t when, struct tm& now, time_t tnow)
514 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
518 if (!(_flags & Broadcast)) {
522 _broadcast_info->set_originator_ref (_session);
523 _broadcast_info->set_origination_time (&now);
525 /* now update header position taking header offset into account */
527 set_header_timeline_position ();
529 if (!_broadcast_info->write_to_file (sf)) {
530 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
531 _path, _broadcast_info->get_error())
533 _flags = Flag (_flags & ~Broadcast);
534 delete _broadcast_info;
542 SndFileSource::set_header_timeline_position ()
544 if (!(_flags & Broadcast)) {
548 _broadcast_info->set_time_reference (_timeline_position);
550 if (!_broadcast_info->write_to_file (sf)) {
551 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
552 _path, _broadcast_info->get_error())
554 _flags = Flag (_flags & ~Broadcast);
555 delete _broadcast_info;
561 SndFileSource::write_float (Sample* data, sframes_t frame_pos, nframes_t cnt)
563 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
565 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
566 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
570 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
578 SndFileSource::natural_position() const
580 return _timeline_position;
584 SndFileSource::set_destructive (bool yn)
587 _flags = Flag (_flags | Destructive);
589 xfade_buf = new Sample[xfade_frames];
591 clear_capture_marks ();
592 _timeline_position = header_position_offset;
594 _flags = Flag (_flags & ~Destructive);
595 _timeline_position = 0;
596 /* leave xfade buf alone in case we need it again later */
603 SndFileSource::clear_capture_marks ()
605 _capture_start = false;
606 _capture_end = false;
610 SndFileSource::mark_capture_start (sframes_t pos)
613 if (pos < _timeline_position) {
614 _capture_start = false;
616 _capture_start = true;
617 capture_start_frame = pos;
623 SndFileSource::mark_capture_end()
631 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
633 nframes_t xfade = min (xfade_frames, cnt);
634 nframes_t nofade = cnt - xfade;
635 Sample* fade_data = 0;
636 nframes_t fade_position = 0; // in frames
641 fade_position = file_pos;
644 fade_position = file_pos + nofade;
645 fade_data = data + nofade;
648 if (fade_position > _length) {
650 /* read starts beyond end of data, just memset to zero */
654 } else if (fade_position + xfade > _length) {
656 /* read ends beyond end of data, read some, memset the rest */
658 file_cnt = _length - fade_position;
662 /* read is entirely within data */
669 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
670 if (retval >= 0 && errno == EAGAIN) {
671 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
672 * short or no data there */
673 memset (xfade_buf, 0, xfade * sizeof(Sample));
675 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
681 if (file_cnt != xfade) {
682 nframes_t delta = xfade - file_cnt;
683 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
686 if (nofade && !fade_in) {
687 if (write_float (data, file_pos, nofade) != nofade) {
688 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
693 if (xfade == xfade_frames) {
697 /* use the standard xfade curve */
701 /* fade new material in */
703 for (n = 0; n < xfade; ++n) {
704 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
710 /* fade new material out */
712 for (n = 0; n < xfade; ++n) {
713 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
717 } else if (xfade < xfade_frames) {
722 /* short xfade, compute custom curve */
724 compute_equal_power_fades (xfade, in, out);
726 for (nframes_t n = 0; n < xfade; ++n) {
727 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
732 /* long xfade length, has to be computed across several calls */
737 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
738 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
743 if (fade_in && nofade) {
744 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
745 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
754 SndFileSource::last_capture_start_frame () const
757 return capture_start_frame;
764 SndFileSource::handle_header_position_change ()
767 if ( _length != 0 ) {
768 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
769 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
770 } else if (writable()) {
771 _timeline_position = header_position_offset;
772 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
778 SndFileSource::setup_standard_crossfades (Session const & s, nframes_t rate)
780 /* This static method is assumed to have been called by the Session
781 before any DFS's are created.
784 xfade_frames = (nframes_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
786 delete [] out_coefficient;
787 delete [] in_coefficient;
789 out_coefficient = new gain_t[xfade_frames];
790 in_coefficient = new gain_t[xfade_frames];
792 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
796 SndFileSource::set_timeline_position (int64_t pos)
798 // destructive track timeline postion does not change
799 // except at instantion or when header_position_offset
800 // (session start) changes
802 if (!destructive()) {
803 AudioFileSource::set_timeline_position (pos);
808 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
814 sf_info.format = 0; // libsndfile says to clear this before sf_open().
816 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
818 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
822 info.samplerate = sf_info.samplerate;
823 info.channels = sf_info.channels;
824 info.length = sf_info.frames;
825 info.format_name = string_compose("Format: %1, %2",
826 sndfile_major_format(sf_info.format),
827 sndfile_minor_format(sf_info.format));
829 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
837 SndFileSource::one_of_several_channels () const
839 return _info.channels > 1;