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.
25 #include <sys/utsname.h>
28 #include <glibmm/miscutils.h>
30 #include <ardour/sndfilesource.h>
31 #include <ardour/sndfile_helpers.h>
32 #include <ardour/utils.h>
37 using namespace ARDOUR;
40 gain_t* SndFileSource::out_coefficient = 0;
41 gain_t* SndFileSource::in_coefficient = 0;
42 nframes_t SndFileSource::xfade_frames = 64;
43 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
44 AudioFileSource::Removable|
45 AudioFileSource::RemovableIfEmpty|
46 AudioFileSource::CanRename);
48 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
49 : AudioFileSource (s, node)
53 cerr << "SndFileSource @ " << _path << " channel = " << channel << endl;
56 throw failed_constructor ();
60 SndFileSource::SndFileSource (Session& s, string path, int chn, Flag flags)
61 /* files created this way are never writable or removable */
62 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
69 throw failed_constructor ();
73 SndFileSource::SndFileSource (Session& s, string path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
74 : AudioFileSource (s, path, flags, sfmt, hf)
80 /* this constructor is used to construct new files, not open
89 _flags = Flag (_flags & ~Broadcast);
94 _flags = Flag (_flags & ~Broadcast);
99 _flags = Flag (_flags | Broadcast);
104 _flags = Flag (_flags & ~Broadcast);
109 _flags = Flag (_flags & ~Broadcast);
113 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
121 fmt |= SF_FORMAT_FLOAT;
125 fmt |= SF_FORMAT_PCM_24;
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;
181 SndFileSource::init ()
185 // lets try to keep the object initalizations here at the top
188 interleave_bufsize = 0;
195 _name = Glib::path_get_basename (_path);
198 /* although libsndfile says we don't need to set this,
199 valgrind and source code shows us that we do.
202 memset (&_info, 0, sizeof(_info));
204 _capture_start = false;
205 _capture_end = false;
209 xfade_buf = new Sample[xfade_frames];
210 timeline_position = header_position_offset;
213 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
217 SndFileSource::open ()
219 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
221 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
222 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
223 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
227 if (channel >= _info.channels) {
228 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg;
234 _length = _info.frames;
236 _broadcast_info = new SF_BROADCAST_INFO;
237 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
239 bool timecode_info_exists;
241 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
243 if (!timecode_info_exists) {
244 delete _broadcast_info;
246 _flags = Flag (_flags & ~Broadcast);
250 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
256 SndFileSource::~SndFileSource ()
258 GoingAway (); /* EMIT SIGNAL */
264 /* stupid libsndfile updated the headers on close,
265 so touch the peakfile if it exists and has data
266 to make sure its time is as new as the audio
273 if (interleave_buf) {
274 delete [] interleave_buf;
277 if (_broadcast_info) {
278 delete _broadcast_info;
287 SndFileSource::sample_rate () const
289 return _info.samplerate;
293 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
300 if (start > _length) {
302 /* read starts beyond end of data, just memset to zero */
306 } else if (start + cnt > _length) {
308 /* read ends beyond end of data, read some, memset the rest */
310 file_cnt = _length - start;
314 /* read is entirely within data */
321 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
323 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
324 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
328 if (_info.channels == 1) {
329 nframes_t ret = sf_read_float (sf, dst, file_cnt);
330 _read_data_count = cnt * sizeof(float);
335 if (file_cnt != cnt) {
336 nframes_t delta = cnt - file_cnt;
337 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
340 real_cnt = cnt * _info.channels;
342 if (interleave_bufsize < real_cnt) {
344 if (interleave_buf) {
345 delete [] interleave_buf;
347 interleave_bufsize = real_cnt;
348 interleave_buf = new float[interleave_bufsize];
351 nread = sf_read_float (sf, interleave_buf, real_cnt);
352 ptr = interleave_buf + channel;
353 nread /= _info.channels;
355 /* stride through the interleaved data */
357 for (int32_t n = 0; n < nread; ++n) {
359 ptr += _info.channels;
362 _read_data_count = cnt * sizeof(float);
368 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
371 return destructive_write_unlocked (data, cnt);
373 return nondestructive_write_unlocked (data, cnt);
378 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
381 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
385 if (_info.channels != 1) {
386 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
392 int32_t frame_pos = _length;
394 if (write_float (data, frame_pos, cnt) != cnt) {
399 update_length (oldlen, cnt);
401 if (_build_peakfiles) {
402 PeakBuildRecord *pbr = 0;
404 if (pending_peak_builds.size()) {
405 pbr = pending_peak_builds.back();
408 if (pbr && pbr->frame + pbr->cnt == oldlen) {
410 /* the last PBR extended to the start of the current write,
411 so just extend it again.
415 pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
418 _peaks_built = false;
422 if (_build_peakfiles) {
423 queue_for_peaks (shared_from_this (), false);
426 _write_data_count = cnt;
432 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
434 nframes_t old_file_pos;
437 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
441 if (_capture_start && _capture_end) {
443 /* start and end of capture both occur within the data we are writing,
444 so do both crossfades.
447 _capture_start = false;
448 _capture_end = false;
450 /* move to the correct location place */
451 file_pos = capture_start_frame - timeline_position;
454 nframes_t subcnt = cnt / 2;
455 nframes_t ofilepos = file_pos;
458 if (crossfade (data, subcnt, 1) != subcnt) {
463 Sample * tmpdata = data + subcnt;
466 subcnt = cnt - subcnt;
467 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
471 file_pos = ofilepos; // adjusted below
473 } else if (_capture_start) {
475 /* start of capture both occur within the data we are writing,
479 _capture_start = false;
480 _capture_end = false;
482 /* move to the correct location place */
483 file_pos = capture_start_frame - timeline_position;
485 if (crossfade (data, cnt, 1) != cnt) {
489 } else if (_capture_end) {
491 /* end of capture both occur within the data we are writing,
495 _capture_start = false;
496 _capture_end = false;
498 if (crossfade (data, cnt, 0) != cnt) {
504 /* in the middle of recording */
506 if (write_float (data, file_pos, cnt) != cnt) {
511 old_file_pos = file_pos;
512 update_length (file_pos, cnt);
515 if (_build_peakfiles) {
516 PeakBuildRecord *pbr = 0;
518 if (pending_peak_builds.size()) {
519 pbr = pending_peak_builds.back();
522 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
524 /* the last PBR extended to the start of the current write,
525 so just extend it again.
530 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
533 _peaks_built = false;
536 if (_build_peakfiles) {
537 queue_for_peaks (shared_from_this (), true);
544 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
546 set_timeline_position (when);
548 if (_flags & Broadcast) {
549 if (setup_broadcast_info (when, now, tnow)) {
554 return flush_header ();
558 SndFileSource::flush_header ()
560 if (!writable() || (sf == 0)) {
561 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
564 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
568 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
571 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
575 if (!(_flags & Broadcast)) {
579 /* random code is 9 digits */
581 int random_code = random() % 999999999;
583 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
584 Config->get_bwf_country_code().c_str(),
585 Config->get_bwf_organization_code().c_str(),
592 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
597 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
602 /* now update header position taking header offset into account */
604 set_header_timeline_position ();
606 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
607 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
608 _flags = Flag (_flags & ~Broadcast);
609 delete _broadcast_info;
618 SndFileSource::set_header_timeline_position ()
620 if (!(_flags & Broadcast)) {
624 _broadcast_info->time_reference_high = (timeline_position >> 32);
625 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
627 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
628 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
629 _flags = Flag (_flags & ~Broadcast);
630 delete _broadcast_info;
639 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
641 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
643 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
644 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
648 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
656 SndFileSource::natural_position() const
658 return timeline_position;
662 SndFileSource::set_destructive (bool yn)
665 _flags = Flag (_flags | Destructive);
667 xfade_buf = new Sample[xfade_frames];
669 clear_capture_marks ();
670 timeline_position = header_position_offset;
672 _flags = Flag (_flags & ~Destructive);
673 timeline_position = 0;
674 /* leave xfade buf alone in case we need it again later */
681 SndFileSource::clear_capture_marks ()
683 _capture_start = false;
684 _capture_end = false;
688 SndFileSource::mark_capture_start (nframes_t pos)
691 if (pos < timeline_position) {
692 _capture_start = false;
694 _capture_start = true;
695 capture_start_frame = pos;
701 SndFileSource::mark_capture_end()
709 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
711 nframes_t xfade = min (xfade_frames, cnt);
712 nframes_t nofade = cnt - xfade;
713 Sample* fade_data = 0;
714 nframes_t fade_position = 0; // in frames
719 fade_position = file_pos;
722 fade_position = file_pos + nofade;
723 fade_data = data + nofade;
726 if (fade_position > _length) {
728 /* read starts beyond end of data, just memset to zero */
732 } else if (fade_position + xfade > _length) {
734 /* read ends beyond end of data, read some, memset the rest */
736 file_cnt = _length - fade_position;
740 /* read is entirely within data */
747 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
748 if (retval >= 0 && errno == EAGAIN) {
749 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
750 * short or no data there */
751 memset (xfade_buf, 0, xfade * sizeof(Sample));
753 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
759 if (file_cnt != xfade) {
760 nframes_t delta = xfade - file_cnt;
761 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
764 if (nofade && !fade_in) {
765 if (write_float (data, file_pos, nofade) != nofade) {
766 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
771 if (xfade == xfade_frames) {
775 /* use the standard xfade curve */
779 /* fade new material in */
781 for (n = 0; n < xfade; ++n) {
782 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
788 /* fade new material out */
790 for (n = 0; n < xfade; ++n) {
791 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
795 } else if (xfade < xfade_frames) {
800 /* short xfade, compute custom curve */
802 compute_equal_power_fades (xfade, in, out);
804 for (nframes_t n = 0; n < xfade; ++n) {
805 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
810 /* long xfade length, has to be computed across several calls */
815 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
816 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
821 if (fade_in && nofade) {
822 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
823 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
832 SndFileSource::last_capture_start_frame () const
835 return capture_start_frame;
842 SndFileSource::handle_header_position_change ()
845 if ( _length != 0 ) {
846 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
847 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
848 } else if (writable()) {
849 timeline_position = header_position_offset;
850 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
856 SndFileSource::setup_standard_crossfades (nframes_t rate)
858 /* This static method is assumed to have been called by the Session
859 before any DFS's are created.
862 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
864 if (out_coefficient) {
865 delete [] out_coefficient;
868 if (in_coefficient) {
869 delete [] in_coefficient;
872 out_coefficient = new gain_t[xfade_frames];
873 in_coefficient = new gain_t[xfade_frames];
875 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
879 SndFileSource::set_timeline_position (int64_t pos)
881 // destructive track timeline postion does not change
882 // except at instantion or when header_position_offset
883 // (session start) changes
885 if (!destructive()) {
886 AudioFileSource::set_timeline_position (pos);
891 SndFileSource::get_soundfile_info (string path, SoundFileInfo& info, string& error_msg)
895 SF_BROADCAST_INFO binfo;
896 bool timecode_exists;
898 sf_info.format = 0; // libsndfile says to clear this before sf_open().
900 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
902 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
906 info.samplerate = sf_info.samplerate;
907 info.channels = sf_info.channels;
908 info.length = sf_info.frames;
909 info.format_name = string_compose("Format: %1, %2",
910 sndfile_major_format(sf_info.format),
911 sndfile_minor_format(sf_info.format));
913 memset (&binfo, 0, sizeof (binfo));
914 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
916 if (!timecode_exists) {
926 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
928 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
930 return (header_position_offset);
933 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
934 of the time reference.
938 int64_t ret = (uint32_t) binfo->time_reference_high;
940 ret |= (uint32_t) binfo->time_reference_low;