diff options
Diffstat (limited to 'libs/ardour/sndfilesource.cc')
-rw-r--r-- | libs/ardour/sndfilesource.cc | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc new file mode 100644 index 0000000000..399f632caa --- /dev/null +++ b/libs/ardour/sndfilesource.cc @@ -0,0 +1,207 @@ +/* + Copyright (C) 2000 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <string> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/time.h> + +#include <pbd/mountpoint.h> +#include <ardour/sndfilesource.h> + +#include "i18n.h" + +using namespace ARDOUR; + +string SndFileSource::peak_dir = ""; + +SndFileSource::SndFileSource (const XMLNode& node) + : Source (node) +{ + if (set_state (node)) { + throw failed_constructor(); + } + + init (_name, true); + SourceCreated (this); /* EMIT SIGNAL */ +} + +SndFileSource::SndFileSource (const string& idstr, bool build_peak) + : Source(build_peak) +{ + init (idstr, build_peak); + + if (build_peak) { + SourceCreated (this); /* EMIT SIGNAL */ + } +} + +void +SndFileSource::init (const string& idstr, bool build_peak) +{ + string::size_type pos; + string file; + + tmpbuf = 0; + tmpbufsize = 0; + sf = 0; + + _name = idstr; + + if ((pos = idstr.find_last_of (':')) == string::npos) { + channel = 0; + file = idstr; + } else { + channel = atoi (idstr.substr (pos+1).c_str()); + file = idstr.substr (0, pos); + } + + /* although libsndfile says we don't need to set this, + valgrind and source code shows us that we do. + */ + + memset (&_info, 0, sizeof(_info)); + + /* note that we temporarily truncated _id at the colon */ + + if ((sf = sf_open (file.c_str(), SFM_READ, &_info)) == 0) { + char errbuf[256]; + sf_error_str (0, errbuf, sizeof (errbuf) - 1); + error << compose(_("SndFileSource: cannot open file \"%1\" (%2)"), file, errbuf) << endmsg; + throw failed_constructor(); + } + + if (channel >= _info.channels) { + error << compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg; + sf_close (sf); + sf = 0; + throw failed_constructor(); + } + + _length = _info.frames; + _path = file; + + if (build_peak) { + if (initialize_peakfile (false, file)) { + sf_close (sf); + sf = 0; + throw failed_constructor (); + } + } +} + +SndFileSource::~SndFileSource () + +{ + GoingAway (this); /* EMIT SIGNAL */ + + if (sf) { + sf_close (sf); + } + + if (tmpbuf) { + delete [] tmpbuf; + } +} + +jack_nframes_t +SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const +{ + return read (dst, start, cnt); +} + +jack_nframes_t +SndFileSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const +{ + int32_t nread; + float *ptr; + uint32_t real_cnt; + + if (sf_seek (sf, (off_t) start, SEEK_SET) < 0) { + char errbuf[256]; + sf_error_str (0, errbuf, sizeof (errbuf) - 1); + error << compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg; + return 0; + } + + if (_info.channels == 1) { + jack_nframes_t ret = sf_read_float (sf, dst, cnt); + _read_data_count = cnt * sizeof(float); + return ret; + } + + real_cnt = cnt * _info.channels; + + { + LockMonitor lm (_tmpbuf_lock, __LINE__, __FILE__); + + if (tmpbufsize < real_cnt) { + + if (tmpbuf) { + delete [] tmpbuf; + } + tmpbufsize = real_cnt; + tmpbuf = new float[tmpbufsize]; + } + + nread = sf_read_float (sf, tmpbuf, real_cnt); + ptr = tmpbuf + channel; + nread /= _info.channels; + + /* stride through the interleaved data */ + + for (int32_t n = 0; n < nread; ++n) { + dst[n] = *ptr; + ptr += _info.channels; + } + } + + _read_data_count = cnt * sizeof(float); + + return nread; +} + +string +SndFileSource::peak_path (string audio_path) +{ + /* XXX hardly bombproof! fix me */ + + struct stat stat_file; + struct stat stat_mount; + + string mp = mountpoint (audio_path); + + stat (audio_path.c_str(), &stat_file); + stat (mp.c_str(), &stat_mount); + + char buf[32]; + snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, channel); + + string res = peak_dir; + res += buf; + + return res; +} + +string +SndFileSource::old_peak_path (string audio_path) +{ + return peak_path (audio_path); +} |