summaryrefslogtreecommitdiff
path: root/src/lib/sndfile_decoder.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-09-17 23:39:05 +0100
committerCarl Hetherington <cth@carlh.net>2013-09-17 23:39:05 +0100
commit373f010a7f04add1f49169cbaa60cb7ae5f508d4 (patch)
treea61fe014cbefc775dcf3a5c9a45d06e391e65b31 /src/lib/sndfile_decoder.cc
parent048f9b6b5569f03d1342a04f75c83a2bad340996 (diff)
parente888e92f354b9868337b0b022ff9be38b9c36c0f (diff)
Merge 1.0 in.
Diffstat (limited to 'src/lib/sndfile_decoder.cc')
-rw-r--r--src/lib/sndfile_decoder.cc120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc
new file mode 100644
index 000000000..1fc1ecaf2
--- /dev/null
+++ b/src/lib/sndfile_decoder.cc
@@ -0,0 +1,120 @@
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ 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.
+
+*/
+
+#include <iostream>
+#include <sndfile.h>
+#include "sndfile_content.h"
+#include "sndfile_decoder.h"
+#include "film.h"
+#include "exceptions.h"
+#include "audio_buffers.h"
+
+#include "i18n.h"
+
+using std::vector;
+using std::string;
+using std::min;
+using std::cout;
+using boost::shared_ptr;
+
+SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<const SndfileContent> c)
+ : Decoder (f)
+ , AudioDecoder (f)
+ , _sndfile_content (c)
+ , _deinterleave_buffer (0)
+{
+ _info.format = 0;
+ _sndfile = sf_open (_sndfile_content->path().string().c_str(), SFM_READ, &_info);
+ if (!_sndfile) {
+ throw DecodeError (_("could not open audio file for reading"));
+ }
+
+ _done = 0;
+ _remaining = _info.frames;
+}
+
+SndfileDecoder::~SndfileDecoder ()
+{
+ sf_close (_sndfile);
+ delete[] _deinterleave_buffer;
+}
+
+void
+SndfileDecoder::pass ()
+{
+ /* Do things in half second blocks as I think there may be limits
+ to what FFmpeg (and in particular the resampler) can cope with.
+ */
+ sf_count_t const block = _sndfile_content->content_audio_frame_rate() / 2;
+ sf_count_t const this_time = min (block, _remaining);
+
+ int const channels = _sndfile_content->audio_channels ();
+
+ shared_ptr<AudioBuffers> data (new AudioBuffers (channels, this_time));
+
+ if (_sndfile_content->audio_channels() == 1) {
+ /* No de-interleaving required */
+ sf_read_float (_sndfile, data->data(0), this_time);
+ } else {
+ /* Deinterleave */
+ if (!_deinterleave_buffer) {
+ _deinterleave_buffer = new float[block * channels];
+ }
+ sf_readf_float (_sndfile, _deinterleave_buffer, this_time);
+ vector<float*> out_ptr (channels);
+ for (int i = 0; i < channels; ++i) {
+ out_ptr[i] = data->data(i);
+ }
+ float* in_ptr = _deinterleave_buffer;
+ for (int i = 0; i < this_time; ++i) {
+ for (int j = 0; j < channels; ++j) {
+ *out_ptr[j]++ = *in_ptr++;
+ }
+ }
+ }
+
+ data->set_frames (this_time);
+ audio (data, _done);
+ _done += this_time;
+ _remaining -= this_time;
+}
+
+int
+SndfileDecoder::audio_channels () const
+{
+ return _info.channels;
+}
+
+AudioContent::Frame
+SndfileDecoder::audio_length () const
+{
+ return _info.frames;
+}
+
+int
+SndfileDecoder::audio_frame_rate () const
+{
+ return _info.samplerate;
+}
+
+bool
+SndfileDecoder::done () const
+{
+ return _audio_position >= _sndfile_content->audio_length ();
+}