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

View File

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

View File

@ -16,7 +16,7 @@
namespace webrtc { namespace webrtc {
TEST(PushResamplerTest, VerifiesInputParameters) { TEST(PushResamplerTest, VerifiesInputParameters) {
PushResampler resampler; PushResampler<int16_t> resampler;
EXPECT_EQ(-1, resampler.InitializeIfNeeded(-1, 16000, 1)); EXPECT_EQ(-1, resampler.InitializeIfNeeded(-1, 16000, 1));
EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, -1, 1)); EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, -1, 1));
EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, 16000, 0)); 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; virtual void Run(int frames, float* destination) OVERRIDE;
SincResampler* get_resampler_for_testing() { return resampler_.get(); } 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: private:
scoped_ptr<SincResampler> resampler_; scoped_ptr<SincResampler> resampler_;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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