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>
29 #include <ardour/sndfilesource.h>
30 #include <ardour/sndfile_helpers.h>
31 #include <ardour/utils.h>
36 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)
54 throw failed_constructor ();
58 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
59 /* files created this way are never writable or removable */
60 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
67 throw failed_constructor ();
71 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
72 : AudioFileSource (s, path, flags, sfmt, hf)
78 /* this constructor is used to construct new files, not open
87 _flags = Flag (_flags & ~Broadcast);
92 _flags = Flag (_flags & ~Broadcast);
97 _flags = Flag (_flags | Broadcast);
102 _flags = Flag (_flags & ~Broadcast);
107 _flags = Flag (_flags & ~Broadcast);
111 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
119 fmt |= SF_FORMAT_FLOAT;
123 fmt |= SF_FORMAT_PCM_24;
127 fmt |= SF_FORMAT_PCM_16;
132 _info.samplerate = rate;
136 throw failed_constructor();
139 if (writable() && (_flags & Broadcast)) {
141 _broadcast_info = new SF_BROADCAST_INFO;
142 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
144 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
146 struct utsname utsinfo;
148 if (uname (&utsinfo)) {
149 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
153 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
154 Glib::get_real_name().c_str(),
160 _broadcast_info->version = 1;
161 _broadcast_info->time_reference_low = 0;
162 _broadcast_info->time_reference_high = 0;
164 /* XXX do something about this field */
166 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
168 /* coding history is added by libsndfile */
170 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
172 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
173 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
174 _flags = Flag (_flags & ~Broadcast);
175 delete _broadcast_info;
183 SndFileSource::init ()
187 // lets try to keep the object initalizations here at the top
190 interleave_bufsize = 0;
197 _name = Glib::path_get_basename (_path);
200 /* although libsndfile says we don't need to set this,
201 valgrind and source code shows us that we do.
204 memset (&_info, 0, sizeof(_info));
206 _capture_start = false;
207 _capture_end = false;
211 xfade_buf = new Sample[xfade_frames];
212 timeline_position = header_position_offset;
215 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
219 SndFileSource::open ()
221 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
223 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
224 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
225 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
229 if (_channel >= _info.channels) {
230 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
236 _length = _info.frames;
238 _broadcast_info = new SF_BROADCAST_INFO;
239 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
241 bool timecode_info_exists;
243 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
245 if (!timecode_info_exists) {
246 delete _broadcast_info;
248 _flags = Flag (_flags & ~Broadcast);
252 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
258 SndFileSource::~SndFileSource ()
260 GoingAway (); /* EMIT SIGNAL */
266 /* stupid libsndfile updated the headers on close,
267 so touch the peakfile if it exists and has data
268 to make sure its time is as new as the audio
275 if (interleave_buf) {
276 delete [] interleave_buf;
279 if (_broadcast_info) {
280 delete _broadcast_info;
289 SndFileSource::sample_rate () const
291 return _info.samplerate;
295 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
302 if (start > _length) {
304 /* read starts beyond end of data, just memset to zero */
308 } else if (start + cnt > _length) {
310 /* read ends beyond end of data, read some, memset the rest */
312 file_cnt = _length - start;
316 /* read is entirely within data */
323 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
325 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
326 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
330 if (_info.channels == 1) {
331 nframes_t ret = sf_read_float (sf, dst, file_cnt);
332 _read_data_count = cnt * sizeof(float);
337 if (file_cnt != cnt) {
338 nframes_t delta = cnt - file_cnt;
339 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
342 real_cnt = cnt * _info.channels;
344 if (interleave_bufsize < real_cnt) {
346 if (interleave_buf) {
347 delete [] interleave_buf;
349 interleave_bufsize = real_cnt;
350 interleave_buf = new float[interleave_bufsize];
353 nread = sf_read_float (sf, interleave_buf, real_cnt);
354 ptr = interleave_buf + _channel;
355 nread /= _info.channels;
357 /* stride through the interleaved data */
359 for (int32_t n = 0; n < nread; ++n) {
361 ptr += _info.channels;
364 _read_data_count = cnt * sizeof(float);
370 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
373 return destructive_write_unlocked (data, cnt);
375 return nondestructive_write_unlocked (data, cnt);
380 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
383 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
387 if (_info.channels != 1) {
388 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
394 int32_t frame_pos = _length;
396 if (write_float (data, frame_pos, cnt) != cnt) {
401 update_length (oldlen, cnt);
403 if (_build_peakfiles) {
404 compute_and_write_peaks (data, frame_pos, cnt, false, true);
407 _write_data_count = cnt;
413 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
415 nframes_t old_file_pos;
418 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
422 if (_capture_start && _capture_end) {
424 /* start and end of capture both occur within the data we are writing,
425 so do both crossfades.
428 _capture_start = false;
429 _capture_end = false;
431 /* move to the correct location place */
432 file_pos = capture_start_frame - timeline_position;
435 nframes_t subcnt = cnt / 2;
436 nframes_t ofilepos = file_pos;
439 if (crossfade (data, subcnt, 1) != subcnt) {
444 Sample * tmpdata = data + subcnt;
447 subcnt = cnt - subcnt;
448 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
452 file_pos = ofilepos; // adjusted below
454 } else if (_capture_start) {
456 /* start of capture both occur within the data we are writing,
460 _capture_start = false;
461 _capture_end = false;
463 /* move to the correct location place */
464 file_pos = capture_start_frame - timeline_position;
466 if (crossfade (data, cnt, 1) != cnt) {
470 } else if (_capture_end) {
472 /* end of capture both occur within the data we are writing,
476 _capture_start = false;
477 _capture_end = false;
479 if (crossfade (data, cnt, 0) != cnt) {
485 /* in the middle of recording */
487 if (write_float (data, file_pos, cnt) != cnt) {
492 old_file_pos = file_pos;
493 update_length (file_pos, cnt);
495 if (_build_peakfiles) {
496 compute_and_write_peaks (data, file_pos, cnt, false, true);
505 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
507 set_timeline_position (when);
509 if (_flags & Broadcast) {
510 if (setup_broadcast_info (when, now, tnow)) {
515 return flush_header ();
519 SndFileSource::flush_header ()
521 if (!writable() || (sf == 0)) {
522 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
525 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
529 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
532 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
536 if (!(_flags & Broadcast)) {
540 /* random code is 9 digits */
542 int random_code = random() % 999999999;
544 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
545 Config->get_bwf_country_code().c_str(),
546 Config->get_bwf_organization_code().c_str(),
553 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
558 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
563 /* now update header position taking header offset into account */
565 set_header_timeline_position ();
567 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
568 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
569 _flags = Flag (_flags & ~Broadcast);
570 delete _broadcast_info;
579 SndFileSource::set_header_timeline_position ()
581 if (!(_flags & Broadcast)) {
585 _broadcast_info->time_reference_high = (timeline_position >> 32);
586 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
588 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
589 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
590 _flags = Flag (_flags & ~Broadcast);
591 delete _broadcast_info;
597 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
599 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
601 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
602 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
606 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
614 SndFileSource::natural_position() const
616 return timeline_position;
620 SndFileSource::set_destructive (bool yn)
623 _flags = Flag (_flags | Destructive);
625 xfade_buf = new Sample[xfade_frames];
627 clear_capture_marks ();
628 timeline_position = header_position_offset;
630 _flags = Flag (_flags & ~Destructive);
631 timeline_position = 0;
632 /* leave xfade buf alone in case we need it again later */
639 SndFileSource::clear_capture_marks ()
641 _capture_start = false;
642 _capture_end = false;
646 SndFileSource::mark_capture_start (nframes_t pos)
649 if (pos < timeline_position) {
650 _capture_start = false;
652 _capture_start = true;
653 capture_start_frame = pos;
659 SndFileSource::mark_capture_end()
667 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
669 nframes_t xfade = min (xfade_frames, cnt);
670 nframes_t nofade = cnt - xfade;
671 Sample* fade_data = 0;
672 nframes_t fade_position = 0; // in frames
677 fade_position = file_pos;
680 fade_position = file_pos + nofade;
681 fade_data = data + nofade;
684 if (fade_position > _length) {
686 /* read starts beyond end of data, just memset to zero */
690 } else if (fade_position + xfade > _length) {
692 /* read ends beyond end of data, read some, memset the rest */
694 file_cnt = _length - fade_position;
698 /* read is entirely within data */
705 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
706 if (retval >= 0 && errno == EAGAIN) {
707 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
708 * short or no data there */
709 memset (xfade_buf, 0, xfade * sizeof(Sample));
711 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
717 if (file_cnt != xfade) {
718 nframes_t delta = xfade - file_cnt;
719 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
722 if (nofade && !fade_in) {
723 if (write_float (data, file_pos, nofade) != nofade) {
724 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
729 if (xfade == xfade_frames) {
733 /* use the standard xfade curve */
737 /* fade new material in */
739 for (n = 0; n < xfade; ++n) {
740 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
746 /* fade new material out */
748 for (n = 0; n < xfade; ++n) {
749 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
753 } else if (xfade < xfade_frames) {
758 /* short xfade, compute custom curve */
760 compute_equal_power_fades (xfade, in, out);
762 for (nframes_t n = 0; n < xfade; ++n) {
763 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
768 /* long xfade length, has to be computed across several calls */
773 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
774 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
779 if (fade_in && nofade) {
780 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
781 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
790 SndFileSource::last_capture_start_frame () const
793 return capture_start_frame;
800 SndFileSource::handle_header_position_change ()
803 if ( _length != 0 ) {
804 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
805 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
806 } else if (writable()) {
807 timeline_position = header_position_offset;
808 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
814 SndFileSource::setup_standard_crossfades (nframes_t rate)
816 /* This static method is assumed to have been called by the Session
817 before any DFS's are created.
820 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
822 if (out_coefficient) {
823 delete [] out_coefficient;
826 if (in_coefficient) {
827 delete [] in_coefficient;
830 out_coefficient = new gain_t[xfade_frames];
831 in_coefficient = new gain_t[xfade_frames];
833 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
837 SndFileSource::set_timeline_position (int64_t pos)
839 // destructive track timeline postion does not change
840 // except at instantion or when header_position_offset
841 // (session start) changes
843 if (!destructive()) {
844 AudioFileSource::set_timeline_position (pos);
849 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
853 SF_BROADCAST_INFO binfo;
854 bool timecode_exists;
856 sf_info.format = 0; // libsndfile says to clear this before sf_open().
858 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
860 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
864 info.samplerate = sf_info.samplerate;
865 info.channels = sf_info.channels;
866 info.length = sf_info.frames;
867 info.format_name = string_compose("%1\n%2",
868 sndfile_major_format(sf_info.format),
869 sndfile_minor_format(sf_info.format));
871 memset (&binfo, 0, sizeof (binfo));
872 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
874 if (!timecode_exists) {
884 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
886 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
888 return (header_position_offset);
891 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
892 of the time reference.
896 int64_t ret = (uint32_t) binfo->time_reference_high;
898 ret |= (uint32_t) binfo->time_reference_low;
903 SndFileSource::one_of_several_channels () const
905 return _info.channels > 1;