X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Flib%2Fresampler.cc;h=322c00c136779f009ad1163119bce5496a191dad;hp=2538f7dca57080d718954fdb6f216753b78ae7c2;hb=a5be11a965c2c38442e4e069874e7e21b5b43a5c;hpb=e60bb3e51bd1508b149e6b8f6608f09b5196ae26 diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc index 2538f7dca..322c00c13 100644 --- a/src/lib/resampler.cc +++ b/src/lib/resampler.cc @@ -1,83 +1,153 @@ /* Copyright (C) 2013-2015 Carl Hetherington - This program is free software; you can redistribute it and/or modify + This file is part of DCP-o-matic. + + DCP-o-matic 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, + DCP-o-matic 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. + along with DCP-o-matic. If not, see . */ -extern "C" { -#include "libavutil/channel_layout.h" -#include "libavutil/opt.h" -} #include "resampler.h" #include "audio_buffers.h" #include "exceptions.h" #include "compose.hpp" +#include "dcpomatic_assert.h" +#include +#include +#include #include "i18n.h" using std::cout; using std::pair; using std::make_pair; +using std::runtime_error; using boost::shared_ptr; +/** @param in Input sampling rate (Hz) + * @param out Output sampling rate (Hz) + * @param channels Number of channels. + */ Resampler::Resampler (int in, int out, int channels) : _in_rate (in) , _out_rate (out) , _channels (channels) { - _swr_context = swr_alloc (); - - /* Sample formats */ - av_opt_set_int (_swr_context, "isf", AV_SAMPLE_FMT_FLTP, 0); - av_opt_set_int (_swr_context, "osf", AV_SAMPLE_FMT_FLTP, 0); - - /* Channel counts */ - av_opt_set_int (_swr_context, "ich", _channels, 0); - av_opt_set_int (_swr_context, "och", _channels, 0); - - /* Sample rates */ - av_opt_set_int (_swr_context, "isr", _in_rate, 0); - av_opt_set_int (_swr_context, "osr", _out_rate, 0); - - swr_init (_swr_context); + int error; + _src = src_new (SRC_SINC_BEST_QUALITY, _channels, &error); + if (!_src) { + throw runtime_error (String::compose (N_("could not create sample-rate converter (%1)"), error)); + } } Resampler::~Resampler () { - swr_free (&_swr_context); + if (_src) { + src_delete (_src); + } +} + +void +Resampler::set_fast () +{ + src_delete (_src); + _src = 0; + + int error; + _src = src_new (SRC_LINEAR, _channels, &error); + if (!_src) { + throw runtime_error (String::compose (N_("could not create sample-rate converter (%1)"), error)); + } } shared_ptr Resampler::run (shared_ptr in) { - /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((double) in->frames() * _out_rate / _in_rate) + 32; - shared_ptr resampled (new AudioBuffers (_channels, max_resampled_frames)); - - int const resampled_frames = swr_convert ( - _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) in->data(), in->frames() - ); - - if (resampled_frames < 0) { - char buf[256]; - av_strerror (resampled_frames, buf, sizeof(buf)); - throw EncodeError (String::compose (_("could not run sample-rate converter for %1 samples (%2) (%3)"), in->frames(), resampled_frames, buf)); + int in_frames = in->frames (); + int in_offset = 0; + int out_offset = 0; + shared_ptr resampled (new AudioBuffers (_channels, 0)); + + while (in_frames > 0) { + + /* Compute the resampled frames count and add 32 for luck */ + int const max_resampled_frames = ceil ((double) in_frames * _out_rate / _in_rate) + 32; + + SRC_DATA data; + float* in_buffer = new float[in_frames * _channels]; + + { + float** p = in->data (); + float* q = in_buffer; + for (int i = 0; i < in_frames; ++i) { + for (int j = 0; j < _channels; ++j) { + *q++ = p[j][in_offset + i]; + } + } + } + + data.data_in = in_buffer; + data.input_frames = in_frames; + + data.data_out = new float[max_resampled_frames * _channels]; + data.output_frames = max_resampled_frames; + + data.end_of_input = 0; + data.src_ratio = double (_out_rate) / _in_rate; + + int const r = src_process (_src, &data); + if (r) { + delete[] data.data_in; + delete[] data.data_out; + throw EncodeError ( + String::compose ( + N_("could not run sample-rate converter (%1) [processing %2 to %3, %4 channels]"), + src_strerror (r), + in_frames, + max_resampled_frames, + _channels + ) + ); + } + + if (data.output_frames_gen == 0) { + delete[] data.data_in; + delete[] data.data_out; + break; + } + + resampled->ensure_size (out_offset + data.output_frames_gen); + resampled->set_frames (out_offset + data.output_frames_gen); + + { + float* p = data.data_out; + float** q = resampled->data (); + for (int i = 0; i < data.output_frames_gen; ++i) { + for (int j = 0; j < _channels; ++j) { + q[j][out_offset + i] = *p++; + } + } + } + + in_frames -= data.input_frames_used; + in_offset += data.input_frames_used; + out_offset += data.output_frames_gen; + + delete[] data.data_in; + delete[] data.data_out; } - resampled->set_frames (resampled_frames); return resampled; } @@ -86,25 +156,44 @@ Resampler::flush () { shared_ptr out (new AudioBuffers (_channels, 0)); int out_offset = 0; - int64_t const pass_size = 256; - shared_ptr pass (new AudioBuffers (_channels, 256)); + int64_t const output_size = 65536; + + float dummy[1]; + float* buffer = new float[output_size]; + + SRC_DATA data; + data.data_in = dummy; + data.input_frames = 0; + data.data_out = buffer; + data.output_frames = output_size; + data.end_of_input = 1; + data.src_ratio = double (_out_rate) / _in_rate; + + int const r = src_process (_src, &data); + if (r) { + delete[] buffer; + throw EncodeError (String::compose (N_("could not run sample-rate converter (%1)"), src_strerror (r))); + } - while (true) { - int const frames = swr_convert (_swr_context, (uint8_t **) pass->data(), pass_size, 0, 0); + out->ensure_size (out_offset + data.output_frames_gen); - if (frames < 0) { - throw EncodeError (_("could not run sample-rate converter")); + float* p = data.data_out; + float** q = out->data (); + for (int i = 0; i < data.output_frames_gen; ++i) { + for (int j = 0; j < _channels; ++j) { + q[j][out_offset + i] = *p++; } - - if (frames == 0) { - break; - } - - out->ensure_size (out_offset + frames); - out->copy_from (pass.get(), frames, 0, out_offset); - out_offset += frames; - out->set_frames (out_offset); } + out_offset += data.output_frames_gen; + out->set_frames (out_offset); + + delete[] buffer; return out; } + +void +Resampler::reset () +{ + src_reset (_src); +}