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);
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;
182 SndFileSource::init ()
186 // lets try to keep the object initalizations here at the top
194 _name = Glib::path_get_basename (_path);
197 /* although libsndfile says we don't need to set this,
198 valgrind and source code shows us that we do.
201 memset (&_info, 0, sizeof(_info));
203 _capture_start = false;
204 _capture_end = false;
208 xfade_buf = new Sample[xfade_frames];
209 timeline_position = header_position_offset;
212 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
216 SndFileSource::open ()
218 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
220 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
221 #ifndef HAVE_COREAUDIO
222 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
223 so we don't want to see this message.
226 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
227 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
232 if (_channel >= _info.channels) {
233 #ifndef HAVE_COREAUDIO
234 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
241 _length = _info.frames;
243 _broadcast_info = new SF_BROADCAST_INFO;
244 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
246 bool timecode_info_exists;
248 set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
250 if (_length != 0 && !timecode_info_exists) {
251 delete _broadcast_info;
253 _flags = Flag (_flags & ~Broadcast);
257 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
263 SndFileSource::~SndFileSource ()
265 GoingAway (); /* EMIT SIGNAL */
271 /* stupid libsndfile updated the headers on close,
272 so touch the peakfile if it exists and has data
273 to make sure its time is as new as the audio
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 */
322 if (file_cnt != cnt) {
323 nframes_t delta = cnt - file_cnt;
324 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
329 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
331 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
332 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
336 if (_info.channels == 1) {
337 nframes_t ret = sf_read_float (sf, dst, file_cnt);
338 _read_data_count = cnt * sizeof(float);
343 real_cnt = cnt * _info.channels;
345 Sample* interleave_buf = get_interleave_buffer (real_cnt);
347 nread = sf_read_float (sf, interleave_buf, real_cnt);
348 ptr = interleave_buf + _channel;
349 nread /= _info.channels;
351 /* stride through the interleaved data */
353 for (int32_t n = 0; n < nread; ++n) {
355 ptr += _info.channels;
358 _read_data_count = cnt * sizeof(float);
364 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
367 return destructive_write_unlocked (data, cnt);
369 return nondestructive_write_unlocked (data, cnt);
374 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
377 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
381 if (_info.channels != 1) {
382 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
388 int32_t frame_pos = _length;
390 if (write_float (data, frame_pos, cnt) != cnt) {
395 update_length (oldlen, cnt);
397 if (_build_peakfiles) {
398 compute_and_write_peaks (data, frame_pos, cnt, false, true);
401 _write_data_count = cnt;
407 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
409 nframes_t old_file_pos;
412 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
416 if (_capture_start && _capture_end) {
418 /* start and end of capture both occur within the data we are writing,
419 so do both crossfades.
422 _capture_start = false;
423 _capture_end = false;
425 /* move to the correct location place */
426 file_pos = capture_start_frame - timeline_position;
429 nframes_t subcnt = cnt / 2;
430 nframes_t ofilepos = file_pos;
433 if (crossfade (data, subcnt, 1) != subcnt) {
438 Sample * tmpdata = data + subcnt;
441 subcnt = cnt - subcnt;
442 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
446 file_pos = ofilepos; // adjusted below
448 } else if (_capture_start) {
450 /* start of capture both occur within the data we are writing,
454 _capture_start = false;
455 _capture_end = false;
457 /* move to the correct location place */
458 file_pos = capture_start_frame - timeline_position;
460 if (crossfade (data, cnt, 1) != cnt) {
464 } else if (_capture_end) {
466 /* end of capture both occur within the data we are writing,
470 _capture_start = false;
471 _capture_end = false;
473 if (crossfade (data, cnt, 0) != cnt) {
479 /* in the middle of recording */
481 if (write_float (data, file_pos, cnt) != cnt) {
486 old_file_pos = file_pos;
487 update_length (file_pos, cnt);
489 if (_build_peakfiles) {
490 compute_and_write_peaks (data, file_pos, cnt, false, true);
499 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
501 set_timeline_position (when);
503 if (_flags & Broadcast) {
504 if (setup_broadcast_info (when, now, tnow)) {
509 return flush_header ();
513 SndFileSource::flush_header ()
515 if (!writable() || (sf == 0)) {
516 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
519 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
523 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
526 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
530 if (!(_flags & Broadcast)) {
534 /* random code is 9 digits */
536 int random_code = random() % 999999999;
538 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
539 Config->get_bwf_country_code().c_str(),
540 Config->get_bwf_organization_code().c_str(),
547 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
552 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
557 /* now update header position taking header offset into account */
559 set_header_timeline_position ();
561 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
562 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
563 _flags = Flag (_flags & ~Broadcast);
564 delete _broadcast_info;
573 SndFileSource::set_header_timeline_position ()
575 if (!(_flags & Broadcast)) {
579 _broadcast_info->time_reference_high = (timeline_position >> 32);
580 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
582 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
583 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
584 _flags = Flag (_flags & ~Broadcast);
585 delete _broadcast_info;
591 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
593 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
595 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
596 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
600 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
608 SndFileSource::natural_position() const
610 return timeline_position;
614 SndFileSource::set_destructive (bool yn)
617 _flags = Flag (_flags | Destructive);
619 xfade_buf = new Sample[xfade_frames];
621 clear_capture_marks ();
622 timeline_position = header_position_offset;
624 _flags = Flag (_flags & ~Destructive);
625 timeline_position = 0;
626 /* leave xfade buf alone in case we need it again later */
633 SndFileSource::clear_capture_marks ()
635 _capture_start = false;
636 _capture_end = false;
640 SndFileSource::mark_capture_start (nframes_t pos)
643 if (pos < timeline_position) {
644 _capture_start = false;
646 _capture_start = true;
647 capture_start_frame = pos;
653 SndFileSource::mark_capture_end()
661 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
663 nframes_t xfade = min (xfade_frames, cnt);
664 nframes_t nofade = cnt - xfade;
665 Sample* fade_data = 0;
666 nframes_t fade_position = 0; // in frames
671 fade_position = file_pos;
674 fade_position = file_pos + nofade;
675 fade_data = data + nofade;
678 if (fade_position > _length) {
680 /* read starts beyond end of data, just memset to zero */
684 } else if (fade_position + xfade > _length) {
686 /* read ends beyond end of data, read some, memset the rest */
688 file_cnt = _length - fade_position;
692 /* read is entirely within data */
699 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
700 if (retval >= 0 && errno == EAGAIN) {
701 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
702 * short or no data there */
703 memset (xfade_buf, 0, xfade * sizeof(Sample));
705 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
711 if (file_cnt != xfade) {
712 nframes_t delta = xfade - file_cnt;
713 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
716 if (nofade && !fade_in) {
717 if (write_float (data, file_pos, nofade) != nofade) {
718 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
723 if (xfade == xfade_frames) {
727 /* use the standard xfade curve */
731 /* fade new material in */
733 for (n = 0; n < xfade; ++n) {
734 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
740 /* fade new material out */
742 for (n = 0; n < xfade; ++n) {
743 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
747 } else if (xfade < xfade_frames) {
752 /* short xfade, compute custom curve */
754 compute_equal_power_fades (xfade, in, out);
756 for (nframes_t n = 0; n < xfade; ++n) {
757 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
762 /* long xfade length, has to be computed across several calls */
767 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
768 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
773 if (fade_in && nofade) {
774 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
775 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
784 SndFileSource::last_capture_start_frame () const
787 return capture_start_frame;
794 SndFileSource::handle_header_position_change ()
797 if ( _length != 0 ) {
798 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
799 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
800 } else if (writable()) {
801 timeline_position = header_position_offset;
802 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
808 SndFileSource::setup_standard_crossfades (nframes_t rate)
810 /* This static method is assumed to have been called by the Session
811 before any DFS's are created.
814 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
816 if (out_coefficient) {
817 delete [] out_coefficient;
820 if (in_coefficient) {
821 delete [] in_coefficient;
824 out_coefficient = new gain_t[xfade_frames];
825 in_coefficient = new gain_t[xfade_frames];
827 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
831 SndFileSource::set_timeline_position (int64_t pos)
833 // destructive track timeline postion does not change
834 // except at instantion or when header_position_offset
835 // (session start) changes
837 if (!destructive()) {
838 AudioFileSource::set_timeline_position (pos);
843 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
847 SF_BROADCAST_INFO binfo;
848 bool timecode_exists;
850 sf_info.format = 0; // libsndfile says to clear this before sf_open().
852 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
854 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
858 info.samplerate = sf_info.samplerate;
859 info.channels = sf_info.channels;
860 info.length = sf_info.frames;
861 info.format_name = string_compose("%1\n%2",
862 sndfile_major_format(sf_info.format),
863 sndfile_minor_format(sf_info.format));
865 memset (&binfo, 0, sizeof (binfo));
866 info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
868 if (!timecode_exists) {
878 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
880 if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
882 return (header_position_offset);
885 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
886 of the time reference.
890 int64_t ret = (uint32_t) binfo->time_reference_high;
892 ret |= (uint32_t) binfo->time_reference_low;
897 SndFileSource::one_of_several_channels () const
899 return _info.channels > 1;