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, const 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 if (!_broadcast_info) {
161 _broadcast_info = new SF_BROADCAST_INFO;
162 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
165 snprintf_bounded_null_filled (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
166 snprintf_bounded_null_filled (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour %d.%d.%d %s",
167 libardour2_major_version,
168 libardour2_minor_version,
169 libardour2_micro_version,
170 Glib::get_real_name().c_str());
172 _broadcast_info->version = 1;
173 _broadcast_info->time_reference_low = 0;
174 _broadcast_info->time_reference_high = 0;
176 /* XXX do something about this field */
178 snprintf_bounded_null_filled (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
180 /* coding history is added by libsndfile */
182 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
184 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
185 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
186 _flags = Flag (_flags & ~Broadcast);
187 delete _broadcast_info;
194 SndFileSource::init ()
198 // lets try to keep the object initalizations here at the top
206 _name = Glib::path_get_basename (_path);
209 /* although libsndfile says we don't need to set this,
210 valgrind and source code shows us that we do.
213 memset (&_info, 0, sizeof(_info));
215 _capture_start = false;
216 _capture_end = false;
220 xfade_buf = new Sample[xfade_frames];
221 timeline_position = header_position_offset;
224 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
228 SndFileSource::open ()
230 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
232 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
233 #ifndef HAVE_COREAUDIO
234 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
235 so we don't want to see this message.
238 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
239 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
244 if (_channel >= _info.channels) {
245 #ifndef HAVE_COREAUDIO
246 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
253 _length = _info.frames;
255 if (!_broadcast_info) {
256 _broadcast_info = new SF_BROADCAST_INFO;
257 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
260 bool timecode_info_exists;
262 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
264 if (_length != 0 && !timecode_info_exists) {
265 delete _broadcast_info;
267 _flags = Flag (_flags & ~Broadcast);
271 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
277 SndFileSource::~SndFileSource ()
279 GoingAway (); /* EMIT SIGNAL */
285 /* stupid libsndfile updated the headers on close,
286 so touch the peakfile if it exists and has data
287 to make sure its time is as new as the audio
294 if (_broadcast_info) {
295 delete _broadcast_info;
304 SndFileSource::sample_rate () const
306 return _info.samplerate;
310 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
317 if (start > _length) {
319 /* read starts beyond end of data, just memset to zero */
323 } else if (start + cnt > _length) {
325 /* read ends beyond end of data, read some, memset the rest */
327 file_cnt = _length - start;
331 /* read is entirely within data */
336 if (file_cnt != cnt) {
337 nframes_t delta = cnt - file_cnt;
338 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
343 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
345 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
346 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
350 if (_info.channels == 1) {
351 nframes_t ret = sf_read_float (sf, dst, file_cnt);
352 _read_data_count = ret * sizeof(float);
353 if (ret != file_cnt) {
355 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
356 cerr << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.substr (1), errbuf, _length) << endl;
362 real_cnt = cnt * _info.channels;
364 Sample* interleave_buf = get_interleave_buffer (real_cnt);
366 nread = sf_read_float (sf, interleave_buf, real_cnt);
367 ptr = interleave_buf + _channel;
368 nread /= _info.channels;
370 /* stride through the interleaved data */
372 for (int32_t n = 0; n < nread; ++n) {
374 ptr += _info.channels;
377 _read_data_count = cnt * sizeof(float);
383 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
386 return destructive_write_unlocked (data, cnt);
388 return nondestructive_write_unlocked (data, cnt);
393 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
396 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
400 if (_info.channels != 1) {
401 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
407 int32_t frame_pos = _length;
409 if (write_float (data, frame_pos, cnt) != cnt) {
414 update_length (oldlen, cnt);
416 if (_build_peakfiles) {
417 compute_and_write_peaks (data, frame_pos, cnt, false, true);
420 _write_data_count = cnt;
426 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
428 nframes_t old_file_pos;
431 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
435 if (_capture_start && _capture_end) {
437 /* start and end of capture both occur within the data we are writing,
438 so do both crossfades.
441 _capture_start = false;
442 _capture_end = false;
444 /* move to the correct location place */
445 file_pos = capture_start_frame - timeline_position;
448 nframes_t subcnt = cnt / 2;
449 nframes_t ofilepos = file_pos;
452 if (crossfade (data, subcnt, 1) != subcnt) {
457 Sample * tmpdata = data + subcnt;
460 subcnt = cnt - subcnt;
461 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
465 file_pos = ofilepos; // adjusted below
467 } else if (_capture_start) {
469 /* start of capture both occur within the data we are writing,
473 _capture_start = false;
474 _capture_end = false;
476 /* move to the correct location place */
477 file_pos = capture_start_frame - timeline_position;
479 if (crossfade (data, cnt, 1) != cnt) {
483 } else if (_capture_end) {
485 /* end of capture both occur within the data we are writing,
489 _capture_start = false;
490 _capture_end = false;
492 if (crossfade (data, cnt, 0) != cnt) {
498 /* in the middle of recording */
500 if (write_float (data, file_pos, cnt) != cnt) {
505 old_file_pos = file_pos;
506 update_length (file_pos, cnt);
508 if (_build_peakfiles) {
509 compute_and_write_peaks (data, file_pos, cnt, false, true);
518 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
520 set_timeline_position (when);
522 if (_flags & Broadcast) {
523 if (setup_broadcast_info (when, now, tnow)) {
528 return flush_header ();
532 SndFileSource::flush_header ()
534 if (!writable() || (sf == 0)) {
535 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
538 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
542 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
545 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
549 if (!(_flags & Broadcast)) {
553 /* random code is 9 digits */
555 int random_code = random() % 999999999;
557 snprintf_bounded_null_filled (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
558 Config->get_bwf_country_code().c_str(),
559 Config->get_bwf_organization_code().c_str(),
566 snprintf_bounded_null_filled (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
568 now.tm_mon + 1, // shift range from 0..11 to 1..12
571 snprintf_bounded_null_filled (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
576 /* now update header position taking header offset into account */
578 set_header_timeline_position ();
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;
592 SndFileSource::set_header_timeline_position ()
594 if (!(_flags & Broadcast)) {
598 _broadcast_info->time_reference_high = (timeline_position >> 32);
599 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
601 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
602 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
603 _flags = Flag (_flags & ~Broadcast);
604 delete _broadcast_info;
610 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
612 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
614 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
615 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
619 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
627 SndFileSource::natural_position() const
629 return timeline_position;
633 SndFileSource::set_destructive (bool yn)
636 _flags = Flag (_flags | Destructive);
638 xfade_buf = new Sample[xfade_frames];
640 clear_capture_marks ();
641 timeline_position = header_position_offset;
643 _flags = Flag (_flags & ~Destructive);
644 timeline_position = 0;
645 /* leave xfade buf alone in case we need it again later */
652 SndFileSource::clear_capture_marks ()
654 _capture_start = false;
655 _capture_end = false;
659 SndFileSource::mark_capture_start (nframes_t pos)
662 if (pos < timeline_position) {
663 _capture_start = false;
665 _capture_start = true;
666 capture_start_frame = pos;
672 SndFileSource::mark_capture_end()
680 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
682 nframes_t xfade = min (xfade_frames, cnt);
683 nframes_t nofade = cnt - xfade;
684 Sample* fade_data = 0;
685 nframes_t fade_position = 0; // in frames
690 fade_position = file_pos;
693 fade_position = file_pos + nofade;
694 fade_data = data + nofade;
697 if (fade_position > _length) {
699 /* read starts beyond end of data, just memset to zero */
703 } else if (fade_position + xfade > _length) {
705 /* read ends beyond end of data, read some, memset the rest */
707 file_cnt = _length - fade_position;
711 /* read is entirely within data */
718 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
719 if (retval >= 0 && errno == EAGAIN) {
720 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
721 * short or no data there */
722 memset (xfade_buf, 0, xfade * sizeof(Sample));
724 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
730 if (file_cnt != xfade) {
731 nframes_t delta = xfade - file_cnt;
732 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
735 if (nofade && !fade_in) {
736 if (write_float (data, file_pos, nofade) != nofade) {
737 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
742 if (xfade == xfade_frames) {
746 /* use the standard xfade curve */
750 /* fade new material in */
752 for (n = 0; n < xfade; ++n) {
753 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
759 /* fade new material out */
761 for (n = 0; n < xfade; ++n) {
762 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
766 } else if (xfade < xfade_frames) {
771 /* short xfade, compute custom curve */
773 compute_equal_power_fades (xfade, in, out);
775 for (nframes_t n = 0; n < xfade; ++n) {
776 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
781 /* long xfade length, has to be computed across several calls */
786 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
787 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
792 if (fade_in && nofade) {
793 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
794 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
803 SndFileSource::last_capture_start_frame () const
806 return capture_start_frame;
813 SndFileSource::handle_header_position_change ()
816 if ( _length != 0 ) {
817 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
818 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
819 } else if (writable()) {
820 timeline_position = header_position_offset;
821 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
827 SndFileSource::setup_standard_crossfades (nframes_t rate)
829 /* This static method is assumed to have been called by the Session
830 before any DFS's are created.
833 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
835 if (out_coefficient) {
836 delete [] out_coefficient;
839 if (in_coefficient) {
840 delete [] in_coefficient;
843 out_coefficient = new gain_t[xfade_frames];
844 in_coefficient = new gain_t[xfade_frames];
846 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
850 SndFileSource::set_timeline_position (int64_t pos)
852 // destructive track timeline postion does not change
853 // except at instantion or when header_position_offset
854 // (session start) changes
856 if (!destructive()) {
857 AudioFileSource::set_timeline_position (pos);
862 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
866 SF_BROADCAST_INFO binfo;
867 bool timecode_exists;
869 sf_info.format = 0; // libsndfile says to clear this before sf_open().
871 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
873 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
877 info.samplerate = sf_info.samplerate;
878 info.channels = sf_info.channels;
879 info.length = sf_info.frames;
880 info.format_name = string_compose("%1\n%2",
881 sndfile_major_format(sf_info.format),
882 sndfile_minor_format(sf_info.format));
884 memset (&binfo, 0, sizeof (binfo));
885 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
887 if (!timecode_exists) {
897 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
899 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
901 return (header_position_offset);
904 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
905 of the time reference.
909 int64_t ret = (uint32_t) binfo->time_reference_high;
911 ret |= (uint32_t) binfo->time_reference_low;
916 SndFileSource::one_of_several_channels () const
918 return _info.channels > 1;