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 <glibmm/thread.h>
29 #include <pbd/stacktrace.h>
31 #include <ardour/sndfilesource.h>
32 #include <ardour/sndfile_helpers.h>
33 #include <ardour/utils.h>
38 using namespace ARDOUR;
42 gain_t* SndFileSource::out_coefficient = 0;
43 gain_t* SndFileSource::in_coefficient = 0;
44 nframes_t SndFileSource::xfade_frames = 64;
45 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
46 AudioFileSource::Removable|
47 AudioFileSource::RemovableIfEmpty|
48 AudioFileSource::CanRename);
49 struct SizedSampleBuffer {
53 SizedSampleBuffer (nframes_t sz) : size (sz) {
54 buf = new Sample[size];
57 ~SizedSampleBuffer() {
62 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
64 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
65 : AudioFileSource (s, node)
70 throw failed_constructor ();
74 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
75 /* files created this way are never writable or removable */
76 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
83 throw failed_constructor ();
87 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
88 : AudioFileSource (s, path, flags, sfmt, hf)
94 /* this constructor is used to construct new files, not open
103 _flags = Flag (_flags & ~Broadcast);
107 fmt = SF_FORMAT_AIFF;
108 _flags = Flag (_flags & ~Broadcast);
113 _flags = Flag (_flags | Broadcast);
118 _flags = Flag (_flags & ~Broadcast);
123 _flags = Flag (_flags & ~Broadcast);
127 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
135 fmt |= SF_FORMAT_FLOAT;
139 fmt |= SF_FORMAT_PCM_24;
143 fmt |= SF_FORMAT_PCM_16;
148 _info.samplerate = rate;
152 throw failed_constructor();
155 if (writable() && (_flags & Broadcast)) {
157 _broadcast_info = new SF_BROADCAST_INFO;
158 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
160 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
162 struct utsname utsinfo;
164 if (uname (&utsinfo)) {
165 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
169 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
170 Glib::get_real_name().c_str(),
176 _broadcast_info->version = 1;
177 _broadcast_info->time_reference_low = 0;
178 _broadcast_info->time_reference_high = 0;
180 /* XXX do something about this field */
182 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
184 /* coding history is added by libsndfile */
186 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
188 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
189 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
190 _flags = Flag (_flags & ~Broadcast);
191 delete _broadcast_info;
199 SndFileSource::init ()
203 // lets try to keep the object initalizations here at the top
211 _name = Glib::path_get_basename (_path);
214 /* although libsndfile says we don't need to set this,
215 valgrind and source code shows us that we do.
218 memset (&_info, 0, sizeof(_info));
220 _capture_start = false;
221 _capture_end = false;
225 xfade_buf = new Sample[xfade_frames];
226 timeline_position = header_position_offset;
229 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
233 SndFileSource::open ()
235 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
237 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
238 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
239 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
243 if (_channel >= _info.channels) {
244 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
250 _length = _info.frames;
252 _broadcast_info = new SF_BROADCAST_INFO;
253 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
255 bool timecode_info_exists;
257 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
259 if (!timecode_info_exists) {
260 delete _broadcast_info;
262 _flags = Flag (_flags & ~Broadcast);
266 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
272 SndFileSource::~SndFileSource ()
274 GoingAway (); /* EMIT SIGNAL */
280 /* stupid libsndfile updated the headers on close,
281 so touch the peakfile if it exists and has data
282 to make sure its time is as new as the audio
289 if (_broadcast_info) {
290 delete _broadcast_info;
299 SndFileSource::sample_rate () const
301 return _info.samplerate;
305 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
312 if (start > _length) {
314 /* read starts beyond end of data, just memset to zero */
318 } else if (start + cnt > _length) {
320 /* read ends beyond end of data, read some, memset the rest */
322 file_cnt = _length - start;
326 /* read is entirely within data */
333 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
335 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
336 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
340 if (_info.channels == 1) {
341 nframes_t ret = sf_read_float (sf, dst, file_cnt);
342 _read_data_count = cnt * sizeof(float);
347 if (file_cnt != cnt) {
348 nframes_t delta = cnt - file_cnt;
349 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
352 real_cnt = cnt * _info.channels;
354 Sample* interleave_buf = get_interleave_buffer (real_cnt);
356 nread = sf_read_float (sf, interleave_buf, real_cnt);
357 ptr = interleave_buf + _channel;
358 nread /= _info.channels;
360 /* stride through the interleaved data */
362 for (int32_t n = 0; n < nread; ++n) {
364 ptr += _info.channels;
367 _read_data_count = cnt * sizeof(float);
373 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
376 return destructive_write_unlocked (data, cnt);
378 return nondestructive_write_unlocked (data, cnt);
383 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
386 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
390 if (_info.channels != 1) {
391 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
397 int32_t frame_pos = _length;
399 if (write_float (data, frame_pos, cnt) != cnt) {
404 update_length (oldlen, cnt);
406 if (_build_peakfiles) {
407 compute_and_write_peaks (data, frame_pos, cnt, false, true);
410 _write_data_count = cnt;
416 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
418 nframes_t old_file_pos;
421 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
425 if (_capture_start && _capture_end) {
427 /* start and end of capture both occur within the data we are writing,
428 so do both crossfades.
431 _capture_start = false;
432 _capture_end = false;
434 /* move to the correct location place */
435 file_pos = capture_start_frame - timeline_position;
438 nframes_t subcnt = cnt / 2;
439 nframes_t ofilepos = file_pos;
442 if (crossfade (data, subcnt, 1) != subcnt) {
447 Sample * tmpdata = data + subcnt;
450 subcnt = cnt - subcnt;
451 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
455 file_pos = ofilepos; // adjusted below
457 } else if (_capture_start) {
459 /* start of capture both occur within the data we are writing,
463 _capture_start = false;
464 _capture_end = false;
466 /* move to the correct location place */
467 file_pos = capture_start_frame - timeline_position;
469 if (crossfade (data, cnt, 1) != cnt) {
473 } else if (_capture_end) {
475 /* end of capture both occur within the data we are writing,
479 _capture_start = false;
480 _capture_end = false;
482 if (crossfade (data, cnt, 0) != cnt) {
488 /* in the middle of recording */
490 if (write_float (data, file_pos, cnt) != cnt) {
495 old_file_pos = file_pos;
496 update_length (file_pos, cnt);
498 if (_build_peakfiles) {
499 compute_and_write_peaks (data, file_pos, cnt, false, true);
508 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
510 set_timeline_position (when);
512 if (_flags & Broadcast) {
513 if (setup_broadcast_info (when, now, tnow)) {
518 return flush_header ();
522 SndFileSource::flush_header ()
524 if (!writable() || (sf == 0)) {
525 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
528 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
532 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
535 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
539 if (!(_flags & Broadcast)) {
543 /* random code is 9 digits */
545 int random_code = random() % 999999999;
547 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
548 Config->get_bwf_country_code().c_str(),
549 Config->get_bwf_organization_code().c_str(),
556 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
561 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
566 /* now update header position taking header offset into account */
568 set_header_timeline_position ();
570 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
571 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
572 _flags = Flag (_flags & ~Broadcast);
573 delete _broadcast_info;
582 SndFileSource::set_header_timeline_position ()
584 if (!(_flags & Broadcast)) {
588 _broadcast_info->time_reference_high = (timeline_position >> 32);
589 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
591 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
592 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
593 _flags = Flag (_flags & ~Broadcast);
594 delete _broadcast_info;
600 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
602 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
604 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
605 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
609 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
617 SndFileSource::natural_position() const
619 return timeline_position;
623 SndFileSource::set_destructive (bool yn)
626 _flags = Flag (_flags | Destructive);
628 xfade_buf = new Sample[xfade_frames];
630 clear_capture_marks ();
631 timeline_position = header_position_offset;
633 _flags = Flag (_flags & ~Destructive);
634 timeline_position = 0;
635 /* leave xfade buf alone in case we need it again later */
642 SndFileSource::clear_capture_marks ()
644 _capture_start = false;
645 _capture_end = false;
649 SndFileSource::mark_capture_start (nframes_t pos)
652 if (pos < timeline_position) {
653 _capture_start = false;
655 _capture_start = true;
656 capture_start_frame = pos;
662 SndFileSource::mark_capture_end()
670 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
672 nframes_t xfade = min (xfade_frames, cnt);
673 nframes_t nofade = cnt - xfade;
674 Sample* fade_data = 0;
675 nframes_t fade_position = 0; // in frames
680 fade_position = file_pos;
683 fade_position = file_pos + nofade;
684 fade_data = data + nofade;
687 if (fade_position > _length) {
689 /* read starts beyond end of data, just memset to zero */
693 } else if (fade_position + xfade > _length) {
695 /* read ends beyond end of data, read some, memset the rest */
697 file_cnt = _length - fade_position;
701 /* read is entirely within data */
708 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
709 if (retval >= 0 && errno == EAGAIN) {
710 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
711 * short or no data there */
712 memset (xfade_buf, 0, xfade * sizeof(Sample));
714 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
720 if (file_cnt != xfade) {
721 nframes_t delta = xfade - file_cnt;
722 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
725 if (nofade && !fade_in) {
726 if (write_float (data, file_pos, nofade) != nofade) {
727 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
732 if (xfade == xfade_frames) {
736 /* use the standard xfade curve */
740 /* fade new material in */
742 for (n = 0; n < xfade; ++n) {
743 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
749 /* fade new material out */
751 for (n = 0; n < xfade; ++n) {
752 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
756 } else if (xfade < xfade_frames) {
761 /* short xfade, compute custom curve */
763 compute_equal_power_fades (xfade, in, out);
765 for (nframes_t n = 0; n < xfade; ++n) {
766 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
771 /* long xfade length, has to be computed across several calls */
776 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
777 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
782 if (fade_in && nofade) {
783 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
784 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
793 SndFileSource::last_capture_start_frame () const
796 return capture_start_frame;
803 SndFileSource::handle_header_position_change ()
806 if ( _length != 0 ) {
807 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
808 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
809 } else if (writable()) {
810 timeline_position = header_position_offset;
811 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
817 SndFileSource::setup_standard_crossfades (nframes_t rate)
819 /* This static method is assumed to have been called by the Session
820 before any DFS's are created.
823 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
825 if (out_coefficient) {
826 delete [] out_coefficient;
829 if (in_coefficient) {
830 delete [] in_coefficient;
833 out_coefficient = new gain_t[xfade_frames];
834 in_coefficient = new gain_t[xfade_frames];
836 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
840 SndFileSource::set_timeline_position (int64_t pos)
842 // destructive track timeline postion does not change
843 // except at instantion or when header_position_offset
844 // (session start) changes
846 if (!destructive()) {
847 AudioFileSource::set_timeline_position (pos);
852 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
856 SF_BROADCAST_INFO binfo;
857 bool timecode_exists;
859 sf_info.format = 0; // libsndfile says to clear this before sf_open().
861 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
863 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
867 info.samplerate = sf_info.samplerate;
868 info.channels = sf_info.channels;
869 info.length = sf_info.frames;
870 info.format_name = string_compose("%1\n%2",
871 sndfile_major_format(sf_info.format),
872 sndfile_minor_format(sf_info.format));
874 memset (&binfo, 0, sizeof (binfo));
875 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
877 if (!timecode_exists) {
887 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
889 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
891 return (header_position_offset);
894 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
895 of the time reference.
899 int64_t ret = (uint32_t) binfo->time_reference_high;
901 ret |= (uint32_t) binfo->time_reference_low;
906 SndFileSource::one_of_several_channels () const
908 return _info.channels > 1;
912 SndFileSource::get_interleave_buffer (nframes_t size)
914 SizedSampleBuffer* ssb;
916 if ((ssb = thread_interleave_buffer.get()) == 0) {
917 ssb = new SizedSampleBuffer (size);
918 thread_interleave_buffer.set (ssb);
921 if (ssb->size < size) {
922 ssb = new SizedSampleBuffer (size);
923 thread_interleave_buffer.set (ssb);