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 <pbd/stacktrace.h>
30 #include <ardour/sndfilesource.h>
31 #include <ardour/sndfile_helpers.h>
32 #include <ardour/utils.h>
37 using namespace ARDOUR;
41 gain_t* SndFileSource::out_coefficient = 0;
42 gain_t* SndFileSource::in_coefficient = 0;
43 nframes_t SndFileSource::xfade_frames = 64;
44 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
45 AudioFileSource::Removable|
46 AudioFileSource::RemovableIfEmpty|
47 AudioFileSource::CanRename);
49 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
50 : AudioFileSource (s, node)
55 throw failed_constructor ();
59 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
60 /* files created this way are never writable or removable */
61 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
68 throw failed_constructor ();
72 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
73 : AudioFileSource (s, path, flags, sfmt, hf)
79 /* this constructor is used to construct new files, not open
88 _flags = Flag (_flags & ~Broadcast);
93 _flags = Flag (_flags & ~Broadcast);
98 _flags = Flag (_flags | Broadcast);
103 _flags = Flag (_flags & ~Broadcast);
108 _flags = Flag (_flags & ~Broadcast);
112 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
120 fmt |= SF_FORMAT_FLOAT;
124 fmt |= SF_FORMAT_PCM_24;
128 fmt |= SF_FORMAT_PCM_16;
133 _info.samplerate = rate;
137 throw failed_constructor();
140 if (writable() && (_flags & Broadcast)) {
142 _broadcast_info = new SF_BROADCAST_INFO;
143 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
145 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
147 struct utsname utsinfo;
149 if (uname (&utsinfo)) {
150 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
154 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
155 Glib::get_real_name().c_str(),
161 _broadcast_info->version = 1;
162 _broadcast_info->time_reference_low = 0;
163 _broadcast_info->time_reference_high = 0;
165 /* XXX do something about this field */
167 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
169 /* coding history is added by libsndfile */
171 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
173 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
174 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
175 _flags = Flag (_flags & ~Broadcast);
176 delete _broadcast_info;
184 SndFileSource::init ()
188 // lets try to keep the object initalizations here at the top
191 interleave_bufsize = 0;
198 _name = Glib::path_get_basename (_path);
201 /* although libsndfile says we don't need to set this,
202 valgrind and source code shows us that we do.
205 memset (&_info, 0, sizeof(_info));
207 _capture_start = false;
208 _capture_end = false;
212 xfade_buf = new Sample[xfade_frames];
213 timeline_position = header_position_offset;
216 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
220 SndFileSource::open ()
222 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
224 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
225 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
226 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
230 if (_channel >= _info.channels) {
231 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
237 _length = _info.frames;
239 _broadcast_info = new SF_BROADCAST_INFO;
240 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
242 bool timecode_info_exists;
244 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
246 if (!timecode_info_exists) {
247 delete _broadcast_info;
249 _flags = Flag (_flags & ~Broadcast);
253 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
259 SndFileSource::~SndFileSource ()
261 GoingAway (); /* EMIT SIGNAL */
267 /* stupid libsndfile updated the headers on close,
268 so touch the peakfile if it exists and has data
269 to make sure its time is as new as the audio
276 if (interleave_buf) {
277 delete [] interleave_buf;
280 if (_broadcast_info) {
281 delete _broadcast_info;
290 SndFileSource::sample_rate () const
292 return _info.samplerate;
296 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
303 if (start > _length) {
305 /* read starts beyond end of data, just memset to zero */
309 } else if (start + cnt > _length) {
311 /* read ends beyond end of data, read some, memset the rest */
313 file_cnt = _length - start;
317 /* read is entirely within data */
324 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
326 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
327 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
331 if (_info.channels == 1) {
332 nframes_t ret = sf_read_float (sf, dst, file_cnt);
333 _read_data_count = cnt * sizeof(float);
338 if (file_cnt != cnt) {
339 nframes_t delta = cnt - file_cnt;
340 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
343 real_cnt = cnt * _info.channels;
345 if (interleave_bufsize < real_cnt) {
347 if (interleave_buf) {
348 delete [] interleave_buf;
350 interleave_bufsize = real_cnt;
351 interleave_buf = new float[interleave_bufsize];
354 nread = sf_read_float (sf, interleave_buf, real_cnt);
355 ptr = interleave_buf + _channel;
356 nread /= _info.channels;
358 /* stride through the interleaved data */
360 for (int32_t n = 0; n < nread; ++n) {
362 ptr += _info.channels;
365 _read_data_count = cnt * sizeof(float);
371 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
374 return destructive_write_unlocked (data, cnt);
376 return nondestructive_write_unlocked (data, cnt);
381 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
384 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
388 if (_info.channels != 1) {
389 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
395 int32_t frame_pos = _length;
397 if (write_float (data, frame_pos, cnt) != cnt) {
402 update_length (oldlen, cnt);
404 if (_build_peakfiles) {
405 compute_and_write_peaks (data, frame_pos, cnt, false, true);
408 _write_data_count = cnt;
414 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
416 nframes_t old_file_pos;
419 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
423 if (_capture_start && _capture_end) {
425 /* start and end of capture both occur within the data we are writing,
426 so do both crossfades.
429 _capture_start = false;
430 _capture_end = false;
432 /* move to the correct location place */
433 file_pos = capture_start_frame - timeline_position;
436 nframes_t subcnt = cnt / 2;
437 nframes_t ofilepos = file_pos;
440 if (crossfade (data, subcnt, 1) != subcnt) {
445 Sample * tmpdata = data + subcnt;
448 subcnt = cnt - subcnt;
449 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
453 file_pos = ofilepos; // adjusted below
455 } else if (_capture_start) {
457 /* start of capture both occur within the data we are writing,
461 _capture_start = false;
462 _capture_end = false;
464 /* move to the correct location place */
465 file_pos = capture_start_frame - timeline_position;
467 if (crossfade (data, cnt, 1) != cnt) {
471 } else if (_capture_end) {
473 /* end of capture both occur within the data we are writing,
477 _capture_start = false;
478 _capture_end = false;
480 if (crossfade (data, cnt, 0) != cnt) {
486 /* in the middle of recording */
488 if (write_float (data, file_pos, cnt) != cnt) {
493 old_file_pos = file_pos;
494 update_length (file_pos, cnt);
496 if (_build_peakfiles) {
497 compute_and_write_peaks (data, file_pos, cnt, false, true);
506 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
508 set_timeline_position (when);
510 if (_flags & Broadcast) {
511 if (setup_broadcast_info (when, now, tnow)) {
516 return flush_header ();
520 SndFileSource::flush_header ()
522 if (!writable() || (sf == 0)) {
523 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
526 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
530 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
533 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
537 if (!(_flags & Broadcast)) {
541 /* random code is 9 digits */
543 int random_code = random() % 999999999;
545 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
546 Config->get_bwf_country_code().c_str(),
547 Config->get_bwf_organization_code().c_str(),
554 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
559 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
564 /* now update header position taking header offset into account */
566 set_header_timeline_position ();
568 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
569 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
570 _flags = Flag (_flags & ~Broadcast);
571 delete _broadcast_info;
580 SndFileSource::set_header_timeline_position ()
582 if (!(_flags & Broadcast)) {
586 _broadcast_info->time_reference_high = (timeline_position >> 32);
587 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
589 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
590 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
591 _flags = Flag (_flags & ~Broadcast);
592 delete _broadcast_info;
598 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
600 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
602 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
603 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
607 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
615 SndFileSource::natural_position() const
617 return timeline_position;
621 SndFileSource::set_destructive (bool yn)
624 _flags = Flag (_flags | Destructive);
626 xfade_buf = new Sample[xfade_frames];
628 clear_capture_marks ();
629 timeline_position = header_position_offset;
631 _flags = Flag (_flags & ~Destructive);
632 timeline_position = 0;
633 /* leave xfade buf alone in case we need it again later */
640 SndFileSource::clear_capture_marks ()
642 _capture_start = false;
643 _capture_end = false;
647 SndFileSource::mark_capture_start (nframes_t pos)
650 if (pos < timeline_position) {
651 _capture_start = false;
653 _capture_start = true;
654 capture_start_frame = pos;
660 SndFileSource::mark_capture_end()
668 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
670 nframes_t xfade = min (xfade_frames, cnt);
671 nframes_t nofade = cnt - xfade;
672 Sample* fade_data = 0;
673 nframes_t fade_position = 0; // in frames
678 fade_position = file_pos;
681 fade_position = file_pos + nofade;
682 fade_data = data + nofade;
685 if (fade_position > _length) {
687 /* read starts beyond end of data, just memset to zero */
691 } else if (fade_position + xfade > _length) {
693 /* read ends beyond end of data, read some, memset the rest */
695 file_cnt = _length - fade_position;
699 /* read is entirely within data */
706 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
707 if (retval >= 0 && errno == EAGAIN) {
708 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
709 * short or no data there */
710 memset (xfade_buf, 0, xfade * sizeof(Sample));
712 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
718 if (file_cnt != xfade) {
719 nframes_t delta = xfade - file_cnt;
720 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
723 if (nofade && !fade_in) {
724 if (write_float (data, file_pos, nofade) != nofade) {
725 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
730 if (xfade == xfade_frames) {
734 /* use the standard xfade curve */
738 /* fade new material in */
740 for (n = 0; n < xfade; ++n) {
741 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
747 /* fade new material out */
749 for (n = 0; n < xfade; ++n) {
750 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
754 } else if (xfade < xfade_frames) {
759 /* short xfade, compute custom curve */
761 compute_equal_power_fades (xfade, in, out);
763 for (nframes_t n = 0; n < xfade; ++n) {
764 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
769 /* long xfade length, has to be computed across several calls */
774 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
775 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
780 if (fade_in && nofade) {
781 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
782 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
791 SndFileSource::last_capture_start_frame () const
794 return capture_start_frame;
801 SndFileSource::handle_header_position_change ()
804 if ( _length != 0 ) {
805 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
806 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
807 } else if (writable()) {
808 timeline_position = header_position_offset;
809 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
815 SndFileSource::setup_standard_crossfades (nframes_t rate)
817 /* This static method is assumed to have been called by the Session
818 before any DFS's are created.
821 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
823 if (out_coefficient) {
824 delete [] out_coefficient;
827 if (in_coefficient) {
828 delete [] in_coefficient;
831 out_coefficient = new gain_t[xfade_frames];
832 in_coefficient = new gain_t[xfade_frames];
834 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
838 SndFileSource::set_timeline_position (int64_t pos)
840 // destructive track timeline postion does not change
841 // except at instantion or when header_position_offset
842 // (session start) changes
844 if (!destructive()) {
845 AudioFileSource::set_timeline_position (pos);
850 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
854 SF_BROADCAST_INFO binfo;
855 bool timecode_exists;
857 sf_info.format = 0; // libsndfile says to clear this before sf_open().
859 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
861 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
865 info.samplerate = sf_info.samplerate;
866 info.channels = sf_info.channels;
867 info.length = sf_info.frames;
868 info.format_name = string_compose("%1\n%2",
869 sndfile_major_format(sf_info.format),
870 sndfile_minor_format(sf_info.format));
872 memset (&binfo, 0, sizeof (binfo));
873 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
875 if (!timecode_exists) {
885 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
887 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
889 return (header_position_offset);
892 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
893 of the time reference.
897 int64_t ret = (uint32_t) binfo->time_reference_high;
899 ret |= (uint32_t) binfo->time_reference_low;
904 SndFileSource::one_of_several_channels () const
906 return _info.channels > 1;