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.
21 #include "libardour-config.h"
30 #include <sys/utsname.h>
33 #include <glibmm/miscutils.h>
35 #include "ardour/sndfilesource.h"
36 #include "ardour/sndfile_helpers.h"
37 #include "ardour/utils.h"
38 #include "ardour/version.h"
39 #include "ardour/rc_configuration.h"
40 #include "ardour/session.h"
45 using namespace ARDOUR
;
49 gain_t
* SndFileSource::out_coefficient
= 0;
50 gain_t
* SndFileSource::in_coefficient
= 0;
51 framecnt_t
SndFileSource::xfade_frames
= 64;
52 const Source::Flag
SndFileSource::default_writable_flags
= Source::Flag (
55 Source::RemovableIfEmpty
|
58 SndFileSource::SndFileSource (Session
& s
, const XMLNode
& node
)
60 , AudioFileSource (s
, node
)
65 throw failed_constructor ();
69 /** Files created this way are never writable or removable */
70 SndFileSource::SndFileSource (Session
& s
, const string
& path
, int chn
, Flag flags
)
71 : Source(s
, DataType::AUDIO
, path
, flags
)
72 /* note that the origin of an external file is itself */
73 , AudioFileSource (s
, path
, Flag (flags
& ~(Writable
|Removable
|RemovableIfEmpty
|RemoveAtDestroy
)))
80 throw failed_constructor ();
84 /** This constructor is used to construct new files, not open existing ones. */
85 SndFileSource::SndFileSource (Session
& s
, const string
& path
, const string
& origin
,
86 SampleFormat sfmt
, HeaderFormat hf
, framecnt_t rate
, Flag flags
)
87 : Source(s
, DataType::AUDIO
, path
, flags
)
88 , AudioFileSource (s
, path
, origin
, flags
, sfmt
, hf
)
99 _flags
= Flag (_flags
& ~Broadcast
);
103 fmt
= SF_FORMAT_AIFF
;
104 _flags
= Flag (_flags
& ~Broadcast
);
109 _flags
= Flag (_flags
| Broadcast
);
114 _flags
= Flag (_flags
& ~Broadcast
);
119 _flags
= Flag (_flags
& ~Broadcast
);
123 fatal
<< string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg
;
131 fmt
|= SF_FORMAT_FLOAT
;
135 fmt
|= SF_FORMAT_PCM_24
;
139 fmt
|= SF_FORMAT_PCM_16
;
144 _info
.samplerate
= rate
;
147 /* do not open the file here - do that in write_unlocked() as needed
152 SndFileSource::init_sndfile ()
158 // lets try to keep the object initalizations here at the top
162 /* although libsndfile says we don't need to set this,
163 valgrind and source code shows us that we do.
166 memset (&_info
, 0, sizeof(_info
));
168 _capture_start
= false;
169 _capture_end
= false;
173 xfade_buf
= new Sample
[xfade_frames
];
174 _timeline_position
= header_position_offset
;
177 AudioFileSource::HeaderPositionOffsetChanged
.connect_same_thread (header_position_connection
, boost::bind (&SndFileSource::handle_header_position_change
, this));
181 SndFileSource::open ()
183 _descriptor
= new SndFileDescriptor (_path
, writable(), &_info
);
184 _descriptor
->Closed
.connect_same_thread (file_manager_connection
, boost::bind (&SndFileSource::file_closed
, this));
185 SNDFILE
* sf
= _descriptor
->allocate ();
189 sf_error_str (0, errbuf
, sizeof (errbuf
) - 1);
190 #ifndef HAVE_COREAUDIO
191 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
192 so we don't want to see this message.
195 cerr
<< "failed to open " << _path
<< " with name " << _name
<< endl
;
197 error
<< string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
198 _path
, (writable() ? "read+write" : "reading"), errbuf
) << endmsg
;
203 if (_channel
>= _info
.channels
) {
204 #ifndef HAVE_COREAUDIO
205 error
<< string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info
.channels
, _channel
) << endmsg
;
212 _length
= _info
.frames
;
214 if (!_broadcast_info
) {
215 _broadcast_info
= new BroadcastInfo
;
218 bool bwf_info_exists
= _broadcast_info
->load_from_file (sf
);
220 set_timeline_position (bwf_info_exists
? _broadcast_info
->get_time_reference() : header_position_offset
);
222 if (_length
!= 0 && !bwf_info_exists
) {
223 delete _broadcast_info
;
225 _flags
= Flag (_flags
& ~Broadcast
);
229 sf_command (sf
, SFC_SET_UPDATE_HEADER_AUTO
, 0, SF_FALSE
);
231 if (_flags
& Broadcast
) {
233 if (!_broadcast_info
) {
234 _broadcast_info
= new BroadcastInfo
;
237 _broadcast_info
->set_from_session (_session
, header_position_offset
);
238 _broadcast_info
->set_description (string_compose ("BWF %1", _name
));
240 if (!_broadcast_info
->write_to_file (sf
)) {
241 error
<< string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
242 _path
, _broadcast_info
->get_error())
244 _flags
= Flag (_flags
& ~Broadcast
);
245 delete _broadcast_info
;
251 _descriptor
->release ();
256 SndFileSource::~SndFileSource ()
259 delete _broadcast_info
;
264 SndFileSource::sample_rate () const
266 return _info
.samplerate
;
270 SndFileSource::read_unlocked (Sample
*dst
, framepos_t start
, framecnt_t cnt
) const
277 if (writable() && !_open
) {
278 /* file has not been opened yet - nothing written to it */
279 memset (dst
, 0, sizeof (Sample
) * cnt
);
283 SNDFILE
* sf
= _descriptor
->allocate ();
286 error
<< string_compose (_("could not allocate file %1 for reading."), _path
) << endmsg
;
290 if (start
> _length
) {
292 /* read starts beyond end of data, just memset to zero */
296 } else if (start
+ cnt
> _length
) {
298 /* read ends beyond end of data, read some, memset the rest */
300 file_cnt
= _length
- start
;
304 /* read is entirely within data */
309 if (file_cnt
!= cnt
) {
310 framepos_t delta
= cnt
- file_cnt
;
311 memset (dst
+file_cnt
, 0, sizeof (Sample
) * delta
);
316 if (sf_seek (sf
, (sf_count_t
) start
, SEEK_SET
|SFM_READ
) != (sf_count_t
) start
) {
318 sf_error_str (0, errbuf
, sizeof (errbuf
) - 1);
319 error
<< string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start
, _name
.val().substr (1), errbuf
) << endmsg
;
320 _descriptor
->release ();
324 if (_info
.channels
== 1) {
325 framecnt_t ret
= sf_read_float (sf
, dst
, file_cnt
);
326 _read_data_count
= ret
* sizeof(float);
327 if (ret
!= file_cnt
) {
329 sf_error_str (0, errbuf
, sizeof (errbuf
) - 1);
330 error
<< string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start
, file_cnt
, _name
.val().substr (1), errbuf
, _length
) << endl
;
332 _descriptor
->release ();
337 real_cnt
= cnt
* _info
.channels
;
339 Sample
* interleave_buf
= get_interleave_buffer (real_cnt
);
341 nread
= sf_read_float (sf
, interleave_buf
, real_cnt
);
342 ptr
= interleave_buf
+ _channel
;
343 nread
/= _info
.channels
;
345 /* stride through the interleaved data */
347 for (int32_t n
= 0; n
< nread
; ++n
) {
349 ptr
+= _info
.channels
;
352 _read_data_count
= cnt
* sizeof(float);
354 _descriptor
->release ();
359 SndFileSource::write_unlocked (Sample
*data
, framecnt_t cnt
)
361 if (!_open
&& open()) {
366 return destructive_write_unlocked (data
, cnt
);
368 return nondestructive_write_unlocked (data
, cnt
);
373 SndFileSource::nondestructive_write_unlocked (Sample
*data
, framecnt_t cnt
)
376 warning
<< string_compose (_("attempt to write a non-writable audio file source (%1)"), _path
) << endmsg
;
380 if (_info
.channels
!= 1) {
381 fatal
<< string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path
) << endmsg
;
387 int32_t frame_pos
= _length
;
389 if (write_float (data
, frame_pos
, cnt
) != cnt
) {
394 update_length (oldlen
, cnt
);
396 if (_build_peakfiles
) {
397 compute_and_write_peaks (data
, frame_pos
, cnt
, false, true);
400 _write_data_count
= cnt
;
406 SndFileSource::destructive_write_unlocked (Sample
* data
, framecnt_t cnt
)
409 warning
<< string_compose (_("attempt to write a non-writable audio file source (%1)"), _path
) << endmsg
;
413 if (_capture_start
&& _capture_end
) {
415 /* start and end of capture both occur within the data we are writing,
416 so do both crossfades.
419 _capture_start
= false;
420 _capture_end
= false;
422 /* move to the correct location place */
423 file_pos
= capture_start_frame
- _timeline_position
;
426 framecnt_t subcnt
= cnt
/ 2;
427 framecnt_t ofilepos
= file_pos
;
430 if (crossfade (data
, subcnt
, 1) != subcnt
) {
435 Sample
* tmpdata
= data
+ subcnt
;
438 subcnt
= cnt
- subcnt
;
439 if (crossfade (tmpdata
, subcnt
, 0) != subcnt
) {
443 file_pos
= ofilepos
; // adjusted below
445 } else if (_capture_start
) {
447 /* start of capture both occur within the data we are writing,
451 _capture_start
= false;
452 _capture_end
= false;
454 /* move to the correct location place */
455 file_pos
= capture_start_frame
- _timeline_position
;
457 if (crossfade (data
, cnt
, 1) != cnt
) {
461 } else if (_capture_end
) {
463 /* end of capture both occur within the data we are writing,
467 _capture_start
= false;
468 _capture_end
= false;
470 if (crossfade (data
, cnt
, 0) != cnt
) {
476 /* in the middle of recording */
478 if (write_float (data
, file_pos
, cnt
) != cnt
) {
483 update_length (file_pos
, cnt
);
485 if (_build_peakfiles
) {
486 compute_and_write_peaks (data
, file_pos
, cnt
, false, true);
495 SndFileSource::update_header (framepos_t when
, struct tm
& now
, time_t tnow
)
497 set_timeline_position (when
);
499 if (_flags
& Broadcast
) {
500 if (setup_broadcast_info (when
, now
, tnow
)) {
505 return flush_header ();
509 SndFileSource::flush_header ()
512 warning
<< string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path
) << endmsg
;
517 warning
<< string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path
) << endmsg
;
521 SNDFILE
* sf
= _descriptor
->allocate ();
523 error
<< string_compose (_("could not allocate file %1 to write header"), _path
) << endmsg
;
527 int const r
= sf_command (sf
, SFC_UPDATE_HEADER_NOW
, 0, 0) != SF_TRUE
;
528 _descriptor
->release ();
534 SndFileSource::setup_broadcast_info (framepos_t
/*when*/, struct tm
& now
, time_t /*tnow*/)
537 warning
<< string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path
) << endmsg
;
542 warning
<< string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path
) << endmsg
;
546 if (!(_flags
& Broadcast
)) {
550 _broadcast_info
->set_originator_ref_from_session (_session
);
551 _broadcast_info
->set_origination_time (&now
);
553 /* now update header position taking header offset into account */
555 set_header_timeline_position ();
557 SNDFILE
* sf
= _descriptor
->allocate ();
559 if (sf
== 0 || !_broadcast_info
->write_to_file (sf
)) {
560 error
<< string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
561 _path
, _broadcast_info
->get_error())
563 _flags
= Flag (_flags
& ~Broadcast
);
564 delete _broadcast_info
;
568 _descriptor
->release ();
573 SndFileSource::set_header_timeline_position ()
575 if (!(_flags
& Broadcast
)) {
579 _broadcast_info
->set_time_reference (_timeline_position
);
581 SNDFILE
* sf
= _descriptor
->allocate ();
583 if (sf
== 0 || !_broadcast_info
->write_to_file (sf
)) {
584 error
<< string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
585 _path
, _broadcast_info
->get_error())
587 _flags
= Flag (_flags
& ~Broadcast
);
588 delete _broadcast_info
;
592 _descriptor
->release ();
596 SndFileSource::write_float (Sample
* data
, framepos_t frame_pos
, framecnt_t cnt
)
598 SNDFILE
* sf
= _descriptor
->allocate ();
600 if (sf
== 0 || sf_seek (sf
, frame_pos
, SEEK_SET
|SFM_WRITE
) < 0) {
602 sf_error_str (0, errbuf
, sizeof (errbuf
) - 1);
603 error
<< string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path
, frame_pos
, errbuf
) << endmsg
;
604 _descriptor
->release ();
608 if (sf_writef_float (sf
, data
, cnt
) != (ssize_t
) cnt
) {
609 _descriptor
->release ();
613 _descriptor
->release ();
618 SndFileSource::natural_position() const
620 return _timeline_position
;
624 SndFileSource::set_destructive (bool yn
)
627 _flags
= Flag (_flags
| Writable
| Destructive
);
629 xfade_buf
= new Sample
[xfade_frames
];
631 clear_capture_marks ();
632 _timeline_position
= header_position_offset
;
634 _flags
= Flag (_flags
& ~Destructive
);
635 _timeline_position
= 0;
636 /* leave xfade buf alone in case we need it again later */
643 SndFileSource::clear_capture_marks ()
645 _capture_start
= false;
646 _capture_end
= false;
649 /** @param pos Capture start position in session frames */
651 SndFileSource::mark_capture_start (framepos_t pos
)
654 if (pos
< _timeline_position
) {
655 _capture_start
= false;
657 _capture_start
= true;
658 capture_start_frame
= pos
;
664 SndFileSource::mark_capture_end()
672 SndFileSource::crossfade (Sample
* data
, framecnt_t cnt
, int fade_in
)
674 framecnt_t xfade
= min (xfade_frames
, cnt
);
675 framecnt_t nofade
= cnt
- xfade
;
676 Sample
* fade_data
= 0;
677 framepos_t fade_position
= 0; // in frames
682 fade_position
= file_pos
;
685 fade_position
= file_pos
+ nofade
;
686 fade_data
= data
+ nofade
;
689 if (fade_position
> _length
) {
691 /* read starts beyond end of data, just memset to zero */
695 } else if (fade_position
+ xfade
> _length
) {
697 /* read ends beyond end of data, read some, memset the rest */
699 file_cnt
= _length
- fade_position
;
703 /* read is entirely within data */
710 if ((retval
= read_unlocked (xfade_buf
, fade_position
, file_cnt
)) != (ssize_t
) file_cnt
) {
711 if (retval
>= 0 && errno
== EAGAIN
) {
712 /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
713 * short or no data there */
714 memset (xfade_buf
, 0, xfade
* sizeof(Sample
));
716 error
<< string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path
, retval
, errno
, strerror (errno
), xfade
) << endmsg
;
722 if (file_cnt
!= xfade
) {
723 framecnt_t delta
= xfade
- file_cnt
;
724 memset (xfade_buf
+file_cnt
, 0, sizeof (Sample
) * delta
);
727 if (nofade
&& !fade_in
) {
728 if (write_float (data
, file_pos
, nofade
) != nofade
) {
729 error
<< string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path
, strerror (errno
)) << endmsg
;
734 if (xfade
== xfade_frames
) {
738 /* use the standard xfade curve */
742 /* fade new material in */
744 for (n
= 0; n
< xfade
; ++n
) {
745 xfade_buf
[n
] = (xfade_buf
[n
] * out_coefficient
[n
]) + (fade_data
[n
] * in_coefficient
[n
]);
751 /* fade new material out */
753 for (n
= 0; n
< xfade
; ++n
) {
754 xfade_buf
[n
] = (xfade_buf
[n
] * in_coefficient
[n
]) + (fade_data
[n
] * out_coefficient
[n
]);
758 } else if (xfade
< xfade_frames
) {
763 /* short xfade, compute custom curve */
765 compute_equal_power_fades (xfade
, in
, out
);
767 for (framecnt_t n
= 0; n
< xfade
; ++n
) {
768 xfade_buf
[n
] = (xfade_buf
[n
] * out
[n
]) + (fade_data
[n
] * in
[n
]);
773 /* long xfade length, has to be computed across several calls */
778 if (write_float (xfade_buf
, fade_position
, xfade
) != xfade
) {
779 error
<< string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path
, strerror (errno
)) << endmsg
;
784 if (fade_in
&& nofade
) {
785 if (write_float (data
+ xfade
, file_pos
+ xfade
, nofade
) != nofade
) {
786 error
<< string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path
, strerror (errno
)) << endmsg
;
795 SndFileSource::last_capture_start_frame () const
798 return capture_start_frame
;
805 SndFileSource::handle_header_position_change ()
808 if ( _length
!= 0 ) {
809 error
<< string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path
) << endmsg
;
810 //in the future, pop up a dialog here that allows user to regenerate file with new start offset
811 } else if (writable()) {
812 _timeline_position
= header_position_offset
;
813 set_header_timeline_position (); //this will get flushed if/when the file is recorded to
819 SndFileSource::setup_standard_crossfades (Session
const & s
, framecnt_t rate
)
821 /* This static method is assumed to have been called by the Session
822 before any DFS's are created.
825 xfade_frames
= (framecnt_t
) floor ((s
.config
.get_destructive_xfade_msecs () / 1000.0) * rate
);
827 delete [] out_coefficient
;
828 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 (framepos_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 string
& path
, SoundFileInfo
& info
, string
& error_msg
)
855 sf_info
.format
= 0; // libsndfile says to clear this before sf_open().
857 if ((sf
= sf_open ((char*) path
.c_str(), SFM_READ
, &sf_info
)) == 0) {
859 error_msg
= sf_error_str (0, errbuf
, sizeof (errbuf
) - 1);
863 info
.samplerate
= sf_info
.samplerate
;
864 info
.channels
= sf_info
.channels
;
865 info
.length
= sf_info
.frames
;
867 string major
= sndfile_major_format(sf_info
.format
);
868 string minor
= sndfile_minor_format(sf_info
.format
);
870 if (major
.length() + minor
.length() < 16) { /* arbitrary */
871 info
.format_name
= string_compose("%1/%2", major
, minor
);
873 info
.format_name
= string_compose("%1\n%2", major
, minor
);
876 info
.timecode
= binfo
.load_from_file (sf
) ? binfo
.get_time_reference() : 0;
884 SndFileSource::one_of_several_channels () const
886 return _info
.channels
> 1;
890 SndFileSource::clamped_at_unity () const
892 int const type
= _info
.format
& SF_FORMAT_TYPEMASK
;
893 int const sub
= _info
.format
& SF_FORMAT_SUBMASK
;
894 /* XXX: this may not be the full list of formats that are unclamped */
895 return (sub
!= SF_FORMAT_FLOAT
&& sub
!= SF_FORMAT_DOUBLE
&& type
!= SF_FORMAT_OGG
);
899 SndFileSource::file_closed ()
901 /* stupid libsndfile updated the headers on close,
902 so touch the peakfile if it exists and has data
903 to make sure its time is as new as the audio
911 SndFileSource::set_path (const string
& p
)
913 FileSource::set_path (p
);
916 _descriptor
->set_path (_path
);