mirror of
https://github.com/mhx/dwarfs.git
synced 2025-08-03 09:47:01 -04:00

The latter doesn't always explicitly initialize the allocated memory, which can help improve performance.
206 lines
6.2 KiB
C++
206 lines
6.2 KiB
C++
/* vim:set ts=2 sw=2 sts=2 et: */
|
|
/**
|
|
* \author Marcus Holland-Moritz (github@mhxnet.de)
|
|
* \copyright Copyright (c) Marcus Holland-Moritz
|
|
*
|
|
* This file is part of dwarfs.
|
|
*
|
|
* dwarfs is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* dwarfs is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with dwarfs. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
*/
|
|
|
|
#include <cmath>
|
|
#include <numbers>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
#include <dwarfs/block_compressor.h>
|
|
#include <dwarfs/block_decompressor.h>
|
|
#include <dwarfs/malloc_byte_buffer.h>
|
|
#include <dwarfs/pcm_sample_transformer.h>
|
|
|
|
using namespace dwarfs;
|
|
|
|
namespace {
|
|
|
|
template <typename T>
|
|
std::vector<T> make_sine(int bits, size_t length, double period) {
|
|
std::vector<T> rv(length);
|
|
double amplitude = (1 << bits) / 2;
|
|
for (size_t i = 0; i < length; ++i) {
|
|
rv[i] = static_cast<T>(
|
|
amplitude * std::sin(2 * std::numbers::pi * i / period) - 0.5);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
template <typename T>
|
|
std::vector<T> multiplex(std::vector<std::vector<T>> const& in) {
|
|
auto samples = in.front().size();
|
|
auto channels = in.size();
|
|
std::vector<T> out(channels * samples);
|
|
|
|
for (size_t i = 0; i < samples; ++i) {
|
|
for (size_t c = 0; c < channels; ++c) {
|
|
out[i * channels + c] = in.at(c).at(i);
|
|
}
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
template <typename T = int32_t>
|
|
shared_byte_buffer
|
|
make_test_data(int channels, int samples, int bytes, int bits,
|
|
pcm_sample_endianness end, pcm_sample_signedness sig,
|
|
pcm_sample_padding pad) {
|
|
std::vector<std::vector<T>> data;
|
|
for (int c = 0; c < channels; ++c) {
|
|
data.emplace_back(
|
|
make_sine<T>(bits, samples, 3.1 * ((599 * (c + 1)) % 256)));
|
|
}
|
|
auto muxed = multiplex(data);
|
|
auto out = malloc_byte_buffer::create();
|
|
out.resize(bytes * channels * samples);
|
|
pcm_sample_transformer<T> xfm(end, sig, pad, bytes, bits);
|
|
xfm.pack(out.span(), muxed);
|
|
return out.share();
|
|
}
|
|
|
|
struct data_params {
|
|
data_params(int channels, int samples, int bytes, int bits)
|
|
: num_channels{channels}
|
|
, num_samples{samples}
|
|
, bytes_per_sample{bytes}
|
|
, bits_per_sample{bits} {}
|
|
|
|
int num_channels;
|
|
int num_samples;
|
|
int bytes_per_sample;
|
|
int bits_per_sample;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, data_params const& p) {
|
|
os << "{channels=" << p.num_channels << ", samples=" << p.num_samples
|
|
<< ", bytes=" << p.bytes_per_sample << ", bits=" << p.bits_per_sample
|
|
<< "}";
|
|
return os;
|
|
}
|
|
|
|
std::vector<data_params> const data_parameters{
|
|
// clang-format off
|
|
{ 1, 1000, 2, 16},
|
|
{ 3, 1000, 1, 8},
|
|
{ 1, 1000, 2, 12},
|
|
{ 1, 100000, 3, 20},
|
|
{ 8, 10000, 3, 20},
|
|
{ 4, 10000, 4, 20},
|
|
{ 4, 10000, 4, 24},
|
|
{ 4, 10000, 3, 24},
|
|
{ 7, 799999, 4, 32},
|
|
// clang-format on
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST(flac_compressor, sine) {
|
|
{
|
|
auto test = make_sine<int8_t>(8, 5, 4.0);
|
|
std::vector<int8_t> ref{0, 127, 0, -128, 0};
|
|
EXPECT_EQ(test, ref);
|
|
}
|
|
{
|
|
auto test = make_sine<int8_t>(5, 5, 4.0);
|
|
std::vector<int8_t> ref{0, 15, 0, -16, 0};
|
|
EXPECT_EQ(test, ref);
|
|
}
|
|
{
|
|
auto test = make_sine<int16_t>(16, 5, 4.0);
|
|
std::vector<int16_t> ref{0, 32767, 0, -32768, 0};
|
|
EXPECT_EQ(test, ref);
|
|
}
|
|
{
|
|
auto test = make_sine<int16_t>(12, 5, 4.0);
|
|
std::vector<int16_t> ref{0, 2047, 0, -2048, 0};
|
|
EXPECT_EQ(test, ref);
|
|
}
|
|
}
|
|
|
|
TEST(flac_compressor, basic) {
|
|
nlohmann::json meta{{"endianness", "little"}, {"signedness", "signed"},
|
|
{"padding", "msb"}, {"bytes_per_sample", 2},
|
|
{"bits_per_sample", 16}, {"number_of_channels", 2}};
|
|
|
|
auto const data =
|
|
make_test_data(2, 1000, 2, 16, pcm_sample_endianness::Little,
|
|
pcm_sample_signedness::Signed, pcm_sample_padding::Msb);
|
|
|
|
block_compressor comp("flac");
|
|
|
|
auto compressed = comp.compress(data, meta.dump());
|
|
|
|
EXPECT_LT(compressed.size(), data.size() / 2);
|
|
|
|
auto decompressed =
|
|
block_decompressor::decompress(compression_type::FLAC, compressed.span());
|
|
|
|
EXPECT_EQ(data, decompressed);
|
|
}
|
|
|
|
class flac_param : public testing::TestWithParam<
|
|
std::tuple<pcm_sample_endianness, pcm_sample_signedness,
|
|
pcm_sample_padding, data_params>> {};
|
|
|
|
TEST_P(flac_param, combinations) {
|
|
auto [end, sig, pad, param] = GetParam();
|
|
|
|
nlohmann::json meta{
|
|
{"endianness", end == pcm_sample_endianness::Big ? "big" : "little"},
|
|
{"signedness",
|
|
sig == pcm_sample_signedness::Signed ? "signed" : "unsigned"},
|
|
{"padding", pad == pcm_sample_padding::Msb ? "msb" : "lsb"},
|
|
{"bytes_per_sample", param.bytes_per_sample},
|
|
{"bits_per_sample", param.bits_per_sample},
|
|
{"number_of_channels", param.num_channels},
|
|
};
|
|
|
|
auto const data = make_test_data(param.num_channels, param.num_samples,
|
|
param.bytes_per_sample,
|
|
param.bits_per_sample, end, sig, pad);
|
|
|
|
block_compressor comp("flac");
|
|
|
|
auto compressed = comp.compress(data, meta.dump());
|
|
|
|
EXPECT_LT(compressed.size(), data.size() / 2);
|
|
|
|
auto decompressed =
|
|
block_decompressor::decompress(compression_type::FLAC, compressed.span());
|
|
|
|
EXPECT_EQ(data, decompressed);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
dwarfs, flac_param,
|
|
::testing::Combine(::testing::Values(pcm_sample_endianness::Big,
|
|
pcm_sample_endianness::Little),
|
|
::testing::Values(pcm_sample_signedness::Signed,
|
|
pcm_sample_signedness::Unsigned),
|
|
::testing::Values(pcm_sample_padding::Lsb,
|
|
pcm_sample_padding::Msb),
|
|
::testing::ValuesIn(data_parameters)));
|