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>
30 #include <pbd/stacktrace.h>
32 #include <ardour/sndfilesource.h>
33 #include <ardour/sndfile_helpers.h>
34 #include <ardour/utils.h>
35 #include <ardour/version.h>
40 using namespace ARDOUR;
44 gain_t* SndFileSource::out_coefficient = 0;
45 gain_t* SndFileSource::in_coefficient = 0;
46 nframes_t SndFileSource::xfade_frames = 64;
47 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
48 AudioFileSource::Removable|
49 AudioFileSource::RemovableIfEmpty|
50 AudioFileSource::CanRename);
53 snprintf_bounded_null_filled (char* target, size_t target_size, char* fmt, ...)
55 char buf[target_size+1];
59 vsnprintf (buf, target_size+1, fmt, ap);
62 memset (target, 0, target_size);
63 memcpy (target, buf, target_size);
67 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
68 : AudioFileSource (s, node)
73 throw failed_constructor ();
77 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
78 /* files created this way are never writable or removable */
79 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
86 throw failed_constructor ();
90 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
91 : AudioFileSource (s, path, flags, sfmt, hf)
97 /* this constructor is used to construct new files, not open
106 _flags = Flag (_flags & ~Broadcast);
110 fmt = SF_FORMAT_AIFF;
111 _flags = Flag (_flags & ~Broadcast);
116 _flags = Flag (_flags | Broadcast);
121 _flags = Flag (_flags & ~Broadcast);
126 _flags = Flag (_flags & ~Broadcast);
130 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
138 fmt |= SF_FORMAT_FLOAT;
142 fmt |= SF_FORMAT_PCM_24;
146 fmt |= SF_FORMAT_PCM_16;
151 _info.samplerate = rate;
155 throw failed_constructor();
158 if (writable() && (_flags & Broadcast)) {
160 _broadcast_info = new SF_BROADCAST_INFO;
161 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
163 snprintf_bounded_null_filled (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
164 snprintf_bounded_null_filled (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour %d.%d.%d %s",
165 libardour2_major_version,
166 libardour2_minor_version,
167 libardour2_micro_version,
168 Glib::get_real_name().c_str());
170 _broadcast_info->version = 1;
171 _broadcast_info->time_reference_low = 0;
172 _broadcast_info->time_reference_high = 0;
174 /* XXX do something about this field */
176 snprintf_bounded_null_filled (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
178 /* coding history is added by libsndfile */
180 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
182 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
183 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
184 _flags = Flag (_flags & ~Broadcast);
185 delete _broadcast_info;
192 SndFileSource::init ()
196 // lets try to keep the object initalizations here at the top
204 _name = Glib::path_get_basename (_path);
207 /* although libsndfile says we don't need to set this,
208 valgrind and source code shows us that we do.
211 memset (&_info, 0, sizeof(_info));
213 _capture_start = false;
214 _capture_end = false;
218 xfade_buf = new Sample[xfade_frames];
219 timeline_position = header_position_offset;
222 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
226 SndFileSource::open ()
228 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
230 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
231 #ifndef HAVE_COREAUDIO
232 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
233 so we don't want to see this message.
236 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
237 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
242 if (_channel >= _info.channels) {
243 #ifndef HAVE_COREAUDIO
244 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
251 _length = _info.frames;
253 _broadcast_info = new SF_BROADCAST_INFO;
254 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
256 bool timecode_info_exists;
258 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
260 if (_length != 0 && !timecode_info_exists) {
261 delete _broadcast_info;
263 _flags = Flag (_flags & ~Broadcast);
267 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
273 SndFileSource::~SndFileSource ()
275 GoingAway (); /* EMIT SIGNAL */
281 /* stupid libsndfile updated the headers on close,
282 so touch the peakfile if it exists and has data
283 to make sure its time is as new as the audio
290 if (_broadcast_info) {
291 delete _broadcast_info;
300 SndFileSource::sample_rate () const
302 return _info.samplerate;
306 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
313 if (start > _length) {
315 /* read starts beyond end of data, just memset to zero */
319 } else if (start + cnt > _length) {
321 /* read ends beyond end of data, read some, memset the rest */
323 file_cnt = _length - start;
327 /* read is entirely within data */
332 if (file_cnt != cnt) {
333 nframes_t delta = cnt - file_cnt;
334 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
339 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
341 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
342 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
346 if (_info.channels == 1) {
347 nframes_t ret = sf_read_float (sf, dst, file_cnt);
348 _read_data_count = cnt * sizeof(float);
353 real_cnt = cnt * _info.channels;
355 Sample* interleave_buf = get_interleave_buffer (real_cnt);
357 nread = sf_read_float (sf, interleave_buf, real_cnt);
358 ptr = interleave_buf + _channel;
359 nread /= _info.channels;
361 /* stride through the interleaved data */
363 for (int32_t n = 0; n < nread; ++n) {
365 ptr += _info.channels;
368 _read_data_count = cnt * sizeof(float);
374 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
377 return destructive_write_unlocked (data, cnt);
379 return nondestructive_write_unlocked (data, cnt);
384 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
387 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
391 if (_info.channels != 1) {
392 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
398 int32_t frame_pos = _length;
400 if (write_float (data, frame_pos, cnt) != cnt) {
405 update_length (oldlen, cnt);
407 if (_build_peakfiles) {
408 compute_and_write_peaks (data, frame_pos, cnt, false, true);
411 _write_data_count = cnt;
417 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
419 nframes_t old_file_pos;
422 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
426 if (_capture_start && _capture_end) {
428 /* start and end of capture both occur within the data we are writing,
429 so do both crossfades.
432 _capture_start = false;
433 _capture_end = false;
435 /* move to the correct location place */
436 file_pos = capture_start_frame - timeline_position;
439 nframes_t subcnt = cnt / 2;
440 nframes_t ofilepos = file_pos;
443 if (crossfade (data, subcnt, 1) != subcnt) {
448 Sample * tmpdata = data + subcnt;
451 subcnt = cnt - subcnt;
452 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
456 file_pos = ofilepos; // adjusted below
458 } else if (_capture_start) {
460 /* start of capture both occur within the data we are writing,
464 _capture_start = false;
465 _capture_end = false;
467 /* move to the correct location place */
468 file_pos = capture_start_frame - timeline_position;
470 if (crossfade (data, cnt, 1) != cnt) {
474 } else if (_capture_end) {
476 /* end of capture both occur within the data we are writing,
480 _capture_start = false;
481 _capture_end = false;
483 if (crossfade (data, cnt, 0) != cnt) {
489 /* in the middle of recording */
491 if (write_float (data, file_pos, cnt) != cnt) {
496 old_file_pos = file_pos;
497 update_length (file_pos, cnt);
499 if (_build_peakfiles) {
500 compute_and_write_peaks (data, file_pos, cnt, false, true);
509 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
511 set_timeline_position (when);
513 if (_flags & Broadcast) {
514 if (setup_broadcast_info (when, now, tnow)) {
519 return flush_header ();
523 SndFileSource::flush_header ()
525 if (!writable() || (sf == 0)) {
526 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
529 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
533 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
536 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
540 if (!(_flags & Broadcast)) {
544 /* random code is 9 digits */
546 int random_code = random() % 999999999;
548 snprintf_bounded_null_filled (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
549 Config->get_bwf_country_code().c_str(),
550 Config->get_bwf_organization_code().c_str(),
557 snprintf_bounded_null_filled (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
559 now.tm_mon + 1, // shift range from 0..11 to 1..12
562 snprintf_bounded_null_filled (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
567 /* now update header position taking header offset into account */
569 set_header_timeline_position ();
571 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
572 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
573 _flags = Flag (_flags & ~Broadcast);
574 delete _broadcast_info;
583 SndFileSource::set_header_timeline_position ()
585 if (!(_flags & Broadcast)) {
589 _broadcast_info->time_reference_high = (timeline_position >> 32);
590 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
592 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
593 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
594 _flags = Flag (_flags & ~Broadcast);
595 delete _broadcast_info;
601 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
603 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
605 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
606 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
610 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
618 SndFileSource::natural_position() const
620 return timeline_position;
624 SndFileSource::set_destructive (bool yn)
627 _flags = Flag (_flags | Destructive);
629 xfade_buf = new Sample[xfade_frames];
631 clear_capture_marks ();
632 timeline_position = header_position_offset;
634 _flags = Flag (_flags & ~Destructive);
635 timeline_position = 0;
636 /* leave xfade buf alone in case we need it again later */
643 SndFileSource::clear_capture_marks ()
645 _capture_start = false;
646 _capture_end = false;
650 SndFileSource::mark_capture_start (nframes_t pos)
653 if (pos < timeline_position) {
654 _capture_start = false;
656 _capture_start = true;
657 capture_start_frame = pos;
663 SndFileSource::mark_capture_end()
671 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
673 nframes_t xfade = min (xfade_frames, cnt);
674 nframes_t nofade = cnt - xfade;
675 Sample* fade_data = 0;
676 nframes_t fade_position = 0; // in frames
681 fade_position = file_pos;
684 fade_position = file_pos + nofade;
685 fade_data = data + nofade;
688 if (fade_position > _length) {
690 /* read starts beyond end of data, just memset to zero */
694 } else if (fade_position + xfade > _length) {
696 /* read ends beyond end of data, read some, memset the rest */
698 file_cnt = _length - fade_position;
702 /* read is entirely within data */
709 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
710 if (retval >= 0 && errno == EAGAIN) {
711 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
712 * short or no data there */
713 memset (xfade_buf, 0, xfade * sizeof(Sample));
715 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
721 if (file_cnt != xfade) {
722 nframes_t delta = xfade - file_cnt;
723 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
726 if (nofade && !fade_in) {
727 if (write_float (data, file_pos, nofade) != nofade) {
728 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
733 if (xfade == xfade_frames) {
737 /* use the standard xfade curve */
741 /* fade new material in */
743 for (n = 0; n < xfade; ++n) {
744 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
750 /* fade new material out */
752 for (n = 0; n < xfade; ++n) {
753 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
757 } else if (xfade < xfade_frames) {
762 /* short xfade, compute custom curve */
764 compute_equal_power_fades (xfade, in, out);
766 for (nframes_t n = 0; n < xfade; ++n) {
767 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
772 /* long xfade length, has to be computed across several calls */
777 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
778 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
783 if (fade_in && nofade) {
784 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
785 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
794 SndFileSource::last_capture_start_frame () const
797 return capture_start_frame;
804 SndFileSource::handle_header_position_change ()
807 if ( _length != 0 ) {
808 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
809 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
810 } else if (writable()) {
811 timeline_position = header_position_offset;
812 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
818 SndFileSource::setup_standard_crossfades (nframes_t rate)
820 /* This static method is assumed to have been called by the Session
821 before any DFS's are created.
824 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
826 if (out_coefficient) {
827 delete [] out_coefficient;
830 if (in_coefficient) {
831 delete [] in_coefficient;
834 out_coefficient = new gain_t[xfade_frames];
835 in_coefficient = new gain_t[xfade_frames];
837 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
841 SndFileSource::set_timeline_position (int64_t pos)
843 // destructive track timeline postion does not change
844 // except at instantion or when header_position_offset
845 // (session start) changes
847 if (!destructive()) {
848 AudioFileSource::set_timeline_position (pos);
853 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
857 SF_BROADCAST_INFO binfo;
858 bool timecode_exists;
860 sf_info.format = 0; // libsndfile says to clear this before sf_open().
862 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
864 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
868 info.samplerate = sf_info.samplerate;
869 info.channels = sf_info.channels;
870 info.length = sf_info.frames;
871 info.format_name = string_compose("%1\n%2",
872 sndfile_major_format(sf_info.format),
873 sndfile_minor_format(sf_info.format));
875 memset (&binfo, 0, sizeof (binfo));
876 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
878 if (!timecode_exists) {
888 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
890 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
892 return (header_position_offset);
895 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
896 of the time reference.
900 int64_t ret = (uint32_t) binfo->time_reference_high;
902 ret |= (uint32_t) binfo->time_reference_low;
907 SndFileSource::one_of_several_channels () const
909 return _info.channels > 1;