Commit f5ae3b14 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Merge branch 'format-tests'

* format-tests:
  TESTS: add a few more checks to existing tests
  TESTS: run testrawconverter in make check
  Add test for RawConverter.
  TESTS: avoid snr output in quiet mode
  TESTS: check snr in wav pipe test to catch conversion errors
  TESTS: add test for wav-pipe format
  Add helpers to audiowmark for better tests.
Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parents a971ce4b 113815ae
......@@ -15,7 +15,8 @@ AM_CXXFLAGS = $(SNDFILE_CFLAGS) $(FFTW_CFLAGS) $(LIBGCRYPT_CFLAGS) $(LIBMPG123_C
audiowmark_SOURCES = audiowmark.cc $(COMMON_SRC)
audiowmark_LDFLAGS = $(COMMON_LIBS)
noinst_PROGRAMS = testconvcode testrandom testmp3 teststream testlimiter testshortcode testmpegts testthreadpool
noinst_PROGRAMS = testconvcode testrandom testmp3 teststream testlimiter testshortcode testmpegts testthreadpool \
testrawconverter
testconvcode_SOURCES = testconvcode.cc $(COMMON_SRC)
testconvcode_LDFLAGS = $(COMMON_LIBS)
......@@ -41,6 +42,9 @@ testmpegts_LDFLAGS = $(COMMON_LIBS)
testthreadpool_SOURCES = testthreadpool.cc $(COMMON_SRC)
testthreadpool_LDFLAGS = $(COMMON_LIBS)
testrawconverter_SOURCES = testrawconverter.cc $(COMMON_SRC)
testrawconverter_LDFLAGS = $(COMMON_LIBS)
if COND_WITH_FFMPEG
COMMON_SRC += hlsoutputstream.cc hlsoutputstream.hh
......
......@@ -373,10 +373,9 @@ test_speed (const Key& key, int seed)
}
int
test_gen_noise (const Key& key, const string& out_file, double seconds, int rate)
test_gen_noise (const Key& key, const string& out_file, double seconds, int rate, int bits)
{
const int channels = 2;
const int bits = 16;
vector<float> noise;
Random rng (key, 0, /* there is no stream for this test */ Random::Stream::data_up_down);
......@@ -433,6 +432,30 @@ test_resample (const string& in_file, const string& out_file, int new_rate)
return 0;
}
int
test_info (const string& in_file, const string& property)
{
WavData in_data;
Error err = in_data.load (in_file);
if (err)
{
error ("audiowmark: error loading %s: %s\n", in_file.c_str(), err.message());
return 1;
}
if (property == "bit_depth")
{
printf ("%d\n", in_data.bit_depth());
return 0;
}
if (property == "frames")
{
printf ("%zd\n", in_data.n_frames());
return 0;
}
error ("audiowmark: unsupported property for test_info: %s\n", property.c_str());
return 1;
}
static string
escape_key_name (const string& name)
{
......@@ -962,10 +985,12 @@ main (int argc, char **argv)
else if (ap.parse_cmd ("test-gen-noise"))
{
parse_shared_options (ap);
int bits = 16;
ap.parse_opt ("--bits", bits);
Key key = parse_key (ap);
args = parse_positional (ap, "output_wav", "seconds", "sample_rate");
return test_gen_noise (key, args[0], atof_or_die (args[1].c_str()), atoi_or_die (args[2].c_str()));
return test_gen_noise (key, args[0], atof_or_die (args[1].c_str()), atoi_or_die (args[2].c_str()), bits);
}
else if (ap.parse_cmd ("test-change-speed"))
{
......@@ -981,6 +1006,13 @@ main (int argc, char **argv)
args = parse_positional (ap, "input_wav", "output_wav", "new_rate");
return test_resample (args[0], args[1], atoi_or_die (args[2].c_str()));
}
else if (ap.parse_cmd ("test-info"))
{
parse_shared_options (ap);
args = parse_positional (ap, "input_wav", "property");
return test_info (args[0], args[1]);
}
else if (ap.remaining_args().size())
{
string s = ap.remaining_args().front();
......
/*
* Copyright (C) 2018-2024 Stefan Westerfeld
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <vector>
#include <assert.h>
#include <math.h>
#include <gcrypt.h>
#include <set>
#include "rawconverter.hh"
using std::vector;
using std::string;
string
hash_bytes (vector<unsigned char>& bytes)
{
string result;
std::array<unsigned char, 20> hash;
gcry_md_hash_buffer (GCRY_MD_SHA1, hash.data(), bytes.data(), bytes.size());
for (auto ch : hash)
result += string_printf ("%02x", ch);
return result;
}
int
main (int argc, char **argv)
{
std::set<string> hashes;
Error error;
RawFormat format;
uint64_t K = 33452759; // prime
vector<float> in_samples (K), out_samples (K);
vector<unsigned char> bytes (K * 4);
for (uint64_t k = 0; k <= K; k++)
in_samples[k] = (-1 + double (2 * k) / K);
for (auto bit_depth : { 16, 24, 32 })
{
for (auto encoding : { RawFormat::SIGNED, RawFormat::UNSIGNED })
{
for (auto endian : { RawFormat::LITTLE, RawFormat::BIG })
{
format.set_bit_depth (bit_depth);
format.set_encoding (encoding);
format.set_endian (endian);
RawConverter *converter = RawConverter::create (format, error);
if (error)
{
printf ("error: %s\n", error.message());
return 1;
}
std::fill (bytes.begin(), bytes.end(), 0);
double time1 = get_time();
converter->to_raw (in_samples.data(), bytes.data(), in_samples.size());
double time2 = get_time();
converter->from_raw (bytes.data(), out_samples.data(), in_samples.size());
double time3 = get_time();
double max_err = 0;
for (size_t i = 0; i < in_samples.size(); i++)
max_err = std::max (max_err, std::abs (double (in_samples[i]) - double (out_samples[i])));
double ebits = log2 (max_err);
printf ("%s %d %s endian %f",
format.encoding() == RawFormat::SIGNED ? "signed" : "unsigned",
format.bit_depth(),
format.endian() == RawFormat::LITTLE ? "little" : "big",
ebits);
double min_ebits = -format.bit_depth() + 0.9;
double max_ebits = -format.bit_depth() + 1;
double ns_per_sample_to = (time2 - time1) * 1e9 / K;
double ns_per_sample_from = (time3 - time2) * 1e9 / K;
printf (" (should be in [%.2f,%.2f]) - to raw: %f ns/sample - from raw: %f ns/sample\n",
min_ebits, max_ebits,
ns_per_sample_to, ns_per_sample_from);
assert (ebits <= max_ebits && ebits >= min_ebits);
/* every raw converted buffer should be different */
string hash = hash_bytes (bytes);
assert (hashes.count (hash) == 0);
hashes.insert (hash);
}
}
printf ("\n");
}
}
CHECKS = detect-speed-test block-decoder-test clip-decoder-test \
pipe-test short-payload-test sync-test sample-rate-test \
key-test
key-test wav-pipe-test test-programs
if COND_WITH_FFMPEG
CHECKS += hls-test
......@@ -8,7 +8,7 @@ endif
EXTRA_DIST = detect-speed-test.sh block-decoder-test.sh clip-decoder-test.sh \
pipe-test.sh short-payload-test.sh sync-test.sh sample-rate-test.sh \
key-test.sh hls-test.sh
key-test.sh hls-test.sh wav-pipe-test.sh test-programs.sh
check: $(CHECKS)
......@@ -24,6 +24,9 @@ clip-decoder-test:
pipe-test:
Q=1 $(top_srcdir)/tests/pipe-test.sh
wav-pipe-test:
Q=1 $(top_srcdir)/tests/wav-pipe-test.sh
short-payload-test:
Q=1 $(top_srcdir)/tests/short-payload-test.sh
......@@ -38,3 +41,6 @@ key-test:
hls-test:
Q=1 $(top_srcdir)/tests/hls-test.sh
test-programs:
Q=1 $(top_srcdir)/tests/test-programs.sh
......@@ -9,5 +9,13 @@ audiowmark test-gen-noise $IN_WAV 200 44100
audiowmark_add $IN_WAV $OUT_WAV $TEST_MSG
audiowmark_cmp --expect-matches 5 $OUT_WAV $TEST_MSG
check_length $IN_WAV $OUT_WAV
audiowmark_add --test-no-limiter $IN_WAV $OUT_WAV $TEST_MSG
audiowmark_cmp --expect-matches 5 $OUT_WAV $TEST_MSG
check_length $IN_WAV $OUT_WAV
check_snr $IN_WAV $OUT_WAV 32.4
rm $IN_WAV $OUT_WAV
exit 0
......@@ -10,5 +10,7 @@ cat $IN_WAV | audiowmark_add - - $TEST_MSG > $OUT_WAV || die "watermark from pip
audiowmark_cmp --expect-matches 5 $OUT_WAV $TEST_MSG
cat $OUT_WAV | audiowmark_cmp --expect-matches 5 - $TEST_MSG || die "watermark detection from pipe failed"
check_length $IN_WAV $OUT_WAV
rm $IN_WAV $OUT_WAV
exit 0
......@@ -2,6 +2,7 @@
AUDIOWMARK=@top_builddir@/src/audiowmark
TEST_MSG=f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0
TOP_BUILDDIR=@top_builddir@
# common shell functions
......@@ -41,3 +42,25 @@ audiowmark_cmp()
fi
$AUDIOWMARK --strict cmp "$@" > $AUDIOWMARK_OUT || die "failed to detect watermark $@"
}
check_length()
{
local in1="$($AUDIOWMARK test-info $1 frames)"
local in2="$($AUDIOWMARK test-info $2 frames)"
[ "x$in1" != "x" ] || die "length of '$1' could not be detected"
[ "x$in1" == "x$in2" ] || die "length of '$1' ($in1) and '$2' ($in2) differs"
}
check_snr()
{
local snr="$($AUDIOWMARK test-snr $1 $2)"
if [ "x$Q" == "x1" ] && [ -z "$V" ]; then
:
else
echo >&2 "==== snr of $1 and $2 is $snr (expected $3) ===="
fi
[ "x$snr" != "x" ] || die "snr of '$1' and '$2' could not be detected"
[ "x$3" != "x" ] || die "need snr bound"
awk "BEGIN {exit !($snr >= $3)}" || die "snr of '$1' and '$2' is worse than $3"
}
#!/bin/bash
source test-common.sh
for TEST in testrawconverter
do
if [ "x$Q" == "x1" ] && [ -z "$V" ]; then
$TOP_BUILDDIR/src/$TEST > /dev/null
else
$TOP_BUILDDIR/src/$TEST
fi
done
exit 0
#!/bin/bash
source test-common.sh
IN_WAV=wav-pipe-test.wav
OUT1_WAV=wav-pipe-test-out1.wav
OUT2_WAV=wav-pipe-test-out2.wav
OUT3_WAV=wav-pipe-test-out3.wav
for BITS in 16 24
do
audiowmark test-gen-noise --bits $BITS $IN_WAV 200 44100
[ "x$BITS" == "x$(audiowmark test-info $IN_WAV bit_depth)" ] || die "generated input bit depth is not correct"
cat $IN_WAV | audiowmark_add --test-key 1 --test-no-limiter --format wav-pipe - - $TEST_MSG > $OUT1_WAV || die "watermark from pipe failed"
cat $OUT1_WAV | audiowmark_add --test-key 2 --test-no-limiter --format wav-pipe - - $TEST_MSG > $OUT2_WAV || die "watermark from pipe failed"
cat $OUT2_WAV | audiowmark_add --test-key 3 --test-no-limiter --format wav-pipe - - $TEST_MSG > $OUT3_WAV || die "watermark from pipe failed"
check_length $IN_WAV $OUT1_WAV
check_length $IN_WAV $OUT2_WAV
check_length $IN_WAV $OUT3_WAV
check_snr $IN_WAV $OUT1_WAV 32
check_snr $IN_WAV $OUT2_WAV 29
check_snr $IN_WAV $OUT3_WAV 27
audiowmark_cmp --expect-matches 0 $OUT3_WAV $TEST_MSG
audiowmark_cmp --expect-matches 5 --test-key 1 $OUT3_WAV $TEST_MSG
audiowmark_cmp --expect-matches 5 --test-key 2 $OUT3_WAV $TEST_MSG
audiowmark_cmp --expect-matches 5 --test-key 3 $OUT3_WAV $TEST_MSG
# for wav-pipe format: 16 bit input should produce 16 bit output; 24 bit input should produce 32 bit output
BTEST=$BITS:$(audiowmark test-info $OUT3_WAV bit_depth)
[[ "$BTEST" =~ ^(16:16|24:32)$ ]] || die "unexpected input/output bit depth $BTEST"
rm $IN_WAV $OUT1_WAV $OUT2_WAV $OUT3_WAV
done
exit 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment