/* 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 #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(kMemoryAlignmentBytes); const size_t kMaxNumFrames = 16; const size_t kMaxNumChannels = 8; int16_t SingleFloatToInt16(float value) { const float kInt16Min = static_cast(-0x7FFF); const float kInt16Max = static_cast(0x7FFF); const float scaled_value = value * kInt16Max; const float clamped_value = std::min(kInt16Max, std::max(kInt16Min, scaled_value)); return static_cast(clamped_value); } // Creates a trivial channel map, i.e. no mapping. std::vector GetTrivialChannelMap(size_t size) { std::vector 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(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(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(c) * 0.1f); } } // Fills a planar buffer with the channel number / 10, in each frame. void FillPlanar(size_t num_frames, std::vector* buffer) { for (size_t c = 0; c < buffer->size(); ++c) { std::fill_n((*buffer)[c], num_frames, static_cast(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(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* 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& expected_output, const std::vector& 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 void VerifyOutputFloatTemplated(size_t num_channels, size_t num_frames, const InputType& expected_output, const OutputType& output, const std::vector& 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( 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& expected_output, const AudioBuffer& output) { VerifyOutputFloatTemplated, 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& output) { VerifyOutputFloatTemplated>( 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& expected_output, const std::vector& output) { VerifyOutputFloatTemplated, std::vector>( 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& expected_output, const std::vector& output) { VerifyOutputFloatTemplated, std::vector>( 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& channel_map) { VerifyOutputFloatTemplated( 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( 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& 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& expected_output, const std::vector& 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& 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& expected_output, const std::vector& output) { for (size_t f = 0; f < length; ++f) { EXPECT_NEAR(expected_output[f], output[f], kIntEpsilon); } } typedef std::tuple TestParams; class PlanarInterleavedConverterTest : public ::testing::Test, public ::testing::WithParamInterface { 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 unaligned_output_memory(num_interleaved_samples); // Create output planar buffers. std::vector aligned_output(num_channels); std::vector 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 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 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 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 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 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 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 planar_aligned_channels_int_buf( num_channels, AudioBuffer::AlignedInt16Vector(num_frames)); std::vector> planar_unaligned_channels_int_buffers( num_channels, std::vector(num_frames)); std::vector planar_aligned_channels_int(num_channels); std::vector 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 planar_aligned_channels_float_buf( num_channels, AudioBuffer::AlignedFloatVector(num_frames)); std::vector> planar_unaligned_channels_float_buffers( num_channels, std::vector(num_frames)); std::vector planar_aligned_channels_float(num_channels); std::vector 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 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 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 planar_aligned_channels_int_buffers( num_channels, AudioBuffer::AlignedInt16Vector(num_frames)); std::vector> planar_unaligned_channels_int_buffers( num_channels, std::vector(num_frames)); std::vector planar_aligned_channels_int(num_channels); std::vector 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 planar_aligned_channels_float_buffer( num_channels, AudioBuffer::AlignedFloatVector(num_frames)); std::vector> planar_unaligned_channels_float_buffers( num_channels, std::vector(num_frames)); std::vector planar_aligned_channels_float(num_channels); std::vector 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 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 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 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 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 planar_aligned_channels_int_bufferss( num_channels, AudioBuffer::AlignedInt16Vector(num_frames)); std::vector> planar_unaligned_channels_int_buffers( num_channels, std::vector(num_frames)); std::vector planar_aligned_channels_int(num_channels); std::vector 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 planar_aligned_channels_float_buffers( num_channels, AudioBuffer::AlignedFloatVector(num_frames)); std::vector> planar_unaligned_channels_float_buffers( num_channels, std::vector(num_frames)); std::vector planar_aligned_channels_float(num_channels); std::vector 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 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 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 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 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 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