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>
39 using namespace ARDOUR;
43 gain_t* SndFileSource::out_coefficient = 0;
44 gain_t* SndFileSource::in_coefficient = 0;
45 nframes_t SndFileSource::xfade_frames = 64;
46 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
47 AudioFileSource::Removable|
48 AudioFileSource::RemovableIfEmpty|
49 AudioFileSource::CanRename);
52 snprintf_bounded_null_filled (char* target, size_t target_size, char* fmt, ...)
54 char buf[target_size+1];
58 vsnprintf (buf, target_size+1, fmt, ap);
61 memset (target, 0, target_size);
62 memcpy (target, buf, target_size);
66 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
67 : AudioFileSource (s, node)
72 throw failed_constructor ();
76 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
77 /* files created this way are never writable or removable */
78 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
85 throw failed_constructor ();
89 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
90 : AudioFileSource (s, path, flags, sfmt, hf)
96 /* this constructor is used to construct new files, not open
105 _flags = Flag (_flags & ~Broadcast);
109 fmt = SF_FORMAT_AIFF;
110 _flags = Flag (_flags & ~Broadcast);
115 _flags = Flag (_flags | Broadcast);
120 _flags = Flag (_flags & ~Broadcast);
125 _flags = Flag (_flags & ~Broadcast);
129 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
137 fmt |= SF_FORMAT_FLOAT;
141 fmt |= SF_FORMAT_PCM_24;
145 fmt |= SF_FORMAT_PCM_16;
150 _info.samplerate = rate;
154 throw failed_constructor();
157 if (writable() && (_flags & Broadcast)) {
159 _broadcast_info = new SF_BROADCAST_INFO;
160 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
162 snprintf_bounded_null_filled (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
163 snprintf_bounded_null_filled (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour %s)", Glib::get_real_name().c_str());
165 _broadcast_info->version = 1;
166 _broadcast_info->time_reference_low = 0;
167 _broadcast_info->time_reference_high = 0;
169 /* XXX do something about this field */
171 snprintf_bounded_null_filled (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
173 /* coding history is added by libsndfile */
175 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
177 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
178 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
179 _flags = Flag (_flags & ~Broadcast);
180 delete _broadcast_info;
187 SndFileSource::init ()
191 // lets try to keep the object initalizations here at the top
199 _name = Glib::path_get_basename (_path);
202 /* although libsndfile says we don't need to set this,
203 valgrind and source code shows us that we do.
206 memset (&_info, 0, sizeof(_info));
208 _capture_start = false;
209 _capture_end = false;
213 xfade_buf = new Sample[xfade_frames];
214 timeline_position = header_position_offset;
217 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
221 SndFileSource::open ()
223 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
225 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
226 #ifndef HAVE_COREAUDIO
227 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
228 so we don't want to see this message.
231 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
232 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
237 if (_channel >= _info.channels) {
238 #ifndef HAVE_COREAUDIO
239 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
246 _length = _info.frames;
248 _broadcast_info = new SF_BROADCAST_INFO;
249 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
251 bool timecode_info_exists;
253 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
255 if (_length != 0 && !timecode_info_exists) {
256 delete _broadcast_info;
258 _flags = Flag (_flags & ~Broadcast);
262 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
268 SndFileSource::~SndFileSource ()
270 GoingAway (); /* EMIT SIGNAL */
276 /* stupid libsndfile updated the headers on close,
277 so touch the peakfile if it exists and has data
278 to make sure its time is as new as the audio
285 if (_broadcast_info) {
286 delete _broadcast_info;
295 SndFileSource::sample_rate () const
297 return _info.samplerate;
301 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
308 if (start > _length) {
310 /* read starts beyond end of data, just memset to zero */
314 } else if (start + cnt > _length) {
316 /* read ends beyond end of data, read some, memset the rest */
318 file_cnt = _length - start;
322 /* read is entirely within data */
327 if (file_cnt != cnt) {
328 nframes_t delta = cnt - file_cnt;
329 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
334 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
336 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
337 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
341 if (_info.channels == 1) {
342 nframes_t ret = sf_read_float (sf, dst, file_cnt);
343 _read_data_count = cnt * sizeof(float);
348 real_cnt = cnt * _info.channels;
350 Sample* interleave_buf = get_interleave_buffer (real_cnt);
352 nread = sf_read_float (sf, interleave_buf, real_cnt);
353 ptr = interleave_buf + _channel;
354 nread /= _info.channels;
356 /* stride through the interleaved data */
358 for (int32_t n = 0; n < nread; ++n) {
360 ptr += _info.channels;
363 _read_data_count = cnt * sizeof(float);
369 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
372 return destructive_write_unlocked (data, cnt);
374 return nondestructive_write_unlocked (data, cnt);
379 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
382 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
386 if (_info.channels != 1) {
387 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
393 int32_t frame_pos = _length;
395 if (write_float (data, frame_pos, cnt) != cnt) {
400 update_length (oldlen, cnt);
402 if (_build_peakfiles) {
403 compute_and_write_peaks (data, frame_pos, cnt, false, true);
406 _write_data_count = cnt;
412 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
414 nframes_t old_file_pos;
417 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
421 if (_capture_start && _capture_end) {
423 /* start and end of capture both occur within the data we are writing,
424 so do both crossfades.
427 _capture_start = false;
428 _capture_end = false;
430 /* move to the correct location place */
431 file_pos = capture_start_frame - timeline_position;
434 nframes_t subcnt = cnt / 2;
435 nframes_t ofilepos = file_pos;
438 if (crossfade (data, subcnt, 1) != subcnt) {
443 Sample * tmpdata = data + subcnt;
446 subcnt = cnt - subcnt;
447 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
451 file_pos = ofilepos; // adjusted below
453 } else if (_capture_start) {
455 /* start of capture both occur within the data we are writing,
459 _capture_start = false;
460 _capture_end = false;
462 /* move to the correct location place */
463 file_pos = capture_start_frame - timeline_position;
465 if (crossfade (data, cnt, 1) != cnt) {
469 } else if (_capture_end) {
471 /* end of capture both occur within the data we are writing,
475 _capture_start = false;
476 _capture_end = false;
478 if (crossfade (data, cnt, 0) != cnt) {
484 /* in the middle of recording */
486 if (write_float (data, file_pos, cnt) != cnt) {
491 old_file_pos = file_pos;
492 update_length (file_pos, cnt);
494 if (_build_peakfiles) {
495 compute_and_write_peaks (data, file_pos, cnt, false, true);
504 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
506 set_timeline_position (when);
508 if (_flags & Broadcast) {
509 if (setup_broadcast_info (when, now, tnow)) {
514 return flush_header ();
518 SndFileSource::flush_header ()
520 if (!writable() || (sf == 0)) {
521 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
524 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
528 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
531 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
535 if (!(_flags & Broadcast)) {
539 /* random code is 9 digits */
541 int random_code = random() % 999999999;
543 snprintf_bounded_null_filled (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
544 Config->get_bwf_country_code().c_str(),
545 Config->get_bwf_organization_code().c_str(),
552 snprintf_bounded_null_filled (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
554 now.tm_mon + 1, // move from 0..11 to 1..12
557 snprintf_bounded_null_filled (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
562 /* now update header position taking header offset into account */
564 set_header_timeline_position ();
566 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
567 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
568 _flags = Flag (_flags & ~Broadcast);
569 delete _broadcast_info;
578 SndFileSource::set_header_timeline_position ()
580 if (!(_flags & Broadcast)) {
584 _broadcast_info->time_reference_high = (timeline_position >> 32);
585 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
587 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
588 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
589 _flags = Flag (_flags & ~Broadcast);
590 delete _broadcast_info;
596 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
598 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
600 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
601 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
605 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
613 SndFileSource::natural_position() const
615 return timeline_position;
619 SndFileSource::set_destructive (bool yn)
622 _flags = Flag (_flags | Destructive);
624 xfade_buf = new Sample[xfade_frames];
626 clear_capture_marks ();
627 timeline_position = header_position_offset;
629 _flags = Flag (_flags & ~Destructive);
630 timeline_position = 0;
631 /* leave xfade buf alone in case we need it again later */
638 SndFileSource::clear_capture_marks ()
640 _capture_start = false;
641 _capture_end = false;
645 SndFileSource::mark_capture_start (nframes_t pos)
648 if (pos < timeline_position) {
649 _capture_start = false;
651 _capture_start = true;
652 capture_start_frame = pos;
658 SndFileSource::mark_capture_end()
666 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
668 nframes_t xfade = min (xfade_frames, cnt);
669 nframes_t nofade = cnt - xfade;
670 Sample* fade_data = 0;
671 nframes_t fade_position = 0; // in frames
676 fade_position = file_pos;
679 fade_position = file_pos + nofade;
680 fade_data = data + nofade;
683 if (fade_position > _length) {
685 /* read starts beyond end of data, just memset to zero */
689 } else if (fade_position + xfade > _length) {
691 /* read ends beyond end of data, read some, memset the rest */
693 file_cnt = _length - fade_position;
697 /* read is entirely within data */
704 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
705 if (retval >= 0 && errno == EAGAIN) {
706 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
707 * short or no data there */
708 memset (xfade_buf, 0, xfade * sizeof(Sample));
710 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
716 if (file_cnt != xfade) {
717 nframes_t delta = xfade - file_cnt;
718 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
721 if (nofade && !fade_in) {
722 if (write_float (data, file_pos, nofade) != nofade) {
723 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
728 if (xfade == xfade_frames) {
732 /* use the standard xfade curve */
736 /* fade new material in */
738 for (n = 0; n < xfade; ++n) {
739 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
745 /* fade new material out */
747 for (n = 0; n < xfade; ++n) {
748 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
752 } else if (xfade < xfade_frames) {
757 /* short xfade, compute custom curve */
759 compute_equal_power_fades (xfade, in, out);
761 for (nframes_t n = 0; n < xfade; ++n) {
762 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
767 /* long xfade length, has to be computed across several calls */
772 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
773 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
778 if (fade_in && nofade) {
779 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
780 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
789 SndFileSource::last_capture_start_frame () const
792 return capture_start_frame;
799 SndFileSource::handle_header_position_change ()
802 if ( _length != 0 ) {
803 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
804 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
805 } else if (writable()) {
806 timeline_position = header_position_offset;
807 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
813 SndFileSource::setup_standard_crossfades (nframes_t rate)
815 /* This static method is assumed to have been called by the Session
816 before any DFS's are created.
819 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
821 if (out_coefficient) {
822 delete [] out_coefficient;
825 if (in_coefficient) {
826 delete [] in_coefficient;
829 out_coefficient = new gain_t[xfade_frames];
830 in_coefficient = new gain_t[xfade_frames];
832 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
836 SndFileSource::set_timeline_position (int64_t pos)
838 // destructive track timeline postion does not change
839 // except at instantion or when header_position_offset
840 // (session start) changes
842 if (!destructive()) {
843 AudioFileSource::set_timeline_position (pos);
848 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
852 SF_BROADCAST_INFO binfo;
853 bool timecode_exists;
855 sf_info.format = 0; // libsndfile says to clear this before sf_open().
857 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
859 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
863 info.samplerate = sf_info.samplerate;
864 info.channels = sf_info.channels;
865 info.length = sf_info.frames;
866 info.format_name = string_compose("Format: %1, %2",
867 sndfile_major_format(sf_info.format),
868 sndfile_minor_format(sf_info.format));
870 memset (&binfo, 0, sizeof (binfo));
871 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
873 if (!timecode_exists) {
883 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
885 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
887 return (header_position_offset);
890 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
891 of the time reference.
895 int64_t ret = (uint32_t) binfo->time_reference_high;
897 ret |= (uint32_t) binfo->time_reference_low;
902 SndFileSource::one_of_several_channels () const
904 return _info.channels > 1;