diff options
Diffstat (limited to 'src/3rdparty/resonance-audio/resonance_audio/utils/planar_interleaved_conversion_test.cc')
-rw-r--r-- | src/3rdparty/resonance-audio/resonance_audio/utils/planar_interleaved_conversion_test.cc | 875 |
1 files changed, 875 insertions, 0 deletions
diff --git a/src/3rdparty/resonance-audio/resonance_audio/utils/planar_interleaved_conversion_test.cc b/src/3rdparty/resonance-audio/resonance_audio/utils/planar_interleaved_conversion_test.cc new file mode 100644 index 000000000..abfd31b82 --- /dev/null +++ b/src/3rdparty/resonance-audio/resonance_audio/utils/planar_interleaved_conversion_test.cc @@ -0,0 +1,875 @@ +/* +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 + + http://www.apache.org/licenses/LICENSE-2.0 + +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 "utils/planar_interleaved_conversion.h" + +#include <algorithm> + +#include "third_party/googletest/googletest/include/gtest/gtest.h" +#include "base/audio_buffer.h" +#include "base/constants_and_types.h" +#include "base/misc_math.h" + +namespace vraudio { + +namespace { + +// Epsilon for conversion from int16_t back to float. +const float kFloatEpsilon = 1e-4f; +const int16_t kIntEpsilon = 1; + +const int kMemoryAlignmentBytesInt = static_cast<int>(kMemoryAlignmentBytes); + +const size_t kMaxNumFrames = 16; +const size_t kMaxNumChannels = 8; + +int16_t SingleFloatToInt16(float value) { + const float kInt16Min = static_cast<float>(-0x7FFF); + const float kInt16Max = static_cast<float>(0x7FFF); + const float scaled_value = value * kInt16Max; + const float clamped_value = + std::min(kInt16Max, std::max(kInt16Min, scaled_value)); + return static_cast<int16_t>(clamped_value); +} + +// Creates a trivial channel map, i.e. no mapping. +std::vector<size_t> GetTrivialChannelMap(size_t size) { + std::vector<size_t> channel_map(size); + for (size_t i = 0; i < size; ++i) { + channel_map[i] = i; + } + return channel_map; +} + +// Fills an interleaved buffer with the channel number / 10, in each frame +// (converted to integer format). +void FillInterleaved(size_t num_channels, size_t num_frames, int16_t* buffer) { + for (size_t f = 0; f < num_frames; ++f) { + for (size_t c = 0; c < num_channels; ++c) { + buffer[f * num_channels + c] = + SingleFloatToInt16(static_cast<float>(c) * 0.1f); + } + } +} + +// Fills an interleaved buffer with the channel number / 10, in each frame. +void FillInterleaved(size_t num_channels, size_t num_frames, float* buffer) { + for (size_t f = 0; f < num_frames; ++f) { + for (size_t c = 0; c < num_channels; ++c) { + buffer[f * num_channels + c] = static_cast<float>(c) * 0.1f; + } + } +} + +// Fills a planar buffer with the channel number / 10, in each frame. +void FillPlanar(AudioBuffer* buffer) { + for (size_t c = 0; c < buffer->num_channels(); ++c) { + std::fill_n(&(*buffer)[c][0], buffer->num_frames(), + static_cast<float>(c) * 0.1f); + } +} + +// Fills a planar buffer with the channel number / 10, in each frame. +void FillPlanar(size_t num_frames, std::vector<float*>* buffer) { + for (size_t c = 0; c < buffer->size(); ++c) { + std::fill_n((*buffer)[c], num_frames, static_cast<float>(c) * 0.1f); + } +} + +// Fills a planar buffer with the channel number / 10, in each frame (converted +// to integer format). +void FillPlanar(size_t num_frames, int16_t** buffer, size_t num_channels) { + for (size_t c = 0; c < num_channels; ++c) { + std::fill_n(buffer[c], num_frames, + SingleFloatToInt16(static_cast<float>(c) * 0.1f)); + } +} + +// Fills a planar buffer with the channel number / 10, in each frame (converted +// to integer format). +void FillPlanar(size_t num_frames, std::vector<int16_t*>* buffer) { + FillPlanar(num_frames, buffer->data(), buffer->size()); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const std::vector<int16_t*>& expected_output, + const std::vector<int16_t*>& output) { + for (size_t c = 0; c < num_channels; ++c) { + for (size_t f = 0; f < num_frames; ++f) { + EXPECT_NEAR(expected_output[c][f], output[c][f], kIntEpsilon); + } + } +} + +// Verifies that the output and expected output match. +template <typename InputType, typename OutputType> +void VerifyOutputFloatTemplated(size_t num_channels, size_t num_frames, + const InputType& expected_output, + const OutputType& output, + const std::vector<size_t>& channel_map, + size_t output_offset) { + for (size_t c = 0; c < num_channels; ++c) { + for (size_t f = output_offset; f < output_offset + num_frames; ++f) { + EXPECT_NEAR(expected_output[channel_map[c]][f], output[c][f], + kFloatEpsilon); + } + } +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const AudioBuffer& expected_output, + const AudioBuffer& output) { + VerifyOutputFloatTemplated<AudioBuffer, AudioBuffer>( + num_channels, num_frames, expected_output, output, + GetTrivialChannelMap(num_channels), 0); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const std::vector<float*>& expected_output, + const AudioBuffer& output) { + VerifyOutputFloatTemplated<std::vector<float*>, AudioBuffer>( + num_channels, num_frames, expected_output, output, + GetTrivialChannelMap(num_channels), 0); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const AudioBuffer& expected_output, + const std::vector<float*>& output) { + VerifyOutputFloatTemplated<AudioBuffer, std::vector<float*>>( + num_channels, num_frames, expected_output, output, + GetTrivialChannelMap(num_channels), 0); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const std::vector<float*>& expected_output, + const std::vector<float*>& output) { + VerifyOutputFloatTemplated<std::vector<float*>, std::vector<float*>>( + num_channels, num_frames, expected_output, output, + GetTrivialChannelMap(num_channels), 0); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const std::vector<const float*>& expected_output, + const std::vector<const float*>& output) { + VerifyOutputFloatTemplated<std::vector<const float*>, + std::vector<const float*>>( + num_channels, num_frames, expected_output, output, + GetTrivialChannelMap(num_channels), 0); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, + const AudioBuffer& expected_output, const AudioBuffer& output, + const std::vector<size_t>& channel_map) { + VerifyOutputFloatTemplated<AudioBuffer, AudioBuffer>( + num_channels, num_frames, expected_output, output, channel_map, 0); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t num_channels, size_t num_frames, size_t output_offset, + const AudioBuffer& expected_output, + const AudioBuffer& output) { + VerifyOutputFloatTemplated<AudioBuffer, AudioBuffer>( + num_channels, num_frames, expected_output, output, + GetTrivialChannelMap(num_channels), output_offset); +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t length, const std::vector<float>& expected_output, + int16_t* output) { + for (size_t f = 0; f < length; ++f) { + EXPECT_NEAR(SingleFloatToInt16(expected_output[f]), output[f], kIntEpsilon); + } +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t length, const std::vector<float>& expected_output, + const std::vector<int16_t>& output) { + for (size_t f = 0; f < length; ++f) { + EXPECT_NEAR(SingleFloatToInt16(expected_output[f]), output[f], kIntEpsilon); + } +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t length, const std::vector<float>& expected_output, + float* output) { + for (size_t f = 0; f < length; ++f) { + EXPECT_NEAR(expected_output[f], output[f], kIntEpsilon); + } +} + +// Verifies that the output and expected output match. +void VerifyOutput(size_t length, const std::vector<float>& expected_output, + const std::vector<float>& output) { + for (size_t f = 0; f < length; ++f) { + EXPECT_NEAR(expected_output[f], output[f], kIntEpsilon); + } +} + +typedef std::tuple<size_t, size_t> TestParams; +class PlanarInterleavedConverterTest + : public ::testing::Test, + public ::testing::WithParamInterface<TestParams> { + protected: + PlanarInterleavedConverterTest() {} + + // Virtual methods from ::testing::Test + ~PlanarInterleavedConverterTest() override {} + + void SetUp() override {} + + void TearDown() override {} +}; + +// Tests that interleaved (float/int16_t) data can be correctly written into +// vectors of float pointers. +TEST_P(PlanarInterleavedConverterTest, TestInterleavedIntoVectorFloatPtr) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + const size_t num_interleaved_samples = num_frames * num_channels; + + AudioBuffer expected_output(kMaxNumChannels, num_frames); + FillPlanar(&expected_output); + + // Create output buffers memory. + AudioBuffer aligned_output_buffer(kMaxNumChannels, num_frames); + std::vector<float> unaligned_output_memory(num_interleaved_samples); + + // Create output planar buffers. + std::vector<float*> aligned_output(num_channels); + std::vector<float*> unaligned_output(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + aligned_output[c] = &aligned_output_buffer[c][0]; + unaligned_output[c] = &unaligned_output_memory[num_frames * c]; + } + + // Integer. + AudioBuffer::AlignedInt16Vector interleaved_aligned_int( + num_interleaved_samples); + std::vector<int16_t> interleaved_unaligned_int(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_int.data()); + FillInterleaved(num_channels, num_frames, &interleaved_unaligned_int[0]); + + // Aligned Input, Aligned Output. + aligned_output_buffer.Clear(); + LOG(INFO) << "aligned_output.size()" << aligned_output.size(); + LOG(INFO) << "num_frames" << num_frames; + PlanarFromInterleaved(interleaved_aligned_int.data(), num_frames, + num_channels, aligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + aligned_output); + + // Unaligned Input, Aligned Output. + aligned_output_buffer.Clear(); + PlanarFromInterleaved(interleaved_unaligned_int.data(), num_frames, + num_channels, aligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + aligned_output); + + // Aligned Input. Unaligned Output. + std::fill(unaligned_output_memory.begin(), unaligned_output_memory.end(), + 0.0f); + PlanarFromInterleaved(interleaved_aligned_int.data(), num_frames, + num_channels, unaligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + unaligned_output); + // Unligned Input. Unaligned Output. + std::fill(unaligned_output_memory.begin(), unaligned_output_memory.end(), + 0.0f); + PlanarFromInterleaved(&interleaved_unaligned_int[0], num_frames, num_channels, + unaligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + unaligned_output); + + // Floating point. + AudioBuffer::AlignedFloatVector interleaved_aligned_float( + num_interleaved_samples); + std::vector<float> interleaved_plane_float(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_float.data()); + FillInterleaved(num_channels, num_frames, &interleaved_plane_float[0]); + // Aligned Input, Aligned Output. + aligned_output_buffer.Clear(); + PlanarFromInterleaved(interleaved_aligned_float.data(), num_frames, + num_channels, aligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + aligned_output); + // Unaligned Input, Aligned Output. + aligned_output_buffer.Clear(); + PlanarFromInterleaved(&interleaved_plane_float[0], num_frames, num_channels, + aligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + aligned_output); + // Aligned Input. Unaligned Output. + std::fill(unaligned_output_memory.begin(), unaligned_output_memory.end(), + 0.0f); + PlanarFromInterleaved(interleaved_aligned_float.data(), num_frames, + num_channels, unaligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + unaligned_output); + // Unligned Input. Unaligned Output. + std::fill(unaligned_output_memory.begin(), unaligned_output_memory.end(), + 0.0f); + PlanarFromInterleaved(&interleaved_plane_float[0], num_frames, num_channels, + unaligned_output, num_frames); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + unaligned_output); +} + +// Tests that interleaved (float/int16_t) data can be correctly written into +// |AudioBuffer|s. +TEST_P(PlanarInterleavedConverterTest, TestInterleavedIntoAudioBuffer) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + const size_t num_interleaved_samples = num_frames * num_channels; + + AudioBuffer expected_output(num_channels, num_frames); + FillPlanar(&expected_output); + + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + // Integer. + AudioBuffer::AlignedInt16Vector interleaved_aligned_int( + num_interleaved_samples); + std::vector<int16_t> interleaved_unaligned_int(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_int.data()); + FillInterleaved(num_channels, num_frames, &interleaved_unaligned_int[0]); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(interleaved_aligned_int.data(), num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&interleaved_unaligned_int[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + + // Floating point. + AudioBuffer::AlignedFloatVector interleaved_aligned_float( + num_interleaved_samples); + std::vector<float> interleaved_plane_float(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_float.data()); + FillInterleaved(num_channels, num_frames, &interleaved_plane_float[0]); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(interleaved_aligned_float.data(), num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&interleaved_plane_float[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); +} + +// Tests that interleaved (float/int16_t) vectors can be correctly written into +// |AudioBuffer|s. +TEST_P(PlanarInterleavedConverterTest, TestInterleavedVectorIntoAudioBuffer) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + const size_t num_interleaved_samples = num_frames * num_channels; + + AudioBuffer expected_output(num_channels, num_frames); + FillPlanar(&expected_output); + + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + // Integer. + std::vector<int16_t> interleaved_unaligned_int(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, &interleaved_unaligned_int[0]); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&interleaved_unaligned_int[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + + // Floating point. + std::vector<float> interleaved_plane_float(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, &interleaved_plane_float[0]); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&interleaved_plane_float[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); +} + +// Tests that vectors of planar (float/int16_t) pointers can be correctly +// written into |AudioBuffer|s. +TEST_P(PlanarInterleavedConverterTest, TestPlanarPtrsIntoAudioBuffer) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + + AudioBuffer expected_output(kMaxNumChannels, num_frames); + FillPlanar(&expected_output); + + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + // Integer. + std::vector<AudioBuffer::AlignedInt16Vector> planar_aligned_channels_int_buf( + num_channels, AudioBuffer::AlignedInt16Vector(num_frames)); + std::vector<std::vector<int16_t>> planar_unaligned_channels_int_buffers( + num_channels, std::vector<int16_t>(num_frames)); + std::vector<int16_t*> planar_aligned_channels_int(num_channels); + std::vector<int16_t*> planar_unaligned_channels_int(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + planar_aligned_channels_int[c] = planar_aligned_channels_int_buf[c].data(); + planar_unaligned_channels_int[c] = + planar_unaligned_channels_int_buffers[c].data(); + } + FillPlanar(num_frames, &planar_aligned_channels_int); + FillPlanar(num_frames, &planar_unaligned_channels_int); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&planar_aligned_channels_int[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&planar_unaligned_channels_int[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + + // Floating point. + std::vector<AudioBuffer::AlignedFloatVector> + planar_aligned_channels_float_buf( + num_channels, AudioBuffer::AlignedFloatVector(num_frames)); + std::vector<std::vector<float>> planar_unaligned_channels_float_buffers( + num_channels, std::vector<float>(num_frames)); + std::vector<float*> planar_aligned_channels_float(num_channels); + std::vector<float*> planar_unaligned_channels_float(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + planar_aligned_channels_float[c] = + planar_aligned_channels_float_buf[c].data(); + planar_unaligned_channels_float[c] = + planar_unaligned_channels_float_buffers[c].data(); + } + FillPlanar(num_frames, &planar_aligned_channels_float); + FillPlanar(num_frames, &planar_unaligned_channels_float); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&planar_aligned_channels_float[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBuffer(&planar_unaligned_channels_float[0], num_frames, num_channels, + &output_buffer); + VerifyOutput(num_channels, std::min(num_frames, num_frames), expected_output, + output_buffer); +} + +// Tests that interleaved (float/int16_t) data can be correctly written into +// |AudioBuffer|s, with offsets into both the input and output data. +TEST_P(PlanarInterleavedConverterTest, + TestInterleavedIntoAudioBufferWithOffset) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + + AudioBuffer expected_output(kMaxNumChannels, num_frames); + FillPlanar(&expected_output); + + const size_t num_interleaved_samples = num_frames * num_channels; + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + AudioBuffer::AlignedInt16Vector interleaved_aligned_int( + num_interleaved_samples); + std::vector<int16_t> interleaved_unaligned_int(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_int.data()); + FillInterleaved(num_channels, num_frames, &interleaved_unaligned_int[0]); + + AudioBuffer::AlignedFloatVector interleaved_aligned_float( + num_interleaved_samples); + std::vector<float> interleaved_plane_float(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_float.data()); + FillInterleaved(num_channels, num_frames, &interleaved_plane_float[0]); + + for (size_t output_offset = 1; output_offset <= 4; ++output_offset) { + for (size_t input_offset = 1; input_offset <= 4; ++input_offset) { + const size_t num_frames_to_copy = + std::min(num_frames - input_offset, num_frames - output_offset); + // Integer. + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(interleaved_aligned_int.data(), num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(&interleaved_unaligned_int[0], num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + + // Floating point. + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(interleaved_aligned_float.data(), num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(&interleaved_plane_float[0], num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + } + } +} + +// Tests that planar (float/int16_t) data can be correctly written into +// |AudioBuffer|s, with offsets into both the input and output data. +TEST_P(PlanarInterleavedConverterTest, + TestPlanarPtrsIntoAudioBufferWithOffset) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + + AudioBuffer expected_output(num_channels, num_frames); + FillPlanar(&expected_output); + + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + std::vector<AudioBuffer::AlignedInt16Vector> + planar_aligned_channels_int_buffers( + num_channels, AudioBuffer::AlignedInt16Vector(num_frames)); + std::vector<std::vector<int16_t>> planar_unaligned_channels_int_buffers( + num_channels, std::vector<int16_t>(num_frames)); + + std::vector<int16_t*> planar_aligned_channels_int(num_channels); + std::vector<int16_t*> planar_unaligned_channels_int(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + planar_aligned_channels_int[c] = + planar_aligned_channels_int_buffers[c].data(); + planar_unaligned_channels_int[c] = + planar_unaligned_channels_int_buffers[c].data(); + } + FillPlanar(num_frames, &planar_aligned_channels_int); + FillPlanar(num_frames, &planar_unaligned_channels_int); + + std::vector<AudioBuffer::AlignedFloatVector> + planar_aligned_channels_float_buffer( + num_channels, AudioBuffer::AlignedFloatVector(num_frames)); + std::vector<std::vector<float>> planar_unaligned_channels_float_buffers( + num_channels, std::vector<float>(num_frames)); + + std::vector<float*> planar_aligned_channels_float(num_channels); + std::vector<float*> planar_unaligned_channels_float(num_channels); + + for (size_t c = 0; c < num_channels; ++c) { + planar_aligned_channels_float[c] = + planar_aligned_channels_float_buffer[c].data(); + planar_unaligned_channels_float[c] = + planar_unaligned_channels_float_buffers[c].data(); + } + FillPlanar(num_frames, &planar_aligned_channels_float); + FillPlanar(num_frames, &planar_unaligned_channels_float); + + for (size_t output_offset = 1; output_offset <= 4; ++output_offset) { + for (size_t input_offset = 1; input_offset <= 4; ++input_offset) { + const size_t num_frames_to_copy = + std::min(num_frames - input_offset, num_frames - output_offset); + // Integer. + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(&planar_aligned_channels_int[0], num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(&planar_unaligned_channels_int[0], num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + + // Floating point. + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(&planar_aligned_channels_float[0], num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithOffset(&planar_unaligned_channels_float[0], num_frames, + num_channels, input_offset, output_offset, + num_frames_to_copy, &output_buffer); + VerifyOutput(num_channels, num_frames_to_copy, output_offset, + expected_output, output_buffer); + } + } +} + +// Tests that interleaved (float/int16_t) data can be correctly written into +// |AudioBuffer|s, with remapping of channels. +TEST_P(PlanarInterleavedConverterTest, + TestInterleavedIntoAudioBufferRemapping) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + + AudioBuffer expected_output(num_channels, num_frames); + FillPlanar(&expected_output); + + std::vector<size_t> channel_map(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + channel_map[c] = c; + } + + // Permute the channel map. + std::next_permutation(channel_map.begin(), channel_map.end()); + const size_t num_interleaved_samples = num_frames * num_channels; + + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + // Integer. + AudioBuffer::AlignedInt16Vector interleaved_aligned_int( + num_interleaved_samples); + std::vector<int16_t> interleaved_unaligned_int(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_int.data()); + FillInterleaved(num_channels, num_frames, &interleaved_unaligned_int[0]); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(interleaved_aligned_int.data(), + num_frames, num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(&interleaved_unaligned_int[0], num_frames, + num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); + + // Floating point. + AudioBuffer::AlignedFloatVector interleaved_aligned_float( + num_interleaved_samples); + std::vector<float> interleaved_plane_float(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, interleaved_aligned_float.data()); + FillInterleaved(num_channels, num_frames, &interleaved_plane_float[0]); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(interleaved_aligned_float.data(), + num_frames, num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(&interleaved_plane_float[0], num_frames, + num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); +} + +// Tests that planar (float/int16_t) data can be correctly written into +// |AudioBuffer|s, with remapping of channels. +TEST_P(PlanarInterleavedConverterTest, TestPlanarPtrsIntoAudioBufferRemapping) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + + AudioBuffer expected_output(num_channels, num_frames); + FillPlanar(&expected_output); + + std::vector<size_t> channel_map(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + channel_map[c] = c; + } + // Permute the channel map. + std::next_permutation(channel_map.begin(), channel_map.end()); + // Create output buffers memory. + AudioBuffer output_buffer(num_channels, num_frames); + + // Integer. + std::vector<AudioBuffer::AlignedInt16Vector> + planar_aligned_channels_int_bufferss( + num_channels, AudioBuffer::AlignedInt16Vector(num_frames)); + std::vector<std::vector<int16_t>> planar_unaligned_channels_int_buffers( + num_channels, std::vector<int16_t>(num_frames)); + + std::vector<int16_t*> planar_aligned_channels_int(num_channels); + std::vector<int16_t*> planar_unaligned_channels_int(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + planar_aligned_channels_int[c] = + planar_aligned_channels_int_bufferss[c].data(); + planar_unaligned_channels_int[c] = + planar_unaligned_channels_int_buffers[c].data(); + } + + FillPlanar(num_frames, &planar_aligned_channels_int); + FillPlanar(num_frames, &planar_unaligned_channels_int); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(&planar_aligned_channels_int[0], + num_frames, num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(&planar_unaligned_channels_int[0], + num_frames, num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); + + // Floating point. + std::vector<AudioBuffer::AlignedFloatVector> + planar_aligned_channels_float_buffers( + num_channels, AudioBuffer::AlignedFloatVector(num_frames)); + std::vector<std::vector<float>> planar_unaligned_channels_float_buffers( + num_channels, std::vector<float>(num_frames)); + + std::vector<float*> planar_aligned_channels_float(num_channels); + std::vector<float*> planar_unaligned_channels_float(num_channels); + for (size_t c = 0; c < num_channels; ++c) { + planar_aligned_channels_float[c] = + planar_aligned_channels_float_buffers[c].data(); + planar_unaligned_channels_float[c] = + planar_unaligned_channels_float_buffers[c].data(); + } + FillPlanar(num_frames, &planar_aligned_channels_float); + FillPlanar(num_frames, &planar_unaligned_channels_float); + // Aligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(&planar_aligned_channels_float[0], + num_frames, num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); + // Unaligned Input, Aligned Output. + output_buffer.Clear(); + FillAudioBufferWithChannelRemapping(&planar_unaligned_channels_float[0], + num_frames, num_channels, channel_map, + &output_buffer); + VerifyOutput(num_channels, num_frames, expected_output, output_buffer, + channel_map); +} + +// Tests that an |AudioBuffer| can be correctly written into an interleaved +// vector of (float/int16_t) data. +TEST_P(PlanarInterleavedConverterTest, TestAudioBufferIntoInterleavedVector) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + const size_t num_interleaved_samples = num_frames * num_channels; + std::vector<float> expected_output(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, &expected_output[0]); + + // Floating point. + AudioBuffer planar_input(num_channels, num_frames); + FillPlanar(&planar_input); + // Aligned Input, Unaligned Output. + std::vector<float> interleaved_output; + FillExternalBuffer(planar_input, &interleaved_output); + VerifyOutput(num_frames * num_channels, expected_output, interleaved_output); +} + +// Tests that an |AudioBuffer| can be correctly written into an interleaved +// (float/int16_t) array. +TEST_P(PlanarInterleavedConverterTest, TestAudioBufferIntoInterleavedPtr) { + const size_t num_channels = ::testing::get<0>(GetParam()); + const size_t num_frames = ::testing::get<1>(GetParam()); + const size_t num_interleaved_samples = num_frames * num_channels; + + std::vector<float> expected_output(num_interleaved_samples); + FillInterleaved(num_channels, num_frames, &expected_output[0]); + + AudioBuffer planar_input(num_channels, num_frames); + FillPlanar(&planar_input); + + // Integer. + AudioBuffer::AlignedInt16Vector interleaved_aligned_int( + num_interleaved_samples); + std::vector<int16_t> interleaved_unaligned_int(num_interleaved_samples); + + // Aligned Input, Aligned Output. + DCHECK_EQ(interleaved_aligned_int.size(), + planar_input.num_frames() * planar_input.num_channels()); + FillExternalBuffer(planar_input, interleaved_aligned_int.data(), + planar_input.num_frames(), planar_input.num_channels()); + VerifyOutput(num_frames * num_channels, expected_output, + interleaved_aligned_int.data()); + // Aligned Input, Unaligned Output. + DCHECK_EQ(interleaved_unaligned_int.size(), + planar_input.num_frames() * planar_input.num_channels()); + FillExternalBuffer(planar_input, interleaved_unaligned_int.data(), + planar_input.num_frames(), planar_input.num_channels()); + VerifyOutput(num_frames * num_channels, expected_output, + interleaved_unaligned_int); + + // Floating point. + AudioBuffer::AlignedFloatVector interleaved_aligned_float( + num_interleaved_samples); + std::vector<float> interleaved_plane_float(num_interleaved_samples); + + // Aligned Input, Aligned Output. + DCHECK_EQ(interleaved_aligned_float.size(), + planar_input.num_frames() * planar_input.num_channels()); + FillExternalBuffer(planar_input, interleaved_aligned_float.data(), + planar_input.num_frames(), planar_input.num_channels()); + VerifyOutput(num_frames * num_channels, expected_output, + interleaved_aligned_float.data()); + // Aligned Input, Unaligned Output. + FillExternalBuffer(planar_input, &interleaved_plane_float[0], + planar_input.num_frames(), planar_input.num_channels()); + VerifyOutput(num_frames * num_channels, expected_output, + interleaved_plane_float); +} + +// Test Params define: channels, frames +INSTANTIATE_TEST_CASE_P( + TestParameters, PlanarInterleavedConverterTest, + testing::Values( + TestParams(2, 8), TestParams(2, 13), TestParams(2, kMaxNumFrames), + TestParams(4, 8), TestParams(4, 13), TestParams(4, kMaxNumFrames), + TestParams(5, 8), TestParams(5, 13), TestParams(5, kMaxNumFrames), + TestParams(kMaxNumChannels, 8), TestParams(kMaxNumChannels, 13), + TestParams(kMaxNumChannels, kMaxNumFrames))); + +} // namespace + +} // namespace vraudio |