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.
24 #include <sys/utsname.h>
27 #include <glibmm/miscutils.h>
28 #include <ardour/sndfilesource.h>
29 #include <ardour/sndfile_helpers.h>
30 #include <ardour/utils.h>
35 using namespace ARDOUR;
39 gain_t* SndFileSource::out_coefficient = 0;
40 gain_t* SndFileSource::in_coefficient = 0;
41 nframes_t SndFileSource::xfade_frames = 64;
42 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
43 AudioFileSource::Removable|
44 AudioFileSource::RemovableIfEmpty|
45 AudioFileSource::CanRename);
46 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
47 : AudioFileSource (s, node)
52 throw failed_constructor ();
56 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
57 /* files created this way are never writable or removable */
58 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
65 throw failed_constructor ();
69 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
70 : AudioFileSource (s, path, flags, sfmt, hf)
76 /* this constructor is used to construct new files, not open
85 _flags = Flag (_flags & ~Broadcast);
90 _flags = Flag (_flags & ~Broadcast);
95 _flags = Flag (_flags | Broadcast);
100 _flags = Flag (_flags & ~Broadcast);
105 _flags = Flag (_flags & ~Broadcast);
109 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
117 fmt |= SF_FORMAT_FLOAT;
121 fmt |= SF_FORMAT_PCM_24;
125 fmt |= SF_FORMAT_PCM_16;
130 _info.samplerate = rate;
134 throw failed_constructor();
137 if (writable() && (_flags & Broadcast)) {
139 _broadcast_info = new SF_BROADCAST_INFO;
140 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
142 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
144 struct utsname utsinfo;
146 if (uname (&utsinfo)) {
147 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
151 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
152 Glib::get_real_name().c_str(),
158 _broadcast_info->version = 1;
159 _broadcast_info->time_reference_low = 0;
160 _broadcast_info->time_reference_high = 0;
162 /* XXX do something about this field */
164 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
166 /* coding history is added by libsndfile */
168 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
170 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
171 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
172 _flags = Flag (_flags & ~Broadcast);
173 delete _broadcast_info;
180 SndFileSource::init ()
184 // lets try to keep the object initalizations here at the top
192 _name = Glib::path_get_basename (_path);
195 /* although libsndfile says we don't need to set this,
196 valgrind and source code shows us that we do.
199 memset (&_info, 0, sizeof(_info));
201 _capture_start = false;
202 _capture_end = false;
206 xfade_buf = new Sample[xfade_frames];
207 timeline_position = header_position_offset;
210 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
214 SndFileSource::open ()
216 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
218 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
219 #ifndef HAVE_COREAUDIO
220 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
221 so we don't want to see this message.
224 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
225 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
230 if (_channel >= _info.channels) {
231 #ifndef HAVE_COREAUDIO
232 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
239 _length = _info.frames;
241 _broadcast_info = new SF_BROADCAST_INFO;
242 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
244 bool timecode_info_exists;
246 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
248 if (_length != 0 && !timecode_info_exists) {
249 delete _broadcast_info;
251 _flags = Flag (_flags & ~Broadcast);
255 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
261 SndFileSource::~SndFileSource ()
263 GoingAway (); /* EMIT SIGNAL */
269 /* stupid libsndfile updated the headers on close,
270 so touch the peakfile if it exists and has data
271 to make sure its time is as new as the audio
278 if (_broadcast_info) {
279 delete _broadcast_info;
288 SndFileSource::sample_rate () const
290 return _info.samplerate;
294 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
301 if (start > _length) {
303 /* read starts beyond end of data, just memset to zero */
307 } else if (start + cnt > _length) {
309 /* read ends beyond end of data, read some, memset the rest */
311 file_cnt = _length - start;
315 /* read is entirely within data */
320 if (file_cnt != cnt) {
321 nframes_t delta = cnt - file_cnt;
322 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
327 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
329 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
330 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
334 if (_info.channels == 1) {
335 nframes_t ret = sf_read_float (sf, dst, file_cnt);
336 _read_data_count = cnt * sizeof(float);
341 real_cnt = cnt * _info.channels;
343 Sample* interleave_buf = get_interleave_buffer (real_cnt);
345 nread = sf_read_float (sf, interleave_buf, real_cnt);
346 ptr = interleave_buf + _channel;
347 nread /= _info.channels;
349 /* stride through the interleaved data */
351 for (int32_t n = 0; n < nread; ++n) {
353 ptr += _info.channels;
356 _read_data_count = cnt * sizeof(float);
362 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
365 return destructive_write_unlocked (data, cnt);
367 return nondestructive_write_unlocked (data, cnt);
372 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
375 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
379 if (_info.channels != 1) {
380 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
386 int32_t frame_pos = _length;
388 if (write_float (data, frame_pos, cnt) != cnt) {
393 update_length (oldlen, cnt);
395 if (_build_peakfiles) {
396 compute_and_write_peaks (data, frame_pos, cnt, false, true);
399 _write_data_count = cnt;
405 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
407 nframes_t old_file_pos;
410 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
414 if (_capture_start && _capture_end) {
416 /* start and end of capture both occur within the data we are writing,
417 so do both crossfades.
420 _capture_start = false;
421 _capture_end = false;
423 /* move to the correct location place */
424 file_pos = capture_start_frame - timeline_position;
427 nframes_t subcnt = cnt / 2;
428 nframes_t ofilepos = file_pos;
431 if (crossfade (data, subcnt, 1) != subcnt) {
436 Sample * tmpdata = data + subcnt;
439 subcnt = cnt - subcnt;
440 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
444 file_pos = ofilepos; // adjusted below
446 } else if (_capture_start) {
448 /* start of capture both occur within the data we are writing,
452 _capture_start = false;
453 _capture_end = false;
455 /* move to the correct location place */
456 file_pos = capture_start_frame - timeline_position;
458 if (crossfade (data, cnt, 1) != cnt) {
462 } else if (_capture_end) {
464 /* end of capture both occur within the data we are writing,
468 _capture_start = false;
469 _capture_end = false;
471 if (crossfade (data, cnt, 0) != cnt) {
477 /* in the middle of recording */
479 if (write_float (data, file_pos, cnt) != cnt) {
484 old_file_pos = file_pos;
485 update_length (file_pos, cnt);
487 if (_build_peakfiles) {
488 compute_and_write_peaks (data, file_pos, cnt, false, true);
497 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
499 set_timeline_position (when);
501 if (_flags & Broadcast) {
502 if (setup_broadcast_info (when, now, tnow)) {
507 return flush_header ();
511 SndFileSource::flush_header ()
513 if (!writable() || (sf == 0)) {
514 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
517 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
521 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
524 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
528 if (!(_flags & Broadcast)) {
532 /* random code is 9 digits */
534 int random_code = random() % 999999999;
536 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
537 Config->get_bwf_country_code().c_str(),
538 Config->get_bwf_organization_code().c_str(),
545 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
550 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
555 /* now update header position taking header offset into account */
557 set_header_timeline_position ();
559 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
560 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
561 _flags = Flag (_flags & ~Broadcast);
562 delete _broadcast_info;
571 SndFileSource::set_header_timeline_position ()
573 if (!(_flags & Broadcast)) {
577 _broadcast_info->time_reference_high = (timeline_position >> 32);
578 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
580 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
581 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
582 _flags = Flag (_flags & ~Broadcast);
583 delete _broadcast_info;
589 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
591 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
593 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
594 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
598 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
606 SndFileSource::natural_position() const
608 return timeline_position;
612 SndFileSource::set_destructive (bool yn)
615 _flags = Flag (_flags | Destructive);
617 xfade_buf = new Sample[xfade_frames];
619 clear_capture_marks ();
620 timeline_position = header_position_offset;
622 _flags = Flag (_flags & ~Destructive);
623 timeline_position = 0;
624 /* leave xfade buf alone in case we need it again later */
631 SndFileSource::clear_capture_marks ()
633 _capture_start = false;
634 _capture_end = false;
638 SndFileSource::mark_capture_start (nframes_t pos)
641 if (pos < timeline_position) {
642 _capture_start = false;
644 _capture_start = true;
645 capture_start_frame = pos;
651 SndFileSource::mark_capture_end()
659 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
661 nframes_t xfade = min (xfade_frames, cnt);
662 nframes_t nofade = cnt - xfade;
663 Sample* fade_data = 0;
664 nframes_t fade_position = 0; // in frames
669 fade_position = file_pos;
672 fade_position = file_pos + nofade;
673 fade_data = data + nofade;
676 if (fade_position > _length) {
678 /* read starts beyond end of data, just memset to zero */
682 } else if (fade_position + xfade > _length) {
684 /* read ends beyond end of data, read some, memset the rest */
686 file_cnt = _length - fade_position;
690 /* read is entirely within data */
697 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
698 if (retval >= 0 && errno == EAGAIN) {
699 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
700 * short or no data there */
701 memset (xfade_buf, 0, xfade * sizeof(Sample));
703 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
709 if (file_cnt != xfade) {
710 nframes_t delta = xfade - file_cnt;
711 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
714 if (nofade && !fade_in) {
715 if (write_float (data, file_pos, nofade) != nofade) {
716 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
721 if (xfade == xfade_frames) {
725 /* use the standard xfade curve */
729 /* fade new material in */
731 for (n = 0; n < xfade; ++n) {
732 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
738 /* fade new material out */
740 for (n = 0; n < xfade; ++n) {
741 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
745 } else if (xfade < xfade_frames) {
750 /* short xfade, compute custom curve */
752 compute_equal_power_fades (xfade, in, out);
754 for (nframes_t n = 0; n < xfade; ++n) {
755 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
760 /* long xfade length, has to be computed across several calls */
765 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
766 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
771 if (fade_in && nofade) {
772 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
773 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
782 SndFileSource::last_capture_start_frame () const
785 return capture_start_frame;
792 SndFileSource::handle_header_position_change ()
795 if ( _length != 0 ) {
796 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
797 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
798 } else if (writable()) {
799 timeline_position = header_position_offset;
800 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
806 SndFileSource::setup_standard_crossfades (nframes_t rate)
808 /* This static method is assumed to have been called by the Session
809 before any DFS's are created.
812 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
814 if (out_coefficient) {
815 delete [] out_coefficient;
818 if (in_coefficient) {
819 delete [] in_coefficient;
822 out_coefficient = new gain_t[xfade_frames];
823 in_coefficient = new gain_t[xfade_frames];
825 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
829 SndFileSource::set_timeline_position (int64_t pos)
831 // destructive track timeline postion does not change
832 // except at instantion or when header_position_offset
833 // (session start) changes
835 if (!destructive()) {
836 AudioFileSource::set_timeline_position (pos);
841 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
845 SF_BROADCAST_INFO binfo;
846 bool timecode_exists;
848 sf_info.format = 0; // libsndfile says to clear this before sf_open().
850 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
852 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
856 info.samplerate = sf_info.samplerate;
857 info.channels = sf_info.channels;
858 info.length = sf_info.frames;
859 info.format_name = string_compose("Format: %1, %2",
860 sndfile_major_format(sf_info.format),
861 sndfile_minor_format(sf_info.format));
863 memset (&binfo, 0, sizeof (binfo));
864 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
866 if (!timecode_exists) {
876 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
878 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
880 return (header_position_offset);
883 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
884 of the time reference.
888 int64_t ret = (uint32_t) binfo->time_reference_high;
890 ret |= (uint32_t) binfo->time_reference_low;
895 SndFileSource::one_of_several_channels () const
897 return _info.channels > 1;