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>
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)
54 throw failed_constructor ();
58 SndFileSource::SndFileSource (Session& s, string idstr, Flag flags)
59 /* files created this way are never writable or removable */
60 : AudioFileSource (s, idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
65 throw failed_constructor ();
69 SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
70 : AudioFileSource (s, idstr, flags, sfmt, hf)
76 /* this constructor is used to construct new files, not open
85 _flags = Flag (_flags & ~Broadcast);
90 _flags = Flag (_flags & ~Broadcast);
95 _flags = Flag (_flags | Broadcast);
100 _flags = Flag (_flags & ~Broadcast);
105 _flags = Flag (_flags & ~Broadcast);
109 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
117 fmt |= SF_FORMAT_FLOAT;
121 fmt |= SF_FORMAT_PCM_24;
126 _info.samplerate = rate;
130 throw failed_constructor();
133 if (writable() && (_flags & Broadcast)) {
135 _broadcast_info = new SF_BROADCAST_INFO;
136 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
138 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
140 struct utsname utsinfo;
142 if (uname (&utsinfo)) {
143 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
147 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
148 Glib::get_real_name().c_str(),
154 _broadcast_info->version = 1;
155 _broadcast_info->time_reference_low = 0;
156 _broadcast_info->time_reference_high = 0;
158 /* XXX do something about this field */
160 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
162 /* coding history is added by libsndfile */
164 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
166 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
167 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
168 _flags = Flag (_flags & ~Broadcast);
169 delete _broadcast_info;
177 SndFileSource::init (string idstr)
179 string::size_type pos;
182 // lets try to keep the object initalizations here at the top
185 interleave_bufsize = 0;
191 if ((pos = idstr.find_last_of (':')) == string::npos) {
195 channel = atoi (idstr.substr (pos+1).c_str());
196 tmp_name = idstr.substr (0, pos);
202 _name = Glib::path_get_basename (tmp_name);
205 /* although libsndfile says we don't need to set this,
206 valgrind and source code shows us that we do.
209 memset (&_info, 0, sizeof(_info));
211 _capture_start = false;
212 _capture_end = false;
216 xfade_buf = new Sample[xfade_frames];
217 timeline_position = header_position_offset;
220 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
224 SndFileSource::open ()
226 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
228 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
229 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
230 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
234 if (channel >= _info.channels) {
235 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 /* lookup broadcast info */
248 if (sf_command (sf, SFC_GET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
250 /* if the file has data but no broadcast info, then clearly, there is no broadcast info */
253 delete _broadcast_info;
255 _flags = Flag (_flags & ~Broadcast);
258 set_timeline_position (header_position_offset);
262 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
263 of the time reference.
266 set_timeline_position ( _broadcast_info->time_reference_low );
270 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
276 SndFileSource::~SndFileSource ()
278 GoingAway (); /* EMIT SIGNAL */
284 /* stupid libsndfile updated the headers on close,
285 so touch the peakfile if it exists and has data
286 to make sure its time is as new as the audio
293 if (interleave_buf) {
294 delete [] interleave_buf;
297 if (_broadcast_info) {
298 delete _broadcast_info;
307 SndFileSource::sample_rate () const
309 return _info.samplerate;
313 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
320 if (start > _length) {
322 /* read starts beyond end of data, just memset to zero */
326 } else if (start + cnt > _length) {
328 /* read ends beyond end of data, read some, memset the rest */
330 file_cnt = _length - start;
334 /* read is entirely within data */
341 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
343 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
344 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
348 if (_info.channels == 1) {
349 nframes_t ret = sf_read_float (sf, dst, file_cnt);
350 _read_data_count = cnt * sizeof(float);
355 if (file_cnt != cnt) {
356 nframes_t delta = cnt - file_cnt;
357 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
360 real_cnt = cnt * _info.channels;
362 if (interleave_bufsize < real_cnt) {
364 if (interleave_buf) {
365 delete [] interleave_buf;
367 interleave_bufsize = real_cnt;
368 interleave_buf = new float[interleave_bufsize];
371 nread = sf_read_float (sf, interleave_buf, real_cnt);
372 ptr = interleave_buf + channel;
373 nread /= _info.channels;
375 /* stride through the interleaved data */
377 for (int32_t n = 0; n < nread; ++n) {
379 ptr += _info.channels;
382 _read_data_count = cnt * sizeof(float);
388 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
391 return destructive_write_unlocked (data, cnt);
393 return nondestructive_write_unlocked (data, cnt);
398 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
404 if (_info.channels != 1) {
405 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
411 int32_t frame_pos = _length;
413 if (write_float (data, frame_pos, cnt) != cnt) {
418 update_length (oldlen, cnt);
420 if (_build_peakfiles) {
421 PeakBuildRecord *pbr = 0;
423 if (pending_peak_builds.size()) {
424 pbr = pending_peak_builds.back();
427 if (pbr && pbr->frame + pbr->cnt == oldlen) {
429 /* the last PBR extended to the start of the current write,
430 so just extend it again.
435 pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
438 _peaks_built = false;
442 if (_build_peakfiles) {
443 queue_for_peaks (shared_from_this ());
446 _write_data_count = cnt;
452 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
454 nframes_t old_file_pos;
460 if (_capture_start && _capture_end) {
462 /* start and end of capture both occur within the data we are writing,
463 so do both crossfades.
466 _capture_start = false;
467 _capture_end = false;
469 /* move to the correct location place */
470 file_pos = capture_start_frame - timeline_position;
473 nframes_t subcnt = cnt / 2;
474 nframes_t ofilepos = file_pos;
477 if (crossfade (data, subcnt, 1) != subcnt) {
482 Sample * tmpdata = data + subcnt;
485 subcnt = cnt - subcnt;
486 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
490 file_pos = ofilepos; // adjusted below
492 } else if (_capture_start) {
494 /* start of capture both occur within the data we are writing,
498 _capture_start = false;
499 _capture_end = false;
501 /* move to the correct location place */
502 file_pos = capture_start_frame - timeline_position;
504 if (crossfade (data, cnt, 1) != cnt) {
508 } else if (_capture_end) {
510 /* end of capture both occur within the data we are writing,
514 _capture_start = false;
515 _capture_end = false;
517 if (crossfade (data, cnt, 0) != cnt) {
523 /* in the middle of recording */
525 if (write_float (data, file_pos, cnt) != cnt) {
530 old_file_pos = file_pos;
531 update_length (file_pos, cnt);
534 if (_build_peakfiles) {
535 PeakBuildRecord *pbr = 0;
537 if (pending_peak_builds.size()) {
538 pbr = pending_peak_builds.back();
541 if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
543 /* the last PBR extended to the start of the current write,
544 so just extend it again.
549 pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
552 _peaks_built = false;
555 if (_build_peakfiles) {
556 queue_for_peaks (shared_from_this ());
563 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
565 set_timeline_position (when);
567 if (_flags & Broadcast) {
568 if (setup_broadcast_info (when, now, tnow)) {
573 return flush_header ();
577 SndFileSource::flush_header ()
579 if (!writable() || (sf == 0)) {
582 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
586 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
592 if (!(_flags & Broadcast)) {
596 /* random code is 9 digits */
598 int random_code = random() % 999999999;
600 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
601 Config->get_bwf_country_code().c_str(),
602 Config->get_bwf_organization_code().c_str(),
609 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
614 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
619 /* now update header position taking header offset into account */
621 set_header_timeline_position ();
623 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
624 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
625 _flags = Flag (_flags & ~Broadcast);
626 delete _broadcast_info;
635 SndFileSource::set_header_timeline_position ()
637 if (!(_flags & Broadcast)) {
641 _broadcast_info->time_reference_high = (timeline_position >> 32);
642 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
644 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
645 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
646 _flags = Flag (_flags & ~Broadcast);
647 delete _broadcast_info;
656 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
658 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
660 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
661 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
665 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
673 SndFileSource::natural_position() const
675 return timeline_position;
679 SndFileSource::set_destructive (bool yn)
682 _flags = Flag (_flags | Destructive);
683 clear_capture_marks ();
684 timeline_position = header_position_offset;
686 _flags = Flag (_flags & ~Destructive);
687 timeline_position = 0;
694 SndFileSource::clear_capture_marks ()
696 _capture_start = false;
697 _capture_end = false;
701 SndFileSource::mark_capture_start (nframes_t pos)
704 if (pos < timeline_position) {
705 _capture_start = false;
707 _capture_start = true;
708 capture_start_frame = pos;
714 SndFileSource::mark_capture_end()
722 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
724 nframes_t xfade = min (xfade_frames, cnt);
725 nframes_t nofade = cnt - xfade;
726 Sample* fade_data = 0;
727 nframes_t fade_position = 0; // in frames
732 fade_position = file_pos;
735 fade_position = file_pos + nofade;
736 fade_data = data + nofade;
739 if (fade_position > _length) {
741 /* read starts beyond end of data, just memset to zero */
745 } else if (fade_position + xfade > _length) {
747 /* read ends beyond end of data, read some, memset the rest */
749 file_cnt = _length - fade_position;
753 /* read is entirely within data */
760 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
761 if (retval >= 0 && errno == EAGAIN) {
762 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
763 * short or no data there */
764 memset (xfade_buf, 0, xfade * sizeof(Sample));
766 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
772 if (file_cnt != xfade) {
773 nframes_t delta = xfade - file_cnt;
774 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
777 if (nofade && !fade_in) {
778 if (write_float (data, file_pos, nofade) != nofade) {
779 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
784 if (xfade == xfade_frames) {
788 /* use the standard xfade curve */
792 /* fade new material in */
794 for (n = 0; n < xfade; ++n) {
795 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
801 /* fade new material out */
803 for (n = 0; n < xfade; ++n) {
804 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
808 } else if (xfade < xfade_frames) {
813 /* short xfade, compute custom curve */
815 compute_equal_power_fades (xfade, in, out);
817 for (nframes_t n = 0; n < xfade; ++n) {
818 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
823 /* long xfade length, has to be computed across several calls */
828 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
829 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
834 if (fade_in && nofade) {
835 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
836 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
845 SndFileSource::last_capture_start_frame () const
848 return capture_start_frame;
855 SndFileSource::handle_header_position_change ()
858 if ( _length != 0 ) {
859 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
860 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
861 } else if (writable()) {
862 timeline_position = header_position_offset;
863 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
869 SndFileSource::setup_standard_crossfades (nframes_t rate)
871 /* This static method is assumed to have been called by the Session
872 before any DFS's are created.
875 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
877 if (out_coefficient) {
878 delete [] out_coefficient;
881 if (in_coefficient) {
882 delete [] in_coefficient;
885 out_coefficient = new gain_t[xfade_frames];
886 in_coefficient = new gain_t[xfade_frames];
888 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
892 SndFileSource::set_timeline_position (nframes_t pos)
894 // destructive track timeline postion does not change
895 // except at instantion or when header_position_offset
896 // (session start) changes
898 if (!destructive()) {
899 AudioFileSource::set_timeline_position (pos);