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 ();
48 SndFileSource::SndFileSource (Session& s, string idstr, Flag flags)
49 /* files created this way are never writable or removable */
50 : AudioFileSource (s, idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
55 throw failed_constructor ();
59 SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
60 : AudioFileSource (s, idstr, flags, sfmt, hf)
66 /* this constructor is used to construct new files, not open
75 _flags = Flag (_flags & ~Broadcast);
80 _flags = Flag (_flags & ~Broadcast);
85 _flags = Flag (_flags | Broadcast);
90 _flags = Flag (_flags & ~Broadcast);
95 _flags = Flag (_flags & ~Broadcast);
99 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
107 fmt |= SF_FORMAT_FLOAT;
111 fmt |= SF_FORMAT_PCM_24;
116 _info.samplerate = rate;
120 throw failed_constructor();
123 if (writable() && (_flags & Broadcast)) {
125 _broadcast_info = new SF_BROADCAST_INFO;
126 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
128 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
130 struct utsname utsinfo;
132 if (uname (&utsinfo)) {
133 error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
137 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
138 Glib::get_real_name().c_str(),
144 _broadcast_info->version = 1;
145 _broadcast_info->time_reference_low = 0;
146 _broadcast_info->time_reference_high = 0;
148 /* XXX do something about this field */
150 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
152 /* coding history is added by libsndfile */
154 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
156 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
157 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
158 _flags = Flag (_flags & ~Broadcast);
159 delete _broadcast_info;
167 SndFileSource::init (const string& idstr)
169 string::size_type pos;
173 interleave_bufsize = 0;
177 if ((pos = idstr.find_last_of (':')) == string::npos) {
179 _name = Glib::path_get_basename (idstr);
181 channel = atoi (idstr.substr (pos+1).c_str());
182 _name = Glib::path_get_basename (idstr.substr (0, pos));
185 /* although libsndfile says we don't need to set this,
186 valgrind and source code shows us that we do.
189 memset (&_info, 0, sizeof(_info));
193 SndFileSource::open ()
195 if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
197 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
198 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
199 _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
203 if (channel >= _info.channels) {
204 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg;
210 _length = _info.frames;
212 _broadcast_info = new SF_BROADCAST_INFO;
213 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
215 /* lookup broadcast info */
217 if (sf_command (sf, SFC_GET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
219 /* if the file has data but no broadcast info, then clearly, there is no broadcast info */
222 delete _broadcast_info;
224 _flags = Flag (_flags & ~Broadcast);
227 set_timeline_position (header_position_offset);
231 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
232 of the time reference.
235 set_timeline_position ( _broadcast_info->time_reference_low );
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 (interleave_buf) {
263 delete [] interleave_buf;
266 if (_broadcast_info) {
267 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 */
306 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
308 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
309 error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
313 if (_info.channels == 1) {
314 nframes_t ret = sf_read_float (sf, dst, file_cnt);
315 _read_data_count = cnt * sizeof(float);
320 if (file_cnt != cnt) {
321 nframes_t delta = cnt - file_cnt;
322 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
325 real_cnt = cnt * _info.channels;
327 if (interleave_bufsize < real_cnt) {
329 if (interleave_buf) {
330 delete [] interleave_buf;
332 interleave_bufsize = real_cnt;
333 interleave_buf = new float[interleave_bufsize];
336 nread = sf_read_float (sf, interleave_buf, real_cnt);
337 ptr = interleave_buf + channel;
338 nread /= _info.channels;
340 /* stride through the interleaved data */
342 for (int32_t n = 0; n < nread; ++n) {
344 ptr += _info.channels;
347 _read_data_count = cnt * sizeof(float);
353 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
359 if (_info.channels != 1) {
360 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
366 int32_t frame_pos = _length;
368 if (write_float (data, frame_pos, cnt) != cnt) {
373 update_length (oldlen, cnt);
375 if (_build_peakfiles) {
376 PeakBuildRecord *pbr = 0;
378 if (pending_peak_builds.size()) {
379 pbr = pending_peak_builds.back();
382 if (pbr && pbr->frame + pbr->cnt == oldlen) {
384 /* the last PBR extended to the start of the current write,
385 so just extend it again.
390 pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
393 _peaks_built = false;
397 if (_build_peakfiles) {
398 queue_for_peaks (shared_from_this ());
401 _write_data_count = cnt;
407 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
409 set_timeline_position (when);
411 if (_flags & Broadcast) {
412 if (setup_broadcast_info (when, now, tnow)) {
417 return flush_header ();
421 SndFileSource::flush_header ()
423 if (!writable() || (sf == 0)) {
426 return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
430 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
436 if (!(_flags & Broadcast)) {
440 /* random code is 9 digits */
442 int random_code = random() % 999999999;
444 snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
446 bwf_organization_code,
453 snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
458 snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
463 /* now update header position taking header offset into account */
465 set_header_timeline_position ();
467 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
468 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
469 _flags = Flag (_flags & ~Broadcast);
470 delete _broadcast_info;
479 SndFileSource::set_header_timeline_position ()
481 if (!(_flags & Broadcast)) {
485 _broadcast_info->time_reference_high = (timeline_position >> 32);
486 _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
488 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
489 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
490 _flags = Flag (_flags & ~Broadcast);
491 delete _broadcast_info;
500 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
502 if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) != frame_pos) {
503 error << string_compose (_("%1: cannot seek to %2"), _path, frame_pos) << endmsg;
507 if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
515 SndFileSource::natural_position() const
517 return timeline_position;