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:
parent
3d9ec1fed4
commit
f5a33f145b
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
|
@ -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_;
|
||||||
|
@ -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
|
||||||
|
@ -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_
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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[],
|
||||||
|
@ -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) /
|
||||||
|
Loading…
x
Reference in New Issue
Block a user