Resampler modifications in preparation for arbitrary audioproc rates.

- Templatize PushResampler to support int16 and float.
- Add a helper method to PushSincResampler to compute the algorithmic
delay.

This is a prerequisite of:
http://review.webrtc.org/9919004/

BUG=2894
R=turaj@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/12169004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5943 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andrew@webrtc.org 2014-04-19 00:32:07 +00:00
parent 3d9ec1fed4
commit f5a33f145b
12 changed files with 52 additions and 48 deletions

View File

@ -20,6 +20,7 @@ class PushSincResampler;
// Wraps PushSincResampler to provide stereo support.
// TODO(ajm): add support for an arbitrary number of channels.
template <typename T>
class PushResampler {
public:
PushResampler();
@ -32,22 +33,18 @@ class PushResampler {
// Returns the total number of samples provided in destination (e.g. 32 kHz,
// 2 channel audio gives 640 samples).
int Resample(const int16_t* src, int src_length, int16_t* dst,
int dst_capacity);
int Resample(const T* src, int src_length, T* dst, int dst_capacity);
private:
int ResampleSinc(const int16_t* src, int src_length, int16_t* dst,
int dst_capacity);
scoped_ptr<PushSincResampler> sinc_resampler_;
scoped_ptr<PushSincResampler> sinc_resampler_right_;
int src_sample_rate_hz_;
int dst_sample_rate_hz_;
int num_channels_;
scoped_array<int16_t> src_left_;
scoped_array<int16_t> src_right_;
scoped_array<int16_t> dst_left_;
scoped_array<int16_t> dst_right_;
scoped_ptr<T[]> src_left_;
scoped_ptr<T[]> src_right_;
scoped_ptr<T[]> dst_left_;
scoped_ptr<T[]> dst_right_;
};
} // namespace webrtc

View File

@ -18,22 +18,21 @@
namespace webrtc {
PushResampler::PushResampler()
template <typename T>
PushResampler<T>::PushResampler()
: src_sample_rate_hz_(0),
dst_sample_rate_hz_(0),
num_channels_(0),
src_left_(NULL),
src_right_(NULL),
dst_left_(NULL),
dst_right_(NULL) {
num_channels_(0) {
}
PushResampler::~PushResampler() {
template <typename T>
PushResampler<T>::~PushResampler() {
}
int PushResampler::InitializeIfNeeded(int src_sample_rate_hz,
int dst_sample_rate_hz,
int num_channels) {
template <typename T>
int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz,
int dst_sample_rate_hz,
int num_channels) {
if (src_sample_rate_hz == src_sample_rate_hz_ &&
dst_sample_rate_hz == dst_sample_rate_hz_ &&
num_channels == num_channels_)
@ -53,10 +52,10 @@ int PushResampler::InitializeIfNeeded(int src_sample_rate_hz,
sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono,
dst_size_10ms_mono));
if (num_channels_ == 2) {
src_left_.reset(new int16_t[src_size_10ms_mono]);
src_right_.reset(new int16_t[src_size_10ms_mono]);
dst_left_.reset(new int16_t[dst_size_10ms_mono]);
dst_right_.reset(new int16_t[dst_size_10ms_mono]);
src_left_.reset(new T[src_size_10ms_mono]);
src_right_.reset(new T[src_size_10ms_mono]);
dst_left_.reset(new T[dst_size_10ms_mono]);
dst_right_.reset(new T[dst_size_10ms_mono]);
sinc_resampler_right_.reset(new PushSincResampler(src_size_10ms_mono,
dst_size_10ms_mono));
}
@ -64,8 +63,9 @@ int PushResampler::InitializeIfNeeded(int src_sample_rate_hz,
return 0;
}
int PushResampler::Resample(const int16_t* src, int src_length,
int16_t* dst, int dst_capacity) {
template <typename T>
int PushResampler<T>::Resample(const T* src, int src_length, T* dst,
int dst_capacity) {
const int src_size_10ms = src_sample_rate_hz_ * num_channels_ / 100;
const int dst_size_10ms = dst_sample_rate_hz_ * num_channels_ / 100;
if (src_length != src_size_10ms || dst_capacity < dst_size_10ms)
@ -74,13 +74,13 @@ int PushResampler::Resample(const int16_t* src, int src_length,
if (src_sample_rate_hz_ == dst_sample_rate_hz_) {
// The old resampler provides this memcpy facility in the case of matching
// sample rates, so reproduce it here for the sinc resampler.
memcpy(dst, src, src_length * sizeof(int16_t));
memcpy(dst, src, src_length * sizeof(T));
return src_length;
}
if (num_channels_ == 2) {
const int src_length_mono = src_length / num_channels_;
const int dst_capacity_mono = dst_capacity / num_channels_;
int16_t* deinterleaved[] = {src_left_.get(), src_right_.get()};
T* deinterleaved[] = {src_left_.get(), src_right_.get()};
Deinterleave(src, src_length_mono, num_channels_, deinterleaved);
int dst_length_mono =
@ -98,4 +98,8 @@ int PushResampler::Resample(const int16_t* src, int src_length,
}
}
// Explictly generate required instantiations.
template class PushResampler<int16_t>;
template class PushResampler<float>;
} // namespace webrtc

View File

@ -16,7 +16,7 @@
namespace webrtc {
TEST(PushResamplerTest, VerifiesInputParameters) {
PushResampler resampler;
PushResampler<int16_t> resampler;
EXPECT_EQ(-1, resampler.InitializeIfNeeded(-1, 16000, 1));
EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, -1, 1));
EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, 16000, 0));

View File

@ -44,6 +44,9 @@ class PushSincResampler : public SincResamplerCallback {
virtual void Run(int frames, float* destination) OVERRIDE;
SincResampler* get_resampler_for_testing() { return resampler_.get(); }
static float AlgorithmicDelaySeconds(int source_rate_hz) {
return 1.f / source_rate_hz * SincResampler::kKernelSize / 2;
}
private:
scoped_ptr<SincResampler> resampler_;

View File

@ -29,7 +29,7 @@ class ACMResampler {
int16_t* out_audio);
private:
PushResampler resampler_;
PushResampler<int16_t> resampler_;
};
} // namespace acm2

View File

@ -15,7 +15,6 @@
#include "webrtc/typedefs.h"
namespace webrtc {
namespace acm1 {
class ACMResampler {
@ -30,11 +29,10 @@ class ACMResampler {
uint8_t num_audio_channels);
private:
PushResampler resampler_;
PushResampler<int16_t> resampler_;
};
} // namespace acm1
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_ACM_RESAMPLER_H_

View File

@ -519,8 +519,8 @@ private:
bool _externalTransport;
AudioFrame _audioFrame;
scoped_ptr<int16_t[]> mono_recording_audio_;
// Resampler is used when input data is stereo while codec is mono.
PushResampler input_resampler_;
// Downsamples to the codec rate if necessary.
PushResampler<int16_t> input_resampler_;
uint8_t _audioLevel_dBov;
FilePlayer* _inputFilePlayerPtr;
FilePlayer* _outputFilePlayerPtr;

View File

@ -133,8 +133,10 @@ private:
CriticalSectionWrapper& _fileCritSect;
AudioConferenceMixer& _mixerModule;
AudioFrame _audioFrame;
PushResampler resampler_; // converts mixed audio to fit ADM format
PushResampler audioproc_resampler_; // converts mixed audio to fit APM rate
// Converts mixed audio to the audio device output rate.
PushResampler<int16_t> resampler_;
// Converts mixed audio to the audio processing rate.
PushResampler<int16_t> audioproc_resampler_;
AudioLevel _audioLevel; // measures audio level for the combined signal
DtmfInband _dtmfGenerator;
int _instanceId;

View File

@ -200,7 +200,7 @@ private:
// owns
MonitorModule _monitorModule;
AudioFrame _audioFrame;
PushResampler resampler_; // ADM sample rate -> mixing rate
PushResampler<int16_t> resampler_; // ADM sample rate -> mixing rate
FilePlayer* _filePlayerPtr;
FileRecorder* _fileRecorderPtr;
FileRecorder* _fileCallRecorderPtr;

View File

@ -25,7 +25,7 @@ namespace voe {
// ConvertToCodecFormat, but if we're to consolidate we should probably make a
// real converter class.
void RemixAndResample(const AudioFrame& src_frame,
PushResampler* resampler,
PushResampler<int16_t>* resampler,
AudioFrame* dst_frame) {
const int16_t* audio_ptr = src_frame.data_;
int audio_ptr_num_channels = src_frame.num_channels_;
@ -76,7 +76,7 @@ void DownConvertToCodecFormat(const int16_t* src_data,
int codec_num_channels,
int codec_rate_hz,
int16_t* mono_buffer,
PushResampler* resampler,
PushResampler<int16_t>* resampler,
AudioFrame* dst_af) {
assert(samples_per_channel <= kMaxMonoDataSizeSamples);
assert(num_channels == 1 || num_channels == 2);

View File

@ -15,12 +15,12 @@
#ifndef WEBRTC_VOICE_ENGINE_UTILITY_H_
#define WEBRTC_VOICE_ENGINE_UTILITY_H_
#include "webrtc/common_audio/resampler/include/push_resampler.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class AudioFrame;
class PushResampler;
namespace voe {
@ -30,7 +30,7 @@ namespace voe {
//
// On failure, returns -1 and copies |src_frame| to |dst_frame|.
void RemixAndResample(const AudioFrame& src_frame,
PushResampler* resampler,
PushResampler<int16_t>* resampler,
AudioFrame* dst_frame);
// Downmix and downsample the audio in |src_data| to |dst_af| as necessary,
@ -44,7 +44,7 @@ void DownConvertToCodecFormat(const int16_t* src_data,
int codec_num_channels,
int codec_rate_hz,
int16_t* mono_buffer,
PushResampler* resampler,
PushResampler<int16_t>* resampler,
AudioFrame* dst_af);
void MixWithSat(int16_t target[],

View File

@ -39,7 +39,7 @@ class UtilityTest : public ::testing::Test {
int dst_channels, int dst_sample_rate_hz,
FunctionToTest function);
PushResampler resampler_;
PushResampler<int16_t> resampler_;
AudioFrame src_frame_;
AudioFrame dst_frame_;
AudioFrame golden_frame_;
@ -127,11 +127,11 @@ void VerifyFramesAreEqual(const AudioFrame& ref_frame,
}
void UtilityTest::RunResampleTest(int src_channels,
int src_sample_rate_hz,
int dst_channels,
int dst_sample_rate_hz,
FunctionToTest function) {
PushResampler resampler; // Create a new one with every test.
int src_sample_rate_hz,
int dst_channels,
int dst_sample_rate_hz,
FunctionToTest function) {
PushResampler<int16_t> resampler; // Create a new one with every test.
const int16_t kSrcLeft = 30; // Shouldn't overflow for any used sample rate.
const int16_t kSrcRight = 15;
const float resampling_factor = (1.0 * src_sample_rate_hz) /