Commit 82f184e4 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Merge branch 'short-clip'

parents d1276514 8cd04688
Overview of Changes in audiowmark-0.3.0:
* replace padding at start with a partial B block
* add algorithm for decoding the watermark from short clips
Overview of Changes in audiowmark-0.2.1:
* add limiter to avoid clipping during watermark generation
......
AC_INIT([audiowmark], [0.2.1])
AC_INIT([audiowmark], [0.3.0])
AC_CONFIG_SRCDIR([src/audiowmark.cc])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
......
......@@ -7,3 +7,4 @@ testconvcode
testmp3
testrandom
teststream
testlimiter
......@@ -441,6 +441,45 @@ test_snr (const string& orig_file, const string& wm_file)
return 0;
}
int
test_clip (const string& in_file, const string& out_file, int seed, int time_seconds)
{
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;
}
bool done = false;
Random rng (seed, /* there is no stream for this test */ Random::Stream::data_up_down);
size_t start_point, end_point;
do
{
// this is unbiased only if 2 * block_size + time_seconds is smaller than overall file length
const size_t values_per_block = (mark_sync_frame_count() + mark_data_frame_count()) * Params::frame_size * in_data.n_channels();
start_point = 2 * values_per_block * (double(rng()) / UINT64_MAX);
start_point /= in_data.n_channels();
end_point = start_point + time_seconds * in_data.sample_rate();
if (end_point < in_data.n_values() / in_data.n_channels())
done = true;
}
while (!done);
//printf ("%.3f %.3f\n", start_point / double (in_data.sample_rate()), end_point / double (in_data.sample_rate()));
vector<float> out_signal (in_data.samples().begin() + start_point * in_data.n_channels(),
in_data.samples().begin() + end_point * in_data.n_channels());
WavData out_wav_data (out_signal, in_data.n_channels(), in_data.sample_rate(), in_data.bit_depth());
err = out_wav_data.save (out_file);
if (err)
{
error ("audiowmark: error saving %s: %s\n", out_file.c_str(), err.message());
return 1;
}
return 0;
}
int
gen_key (const string& outfile)
{
......@@ -495,6 +534,10 @@ main (int argc, char **argv)
{
test_snr (argv[2], argv[3]);
}
else if (op == "test-clip" && argc == 6)
{
test_clip (argv[2], argv[3], atoi (argv[4]), atoi (argv[5]));
}
else if (op == "gen-key" && argc == 3)
{
return gen_key (argv[2]);
......
......@@ -16,6 +16,9 @@ fi
if [ "x$AWM_FILE" == "x" ]; then
AWM_FILE=t
fi
if [ "x$AWM_MULTI_CLIP" == "x" ]; then
AWM_MULTI_CLIP=1
fi
{
if [ "x$AWM_SET" == "xsmall" ]; then
......@@ -47,8 +50,8 @@ do
PATTERN=4e1243bd22c66e76c2ba9eddc1f91394
fi
echo in_pattern $PATTERN
echo in_flags $AWM_PARAMS --test-key $SEED
audiowmark add "$i" ${AWM_FILE}.wav $PATTERN $AWM_PARAMS --test-key $SEED >/dev/null
echo in_flags $AWM_PARAMS $AWM_PARAMS_ADD --test-key $SEED
audiowmark add "$i" ${AWM_FILE}.wav $PATTERN $AWM_PARAMS $AWM_PARAMS_ADD --test-key $SEED --quiet
if [ "x$AWM_RAND_CUT" != x ]; then
CUT=$RANDOM
audiowmark cut-start "${AWM_FILE}.wav" "${AWM_FILE}.wav" $CUT
......@@ -91,7 +94,15 @@ do
exit 1
fi
echo
if [ "x$AWM_REPORT" == "xtruncv" ]; then
if [ "x${AWM_CLIP}" != "x" ]; then
for CLIP in $(seq $AWM_MULTI_CLIP)
do
audiowmark test-clip $OUT_FILE ${OUT_FILE}.clip.wav $((CLIP_SEED++)) $AWM_CLIP --test-key $SEED
audiowmark cmp ${OUT_FILE}.clip.wav $PATTERN $AWM_PARAMS --test-key $SEED $TEST_CUT_ARGS
rm ${OUT_FILE}.clip.wav
echo
done
elif [ "x$AWM_REPORT" == "xtruncv" ]; then
for TRUNC in $AWM_TRUNCATE
do
audiowmark cmp $OUT_FILE $PATTERN $AWM_PARAMS --test-key $SEED $TEST_CUT_ARGS --test-truncate $TRUNC | sed "s/^/$TRUNC /g"
......
#!/bin/bash
STRENGTHS="10 15 20 30"
STR_CLIPS="5 10 15 20 25 30"
MAIN_CLIPS="5 10 15 20 30 40 50 60"
echo ".performance-by-clip-length"
echo '[frame="topbot",options="header",cols="<2,8*>1"]'
echo '|=========================='
echo -n "| Quality "
for CLIP in $MAIN_CLIPS
do
echo -n "| $CLIP"
done
echo
for TEST in mp3-256 mp3-128 double-mp3-128 ogg-128
do
echo -n "| $TEST "
for CLIP in $MAIN_CLIPS
do
cat main-$TEST-*-$CLIP | awk '{bad += $1; n += $2} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
done
echo
done
echo
echo '|=========================='
echo ".effects-of-watermarking-strength"
echo '[frame="topbot",options="header",cols="<1,7*>1"]'
echo '|=========================='
echo -n "| Strength | SNR "
for CLIP in $STR_CLIPS
do
echo -n "| $CLIP"
done
echo
for STRENGTH in $STRENGTHS
do
echo -n "| $STRENGTH "
cat snr-$STRENGTH | awk '{printf ("| %.2f ", $1);}'
for CLIP in $STR_CLIPS
do
cat str-$STRENGTH-mp3-*-$CLIP | awk '{bad += $1; n += $2} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
done
echo
done
echo
echo '|=========================='
#!/bin/bash
SEEDS=$(seq 5)
STRENGTHS="10 15 20 30"
STR_CLIPS="5 10 15 20 25 30"
MAIN_CLIPS="5 10 15 20 30 40 50 60"
MULTI_CLIP=4
echo -n "all:"
for STRENGTH in $STRENGTHS
do
FILE="snr-$STRENGTH"
echo -n " $FILE"
done
for SEED in $SEEDS
do
for STRENGTH in $STRENGTHS
do
for CLIP in $STR_CLIPS
do
FILE="str-$STRENGTH-mp3-$SEED-$CLIP"
echo -n " $FILE"
done
done
for CLIP in $MAIN_CLIPS
do
echo -n " main-mp3-256-$SEED-$CLIP main-mp3-128-$SEED-$CLIP main-ogg-128-$SEED-$CLIP main-double-mp3-128-$SEED-$CLIP"
done
done
echo
echo
for SEED in $SEEDS
do
for STRENGTH in $STRENGTHS
do
for CLIP in $STR_CLIPS
do
FILE="str-$STRENGTH-mp3-$SEED-$CLIP"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_SET=huge2 AWM_PARAMS_ADD='--strength $STRENGTH' AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
done
done
done
for STRENGTH in $STRENGTHS
do
FILE="snr-$STRENGTH"
echo "$FILE:"
echo -e "\t( cd ..; AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' snr.sh ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
done
for SEED in $SEEDS
do
for CLIP in $MAIN_CLIPS
do
FILE="main-mp3-256-$SEED-$CLIP"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_SET=huge2 AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 256 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="main-mp3-128-$SEED-$CLIP"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_SET=huge2 AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="main-ogg-128-$SEED-$CLIP"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_SET=huge2 AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh ogg 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="main-double-mp3-128-$SEED-$CLIP"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_SET=huge2 AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh double-mp3 128 ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
done
done
......@@ -13,7 +13,7 @@ public:
enum class Stream {
data_up_down = 1,
sync_up_down = 2,
pad_up_down = 3,
pad_up_down = 3, /* unused */
mix = 4,
bit_order = 5,
frame_position = 6
......
all: short-60 short-60-mp3 \
short-50 short-50-mp3 \
short-40 short-40-mp3 \
short-30 short-30-mp3 \
short-20 short-20-mp3 \
short-10 short-10-mp3
short-60:
AWM_FILE=t-short-60 AWM_CLIP=60 fer-test.sh 10 "" > tmp-short-60
mv tmp-short-60 short-60
short-60-mp3:
AWM_FILE=t-short-60-mp3 AWM_CLIP=60 fer-test.sh 10 "" mp3 128 > tmp-short-60-mp3
mv tmp-short-60-mp3 short-60-mp3
short-50:
AWM_FILE=t-short-50 AWM_CLIP=50 fer-test.sh 10 "" > tmp-short-50
mv tmp-short-50 short-50
short-50-mp3:
AWM_FILE=t-short-50-mp3 AWM_CLIP=50 fer-test.sh 10 "" mp3 128 > tmp-short-50-mp3
mv tmp-short-50-mp3 short-50-mp3
short-40:
AWM_FILE=t-short-40 AWM_CLIP=40 fer-test.sh 10 "" > tmp-short-40
mv tmp-short-40 short-40
short-40-mp3:
AWM_FILE=t-short-40-mp3 AWM_CLIP=40 fer-test.sh 10 "" mp3 128 > tmp-short-40-mp3
mv tmp-short-40-mp3 short-40-mp3
short-30:
AWM_FILE=t-short-30 AWM_CLIP=30 fer-test.sh 10 "" > tmp-short-30
mv tmp-short-30 short-30
short-30-mp3:
AWM_FILE=t-short-30-mp3 AWM_CLIP=30 fer-test.sh 10 "" mp3 128 > tmp-short-30-mp3
mv tmp-short-30-mp3 short-30-mp3
short-20:
AWM_FILE=t-short-20 AWM_CLIP=20 fer-test.sh 10 "" > tmp-short-20
mv tmp-short-20 short-20
short-20-mp3:
AWM_FILE=t-short-20-mp3 AWM_CLIP=20 fer-test.sh 10 "" mp3 128 > tmp-short-20-mp3
mv tmp-short-20-mp3 short-20-mp3
short-10:
AWM_FILE=t-short-10 AWM_CLIP=10 fer-test.sh 10 "" > tmp-short-10
mv tmp-short-10 short-10
short-10-mp3:
AWM_FILE=t-short-10-mp3 AWM_CLIP=10 fer-test.sh 10 "" mp3 128 > tmp-short-10-mp3
mv tmp-short-10-mp3 short-10-mp3
......@@ -4,5 +4,5 @@ PATTERN=4e1243bd22c66e76c2ba9eddc1f91394
for i in test/T*
do
echo $i $(audiowmark add $i t.wav $PATTERN $AWM_PARAMS --snr | grep SNR)
echo $i $(audiowmark add $i t.wav $PATTERN $AWM_PARAMS --snr 2>&1 | grep SNR)
done | awk '{s += $3; n++} END { print s/n; }'
......@@ -17,6 +17,7 @@
using std::string;
using std::vector;
using std::complex;
using std::max;
enum class FrameMod : uint8_t {
KEEP = 0,
......@@ -121,20 +122,6 @@ mark_sync (vector<vector<FrameMod>>& frame_mod, int ab)
}
}
static void
init_pad_mod_vec (vector<vector<FrameMod>>& pad_mod_vec)
{
UpDownGen up_down_gen (Random::Stream::pad_up_down);
for (size_t f = 0; f < Params::frames_pad_start; f++)
{
vector<FrameMod> mod (Params::max_band + 1);
prepare_frame_mod (up_down_gen, f, mod, 0);
pad_mod_vec.push_back (mod);
}
}
static void
init_frame_mod_vec (vector<vector<FrameMod>>& frame_mod_vec, int ab, const vector<int>& bitvec)
{
......@@ -245,11 +232,8 @@ public:
*/
class WatermarkGen
{
enum State { PAD, WATERMARK } state = State::PAD;
const int n_channels = 0;
int frame_number = 0;
int frame_bound = Params::frames_pad_start;
size_t frame_number = 0;
int ab = 0;
int m_data_blocks = 0;
......@@ -257,7 +241,6 @@ class WatermarkGen
WatermarkSynth wm_synth;
vector<int> bitvec;
vector<vector<FrameMod>> pad_mod_vec;
vector<vector<FrameMod>> frame_mod_vec_a;
vector<vector<FrameMod>> frame_mod_vec_b;
public:
......@@ -267,7 +250,12 @@ public:
wm_synth (n_channels),
bitvec (bitvec)
{
init_pad_mod_vec (pad_mod_vec);
/* start writing a partial B-block as padding */
init_frame_mod_vec (frame_mod_vec_b, 1, bitvec);
assert (frame_mod_vec_b.size() > Params::frames_pad_start);
frame_number = frame_mod_vec_b.size() - Params::frames_pad_start;
ab = 1;
}
vector<float>
run (const vector<float>& samples)
......@@ -280,50 +268,29 @@ public:
for (int ch = 0; ch < n_channels; ch++)
fft_delta_spect.push_back (vector<complex<float>> (fft_out.back().size()));
if (state == State::PAD)
{
for (int ch = 0; ch < n_channels; ch++)
apply_frame_mod (pad_mod_vec[frame_number], fft_out[ch], fft_delta_spect[ch]);
}
else if (state == State::WATERMARK)
{
for (int ch = 0; ch < n_channels; ch++)
apply_frame_mod (ab ? frame_mod_vec_b[frame_number] : frame_mod_vec_a[frame_number], fft_out[ch], fft_delta_spect[ch]);
}
const vector<vector<FrameMod>>& frame_mod_vec = ab ? frame_mod_vec_b : frame_mod_vec_a;
for (int ch = 0; ch < n_channels; ch++)
apply_frame_mod (frame_mod_vec[frame_number], fft_out[ch], fft_delta_spect[ch]);
frame_number++;
if (frame_number == frame_bound)
if (frame_number == frame_mod_vec.size())
{
frame_number = 0;
if (state == PAD)
{
state = WATERMARK;
frame_bound = mark_sync_frame_count() + mark_data_frame_count();
ab = (ab + 1) & 1; // write A|B|A|B|...
m_data_blocks++;
// initialize a-block frame mod vector here to minimize startup latency
assert (frame_mod_vec_a.empty());
init_frame_mod_vec (frame_mod_vec_a, 0, bitvec);
}
else if (state == WATERMARK)
{
ab = (ab + 1) & 1; // write A|B|A|B|...
frame_bound = mark_sync_frame_count() + mark_data_frame_count();
m_data_blocks++;
if (frame_mod_vec_b.empty())
{
// initialize b-block frame mod vector here to minimize startup latency
init_frame_mod_vec (frame_mod_vec_b, 1, bitvec);
}
}
// initialize A-block frame mod vector here to minimize startup latency
if (frame_mod_vec_a.empty())
init_frame_mod_vec (frame_mod_vec_a, 0, bitvec);
}
return wm_synth.run (fft_delta_spect);
}
int
data_blocks() const
{
return m_data_blocks;
// first block is padding - a partial B block
return max (m_data_blocks - 1, 0);
}
};
......
This diff is collapsed.
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