diff options
Diffstat (limited to 'dom/media/gtest/TestAudioSegment.cpp')
-rw-r--r-- | dom/media/gtest/TestAudioSegment.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/dom/media/gtest/TestAudioSegment.cpp b/dom/media/gtest/TestAudioSegment.cpp new file mode 100644 index 000000000..968b4b5a1 --- /dev/null +++ b/dom/media/gtest/TestAudioSegment.cpp @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AudioSegment.h" +#include <iostream> +#include "gtest/gtest.h" + +using namespace mozilla; + +namespace audio_segment { + +/* Helper function to give us the maximum and minimum value that don't clip, + * for a given sample format (integer or floating-point). */ +template<typename T> +T GetLowValue(); + +template<typename T> +T GetHighValue(); + +template<typename T> +T GetSilentValue(); + +template<> +float GetLowValue<float>() { + return -1.0; +} + +template<> +int16_t GetLowValue<short>() { + return -INT16_MAX; +} + +template<> +float GetHighValue<float>() { + return 1.0; +} + +template<> +int16_t GetHighValue<short>() { + return INT16_MAX; +} + +template<> +float GetSilentValue() { + return 0.0; +} + +template<> +int16_t GetSilentValue() { + return 0; +} + + +// Get an array of planar audio buffers that has the inverse of the index of the +// channel (1-indexed) as samples. +template<typename T> +const T* const* GetPlanarChannelArray(size_t aChannels, size_t aSize) +{ + T** channels = new T*[aChannels]; + for (size_t c = 0; c < aChannels; c++) { + channels[c] = new T[aSize]; + for (size_t i = 0; i < aSize; i++) { + channels[c][i] = FloatToAudioSample<T>(1. / (c + 1)); + } + } + return channels; +} + +template<typename T> +void DeletePlanarChannelsArray(const T* const* aArrays, size_t aChannels) +{ + for (size_t channel = 0; channel < aChannels; channel++) { + delete [] aArrays[channel]; + } + delete [] aArrays; +} + +template<typename T> +T** GetPlanarArray(size_t aChannels, size_t aSize) +{ + T** channels = new T*[aChannels]; + for (size_t c = 0; c < aChannels; c++) { + channels[c] = new T[aSize]; + for (size_t i = 0; i < aSize; i++) { + channels[c][i] = 0.0f; + } + } + return channels; +} + +template<typename T> +void DeletePlanarArray(T** aArrays, size_t aChannels) +{ + for (size_t channel = 0; channel < aChannels; channel++) { + delete [] aArrays[channel]; + } + delete [] aArrays; +} + +// Get an array of audio samples that have the inverse of the index of the +// channel (1-indexed) as samples. +template<typename T> +const T* GetInterleavedChannelArray(size_t aChannels, size_t aSize) +{ + size_t sampleCount = aChannels * aSize; + T* samples = new T[sampleCount]; + for (size_t i = 0; i < sampleCount; i++) { + uint32_t channel = (i % aChannels) + 1; + samples[i] = FloatToAudioSample<T>(1. / channel); + } + return samples; +} + +template<typename T> +void DeleteInterleavedChannelArray(const T* aArray) +{ + delete [] aArray; +} + +bool FuzzyEqual(float aLhs, float aRhs) { + return std::abs(aLhs - aRhs) < 0.01; +} + +template<typename SrcT, typename DstT> +void TestInterleaveAndConvert() +{ + size_t arraySize = 1024; + size_t maxChannels = 8; // 7.1 + for (uint32_t channels = 1; channels < maxChannels; channels++) { + const SrcT* const* src = GetPlanarChannelArray<SrcT>(channels, arraySize); + DstT* dst = new DstT[channels * arraySize]; + + InterleaveAndConvertBuffer(src, arraySize, 1.0, channels, dst); + + uint32_t channelIndex = 0; + for (size_t i = 0; i < arraySize * channels; i++) { + ASSERT_TRUE(FuzzyEqual(dst[i], + FloatToAudioSample<DstT>(1. / (channelIndex + 1)))); + channelIndex++; + channelIndex %= channels; + } + + DeletePlanarChannelsArray(src, channels); + delete [] dst; + } +} + +template<typename SrcT, typename DstT> +void TestDeinterleaveAndConvert() +{ + size_t arraySize = 1024; + size_t maxChannels = 8; // 7.1 + for (uint32_t channels = 1; channels < maxChannels; channels++) { + const SrcT* src = GetInterleavedChannelArray<SrcT>(channels, arraySize); + DstT** dst = GetPlanarArray<DstT>(channels, arraySize); + + DeinterleaveAndConvertBuffer(src, arraySize, channels, dst); + + for (size_t channel = 0; channel < channels; channel++) { + for (size_t i = 0; i < arraySize; i++) { + ASSERT_TRUE(FuzzyEqual(dst[channel][i], + FloatToAudioSample<DstT>(1. / (channel + 1)))); + } + } + + DeleteInterleavedChannelArray(src); + DeletePlanarArray(dst, channels); + } +} + +uint8_t gSilence[4096] = {0}; + +template<typename T> +T* SilentChannel() +{ + return reinterpret_cast<T*>(gSilence); +} + +template<typename T> +void TestUpmixStereo() +{ + size_t arraySize = 1024; + nsTArray<T*> channels; + nsTArray<const T*> channelsptr; + + channels.SetLength(1); + channelsptr.SetLength(1); + + channels[0] = new T[arraySize]; + + for (size_t i = 0; i < arraySize; i++) { + channels[0][i] = GetHighValue<T>(); + } + channelsptr[0] = channels[0]; + + AudioChannelsUpMix(&channelsptr, 2, SilentChannel<T>()); + + for (size_t channel = 0; channel < 2; channel++) { + for (size_t i = 0; i < arraySize; i++) { + ASSERT_TRUE(channelsptr[channel][i] == GetHighValue<T>()); + } + } + delete channels[0]; +} + +template<typename T> +void TestDownmixStereo() +{ + const size_t arraySize = 1024; + nsTArray<const T*> inputptr; + nsTArray<T*> input; + T** output; + + output = new T*[1]; + output[0] = new T[arraySize]; + + input.SetLength(2); + inputptr.SetLength(2); + + for (size_t channel = 0; channel < input.Length(); channel++) { + input[channel] = new T[arraySize]; + for (size_t i = 0; i < arraySize; i++) { + input[channel][i] = channel == 0 ? GetLowValue<T>() : GetHighValue<T>(); + } + inputptr[channel] = input[channel]; + } + + AudioChannelsDownMix(inputptr, output, 1, arraySize); + + for (size_t i = 0; i < arraySize; i++) { + ASSERT_TRUE(output[0][i] == GetSilentValue<T>()); + ASSERT_TRUE(output[0][i] == GetSilentValue<T>()); + } + + delete output[0]; + delete output; +} + +TEST(AudioSegment, Test) +{ + TestInterleaveAndConvert<float, float>(); + TestInterleaveAndConvert<float, int16_t>(); + TestInterleaveAndConvert<int16_t, float>(); + TestInterleaveAndConvert<int16_t, int16_t>(); + TestDeinterleaveAndConvert<float, float>(); + TestDeinterleaveAndConvert<float, int16_t>(); + TestDeinterleaveAndConvert<int16_t, float>(); + TestDeinterleaveAndConvert<int16_t, int16_t>(); + TestUpmixStereo<float>(); + TestUpmixStereo<int16_t>(); + TestDownmixStereo<float>(); + TestDownmixStereo<int16_t>(); +} + +} // namespace audio_segment |