Revision control

Copy as Markdown

/*
Copyright 2018 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS-IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "graph/occlusion_node.h"
#include "third_party/googletest/googletest/include/gtest/gtest.h"
#include "base/constants_and_types.h"
#include "utils/test_util.h"
namespace vraudio {
namespace {
// Number of frames per buffer.
const size_t kFramesPerBuffer = 256;
// Sampling rate.
const int kSampleRate = 48000;
// Generated sawtooth length for test buffers.
const size_t kSawtoothLength = 16;
// Source id.
const SourceId kSourceId = 1;
} // namespace
class OcclusionNodeTest : public ::testing::Test {
protected:
OcclusionNodeTest()
: system_settings_(kNumStereoChannels, kFramesPerBuffer, kSampleRate) {}
void SetUp() override {
system_settings_.GetSourceParametersManager()->Register(kSourceId);
}
// Function which wraps the buffer passed in a vector for processing and
// returns the output of the occlusion nodes AudioProcess method.
const AudioBuffer* GetProcessedData(const AudioBuffer* input_buffer,
OcclusionNode* occlusion_node) {
std::vector<const AudioBuffer*> input_buffers;
input_buffers.push_back(input_buffer);
return occlusion_node->AudioProcess(
ProcessingNode::NodeInput(input_buffers));
}
// Returns a pointer to the parameters of the source.
SourceParameters* GetParameters() {
return system_settings_.GetSourceParametersManager()->GetMutableParameters(
kSourceId);
}
// System settings.
SystemSettings system_settings_;
};
// Test to ensure that no effect is made on a buffer of input if both occlusion
// and self-occlusion are absent.
TEST_F(OcclusionNodeTest, NoOcclusionTest) {
OcclusionNode occlusion_processor(kSourceId, system_settings_);
AudioBuffer input(1, kFramesPerBuffer);
input.set_source_id(kSourceId);
GenerateSawToothSignal(kSawtoothLength, &input[0]);
const AudioBuffer* output = GetProcessedData(&input, &occlusion_processor);
const bool buffers_identical =
CompareAudioBuffers((*output)[0], input[0], kEpsilonFloat);
EXPECT_TRUE(buffers_identical);
}
// Test to ensure that a more heavily occluded object shows a lower energy
// output.
TEST_F(OcclusionNodeTest, OcclusionTest) {
OcclusionNode occlusion_processor_1(kSourceId, system_settings_);
OcclusionNode occlusion_processor_2(kSourceId, system_settings_);
AudioBuffer input(kNumMonoChannels, kFramesPerBuffer);
GenerateSawToothSignal(kSawtoothLength, &input[0]);
AudioBuffer input_1;
input_1 = input;
input_1.set_source_id(kSourceId);
AudioBuffer input_2;
input_2 = input;
input_2.set_source_id(kSourceId);
SourceParameters* parameters = GetParameters();
parameters->occlusion_intensity = 0.5f;
const AudioBuffer* output_1 =
GetProcessedData(&input_1, &occlusion_processor_1);
parameters->occlusion_intensity = 1.0f;
const AudioBuffer* output_2 =
GetProcessedData(&input_2, &occlusion_processor_2);
const double output_1_energy = CalculateSignalRms((*output_1)[0]);
const double output_2_energy = CalculateSignalRms((*output_2)[0]);
const double input_energy = CalculateSignalRms(input[0]);
EXPECT_LT(output_1_energy, input_energy);
EXPECT_LT(output_2_energy, output_1_energy);
}
// Test to ensure that setting a non-omnidirectional listener directivity
// pattern shows a lower energy output when the listener orientation is pointing
// away from a source.
TEST_F(OcclusionNodeTest, ListenerDirectivityTest) {
OcclusionNode occlusion_processor(kSourceId, system_settings_);
AudioBuffer input(kNumMonoChannels, kFramesPerBuffer);
input.set_source_id(kSourceId);
GenerateSawToothSignal(kSawtoothLength, &input[0]);
// Set a hyper-cardioid shaped listener directivity for the source input.
SourceParameters* parameters = GetParameters();
parameters->listener_directivity_alpha = 0.5f;
parameters->listener_directivity_order = 2.0f;
// Set listener position to one meter away from the origin in Z axis. This is
// required for the listener directivity properties to take effect.
system_settings_.SetHeadPosition(WorldPosition(0.0f, 0.0f, 1.0f));
const double input_energy = CalculateSignalRms(input[0]);
// Process input with identity listener orientation.
const AudioBuffer* output_default =
GetProcessedData(&input, &occlusion_processor);
const double output_default_energy = CalculateSignalRms((*output_default)[0]);
// Process input with 90 degrees rotated listener orientation about Y axis.
system_settings_.SetHeadRotation(
WorldRotation(0.0f, kInverseSqrtTwo, 0.0f, kInverseSqrtTwo));
const AudioBuffer* output_rotated =
GetProcessedData(&input, &occlusion_processor);
const double output_rotated_energy = CalculateSignalRms((*output_rotated)[0]);
// Test if the output energy is lower when the listener was rotated away from
// the source.
EXPECT_NEAR(output_default_energy, input_energy, kEpsilonFloat);
EXPECT_LT(output_rotated_energy, output_default_energy);
}
// Test to ensure that a more heavily self occluded source shows a lower energy
// output.
TEST_F(OcclusionNodeTest, SourceDirectivityTest) {
OcclusionNode occlusion_processor_1(kSourceId, system_settings_);
OcclusionNode occlusion_processor_2(kSourceId, system_settings_);
AudioBuffer input(kNumMonoChannels, kFramesPerBuffer);
input.set_source_id(kSourceId);
GenerateSawToothSignal(kSawtoothLength, &input[0]);
AudioBuffer input_1;
input_1 = input;
AudioBuffer input_2;
input_2 = input;
SourceParameters* parameters = GetParameters();
parameters->directivity_alpha = 0.25f;
parameters->directivity_order = 2.0f;
const AudioBuffer* output_1 =
GetProcessedData(&input_1, &occlusion_processor_1);
parameters->directivity_order = 4.0f;
parameters->directivity_alpha = 0.25f;
const AudioBuffer* output_2 =
GetProcessedData(&input_2, &occlusion_processor_2);
const double output_1_energy = CalculateSignalRms((*output_1)[0]);
const double output_2_energy = CalculateSignalRms((*output_2)[0]);
const double input_energy = CalculateSignalRms(input[0]);
EXPECT_LT(output_1_energy, input_energy);
EXPECT_LT(output_2_energy, output_1_energy);
}
} // namespace vraudio