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>
35 using namespace ARDOUR;
38 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
39 : AudioFileSource (s, node)
44 throw failed_constructor ();
47 if (_build_peakfiles) {
48 if (initialize_peakfile (false, _path)) {
51 throw failed_constructor ();
56 SndFileSource::SndFileSource (Session& s, string idstr, Flag flags)
57 /* files created this way are never writable or removable */
58 : AudioFileSource (s, idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
63 throw failed_constructor ();
66 if (!(_flags & NoPeakFile) && _build_peakfiles) {
67 if (initialize_peakfile (false, _path)) {
70 throw failed_constructor ();
75 SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
76 : AudioFileSource (s, idstr, flags, sfmt, hf)
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;
175 if (!(_flags & NoPeakFile) && _build_peakfiles) {
176 if (initialize_peakfile (true, _path)) {
179 throw failed_constructor ();
185 SndFileSource::init (const string& idstr)
187 string::size_type pos;
191 interleave_bufsize = 0;
195 if ((pos = idstr.find_last_of (':')) == string::npos) {
197 _name = Glib::path_get_basename (idstr);
199 channel = atoi (idstr.substr (pos+1).c_str());
200 _name = Glib::path_get_basename (idstr.substr (0, pos));
203 /* although libsndfile says we don't need to set this,
204 valgrind and source code shows us that we do.
207 memset (&_info, 0, sizeof(_info));
211 SndFileSource::open ()
213 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
215 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
216 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
217 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
221 if (channel >= _info.channels) {
222 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg;
228 _length = _info.frames;
230 _broadcast_info = new SF_BROADCAST_INFO;
231 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
233 /* lookup broadcast info */
235 if (sf_command (sf, SFC_GET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
237 /* if the file has data but no broadcast info, then clearly, there is no broadcast info */
240 delete _broadcast_info;
242 _flags = Flag (_flags & ~Broadcast);
245 set_timeline_position (header_position_offset);
249 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
250 of the time reference.
253 set_timeline_position ( _broadcast_info->time_reference_low );
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 (interleave_buf) {
281 delete [] interleave_buf;
284 if (_broadcast_info) {
285 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 */
324 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
326 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
327 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
331 if (_info.channels == 1) {
332 nframes_t ret = sf_read_float (sf, dst, file_cnt);
333 _read_data_count = cnt * sizeof(float);
338 if (file_cnt != cnt) {
339 nframes_t delta = cnt - file_cnt;
340 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
343 real_cnt = cnt * _info.channels;
345 if (interleave_bufsize < real_cnt) {
347 if (interleave_buf) {
348 delete [] interleave_buf;
350 interleave_bufsize = real_cnt;
351 interleave_buf = new float[interleave_bufsize];
354 nread = sf_read_float (sf, interleave_buf, real_cnt);
355 ptr = interleave_buf + channel;
356 nread /= _info.channels;
358 /* stride through the interleaved data */
360 for (int32_t n = 0; n < nread; ++n) {
362 ptr += _info.channels;
365 _read_data_count = cnt * sizeof(float);
371 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
377 if (_info.channels != 1) {
378 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
384 int32_t frame_pos = _length;
386 if (write_float (data, frame_pos, cnt) != cnt) {
391 update_length (oldlen, cnt);
393 if (_build_peakfiles) {
394 PeakBuildRecord *pbr = 0;
396 if (pending_peak_builds.size()) {
397 pbr = pending_peak_builds.back();
400 if (pbr && pbr->frame + pbr->cnt == oldlen) {
402 /* the last PBR extended to the start of the current write,
403 so just extend it again.
408 pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
411 _peaks_built = false;
415 if (_build_peakfiles) {
416 queue_for_peaks (this);
419 _write_data_count = cnt;
425 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
427 set_timeline_position (when);
429 if (_flags & Broadcast) {
430 if (setup_broadcast_info (when, now, tnow)) {
435 return flush_header ();
439 SndFileSource::flush_header ()
441 if (!writable() || (sf == 0)) {
444 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
448 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
454 if (!(_flags & Broadcast)) {
458 /* random code is 9 digits */
460 int random_code = random() % 999999999;
462 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
464 bwf_organization_code,
471 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
476 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
481 /* now update header position taking header offset into account */
483 set_header_timeline_position ();
485 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
486 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
487 _flags = Flag (_flags & ~Broadcast);
488 delete _broadcast_info;
497 SndFileSource::set_header_timeline_position ()
499 if (!(_flags & Broadcast)) {
503 _broadcast_info->time_reference_high = (timeline_position >> 32);
504 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
506 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
507 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
508 _flags = Flag (_flags & ~Broadcast);
509 delete _broadcast_info;
518 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
520 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) != frame_pos) {
521 error << string_compose (_("%1: cannot seek to %2"), _path, frame_pos) << endmsg;
525 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
533 SndFileSource::natural_position() const
535 return timeline_position;