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 <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 struct SizedSampleBuffer {
52 SizedSampleBuffer (nframes_t sz) : size (sz) {
53 buf = new Sample[size];
56 ~SizedSampleBuffer() {
61 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
63 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
64 : AudioFileSource (s, node)
69 throw failed_constructor ();
73 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
74 /* files created this way are never writable or removable */
75 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
82 throw failed_constructor ();
86 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
87 : AudioFileSource (s, path, flags, sfmt, hf)
93 /* this constructor is used to construct new files, not open
102 _flags = Flag (_flags & ~Broadcast);
106 fmt = SF_FORMAT_AIFF;
107 _flags = Flag (_flags & ~Broadcast);
112 _flags = Flag (_flags | Broadcast);
117 _flags = Flag (_flags & ~Broadcast);
122 _flags = Flag (_flags & ~Broadcast);
126 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
134 fmt |= SF_FORMAT_FLOAT;
138 fmt |= SF_FORMAT_PCM_24;
142 fmt |= SF_FORMAT_PCM_16;
147 _info.samplerate = rate;
151 throw failed_constructor();
154 if (writable() && (_flags & Broadcast)) {
156 _broadcast_info = new SF_BROADCAST_INFO;
157 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
159 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
161 struct utsname utsinfo;
163 if (uname (&utsinfo)) {
164 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
168 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
169 Glib::get_real_name().c_str(),
175 _broadcast_info->version = 1;
176 _broadcast_info->time_reference_low = 0;
177 _broadcast_info->time_reference_high = 0;
179 /* XXX do something about this field */
181 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
183 /* coding history is added by libsndfile */
185 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
187 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
188 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
189 _flags = Flag (_flags & ~Broadcast);
190 delete _broadcast_info;
198 SndFileSource::init ()
202 // lets try to keep the object initalizations here at the top
210 _name = Glib::path_get_basename (_path);
213 /* although libsndfile says we don't need to set this,
214 valgrind and source code shows us that we do.
217 memset (&_info, 0, sizeof(_info));
219 _capture_start = false;
220 _capture_end = false;
224 xfade_buf = new Sample[xfade_frames];
225 timeline_position = header_position_offset;
228 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
232 SndFileSource::open ()
234 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
236 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
237 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
238 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
242 if (_channel >= _info.channels) {
243 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
249 _length = _info.frames;
251 _broadcast_info = new SF_BROADCAST_INFO;
252 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
254 bool timecode_info_exists;
256 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
258 if (!timecode_info_exists) {
259 delete _broadcast_info;
261 _flags = Flag (_flags & ~Broadcast);
265 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
271 SndFileSource::~SndFileSource ()
273 GoingAway (); /* EMIT SIGNAL */
279 /* stupid libsndfile updated the headers on close,
280 so touch the peakfile if it exists and has data
281 to make sure its time is as new as the audio
288 if (_broadcast_info) {
289 delete _broadcast_info;
298 SndFileSource::sample_rate () const
300 return _info.samplerate;
304 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
311 if (start > _length) {
313 /* read starts beyond end of data, just memset to zero */
317 } else if (start + cnt > _length) {
319 /* read ends beyond end of data, read some, memset the rest */
321 file_cnt = _length - start;
325 /* read is entirely within data */
332 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
334 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
335 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
339 if (_info.channels == 1) {
340 nframes_t ret = sf_read_float (sf, dst, file_cnt);
341 _read_data_count = cnt * sizeof(float);
346 if (file_cnt != cnt) {
347 nframes_t delta = cnt - file_cnt;
348 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
351 real_cnt = cnt * _info.channels;
353 Sample* interleave_buf = get_interleave_buffer (real_cnt);
355 nread = sf_read_float (sf, interleave_buf, real_cnt);
356 ptr = interleave_buf + _channel;
357 nread /= _info.channels;
359 /* stride through the interleaved data */
361 for (int32_t n = 0; n < nread; ++n) {
363 ptr += _info.channels;
366 _read_data_count = cnt * sizeof(float);
372 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
375 return destructive_write_unlocked (data, cnt);
377 return nondestructive_write_unlocked (data, cnt);
382 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
385 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
389 if (_info.channels != 1) {
390 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
396 int32_t frame_pos = _length;
398 if (write_float (data, frame_pos, cnt) != cnt) {
403 update_length (oldlen, cnt);
405 if (_build_peakfiles) {
406 compute_and_write_peaks (data, frame_pos, cnt, false, true);
409 _write_data_count = cnt;
415 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
417 nframes_t old_file_pos;
420 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
424 if (_capture_start && _capture_end) {
426 /* start and end of capture both occur within the data we are writing,
427 so do both crossfades.
430 _capture_start = false;
431 _capture_end = false;
433 /* move to the correct location place */
434 file_pos = capture_start_frame - timeline_position;
437 nframes_t subcnt = cnt / 2;
438 nframes_t ofilepos = file_pos;
441 if (crossfade (data, subcnt, 1) != subcnt) {
446 Sample * tmpdata = data + subcnt;
449 subcnt = cnt - subcnt;
450 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
454 file_pos = ofilepos; // adjusted below
456 } else if (_capture_start) {
458 /* start of capture both occur within the data we are writing,
462 _capture_start = false;
463 _capture_end = false;
465 /* move to the correct location place */
466 file_pos = capture_start_frame - timeline_position;
468 if (crossfade (data, cnt, 1) != cnt) {
472 } else if (_capture_end) {
474 /* end of capture both occur within the data we are writing,
478 _capture_start = false;
479 _capture_end = false;
481 if (crossfade (data, cnt, 0) != cnt) {
487 /* in the middle of recording */
489 if (write_float (data, file_pos, cnt) != cnt) {
494 old_file_pos = file_pos;
495 update_length (file_pos, cnt);
497 if (_build_peakfiles) {
498 compute_and_write_peaks (data, file_pos, cnt, false, true);
507 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
509 set_timeline_position (when);
511 if (_flags & Broadcast) {
512 if (setup_broadcast_info (when, now, tnow)) {
517 return flush_header ();
521 SndFileSource::flush_header ()
523 if (!writable() || (sf == 0)) {
524 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
527 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
531 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
534 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
538 if (!(_flags & Broadcast)) {
542 /* random code is 9 digits */
544 int random_code = random() % 999999999;
546 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
547 Config->get_bwf_country_code().c_str(),
548 Config->get_bwf_organization_code().c_str(),
555 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
560 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
565 /* now update header position taking header offset into account */
567 set_header_timeline_position ();
569 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
570 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
571 _flags = Flag (_flags & ~Broadcast);
572 delete _broadcast_info;
581 SndFileSource::set_header_timeline_position ()
583 if (!(_flags & Broadcast)) {
587 _broadcast_info->time_reference_high = (timeline_position >> 32);
588 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
590 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
591 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
592 _flags = Flag (_flags & ~Broadcast);
593 delete _broadcast_info;
599 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
601 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
603 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
604 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
608 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
616 SndFileSource::natural_position() const
618 return timeline_position;
622 SndFileSource::set_destructive (bool yn)
625 _flags = Flag (_flags | Destructive);
627 xfade_buf = new Sample[xfade_frames];
629 clear_capture_marks ();
630 timeline_position = header_position_offset;
632 _flags = Flag (_flags & ~Destructive);
633 timeline_position = 0;
634 /* leave xfade buf alone in case we need it again later */
641 SndFileSource::clear_capture_marks ()
643 _capture_start = false;
644 _capture_end = false;
648 SndFileSource::mark_capture_start (nframes_t pos)
651 if (pos < timeline_position) {
652 _capture_start = false;
654 _capture_start = true;
655 capture_start_frame = pos;
661 SndFileSource::mark_capture_end()
669 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
671 nframes_t xfade = min (xfade_frames, cnt);
672 nframes_t nofade = cnt - xfade;
673 Sample* fade_data = 0;
674 nframes_t fade_position = 0; // in frames
679 fade_position = file_pos;
682 fade_position = file_pos + nofade;
683 fade_data = data + nofade;
686 if (fade_position > _length) {
688 /* read starts beyond end of data, just memset to zero */
692 } else if (fade_position + xfade > _length) {
694 /* read ends beyond end of data, read some, memset the rest */
696 file_cnt = _length - fade_position;
700 /* read is entirely within data */
707 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
708 if (retval >= 0 && errno == EAGAIN) {
709 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
710 * short or no data there */
711 memset (xfade_buf, 0, xfade * sizeof(Sample));
713 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
719 if (file_cnt != xfade) {
720 nframes_t delta = xfade - file_cnt;
721 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
724 if (nofade && !fade_in) {
725 if (write_float (data, file_pos, nofade) != nofade) {
726 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
731 if (xfade == xfade_frames) {
735 /* use the standard xfade curve */
739 /* fade new material in */
741 for (n = 0; n < xfade; ++n) {
742 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
748 /* fade new material out */
750 for (n = 0; n < xfade; ++n) {
751 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
755 } else if (xfade < xfade_frames) {
760 /* short xfade, compute custom curve */
762 compute_equal_power_fades (xfade, in, out);
764 for (nframes_t n = 0; n < xfade; ++n) {
765 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
770 /* long xfade length, has to be computed across several calls */
775 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
776 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
781 if (fade_in && nofade) {
782 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
783 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
792 SndFileSource::last_capture_start_frame () const
795 return capture_start_frame;
802 SndFileSource::handle_header_position_change ()
805 if ( _length != 0 ) {
806 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
807 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
808 } else if (writable()) {
809 timeline_position = header_position_offset;
810 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
816 SndFileSource::setup_standard_crossfades (nframes_t rate)
818 /* This static method is assumed to have been called by the Session
819 before any DFS's are created.
822 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
824 if (out_coefficient) {
825 delete [] out_coefficient;
828 if (in_coefficient) {
829 delete [] in_coefficient;
832 out_coefficient = new gain_t[xfade_frames];
833 in_coefficient = new gain_t[xfade_frames];
835 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
839 SndFileSource::set_timeline_position (int64_t pos)
841 // destructive track timeline postion does not change
842 // except at instantion or when header_position_offset
843 // (session start) changes
845 if (!destructive()) {
846 AudioFileSource::set_timeline_position (pos);
851 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
855 SF_BROADCAST_INFO binfo;
856 bool timecode_exists;
858 sf_info.format = 0; // libsndfile says to clear this before sf_open().
860 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
862 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
866 info.samplerate = sf_info.samplerate;
867 info.channels = sf_info.channels;
868 info.length = sf_info.frames;
869 info.format_name = string_compose("Format: %1, %2",
870 sndfile_major_format(sf_info.format),
871 sndfile_minor_format(sf_info.format));
873 memset (&binfo, 0, sizeof (binfo));
874 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
876 if (!timecode_exists) {
886 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
888 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
890 return (header_position_offset);
893 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
894 of the time reference.
898 int64_t ret = (uint32_t) binfo->time_reference_high;
900 ret |= (uint32_t) binfo->time_reference_low;
905 SndFileSource::one_of_several_channels () const
907 return _info.channels > 1;
911 SndFileSource::get_interleave_buffer (nframes_t size)
913 SizedSampleBuffer* ssb;
915 if ((ssb = thread_interleave_buffer.get()) == 0) {
916 ssb = new SizedSampleBuffer (size);
917 thread_interleave_buffer.set (ssb);
920 if (ssb->size < size) {
921 ssb = new SizedSampleBuffer (size);
922 thread_interleave_buffer.set (ssb);