Commit 1b06d759 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Merge branch 'short-payload'

parents 597fc3fc c18b949b
Overview of Changes in audiowmark-0.4.2:
* compile fixes for g++-9 and clang++-10
* add experimental support for short payload
Overview of Changes in audiowmark-0.4.1:
* initial public release
......
......@@ -170,6 +170,29 @@ watermark. Fractional strengths (like 7.5) are possible.
audiowmark add --strength 15 in.wav out.wav 0123456789abcdef0011223344556677
audiowmark get --strength 15 out.wav
== Short Payload (experimental)
By default, the watermark will store a 128-bit message. In this mode, we
recommend using a 128bit hash (or HMAC) as payload. No error checking is
performed, the user needs to test patterns that the watermarker decodes to
ensure that they really are one of the expected patterns, not a decoding
error.
As an alternative, an experimental short payload option is available, for very
short payloads (12, 16 or 20 bits). It is enabled using the `--short <bits>`
command line option, for instance for 16 bits:
audiowmark add --short 16 in.wav out.wav abcd
audiowmark get --short 16 out.wav
Internally, a larger set of bits is sent to ensure that decoded short patterns
are really valid, so in this mode, error checking is performed after decoding,
and only valid patterns are reported.
Besides error checking, the advantage of a short payload is that fewer bits
need to be sent, so decoding will more likely to be successful on shorter
clips.
== Video Files
For video files, `videowmark` can be used to add a watermark to the audio track
......
AC_INIT([audiowmark], [0.4.1])
AC_INIT([audiowmark], [0.4.2])
AC_CONFIG_SRCDIR([src/audiowmark.cc])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
......@@ -72,8 +72,8 @@ AC_ZITA_REQUIREMENTS
AC_FFTW_CHECK
AM_PATH_LIBGCRYPT
# need c++11 mode
AX_CXX_COMPILE_STDCXX_11(ext)
# need c++14 mode
AX_CXX_COMPILE_STDCXX_14(ext)
# use -Wall
AC_LANG_PUSH([C++])
......
......@@ -5,13 +5,13 @@ COMMON_SRC = utils.hh utils.cc convcode.hh convcode.cc random.hh random.cc wavda
audiostream.cc audiostream.hh sfinputstream.cc sfinputstream.hh stdoutwavoutputstream.cc stdoutwavoutputstream.hh \
sfoutputstream.cc sfoutputstream.hh rawinputstream.cc rawinputstream.hh rawoutputstream.cc rawoutputstream.hh \
rawconverter.cc rawconverter.hh mp3inputstream.cc mp3inputstream.hh wmcommon.cc wmcommon.hh fft.cc fft.hh \
limiter.cc limiter.hh
limiter.cc limiter.hh shortcode.cc shortcode.hh
COMMON_LIBS = $(SNDFILE_LIBS) $(FFTW_LIBS) $(LIBGCRYPT_LIBS) $(LIBMPG123_LIBS)
audiowmark_SOURCES = audiowmark.cc wmget.cc wmadd.cc $(COMMON_SRC)
audiowmark_LDFLAGS = $(COMMON_LIBS)
noinst_PROGRAMS = testconvcode testrandom testmp3 teststream testlimiter
noinst_PROGRAMS = testconvcode testrandom testmp3 teststream testlimiter testshortcode
testconvcode_SOURCES = testconvcode.cc $(COMMON_SRC)
testconvcode_LDFLAGS = $(COMMON_LIBS)
......@@ -27,3 +27,6 @@ teststream_LDFLAGS = $(COMMON_LIBS)
testlimiter_SOURCES = testlimiter.cc $(COMMON_SRC)
testlimiter_LDFLAGS = $(COMMON_LIBS)
testshortcode_SOURCES = testshortcode.cc $(COMMON_SRC)
testshortcode_LDFLAGS = $(COMMON_LIBS)
......@@ -26,6 +26,7 @@
#include "utils.hh"
#include "random.hh"
#include "wmcommon.hh"
#include "shortcode.hh"
#include <assert.h>
......@@ -57,6 +58,7 @@ print_usage()
printf ("Global options:\n");
printf (" --strength <s> set watermark strength [%.6g]\n", Params::water_delta * 1000);
printf (" --linear disable non-linear bit storage\n");
printf (" --short <bits> enable short payload mode\n");
printf (" --key <file> load watermarking key from file\n");
printf (" -q, --quiet disable information messages\n");
printf ("\n");
......@@ -183,6 +185,16 @@ parse_options (int *argc_p,
{
Params::mix = false;
}
else if (check_arg (argc, argv, &i, "--short", &opt_arg))
{
Params::payload_size = atoi (opt_arg);
if (!short_code_init (Params::payload_size))
{
error ("audiowmark: unsupported short payload size %zd\n", Params::payload_size);
exit (1);
}
Params::payload_short = true;
}
else if (check_arg (argc, argv, &i, "--hard"))
{
Params::hard = true;
......
......@@ -19,6 +19,9 @@ fi
if [ "x$AWM_MULTI_CLIP" == "x" ]; then
AWM_MULTI_CLIP=1
fi
if [ "x$AWM_PATTERN_BITS" == "x" ]; then
AWM_PATTERN_BITS=128
fi
{
if [ "x$AWM_SET" == "xsmall" ]; then
......@@ -49,11 +52,18 @@ do
# pseudo random pattern, 128 bit
PATTERN=4e1243bd22c66e76c2ba9eddc1f91394
fi
PATTERN=${PATTERN:0:$((AWM_PATTERN_BITS / 4))}
echo in_pattern $PATTERN
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
CUT=0
if [ "x$AWM_ALWAYS_CUT" != x ]; then
CUT="$AWM_ALWAYS_CUT"
fi
if [ "x$AWM_RAND_CUT" != x ]; then
CUT=$RANDOM
CUT=$((CUT + RANDOM))
fi
if [ "x$CUT" != x0 ]; then
audiowmark cut-start "${AWM_FILE}.wav" "${AWM_FILE}.wav" $CUT
TEST_CUT_ARGS="--test-cut $CUT"
echo in_cut $CUT
......
#!/bin/bash
STRENGTHS="10 15"
STR_CLIPS="6 10 15 20 25 30"
QUALITIES="128 256"
for LS in long short
do
echo ".watermarking-with-$LS-payload"
echo '[frame="topbot",options="header",cols="<1,7*>1"]'
echo '|=========================='
echo -n "| Strength | Quality "
for CLIP in $STR_CLIPS
do
echo -n "| $CLIP"
done
echo
for STRENGTH in $STRENGTHS
do
for QUALITY in $QUALITIES
do
echo -n "| $STRENGTH | $QUALITY "
for CLIP in $STR_CLIPS
do
cat $LS-$CLIP-$STRENGTH-$QUALITY-* | 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
done
echo '|=========================='
done
#!/bin/bash
SEEDS=$(seq 5)
STRENGTHS="10 15"
QUALITIES="128 256"
CLIPS="6 10 15 20 25 30"
MULTI_CLIP=4
echo -n "all:"
for SEED in $SEEDS
do
for STRENGTH in $STRENGTHS
do
for QUALITY in $QUALITIES
do
for CLIP in $CLIPS
do
echo -n " long-$CLIP-$STRENGTH-$QUALITY-$SEED short-$CLIP-$STRENGTH-$QUALITY-$SEED"
done
done
done
done
echo
echo
for SEED in $SEEDS
do
for STRENGTH in $STRENGTHS
do
for QUALITY in $QUALITIES
do
for CLIP in $CLIPS
do
FILE="long-$CLIP-$STRENGTH-$QUALITY-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_RAND_PATTERN=1 AWM_ALWAYS_CUT=500000 AWM_SET=huge2 AWM_PARAMS='--strength $STRENGTH' AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 $QUALITY ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
FILE="short-$CLIP-$STRENGTH-$QUALITY-$SEED"
echo "$FILE:"
echo -e "\t( cd ..; AWM_PATTERN_BITS=12 AWM_RAND_PATTERN=1 AWM_ALWAYS_CUT=500000 AWM_SET=huge2 AWM_PARAMS='--short --strength $STRENGTH' AWM_CLIP='$CLIP' AWM_MULTI_CLIP='$MULTI_CLIP' AWM_SEEDS=$SEED AWM_FILE='t-$FILE' ber-test.sh mp3 $QUALITY ) >x$FILE"
echo -e "\tmv x$FILE $FILE"
echo
done
done
done
done
......@@ -44,7 +44,7 @@ public:
~MP3InputStream();
Error open (const std::string& filename);
Error read_frames (std::vector<float>& samples, size_t count);
Error read_frames (std::vector<float>& samples, size_t count) override;
void close();
int bit_depth() const override;
......
......@@ -120,9 +120,10 @@ Random::seed (uint64_t seed, Stream stream)
buffer_pos = 0;
buffer.clear();
unsigned char plain_text[aes_key.size()] = { 0, };
unsigned char plain_text[aes_key.size()];
unsigned char cipher_text[aes_key.size()];
memset (plain_text, 0, sizeof (plain_text));
uint64_to_buffer (seed, &plain_text[0]);
plain_text[8] = uint8_t (stream);
......
......@@ -21,6 +21,10 @@
using std::vector;
RawConverter::~RawConverter()
{
}
template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
class RawConverterImpl : public RawConverter
{
......
......@@ -25,6 +25,8 @@ class RawConverter
public:
static RawConverter *create (const RawFormat& raw_format, Error& error);
virtual ~RawConverter() = 0;
virtual void to_raw (const std::vector<float>& samples, std::vector<unsigned char>& bytes) = 0;
virtual void from_raw (const std::vector<unsigned char>& bytes, std::vector<float>& samples) = 0;
};
......
......@@ -45,7 +45,7 @@ public:
Error open (const std::string& filename, const RawFormat& format);
Error write_frames (const std::vector<float>& frames) override;
Error close();
Error close() override;
};
#endif /* AUDIOWMARK_RAW_OUTPUT_STREAM_HH */
......@@ -43,11 +43,11 @@ public:
~SFInputStream();
Error open (const std::string& filename);
Error read_frames (std::vector<float>& samples, size_t count);
Error read_frames (std::vector<float>& samples, size_t count) override;
void close();
int
n_channels() const
n_channels() const override
{
return m_n_channels;
}
......
This diff is collapsed.
/*
* Copyright (C) 2018-2020 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/>.
*/
#ifndef AUDIOWMARK_SHORT_CODE_HH
#define AUDIOWMARK_SHORT_CODE_HH
#include <vector>
#include <string>
#include "convcode.hh"
size_t code_size (ConvBlockType block_type, size_t msg_size);
std::vector<int> code_encode (ConvBlockType block_type, const std::vector<int>& in_bits);
std::vector<int> code_decode_soft (ConvBlockType block_type, const std::vector<float>& coded_bits, float *error_out = nullptr);
size_t short_code_size (ConvBlockType block_type, size_t msg_size);
std::vector<int> short_encode (ConvBlockType block_type, const std::vector<int>& in_bits);
std::vector<int> short_decode_soft (ConvBlockType block_type, const std::vector<float>& coded_bits, float *error_out = nullptr);
std::vector<int> short_encode_blk (const std::vector<int>& in_bits);
std::vector<int> short_decode_blk (const std::vector<int>& coded_bits);
size_t short_code_init (size_t k);
#endif /* AUDIOWMARK_SHORT_CODE_HH */
......@@ -44,7 +44,7 @@ public:
Error open (int n_channels, int sample_rate, int bit_depth, size_t n_frames);
Error write_frames (const std::vector<float>& frames) override;
Error close();
Error close() override;
int sample_rate() const override;
int bit_depth() const override;
int n_channels() const override;
......
/*
* Copyright (C) 2018-2020 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 <vector>
#include <map>
#include <sstream>
#include <sys/time.h>
#include <assert.h>
#include "shortcode.hh"
using std::vector;
using std::string;
using std::map;
static double
gettime()
{
timeval tv;
gettimeofday (&tv, 0);
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
vector<int>
generate_error_vector (size_t n, int errors)
{
vector<int> ev (n);
while (errors)
{
size_t pos = rand() % ev.size();
if (ev[pos] != 1)
{
ev[pos] = 1;
errors--;
}
}
return ev;
}
int
hamming_weight (const vector<int>& bits)
{
int w = 0;
for (auto b : bits)
w += b;
return w;
}
double
factorial (int x)
{
double p = 1;
for (int i = 1; i <= x; i++)
p *= i;
return p;
}
string
number_format (double d)
{
std::ostringstream buff;
buff.imbue (std::locale(""));
buff << (uint64_t) d;
return buff.str();
}
int
main (int argc, char **argv)
{
srand (time (NULL));
if (argc < 2)
{
printf ("first argument must be code size (12, 16, 20)\n");
return 1;
}
size_t K = atoi (argv[1]);
size_t N = short_code_init (K);
if (!N)
{
printf ("bad code size\n");
return 1;
}
printf ("using (%zd,%zd) code\n", N, K);
if (argc == 2)
{
vector<int> in_bits;
while (in_bits.size() != K)
in_bits.push_back (rand() & 1);
printf ("in: ");
for (auto b : in_bits)
printf ("%d", b);
printf ("\n");
printf ("coded: ");
vector<int> coded_bits = short_encode_blk (in_bits);
for (auto b : coded_bits)
printf ("%d", b);
printf ("\n");
vector<int> decoded_bits = short_decode_blk (coded_bits);
printf ("out: ");
for (auto b : decoded_bits)
printf ("%d", b);
printf ("\n");
}
if (argc == 3 && string (argv[2]) == "perf")
{
const double start_t = gettime();
const size_t runs = 100;
for (size_t i = 0; i < runs; i++)
{
vector<int> in_bits;
while (in_bits.size() != K)
in_bits.push_back (rand() & 1);
vector<int> out_bits = short_decode_blk (short_encode_blk (in_bits));
assert (out_bits == in_bits);
}
printf ("%.1f ms/block\n", (gettime() - start_t) / runs * 1000.0);
}
if (argc == 3 && string (argv[2]) == "table")
{
map<vector<int>, vector<int>> table;
vector<int> weight (N + 1);
for (size_t i = 0; i < size_t (1 << K); i++)
{
vector<int> in;
for (size_t bit = 0; bit < K; bit++)
{
if (i & (1 << bit))
in.push_back (1);
else
in.push_back (0);
}
vector<int> coded_bits = short_encode_blk (in);
table[coded_bits] = in;
weight[hamming_weight (coded_bits)]++;
printf ("T: ");
for (auto b : coded_bits)
printf ("%d", b);
printf ("\n");
}
for (size_t i = 0; i <= N; i++)
{
if (weight[i])
printf ("W %3zd %6d %20s\n", i, weight[i], number_format (factorial (N) / (factorial (i) * factorial (N - i)) / weight[i]).c_str());
}
/* decoding test */
for (auto it : table)
{
assert (short_decode_blk (it.first) == it.second);
}
const size_t runs = 50LL * 1000 * 1000 * 1000;
size_t match = 0;
for (size_t i = 0; i < runs; i++)
{
vector<int> in_bits = generate_error_vector (N, K);
auto it = table.find (in_bits);
if (it != table.end())
match++;
if ((i % 1000000) == 0)
{
printf ("%zd / %zd\r", match, i);
fflush (stdout);
}
}
}
if (argc == 3 && string (argv[2]) == "distance")
{
vector<vector<int>> cwords;
for (size_t i = 0; i < size_t (1 << K); i++)
{
vector<int> in;
for (size_t bit = 0; bit < K; bit++)
{
if (i & (1 << bit))
in.push_back (1);
else
in.push_back (0);
}
cwords.push_back (short_encode_blk (in));
}
int mhd = 100000;
for (size_t a = 0; a < cwords.size(); a++)
{
for (size_t b = 0; b < cwords.size(); b++)
{
if (a != b)
{
int hd = 0;
for (size_t c = 0; c < cwords[a].size(); c++)
hd += cwords[a][c] ^ cwords[b][c];
if (hd < mhd)
mhd = hd;
}
}
if ((a & 255) == 0)
{
printf ("%zd\r", a);
fflush (stdout);
}
}
printf ("\n");
printf ("%d\n", mhd);
}
}
......@@ -30,6 +30,7 @@
#include "rawinputstream.hh"
#include "rawoutputstream.hh"
#include "stdoutwavoutputstream.hh"
#include "shortcode.hh"
using std::string;
using std::vector;
......@@ -149,7 +150,7 @@ init_frame_mod_vec (vector<vector<FrameMod>>& frame_mod_vec, int ab, const vecto
/* forward error correction */
ConvBlockType block_type = ab ? ConvBlockType::b : ConvBlockType::a;
vector<int> bitvec_fec = randomize_bit_order (conv_encode (block_type, bitvec), /* encode */ true);
vector<int> bitvec_fec = randomize_bit_order (code_encode (block_type, bitvec), /* encode */ true);
mark_sync (frame_mod_vec, ab);
mark_data (frame_mod_vec, bitvec_fec);
......@@ -553,6 +554,11 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
error ("audiowmark: cannot parse bits %s\n", bits.c_str());
return 1;
}
if (Params::payload_short && bitvec.size() != Params::payload_size)
{
error ("audiowmark: number of message bits must match payload size (%zd bits)\n", Params::payload_size);
return 1;
}
if (bitvec.size() > Params::payload_size)
{
error ("audiowmark: number of bits in message '%s' larger than payload size\n", bits.c_str());
......
......@@ -18,6 +18,7 @@
#include "wmcommon.hh"
#include "fft.hh"
#include "convcode.hh"
#include "shortcode.hh"
int Params::frames_per_bit = 2;
double Params::water_delta = 0.01;
......@@ -25,6 +26,8 @@ bool Params::mix = true;
bool Params::hard = false; // hard decode bits? (soft decoding is better)
bool Params::snr = false; // compute/show snr while adding watermark
int Params::have_key = 0;
size_t Params::payload_size = 128;
bool Params::payload_short = false;
int Params::test_cut = 0; // for sync test
bool Params::test_no_sync = false; // disable sync
bool Params::test_no_limiter = false; // disable limiter
......@@ -209,7 +212,7 @@ data_frame_pos (int f)
size_t
mark_data_frame_count()
{
return conv_code_size (ConvBlockType::a, Params::payload_size) * Params::frames_per_bit;
return code_size (ConvBlockType::a, Params::payload_size) * Params::frames_per_bit;
}
size_t
......
......@@ -43,7 +43,8 @@ public:
static bool snr; // compute/show snr while adding watermark
static int have_key;
static constexpr size_t payload_size = 128; // number of payload bits for the watermark
static size_t payload_size; // number of payload bits for the watermark
static bool payload_short;
static constexpr int sync_bits = 6;
static constexpr int sync_frames_per_bit = 85;
......
......@@ -24,6 +24,7 @@
#include "wavdata.hh"
#include "wmcommon.hh"
#include "convcode.hh"
#include "shortcode.hh"
using std::string;
using std::vector;
......@@ -758,7 +759,7 @@ public:
SyncFinder sync_finder;
sync_scores = sync_finder.search (wav_data, SyncFinder::Mode::BLOCK);
vector<float> raw_bit_vec_all (conv_code_size (ConvBlockType::ab, Params::payload_size));
vector<float> raw_bit_vec_all (code_size (ConvBlockType::ab, Params::payload_size));
vector<int> raw_bit_vec_norm (2);
SyncFinder::Score score_all { 0, 0 };
......@@ -787,15 +788,16 @@ public:
{
raw_bit_vec = linear_decode (fft_range_out, wav_data.n_channels());
}
assert (raw_bit_vec.size() == conv_code_size (ConvBlockType::a, Params::payload_size));
assert (raw_bit_vec.size() == code_size (ConvBlockType::a, Params::payload_size));
raw_bit_vec = randomize_bit_order (raw_bit_vec, /* encode */ false);
/* ---- deal with this pattern ---- */
float decode_error = 0;
vector<int> bit_vec = conv_decode_soft (sync_score.block_type, normalize_soft_bits (raw_bit_vec), &decode_error);
vector<int> bit_vec = code_decode_soft (sync_score.block_type, normalize_soft_bits (raw_bit_vec), &decode_error);
result_set.add_pattern (sync_score, bit_vec, decode_error, ResultSet::Type::BLOCK);
if (!bit_vec.empty())
result_set.add_pattern (sync_score, bit_vec, decode_error, ResultSet::Type::BLOCK);
total_count += 1;
/* ---- update "all" pattern ---- */
......@@ -819,10 +821,13 @@ public:
ab_bits[i * 2] = ab_raw_bit_vec[0][i];
ab_bits[i * 2 + 1] = ab_raw_bit_vec[1][i];
}
vector<int> bit_vec = conv_decode_soft (ConvBlockType::ab, normalize_soft_bits (ab_bits), &decode_error);
score_ab.index = sync_score.index;
score_ab.quality = (ab_quality[0] + ab_quality[1]) / 2;
result_set.add_pattern (score_ab, bit_vec, decode_error, ResultSet::Type::BLOCK);
vector<int> bit_vec = code_decode_soft (ConvBlockType::ab, normalize_soft_bits (ab_bits), &decode_error);
if (!bit_vec.empty())
{
score_ab.index = sync_score.index;
score_ab.quality = (ab_quality[0] + ab_quality[1]) / 2;
result_set.add_pattern (score_ab, bit_vec, decode_error, ResultSet::Type::BLOCK);
}
}
last_block_type = sync_score.block_type;
}
......@@ -839,9 +844,10 @@ public:
vector<float> soft_bit_vec = normalize_soft_bits (raw_bit_vec_all);
float decode_error = 0;
vector<int> bit_vec = conv_decode_soft (ConvBlockType::ab, soft_bit_vec, &decode_error);
vector<int> bit_vec = code_decode_soft (ConvBlockType::ab, soft_bit_vec, &decode_error);
result_set.add_pattern (score_all, bit_vec, decode_error, ResultSet::Type::ALL);
if (!bit_vec.empty())
result_set.add_pattern (score_all, bit_vec, decode_error, ResultSet::Type::ALL);
}
debug_sync_frame_count = frame_count (wav_data);
......@@ -943,11 +949,13 @@ class ClipDecoder
}
float decode_error = 0;
vector<int> bit_vec = conv_decode_soft (ConvBlockType::ab, normalize_soft_bits (raw_bit_vec), &decode_error);
SyncFinder::Score sync_score_nopad = sync_score;
sync_score_nopad.index = time_offset_sec * wav_data.sample_rate();
result_set.add_pattern (sync_score_nopad, bit_vec, decode_error, ResultSet::Type::CLIP);
vector<int> bit_vec = code_decode_soft (ConvBlockType::ab, normalize_soft_bits (raw_bit_vec), &decode_error);
if (!bit_vec.empty())
{
SyncFinder::Score sync_score_nopad = sync_score;
sync_score_nopad.index = time_offset_sec * wav_data.sample_rate();
result_set.add_pattern (sync_score_nopad, bit_vec, decode_error, ResultSet::Type::CLIP);
}
}
}
}
......
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