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.
26 #include <sys/utsname.h>
29 #include <glibmm/miscutils.h>
31 #include <ardour/sndfilesource.h>
32 #include <ardour/sndfile_helpers.h>
33 #include <ardour/utils.h>
34 #include <ardour/version.h>
39 using namespace ARDOUR;
43 gain_t* SndFileSource::out_coefficient = 0;
44 gain_t* SndFileSource::in_coefficient = 0;
45 nframes_t SndFileSource::xfade_frames = 64;
46 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
47 AudioFileSource::Removable|
48 AudioFileSource::RemovableIfEmpty|
49 AudioFileSource::CanRename);
51 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
52 : AudioFileSource (s, node)
57 throw failed_constructor ();
61 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
62 /* files created this way are never writable or removable */
63 : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
70 throw failed_constructor ();
74 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
75 : AudioFileSource (s, path, flags, sfmt, hf)
81 /* this constructor is used to construct new files, not open
90 _flags = Flag (_flags & ~Broadcast);
95 _flags = Flag (_flags & ~Broadcast);
100 _flags = Flag (_flags | Broadcast);
105 _flags = Flag (_flags & ~Broadcast);
110 _flags = Flag (_flags & ~Broadcast);
114 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
122 fmt |= SF_FORMAT_FLOAT;
126 fmt |= SF_FORMAT_PCM_24;
130 fmt |= SF_FORMAT_PCM_16;
135 _info.samplerate = rate;
139 throw failed_constructor();
142 if (writable() && (_flags & Broadcast)) {
144 if (!_broadcast_info) {
145 _broadcast_info = new BroadcastInfo;
148 _broadcast_info->set_from_session (s, header_position_offset);
149 _broadcast_info->set_description (string_compose ("BWF %1", _name));
151 if (!_broadcast_info->write_to_file (sf)) {
152 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
153 _path, _broadcast_info->get_error())
155 _flags = Flag (_flags & ~Broadcast);
156 delete _broadcast_info;
163 SndFileSource::init ()
167 // lets try to keep the object initalizations here at the top
175 _name = Glib::path_get_basename (_path);
178 /* although libsndfile says we don't need to set this,
179 valgrind and source code shows us that we do.
182 memset (&_info, 0, sizeof(_info));
184 _capture_start = false;
185 _capture_end = false;
189 xfade_buf = new Sample[xfade_frames];
190 timeline_position = header_position_offset;
193 AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
197 SndFileSource::open ()
199 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
201 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
202 #ifndef HAVE_COREAUDIO
203 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
204 so we don't want to see this message.
207 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
208 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
213 if (_channel >= _info.channels) {
214 #ifndef HAVE_COREAUDIO
215 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
222 _length = _info.frames;
224 if (!_broadcast_info) {
225 _broadcast_info = new BroadcastInfo;
228 bool bwf_info_exists = _broadcast_info->load_from_file (sf);
230 set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
232 if (_length != 0 && !bwf_info_exists) {
233 delete _broadcast_info;
235 _flags = Flag (_flags & ~Broadcast);
239 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
245 SndFileSource::~SndFileSource ()
247 GoingAway (); /* EMIT SIGNAL */
253 /* stupid libsndfile updated the headers on close,
254 so touch the peakfile if it exists and has data
255 to make sure its time is as new as the audio
262 if (_broadcast_info) {
263 delete _broadcast_info;
272 SndFileSource::sample_rate () const
274 return _info.samplerate;
278 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
285 if (start > _length) {
287 /* read starts beyond end of data, just memset to zero */
291 } else if (start + cnt > _length) {
293 /* read ends beyond end of data, read some, memset the rest */
295 file_cnt = _length - start;
299 /* read is entirely within data */
304 if (file_cnt != cnt) {
305 nframes_t delta = cnt - file_cnt;
306 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
311 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
313 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
314 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
318 if (_info.channels == 1) {
319 nframes_t ret = sf_read_float (sf, dst, file_cnt);
320 _read_data_count = ret * sizeof(float);
321 if (ret != file_cnt) {
323 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
324 cerr << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.substr (1), errbuf, _length) << endl;
330 real_cnt = cnt * _info.channels;
332 Sample* interleave_buf = get_interleave_buffer (real_cnt);
334 nread = sf_read_float (sf, interleave_buf, real_cnt);
335 ptr = interleave_buf + _channel;
336 nread /= _info.channels;
338 /* stride through the interleaved data */
340 for (int32_t n = 0; n < nread; ++n) {
342 ptr += _info.channels;
345 _read_data_count = cnt * sizeof(float);
351 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
354 return destructive_write_unlocked (data, cnt);
356 return nondestructive_write_unlocked (data, cnt);
361 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
364 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
368 if (_info.channels != 1) {
369 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
375 int32_t frame_pos = _length;
377 if (write_float (data, frame_pos, cnt) != cnt) {
382 update_length (oldlen, cnt);
384 if (_build_peakfiles) {
385 compute_and_write_peaks (data, frame_pos, cnt, false, true);
388 _write_data_count = cnt;
394 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
396 nframes_t old_file_pos;
399 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
403 if (_capture_start && _capture_end) {
405 /* start and end of capture both occur within the data we are writing,
406 so do both crossfades.
409 _capture_start = false;
410 _capture_end = false;
412 /* move to the correct location place */
413 file_pos = capture_start_frame - timeline_position;
416 nframes_t subcnt = cnt / 2;
417 nframes_t ofilepos = file_pos;
420 if (crossfade (data, subcnt, 1) != subcnt) {
425 Sample * tmpdata = data + subcnt;
428 subcnt = cnt - subcnt;
429 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
433 file_pos = ofilepos; // adjusted below
435 } else if (_capture_start) {
437 /* start of capture both occur within the data we are writing,
441 _capture_start = false;
442 _capture_end = false;
444 /* move to the correct location place */
445 file_pos = capture_start_frame - timeline_position;
447 if (crossfade (data, cnt, 1) != cnt) {
451 } else if (_capture_end) {
453 /* end of capture both occur within the data we are writing,
457 _capture_start = false;
458 _capture_end = false;
460 if (crossfade (data, cnt, 0) != cnt) {
466 /* in the middle of recording */
468 if (write_float (data, file_pos, cnt) != cnt) {
473 old_file_pos = file_pos;
474 update_length (file_pos, cnt);
476 if (_build_peakfiles) {
477 compute_and_write_peaks (data, file_pos, cnt, false, true);
486 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
488 set_timeline_position (when);
490 if (_flags & Broadcast) {
491 if (setup_broadcast_info (when, now, tnow)) {
496 return flush_header ();
500 SndFileSource::flush_header ()
502 if (!writable() || (sf == 0)) {
503 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
506 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
510 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
513 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
517 if (!(_flags & Broadcast)) {
521 _broadcast_info->set_originator_ref ();
522 _broadcast_info->set_origination_time (&now);
524 /* now update header position taking header offset into account */
526 set_header_timeline_position ();
528 if (!_broadcast_info->write_to_file (sf)) {
529 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
530 _path, _broadcast_info->get_error())
532 _flags = Flag (_flags & ~Broadcast);
533 delete _broadcast_info;
541 SndFileSource::set_header_timeline_position ()
543 if (!(_flags & Broadcast)) {
547 _broadcast_info->set_time_reference (timeline_position);
549 if (!_broadcast_info->write_to_file (sf)) {
550 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
551 _path, _broadcast_info->get_error())
553 _flags = Flag (_flags & ~Broadcast);
554 delete _broadcast_info;
560 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
562 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
564 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
565 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
569 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
577 SndFileSource::natural_position() const
579 return timeline_position;
583 SndFileSource::set_destructive (bool yn)
586 _flags = Flag (_flags | Destructive);
588 xfade_buf = new Sample[xfade_frames];
590 clear_capture_marks ();
591 timeline_position = header_position_offset;
593 _flags = Flag (_flags & ~Destructive);
594 timeline_position = 0;
595 /* leave xfade buf alone in case we need it again later */
602 SndFileSource::clear_capture_marks ()
604 _capture_start = false;
605 _capture_end = false;
609 SndFileSource::mark_capture_start (nframes_t pos)
612 if (pos < timeline_position) {
613 _capture_start = false;
615 _capture_start = true;
616 capture_start_frame = pos;
622 SndFileSource::mark_capture_end()
630 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
632 nframes_t xfade = min (xfade_frames, cnt);
633 nframes_t nofade = cnt - xfade;
634 Sample* fade_data = 0;
635 nframes_t fade_position = 0; // in frames
640 fade_position = file_pos;
643 fade_position = file_pos + nofade;
644 fade_data = data + nofade;
647 if (fade_position > _length) {
649 /* read starts beyond end of data, just memset to zero */
653 } else if (fade_position + xfade > _length) {
655 /* read ends beyond end of data, read some, memset the rest */
657 file_cnt = _length - fade_position;
661 /* read is entirely within data */
668 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
669 if (retval >= 0 && errno == EAGAIN) {
670 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
671 * short or no data there */
672 memset (xfade_buf, 0, xfade * sizeof(Sample));
674 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
680 if (file_cnt != xfade) {
681 nframes_t delta = xfade - file_cnt;
682 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
685 if (nofade && !fade_in) {
686 if (write_float (data, file_pos, nofade) != nofade) {
687 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
692 if (xfade == xfade_frames) {
696 /* use the standard xfade curve */
700 /* fade new material in */
702 for (n = 0; n < xfade; ++n) {
703 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
709 /* fade new material out */
711 for (n = 0; n < xfade; ++n) {
712 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
716 } else if (xfade < xfade_frames) {
721 /* short xfade, compute custom curve */
723 compute_equal_power_fades (xfade, in, out);
725 for (nframes_t n = 0; n < xfade; ++n) {
726 xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
731 /* long xfade length, has to be computed across several calls */
736 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
737 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
742 if (fade_in && nofade) {
743 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
744 error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
753 SndFileSource::last_capture_start_frame () const
756 return capture_start_frame;
763 SndFileSource::handle_header_position_change ()
766 if ( _length != 0 ) {
767 error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
768 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
769 } else if (writable()) {
770 timeline_position = header_position_offset;
771 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
777 SndFileSource::setup_standard_crossfades (nframes_t rate)
779 /* This static method is assumed to have been called by the Session
780 before any DFS's are created.
783 xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
785 if (out_coefficient) {
786 delete [] out_coefficient;
789 if (in_coefficient) {
790 delete [] in_coefficient;
793 out_coefficient = new gain_t[xfade_frames];
794 in_coefficient = new gain_t[xfade_frames];
796 compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
800 SndFileSource::set_timeline_position (int64_t pos)
802 // destructive track timeline postion does not change
803 // except at instantion or when header_position_offset
804 // (session start) changes
806 if (!destructive()) {
807 AudioFileSource::set_timeline_position (pos);
812 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
818 sf_info.format = 0; // libsndfile says to clear this before sf_open().
820 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
822 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
826 info.samplerate = sf_info.samplerate;
827 info.channels = sf_info.channels;
828 info.length = sf_info.frames;
829 info.format_name = string_compose("Format: %1, %2",
830 sndfile_major_format(sf_info.format),
831 sndfile_minor_format(sf_info.format));
833 info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
841 SndFileSource::one_of_several_channels () const
843 return _info.channels > 1;