Optimize minimum delay in blocker
Could not hear any difference when running the beamformer_test, although sample-wise it changes because of the non-linear character of the processing. R=andrew@webrtc.org Review URL: https://webrtc-codereview.appspot.com/35679004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@8051 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -83,6 +83,16 @@ void ApplyWindow(const float* window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gcd(int a, int b) {
|
||||||
|
int tmp;
|
||||||
|
while (b) {
|
||||||
|
tmp = a;
|
||||||
|
a = b;
|
||||||
|
b = tmp % b;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@@ -98,7 +108,7 @@ Blocker::Blocker(int chunk_size,
|
|||||||
block_size_(block_size),
|
block_size_(block_size),
|
||||||
num_input_channels_(num_input_channels),
|
num_input_channels_(num_input_channels),
|
||||||
num_output_channels_(num_output_channels),
|
num_output_channels_(num_output_channels),
|
||||||
initial_delay_(block_size_),
|
initial_delay_(block_size_ - gcd(chunk_size, shift_amount)),
|
||||||
frame_offset_(0),
|
frame_offset_(0),
|
||||||
input_buffer_(chunk_size_ + initial_delay_, num_input_channels_),
|
input_buffer_(chunk_size_ + initial_delay_, num_input_channels_),
|
||||||
output_buffer_(chunk_size_ + initial_delay_, num_output_channels_),
|
output_buffer_(chunk_size_ + initial_delay_, num_output_channels_),
|
||||||
|
@@ -80,8 +80,6 @@ class Blocker {
|
|||||||
const int num_output_channels_;
|
const int num_output_channels_;
|
||||||
|
|
||||||
// The number of frames of delay to add at the beginning of the first chunk.
|
// The number of frames of delay to add at the beginning of the first chunk.
|
||||||
//
|
|
||||||
// TODO(claguna): find a lower cap for this than |block_size_|.
|
|
||||||
const int initial_delay_;
|
const int initial_delay_;
|
||||||
|
|
||||||
// The frame index into the input buffer where the first block should be read
|
// The frame index into the input buffer where the first block should be read
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Callback Function to add 3 to every sample in the signal.
|
// Callback Function to add 3 to every sample in the signal.
|
||||||
class SimpleBlockerCallback : public webrtc::BlockerCallback {
|
class PlusThreeBlockerCallback : public webrtc::BlockerCallback {
|
||||||
public:
|
public:
|
||||||
virtual void ProcessBlock(const float* const* input,
|
virtual void ProcessBlock(const float* const* input,
|
||||||
int num_frames,
|
int num_frames,
|
||||||
@@ -30,6 +30,22 @@ class SimpleBlockerCallback : public webrtc::BlockerCallback {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// No-op Callback Function.
|
||||||
|
class CopyBlockerCallback : public webrtc::BlockerCallback {
|
||||||
|
public:
|
||||||
|
virtual void ProcessBlock(const float* const* input,
|
||||||
|
int num_frames,
|
||||||
|
int num_input_channels,
|
||||||
|
int num_output_channels,
|
||||||
|
float* const* output) OVERRIDE {
|
||||||
|
for (int i = 0; i < num_output_channels; ++i) {
|
||||||
|
for (int j = 0; j < num_frames; ++j) {
|
||||||
|
output[i][j] = input[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@@ -75,6 +91,21 @@ class BlockerTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValidateInitialDelay(const float* const* output,
|
||||||
|
int num_channels,
|
||||||
|
int num_frames,
|
||||||
|
int initial_delay) {
|
||||||
|
for (int i = 0; i < num_channels; ++i) {
|
||||||
|
for (int j = 0; j < num_frames; ++j) {
|
||||||
|
if (j < initial_delay) {
|
||||||
|
EXPECT_FLOAT_EQ(output[i][j], 0.f);
|
||||||
|
} else {
|
||||||
|
EXPECT_GT(output[i][j], 0.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void CopyTo(float* const* dst,
|
static void CopyTo(float* const* dst,
|
||||||
int start_index_dst,
|
int start_index_dst,
|
||||||
int start_index_src,
|
int start_index_src,
|
||||||
@@ -104,8 +135,8 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) {
|
|||||||
const ChannelBuffer<float> input_cb(kInput[0], kNumFrames, kNumInputChannels);
|
const ChannelBuffer<float> input_cb(kInput[0], kNumFrames, kNumInputChannels);
|
||||||
|
|
||||||
const float kExpectedOutput[kNumInputChannels][kNumFrames] = {
|
const float kExpectedOutput[kNumInputChannels][kNumFrames] = {
|
||||||
{6, 6, 12, 12, 20, 20, 20, 20, 20, 20},
|
{6, 6, 12, 20, 20, 20, 20, 20, 20, 20},
|
||||||
{6, 6, 12, 12, 28, 28, 28, 28, 28, 28}};
|
{6, 6, 12, 28, 28, 28, 28, 28, 28, 28}};
|
||||||
const ChannelBuffer<float> expected_output_cb(
|
const ChannelBuffer<float> expected_output_cb(
|
||||||
kExpectedOutput[0], kNumFrames, kNumInputChannels);
|
kExpectedOutput[0], kNumFrames, kNumInputChannels);
|
||||||
|
|
||||||
@@ -115,7 +146,7 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) {
|
|||||||
ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
|
ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
|
||||||
ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
|
ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
|
||||||
|
|
||||||
SimpleBlockerCallback callback;
|
PlusThreeBlockerCallback callback;
|
||||||
Blocker blocker(kChunkSize,
|
Blocker blocker(kChunkSize,
|
||||||
kBlockSize,
|
kBlockSize,
|
||||||
kNumInputChannels,
|
kNumInputChannels,
|
||||||
@@ -154,11 +185,11 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) {
|
|||||||
{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
|
{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
|
||||||
const ChannelBuffer<float> input_cb(kInput[0], kNumFrames, kNumInputChannels);
|
const ChannelBuffer<float> input_cb(kInput[0], kNumFrames, kNumInputChannels);
|
||||||
|
|
||||||
const float kExpectedOutput[kNumInputChannels][kNumFrames] = {
|
const float kExpectedOutput[kNumOutputChannels][kNumFrames] = {
|
||||||
{6, 6, 6, 12, 10, 10, 20, 10, 10, 20, 10, 10},
|
{6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10},
|
||||||
{6, 6, 6, 12, 14, 14, 28, 14, 14, 28, 14, 14}};
|
{6, 14, 14, 28, 14, 14, 28, 14, 14, 28, 14, 14}};
|
||||||
const ChannelBuffer<float> expected_output_cb(
|
const ChannelBuffer<float> expected_output_cb(
|
||||||
kExpectedOutput[0], kNumFrames, kNumInputChannels);
|
kExpectedOutput[0], kNumFrames, kNumOutputChannels);
|
||||||
|
|
||||||
const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
|
const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
|
||||||
|
|
||||||
@@ -166,7 +197,7 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) {
|
|||||||
ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
|
ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
|
||||||
ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
|
ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
|
||||||
|
|
||||||
SimpleBlockerCallback callback;
|
PlusThreeBlockerCallback callback;
|
||||||
Blocker blocker(kChunkSize,
|
Blocker blocker(kChunkSize,
|
||||||
kBlockSize,
|
kBlockSize,
|
||||||
kNumInputChannels,
|
kNumInputChannels,
|
||||||
@@ -205,11 +236,11 @@ TEST_F(BlockerTest, TestBlockerNoOverlap) {
|
|||||||
{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
|
{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
|
||||||
const ChannelBuffer<float> input_cb(kInput[0], kNumFrames, kNumInputChannels);
|
const ChannelBuffer<float> input_cb(kInput[0], kNumFrames, kNumInputChannels);
|
||||||
|
|
||||||
const float kExpectedOutput[kNumInputChannels][kNumFrames] = {
|
const float kExpectedOutput[kNumOutputChannels][kNumFrames] = {
|
||||||
{6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10},
|
{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
|
||||||
{6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, 14}};
|
{14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}};
|
||||||
const ChannelBuffer<float> expected_output_cb(
|
const ChannelBuffer<float> expected_output_cb(
|
||||||
kExpectedOutput[0], kNumFrames, kNumInputChannels);
|
kExpectedOutput[0], kNumFrames, kNumOutputChannels);
|
||||||
|
|
||||||
const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
|
const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
|
||||||
|
|
||||||
@@ -217,7 +248,7 @@ TEST_F(BlockerTest, TestBlockerNoOverlap) {
|
|||||||
ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
|
ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
|
||||||
ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
|
ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
|
||||||
|
|
||||||
SimpleBlockerCallback callback;
|
PlusThreeBlockerCallback callback;
|
||||||
Blocker blocker(kChunkSize,
|
Blocker blocker(kChunkSize,
|
||||||
kBlockSize,
|
kBlockSize,
|
||||||
kNumInputChannels,
|
kNumInputChannels,
|
||||||
@@ -242,4 +273,63 @@ TEST_F(BlockerTest, TestBlockerNoOverlap) {
|
|||||||
kNumFrames);
|
kNumFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(BlockerTest, InitialDelaysAreMinimum) {
|
||||||
|
const int kNumInputChannels = 3;
|
||||||
|
const int kNumOutputChannels = 2;
|
||||||
|
const int kNumFrames = 1280;
|
||||||
|
const int kChunkSize[] =
|
||||||
|
{80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160};
|
||||||
|
const int kBlockSize[] =
|
||||||
|
{64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256};
|
||||||
|
const int kShiftAmount[] =
|
||||||
|
{16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256};
|
||||||
|
const int kInitialDelay[] =
|
||||||
|
{48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224};
|
||||||
|
|
||||||
|
float input[kNumInputChannels][kNumFrames];
|
||||||
|
for (int i = 0; i < kNumInputChannels; ++i) {
|
||||||
|
for (int j = 0; j < kNumFrames; ++j) {
|
||||||
|
input[i][j] = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const ChannelBuffer<float> input_cb(input[0], kNumFrames, kNumInputChannels);
|
||||||
|
|
||||||
|
ChannelBuffer<float> output_cb(kNumFrames, kNumOutputChannels);
|
||||||
|
|
||||||
|
CopyBlockerCallback callback;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (sizeof(kChunkSize) / sizeof(*kChunkSize)); ++i) {
|
||||||
|
scoped_ptr<float[]> window(new float[kBlockSize[i]]);
|
||||||
|
for (int j = 0; j < kBlockSize[i]; ++j) {
|
||||||
|
window[j] = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels);
|
||||||
|
ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels);
|
||||||
|
|
||||||
|
Blocker blocker(kChunkSize[i],
|
||||||
|
kBlockSize[i],
|
||||||
|
kNumInputChannels,
|
||||||
|
kNumOutputChannels,
|
||||||
|
window.get(),
|
||||||
|
kShiftAmount[i],
|
||||||
|
&callback);
|
||||||
|
|
||||||
|
RunTest(&blocker,
|
||||||
|
kChunkSize[i],
|
||||||
|
kNumFrames,
|
||||||
|
input_cb.channels(),
|
||||||
|
input_chunk_cb.channels(),
|
||||||
|
output_cb.channels(),
|
||||||
|
output_chunk_cb.channels(),
|
||||||
|
kNumInputChannels,
|
||||||
|
kNumOutputChannels);
|
||||||
|
|
||||||
|
ValidateInitialDelay(output_cb.channels(),
|
||||||
|
kNumOutputChannels,
|
||||||
|
kNumFrames,
|
||||||
|
kInitialDelay[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@@ -53,12 +53,7 @@ class FftCheckerCallback : public webrtc::LappedTransform::Callback {
|
|||||||
float full_length = (frames - 1) * 2;
|
float full_length = (frames - 1) * 2;
|
||||||
++block_num_;
|
++block_num_;
|
||||||
|
|
||||||
if (block_num_ == 1) {
|
if (block_num_ > 0) {
|
||||||
for (int i = 0; i < frames; ++i) {
|
|
||||||
ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
|
|
||||||
ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ASSERT_NEAR(in_block[0][0].real(), full_length, 1e-5f);
|
ASSERT_NEAR(in_block[0][0].real(), full_length, 1e-5f);
|
||||||
ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
|
ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
|
||||||
for (int i = 1; i < frames; ++i) {
|
for (int i = 1; i < frames; ++i) {
|
||||||
@@ -114,7 +109,7 @@ TEST(LappedTransformTest, Windowless) {
|
|||||||
|
|
||||||
for (int i = 0; i < kChannels; ++i) {
|
for (int i = 0; i < kChannels; ++i) {
|
||||||
for (int j = 0; j < kChunkLength; ++j) {
|
for (int j = 0; j < kChunkLength; ++j) {
|
||||||
ASSERT_NEAR(out_chunk[i][j], (j < kBlockLength) ? 0.0f : 2.0f, 1e-5f);
|
ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +140,9 @@ TEST(LappedTransformTest, IdentityProcessor) {
|
|||||||
trans.ProcessChunk(&in_chunk, &out_chunk);
|
trans.ProcessChunk(&in_chunk, &out_chunk);
|
||||||
|
|
||||||
for (int i = 0; i < kChunkLength; ++i) {
|
for (int i = 0; i < kChunkLength; ++i) {
|
||||||
ASSERT_NEAR(out_chunk[i], (i < kBlockLength) ? 0.0f : 2.0f, 1e-5f);
|
ASSERT_NEAR(out_chunk[i],
|
||||||
|
(i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
|
||||||
|
1e-5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
|
ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
|
||||||
|
Reference in New Issue
Block a user