along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
+#include <cstring>
#include <cerrno>
#include <climits>
+#include <cstdarg>
#include <pwd.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <glibmm/miscutils.h>
+#include <pbd/stacktrace.h>
#include <ardour/sndfilesource.h>
#include <ardour/sndfile_helpers.h>
#include <ardour/utils.h>
+#include <ardour/version.h>
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
+using Glib::ustring;
gain_t* SndFileSource::out_coefficient = 0;
gain_t* SndFileSource::in_coefficient = 0;
AudioFileSource::RemovableIfEmpty|
AudioFileSource::CanRename);
+static void
+snprintf_bounded_null_filled (char* target, size_t target_size, const char* fmt, ...)
+{
+ char buf[target_size+1];
+ va_list ap;
+
+ va_start (ap, fmt);
+ vsnprintf (buf, target_size+1, fmt, ap);
+ va_end (ap);
+
+ memset (target, 0, target_size);
+ memcpy (target, buf, target_size);
+
+}
+
SndFileSource::SndFileSource (Session& s, const XMLNode& node)
: AudioFileSource (s, node)
{
}
}
-SndFileSource::SndFileSource (Session& s, string path, int chn, Flag flags)
+SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
/* files created this way are never writable or removable */
: AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
{
- channel = chn;
+ _channel = chn;
init ();
}
}
-SndFileSource::SndFileSource (Session& s, string path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
+SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
: AudioFileSource (s, path, flags, sfmt, hf)
{
int fmt = 0;
*/
file_is_new = true;
-
+
switch (hf) {
case CAF:
fmt = SF_FORMAT_CAF;
case FormatInt24:
fmt |= SF_FORMAT_PCM_24;
break;
+
+ case FormatInt16:
+ fmt |= SF_FORMAT_PCM_16;
+ break;
}
_info.channels = 1;
if (writable() && (_flags & Broadcast)) {
- _broadcast_info = new SF_BROADCAST_INFO;
- memset (_broadcast_info, 0, sizeof (*_broadcast_info));
-
- snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
-
- struct utsname utsinfo;
-
- if (uname (&utsinfo)) {
- error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
- return;
+ if (!_broadcast_info) {
+ _broadcast_info = new SF_BROADCAST_INFO;
+ memset (_broadcast_info, 0, sizeof (*_broadcast_info));
}
- snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)",
- Glib::get_real_name().c_str(),
- utsinfo.nodename,
- utsinfo.sysname,
- utsinfo.release,
- utsinfo.version);
+ snprintf_bounded_null_filled (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
+ snprintf_bounded_null_filled (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour %d.%d.%d %s",
+ libardour2_major_version,
+ libardour2_minor_version,
+ libardour2_micro_version,
+ Glib::get_real_name().c_str());
_broadcast_info->version = 1;
_broadcast_info->time_reference_low = 0;
/* XXX do something about this field */
- snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
+ snprintf_bounded_null_filled (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
/* coding history is added by libsndfile */
- if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
+ if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
char errbuf[256];
sf_error_str (0, errbuf, sizeof (errbuf) - 1);
error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
_flags = Flag (_flags & ~Broadcast);
delete _broadcast_info;
_broadcast_info = 0;
- }
-
- }
+ }
+ }
}
void
SndFileSource::init ()
{
- string file;
+ ustring file;
// lets try to keep the object initalizations here at the top
xfade_buf = 0;
- interleave_buf = 0;
- interleave_bufsize = 0;
sf = 0;
_broadcast_info = 0;
if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
char errbuf[256];
sf_error_str (0, errbuf, sizeof (errbuf) - 1);
+#ifndef HAVE_COREAUDIO
+ /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
+ so we don't want to see this message.
+ */
+
error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
_path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
+#endif
return -1;
}
- if (channel >= _info.channels) {
- error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg;
+ if (_channel >= _info.channels) {
+#ifndef HAVE_COREAUDIO
+ error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
+#endif
sf_close (sf);
sf = 0;
return -1;
_length = _info.frames;
- _broadcast_info = new SF_BROADCAST_INFO;
- memset (_broadcast_info, 0, sizeof (*_broadcast_info));
+ if (!_broadcast_info) {
+ _broadcast_info = new SF_BROADCAST_INFO;
+ memset (_broadcast_info, 0, sizeof (*_broadcast_info));
+ }
bool timecode_info_exists;
set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
- if (!timecode_info_exists) {
+ if (_length != 0 && !timecode_info_exists) {
delete _broadcast_info;
_broadcast_info = 0;
_flags = Flag (_flags & ~Broadcast);
touch_peakfile ();
}
- if (interleave_buf) {
- delete [] interleave_buf;
- }
-
if (_broadcast_info) {
delete _broadcast_info;
}
file_cnt = cnt;
}
+ if (file_cnt != cnt) {
+ nframes_t delta = cnt - file_cnt;
+ memset (dst+file_cnt, 0, sizeof (Sample) * delta);
+ }
+
if (file_cnt) {
if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
if (_info.channels == 1) {
nframes_t ret = sf_read_float (sf, dst, file_cnt);
- _read_data_count = cnt * sizeof(float);
+ _read_data_count = ret * sizeof(float);
+ if (ret != file_cnt) {
+ char errbuf[256];
+ sf_error_str (0, errbuf, sizeof (errbuf) - 1);
+ cerr << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5)"), start, file_cnt, _name.substr (1), errbuf, _length) << endl;
+ }
return ret;
}
}
- if (file_cnt != cnt) {
- nframes_t delta = cnt - file_cnt;
- memset (dst+file_cnt, 0, sizeof (Sample) * delta);
- }
-
real_cnt = cnt * _info.channels;
- if (interleave_bufsize < real_cnt) {
-
- if (interleave_buf) {
- delete [] interleave_buf;
- }
- interleave_bufsize = real_cnt;
- interleave_buf = new float[interleave_bufsize];
- }
+ Sample* interleave_buf = get_interleave_buffer (real_cnt);
nread = sf_read_float (sf, interleave_buf, real_cnt);
- ptr = interleave_buf + channel;
+ ptr = interleave_buf + _channel;
nread /= _info.channels;
/* stride through the interleaved data */
nframes_t oldlen;
int32_t frame_pos = _length;
-
+
if (write_float (data, frame_pos, cnt) != cnt) {
return 0;
}
update_length (oldlen, cnt);
if (_build_peakfiles) {
- PeakBuildRecord *pbr = 0;
-
- if (pending_peak_builds.size()) {
- pbr = pending_peak_builds.back();
- }
-
- if (pbr && pbr->frame + pbr->cnt == oldlen) {
-
- /* the last PBR extended to the start of the current write,
- so just extend it again.
- */
- pbr->cnt += cnt;
- } else {
- pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
- }
-
- _peaks_built = false;
- }
-
-
- if (_build_peakfiles) {
- queue_for_peaks (shared_from_this (), false);
+ compute_and_write_peaks (data, frame_pos, cnt, false, true);
}
_write_data_count = cnt;
-
+
return cnt;
}
old_file_pos = file_pos;
update_length (file_pos, cnt);
- file_pos += cnt;
if (_build_peakfiles) {
- PeakBuildRecord *pbr = 0;
-
- if (pending_peak_builds.size()) {
- pbr = pending_peak_builds.back();
- }
-
- if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
-
- /* the last PBR extended to the start of the current write,
- so just extend it again.
- */
-
- pbr->cnt += cnt;
- } else {
- pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
- }
-
- _peaks_built = false;
+ compute_and_write_peaks (data, file_pos, cnt, false, true);
}
- if (_build_peakfiles) {
- queue_for_peaks (shared_from_this (), true);
- }
+ file_pos += cnt;
return cnt;
}
int random_code = random() % 999999999;
- snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
- Config->get_bwf_country_code().c_str(),
- Config->get_bwf_organization_code().c_str(),
- bwf_serial_number,
- now.tm_hour,
- now.tm_min,
- now.tm_sec,
- random_code);
+ snprintf_bounded_null_filled (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
+ Config->get_bwf_country_code().c_str(),
+ Config->get_bwf_organization_code().c_str(),
+ bwf_serial_number,
+ now.tm_hour,
+ now.tm_min,
+ now.tm_sec,
+ random_code);
- snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
- 1900 + now.tm_year,
- now.tm_mon,
- now.tm_mday);
+ snprintf_bounded_null_filled (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
+ 1900 + now.tm_year,
+ now.tm_mon + 1, // shift range from 0..11 to 1..12
+ now.tm_mday);
+
+ snprintf_bounded_null_filled (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
+ now.tm_hour,
+ now.tm_min,
+ now.tm_sec);
- snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
- now.tm_hour,
- now.tm_min,
- now.tm_sec);
-
/* now update header position taking header offset into account */
set_header_timeline_position ();
delete _broadcast_info;
_broadcast_info = 0;
}
-
-
-
}
nframes_t
}
int
-SndFileSource::get_soundfile_info (string path, SoundFileInfo& info, string& error_msg)
+SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
{
SNDFILE *sf;
SF_INFO sf_info;
info.samplerate = sf_info.samplerate;
info.channels = sf_info.channels;
info.length = sf_info.frames;
- info.format_name = string_compose("Format: %1, %2",
- sndfile_major_format(sf_info.format),
- sndfile_minor_format(sf_info.format));
+
+ string major = sndfile_major_format(sf_info.format);
+ string minor = sndfile_minor_format(sf_info.format);
+
+ if (major.length() + minor.length() < 16) { /* arbitrary */
+ info.format_name = string_compose("%1/%2", major, minor);
+ } else {
+ info.format_name = string_compose("%1\n%2", major, minor);
+ }
memset (&binfo, 0, sizeof (binfo));
info.timecode = get_timecode_info (sf, &binfo, timecode_exists);
ret |= (uint32_t) binfo->time_reference_low;
return ret;
}
+
+bool
+SndFileSource::one_of_several_channels () const
+{
+ return _info.channels > 1;
+}
+