Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Unified Diff: media/filters/audio_renderer_algorithm_unittest.cc

Issue 19111004: Upgrade AudioRendererAlgorithm to use WSOLA, (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/filters/audio_renderer_algorithm_unittest.cc
diff --git a/media/filters/audio_renderer_algorithm_unittest.cc b/media/filters/audio_renderer_algorithm_unittest.cc
index d5119c00c2b116022f095c868bd059b7f5d67a5b..5cd3eeb01ec7e56efb6f127954e259312dbb05f3 100644
--- a/media/filters/audio_renderer_algorithm_unittest.cc
+++ b/media/filters/audio_renderer_algorithm_unittest.cc
@@ -12,19 +12,49 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
#include "media/base/audio_buffer.h"
#include "media/base/audio_bus.h"
#include "media/base/buffers.h"
#include "media/base/channel_layout.h"
#include "media/base/test_helpers.h"
#include "media/filters/audio_renderer_algorithm.h"
+#include "media/filters/audio_renderer_algorithm_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-
namespace media {
static const int kFrameSize = 250;
static const int kSamplesPerSecond = 3000;
static const SampleFormat kSampleFormat = kSampleFormatS16;
+static const int kOutputDurationInSec = 10;
+
+static void FillWithSquarePuleTrain(
ajm 2013/07/23 18:03:28 Pule -> Pulse
turaj 2013/07/29 22:09:57 Done.
+ int pulse_width, int offset, int channel, AudioBus* audio_bus) {
+ float* ch = audio_bus->channel(channel);
+
+ // Fill backward from |offset| - 1 toward zero, starting with -1, alternating
+ // between -1 and 1 every |pulse_width| samples.
+ int pulse = -1;
+ for (int n = offset - 1, k = 0; n >= 0; --n, ++k) {
+ if (k >= pulse_width) {
+ pulse = -pulse;
+ k = 0;
+ }
+ ch[n] = pulse;
+ }
+
+ // Fill forward from |offset| towards the end, starting with 1, alternating
+ // between 1 and -1 every |pulse_width| samples.
+ pulse = 1;
+ for (int n = offset, k = 0; n < audio_bus->frames(); ++n, ++k) {
+ if (k >= pulse_width) {
+ pulse = -pulse;
+ k = 0;
+ }
+ ch[n] = pulse;
+ }
+}
+
class AudioRendererAlgorithmTest : public testing::Test {
public:
@@ -118,7 +148,8 @@ class AudioRendererAlgorithmTest : public testing::Test {
void TestPlaybackRate(double playback_rate) {
const int kDefaultBufferSize = algorithm_.samples_per_second() / 100;
- const int kDefaultFramesRequested = 2 * algorithm_.samples_per_second();
+ const int kDefaultFramesRequested = kOutputDurationInSec *
+ algorithm_.samples_per_second();
TestPlaybackRate(
playback_rate, kDefaultBufferSize, kDefaultFramesRequested);
@@ -270,7 +301,7 @@ TEST_F(AudioRendererAlgorithmTest, FillBuffer_JumpAroundSpeeds) {
TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) {
Initialize();
static const int kBufferSizeInFrames = 1;
- static const int kFramesRequested = 2 * kSamplesPerSecond;
+ static const int kFramesRequested = kOutputDurationInSec * kSamplesPerSecond;
TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested);
TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested);
TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested);
@@ -297,4 +328,174 @@ TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) {
TestPlaybackRate(1.5);
}
+TEST_F(AudioRendererAlgorithmTest, DotProduct) {
+ const int kChannels = 3;
+ const int kFrames = 20;
+ const int kPulseWidth = 2;
+
+ scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
+ scoped_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames);
+
+ scoped_ptr<float[]> dot_prod(new float[kChannels]);
+
+ FillWithSquarePuleTrain(kPulseWidth, 0, 0, a.get());
+ FillWithSquarePuleTrain(kPulseWidth, 1, 1, a.get());
+ FillWithSquarePuleTrain(kPulseWidth, 2, 2, a.get());
+
+ FillWithSquarePuleTrain(kPulseWidth, 0, 0, b.get());
+ FillWithSquarePuleTrain(kPulseWidth, 0, 1, b.get());
+ FillWithSquarePuleTrain(kPulseWidth, 0, 2, b.get());
+
+ MultiChannelDotProduct(a.get(), 0, b.get(), 0, kFrames, dot_prod.get());
+
+ EXPECT_FLOAT_EQ(kFrames, dot_prod[0]);
+ EXPECT_FLOAT_EQ(0, dot_prod[1]);
+ EXPECT_FLOAT_EQ(-kFrames, dot_prod[2]);
+
+ MultiChannelDotProduct(a.get(), 4, b.get(), 8, kFrames / 2, dot_prod.get());
+
+ EXPECT_FLOAT_EQ(kFrames / 2, dot_prod[0]);
+ EXPECT_FLOAT_EQ(0, dot_prod[1]);
+ EXPECT_FLOAT_EQ(-kFrames / 2, dot_prod[2]);
+}
+
+TEST_F(AudioRendererAlgorithmTest, MovingWindowEnergy) {
+ const int kChannels = 2;
+ const int kFrames = 20;
+ const int kFramesPerBlock = 3;
+ const int kNumBlocks = kFrames - (kFramesPerBlock - 1);
+ scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
+ scoped_ptr<float[]> energies(new float[kChannels * kNumBlocks]);
+ float* ch_left = a->channel(0);
+ float* ch_right = a->channel(1);
+
+ // Fill up both channels.
+ for (int n = 0; n < kFrames; ++n) {
+ ch_left[n] = n;
+ ch_right[n] = kFrames - 1 - n;
+ }
+
+ MultiChannelMovingWindowEnergies(a.get(), kFramesPerBlock, energies.get());
+
+ for (int n = 0; n < kNumBlocks; ++n) {
+ float expected_energy = 0;
+ for (int k = 0; k < kFramesPerBlock; ++k)
+ expected_energy += ch_left[n + k] * ch_left[n + k];
+ EXPECT_FLOAT_EQ(expected_energy, energies[2 * n]);
+
+ expected_energy = 0;
+ for (int k = 0; k < kFramesPerBlock; ++k)
+ expected_energy += ch_right[n + k] * ch_right[n + k];
+ EXPECT_FLOAT_EQ(expected_energy, energies[2 * n + 1]);
+ }
+}
+
+TEST_F(AudioRendererAlgorithmTest, PartialAndDecimatedSearch) {
+ const int kFramesInSearchRegion = 12;
+ const int kChannels = 2;
+ float ch_0[] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0};
+ float ch_1[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 1.0, 0.1, 0.0, 0.0};
+ ASSERT_EQ(sizeof(ch_0), sizeof(ch_1));
+ ASSERT_EQ(static_cast<size_t>(kFramesInSearchRegion),
+ sizeof(ch_0) / sizeof(*ch_0));
+ scoped_ptr<AudioBus> search_region = AudioBus::CreateWrapper(kChannels);
+
+ search_region->SetChannelData(0, ch_0);
+ search_region->SetChannelData(1, ch_1);
+ search_region->set_frames(kFramesInSearchRegion);
+ ASSERT_EQ(kFramesInSearchRegion, search_region->frames());
+
+ const int kFramePerBlock = 4;
+ float target_0[] = {1.0, 1.0, 1.0, 0.0};
+ float target_1[] = {0.0, 1.0, 0.1, 1.0};
+ ASSERT_EQ(sizeof(target_0), sizeof(target_1));
+ ASSERT_EQ(static_cast<size_t>(kFramePerBlock),
+ sizeof(target_0) / sizeof(*target_0));
+
+ scoped_ptr<AudioBus> target = AudioBus::CreateWrapper(2);
+ target->SetChannelData(0, target_0);
+ target->SetChannelData(1, target_1);
+ target->set_frames(kFramePerBlock);
+ ASSERT_EQ(kFramePerBlock, target->frames());
+
+ scoped_ptr<float[]> energy_target(new float[kChannels]);
+
+ MultiChannelDotProduct(target.get(), 0, target.get(), 0, kFramePerBlock,
+ energy_target.get());
+
+ ASSERT_EQ(3.f, energy_target[0]);
+ ASSERT_EQ(2.01f, energy_target[1]);
+
+ const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1);
+ scoped_ptr<float[]> energy_candid_blocks(new float[kNumCandidBlocks *
+ kChannels]);
+
+ MultiChannelMovingWindowEnergies(search_region.get(), kFramePerBlock,
+ energy_candid_blocks.get());
+
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[0]);
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[2]);
+ ASSERT_FLOAT_EQ(1, energy_candid_blocks[4]);
+ ASSERT_FLOAT_EQ(2, energy_candid_blocks[6]);
+ ASSERT_FLOAT_EQ(3, energy_candid_blocks[8]);
+ ASSERT_FLOAT_EQ(3, energy_candid_blocks[10]);
+ ASSERT_FLOAT_EQ(2, energy_candid_blocks[12]);
+ ASSERT_FLOAT_EQ(1, energy_candid_blocks[14]);
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[16]);
+
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[1]);
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[3]);
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[5]);
+ ASSERT_FLOAT_EQ(0, energy_candid_blocks[7]);
+ ASSERT_FLOAT_EQ(0.01, energy_candid_blocks[9]);
+ ASSERT_FLOAT_EQ(1.01, energy_candid_blocks[11]);
+ ASSERT_FLOAT_EQ(1.02, energy_candid_blocks[13]);
+ ASSERT_FLOAT_EQ(1.02, energy_candid_blocks[15]);
+ ASSERT_FLOAT_EQ(1.01, energy_candid_blocks[17]);
+
+ // An interval which is of no effect.
+ interval exclude_interval = std::make_pair(-100, -10);
+ EXPECT_EQ(5, PartialSearch(0, kNumCandidBlocks - 1, exclude_interval,
+ target.get(), search_region.get(),
+ energy_target.get(), energy_candid_blocks.get()));
+
+ // Exclude the the best match.
+ exclude_interval = std::make_pair(2, 5);
+ EXPECT_EQ(7, PartialSearch(0, kNumCandidBlocks - 1, exclude_interval,
+ target.get(), search_region.get(),
+ energy_target.get(), energy_candid_blocks.get()));
+
+ // An interval which is of no effect.
+ exclude_interval = std::make_pair(-100, -10);
+ EXPECT_EQ(4, DecimatedSearch(4, exclude_interval, target.get(),
+ search_region.get(), energy_target.get(),
+ energy_candid_blocks.get()));
+
+ EXPECT_EQ(5, OptimalIndex(search_region.get(), target.get(),
+ exclude_interval));
+}
+
+TEST_F(AudioRendererAlgorithmTest, CubicInterpolation) {
+ // Arbitrary coefficients.
+ const float kA = 0.7;
+ const float kB = 1.2;
+ const float kC = 0.8;
+
+ float y_values[3];
+ y_values[0] = kA - kB + kC;
+ y_values[1] = kC;
+ y_values[2] = kA + kB + kC;
+
+ float extremum;
+ float extremum_value;
+
+ CubicInterpol(y_values, &extremum, &extremum_value);
+
+ float x_star = -kB / (2.f * kA);
+ float y_star = kA * x_star * x_star + kB * x_star + kC;
+
+ EXPECT_FLOAT_EQ(x_star, extremum);
+ EXPECT_FLOAT_EQ(y_star, extremum_value);
+}
+
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698