summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Szmigin <smidge@xsco.net>2020-02-19 21:45:21 +0000
committerAdam Szmigin <smidge@xsco.net>2020-02-19 21:45:21 +0000
commitf249029a1672be07a286d99cc1206c5cff754887 (patch)
tree198bb02a44667ef7a92682d974360cf29879dcc8
parent7ea64154ccd94a1e2152315e9c221062521bc145 (diff)
Corrected some encoding regression bugs.
* Fixed some encoding bugs introduced in earlier refactoring. * Quantised some amounts used for waveform encoding better (WIP).
-rw-r--r--.gitignore3
-rw-r--r--src/djinterop/enginelibrary/el_track_impl.cpp55
-rw-r--r--src/djinterop/enginelibrary/el_track_impl.hpp5
-rw-r--r--src/djinterop/enginelibrary/performance_data_format.cpp63
-rw-r--r--test/enginelibrary/performance_data_test.cpp4
5 files changed, 89 insertions, 41 deletions
diff --git a/.gitignore b/.gitignore
index e229d03..e70b181 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,9 @@
# Sub-projects
/subprojects/
-# Helper for bear (b-ear)
+# Compilation database
compile_commands.json
+.clangd/
# direnv configuration file
.envrc
diff --git a/src/djinterop/enginelibrary/el_track_impl.cpp b/src/djinterop/enginelibrary/el_track_impl.cpp
index 66acd29..3618c73 100644
--- a/src/djinterop/enginelibrary/el_track_impl.cpp
+++ b/src/djinterop/enginelibrary/el_track_impl.cpp
@@ -56,6 +56,42 @@ boost::optional<int64_t> to_timestamp(
}
return result;
}
+
+/// Calculate the quantisation number for waveforms, given a quantisation number.
+///
+/// A few numbers written to the waveform performance data are rounded
+/// to multiples of a particular "quantisation number", that is equal to
+/// the sample rate divided by 105, and then rounded to the nearest
+/// multiple of two.
+inline int64_t quantisation_number(int64_t sample_rate)
+{
+ return (sample_rate / 210) * 2;
+}
+
+/// Calculate the samples-per-entry in an overview waveform.
+///
+/// An overview waveform always has 1024 entries, and the number of samples
+/// that each one represents must be calculated from the true sample count by
+/// rounding the number of samples to the quantisation number first.
+inline int64_t calculate_overview_waveform_samples_per_entry(
+ int64_t sample_rate, int64_t sample_count)
+{
+ auto qn = quantisation_number(sample_rate);
+ return ((sample_count / qn) * qn) / 1024;
+}
+
+/// Calculate the recommended number of entries in the high-resolution waveform.
+///
+/// The recommended number of entries in any high-resolution end-point is
+/// expected to be the ceiling division of number of samples by quantisation
+/// number.
+inline int64_t calculate_high_resolution_waveform_num_entries(
+ int64_t sample_rate, int64_t sample_count)
+{
+ auto qn = quantisation_number(sample_rate);
+ return sample_count / qn + (sample_count % qn != 0);
+}
+
} // namespace
el_track_impl::el_track_impl(std::shared_ptr<el_storage> storage, int64_t id)
@@ -660,7 +696,9 @@ int64_t el_track_impl::recommended_waveform_size()
throw track_database_inconsistency{"Track has non-positive sample rate",
id()};
}
- return static_cast<int64_t>(smp->sample_count * 105 / smp->sample_rate);
+
+ return calculate_high_resolution_waveform_num_entries(
+ smp->sample_rate, smp->sample_count);
}
std::string el_track_impl::relative_path()
@@ -722,6 +760,7 @@ void el_track_impl::set_sampling(boost::optional<sampling_info> sampling)
set_beat_data(std::move(beat_d));
set_track_data(std::move(track_d));
+ int64_t sample_rate = sampling ? sampling->sample_rate : 0;
int64_t sample_count = sampling ? sampling->sample_count : 0;
if (!high_res_waveform_d.waveform.empty())
@@ -734,7 +773,8 @@ void el_track_impl::set_sampling(boost::optional<sampling_info> sampling)
if (!overview_waveform_d.waveform.empty())
{
overview_waveform_d.samples_per_entry =
- sample_count / overview_waveform_d.waveform.size();
+ calculate_overview_waveform_samples_per_entry(
+ sample_rate, sample_count);
set_overview_waveform_data(std::move(overview_waveform_d));
}
@@ -778,13 +818,22 @@ void el_track_impl::set_waveform(std::vector<waveform_entry> waveform)
{
auto smp = sampling();
int64_t sample_count = smp ? smp->sample_count : 0;
- overview_waveform_d.samples_per_entry = sample_count / 1024;
+ int64_t sample_rate = smp ? smp->sample_rate : 0;
+
+ // Calculate an overview waveform automatically.
+ // Note that the overview waveform always has 1024 entries in it.
+ overview_waveform_d.samples_per_entry =
+ calculate_overview_waveform_samples_per_entry(
+ sample_rate, sample_count);
overview_waveform_d.waveform.reserve(1024);
for (int32_t i = 0; i < 1024; ++i)
{
auto entry = waveform[waveform.size() * (2 * i + 1) / 2048];
overview_waveform_d.waveform.push_back(entry);
}
+
+ // TODO (mr-smidge) resize waveform to be compatible with quantisation
+ // number, padding out with zeroes at end as necessary.
high_res_waveform_d.samples_per_entry = sample_count / waveform.size();
high_res_waveform_d.waveform = std::move(waveform);
}
diff --git a/src/djinterop/enginelibrary/el_track_impl.hpp b/src/djinterop/enginelibrary/el_track_impl.hpp
index f5437fc..3074f5f 100644
--- a/src/djinterop/enginelibrary/el_track_impl.hpp
+++ b/src/djinterop/enginelibrary/el_track_impl.hpp
@@ -160,7 +160,7 @@ public:
"overviewWaveFormData, beatData, quickCues, loops, "
"hasSeratoValues) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
<< id() //
- << 0.0 // isAnalyzed
+ << 1.0 // isAnalyzed
<< 0.0 // isRendered
<< track_data{}.encode() //
<< high_res_waveform_data{}.encode() //
@@ -181,7 +181,7 @@ public:
}
storage_->db << (std::string{"UPDATE PerformanceData SET "} +
- column_name + " = ? WHERE id = ?")
+ column_name + " = ?, isAnalyzed = 1 WHERE id = ?")
<< content.encode() << id();
}
@@ -193,6 +193,7 @@ public:
void set_loops_data(loops_data data);
overview_waveform_data get_overview_waveform_data();
void set_overview_waveform_data(overview_waveform_data data);
+
quick_cues_data get_quick_cues_data();
void set_quick_cues_data(quick_cues_data data);
track_data get_track_data();
diff --git a/src/djinterop/enginelibrary/performance_data_format.cpp b/src/djinterop/enginelibrary/performance_data_format.cpp
index eb9204a..e346448 100644
--- a/src/djinterop/enginelibrary/performance_data_format.cpp
+++ b/src/djinterop/enginelibrary/performance_data_format.cpp
@@ -132,35 +132,6 @@ std::pair<std::vector<beatgrid_marker>, const char*> decode_beatgrid(
return {std::move(result), ptr};
}
-char* encode_opt_sampling_info(
- boost::optional<sampling_info> sampling, char* ptr)
-{
- if (sampling)
- {
- ptr = encode_double_be(sampling->sample_rate, ptr);
- ptr = encode_int64_be(sampling->sample_count, ptr);
- }
- else
- {
- ptr = encode_double_be(0, ptr); // TODO (haslersn): is 0 ok?
- ptr = encode_int64_be(0, ptr);
- }
- return ptr;
-}
-
-std::pair<boost::optional<sampling_info>, const char*> decode_opt_sampling_info(
- const char* ptr)
-{
- sampling_info sampling;
- std::tie(sampling.sample_rate, ptr) = decode_double_be(ptr);
- std::tie(sampling.sample_count, ptr) = decode_int64_be(ptr);
- if (sampling.sample_rate == 0)
- {
- return {boost::none, ptr};
- }
- return {sampling, ptr};
-}
-
} // namespace
// Encode beat data into a byte array
@@ -171,7 +142,16 @@ std::vector<char> beat_data::encode() const
auto ptr = uncompressed.data();
const auto end = ptr + uncompressed.size();
- ptr = encode_opt_sampling_info(sampling, ptr);
+ if (sampling)
+ {
+ ptr = encode_double_be(sampling->sample_rate, ptr);
+ ptr = encode_double_be(sampling->sample_count, ptr);
+ }
+ else
+ {
+ ptr = encode_double_be(0, ptr); // TODO (haslersn): is 0 ok?
+ ptr = encode_double_be(0, ptr);
+ }
ptr = encode_uint8(1, ptr);
ptr = encode_beatgrid(default_beatgrid, ptr);
ptr = encode_beatgrid(adjusted_beatgrid, ptr);
@@ -200,7 +180,11 @@ beat_data beat_data::decode(const std::vector<char>& compressed_data)
beat_data result;
- std::tie(result.sampling, ptr) = decode_opt_sampling_info(ptr);
+ sampling_info sampling;
+ std::tie(sampling.sample_rate, ptr) = decode_double_be(ptr);
+ std::tie(sampling.sample_count, ptr) = decode_double_be(ptr);
+ result.sampling = sampling.sample_rate != 0
+ ? boost::make_optional(sampling) : boost::none;
uint8_t is_beat_data_set;
std::tie(is_beat_data_set, ptr) = decode_uint8(ptr);
@@ -705,7 +689,16 @@ std::vector<char> track_data::encode() const
auto ptr = uncompressed.data();
const auto end = ptr + uncompressed.size();
- ptr = encode_opt_sampling_info(sampling, ptr);
+ if (sampling)
+ {
+ ptr = encode_double_be(sampling->sample_rate, ptr);
+ ptr = encode_int64_be(sampling->sample_count, ptr);
+ }
+ else
+ {
+ ptr = encode_double_be(0, ptr); // TODO (haslersn): is 0 ok?
+ ptr = encode_int64_be(0, ptr);
+ }
ptr = encode_double_be(average_loudness.value_or(0), ptr);
ptr = encode_int32_be(key ? static_cast<int32_t>(*key) : 0, ptr);
@@ -733,7 +726,11 @@ track_data track_data::decode(const std::vector<char>& compressed_track_data)
track_data result;
- std::tie(result.sampling, ptr) = decode_opt_sampling_info(ptr);
+ sampling_info sampling;
+ std::tie(sampling.sample_rate, ptr) = decode_double_be(ptr);
+ std::tie(sampling.sample_count, ptr) = decode_int64_be(ptr);
+ result.sampling = sampling.sample_rate != 0
+ ? boost::make_optional(sampling) : boost::none;
double raw_average_loudness;
std::tie(raw_average_loudness, ptr) = decode_double_be(ptr);
diff --git a/test/enginelibrary/performance_data_test.cpp b/test/enginelibrary/performance_data_test.cpp
index 9ab3bb9..9e2cb58 100644
--- a/test/enginelibrary/performance_data_test.cpp
+++ b/test/enginelibrary/performance_data_test.cpp
@@ -213,7 +213,7 @@ static void check_track_1(const djinterop::track& t)
BOOST_CHECK_EQUAL(t.overview_waveform().size(), 1024);
// High-res waveform data
- BOOST_CHECK_EQUAL(t.waveform().size(), 41554);
+ BOOST_CHECK_EQUAL(t.waveform().size(), 41555);
}
static void populate_track_2(djinterop::track& t)
@@ -340,7 +340,7 @@ static void check_track_2(const djinterop::track& t)
BOOST_CHECK_EQUAL(t.overview_waveform().size(), 1024);
// High-res waveform data
- BOOST_CHECK_EQUAL(t.waveform().size(), 23614);
+ BOOST_CHECK_EQUAL(t.waveform().size(), 23675);
}
BOOST_AUTO_TEST_CASE(save__new_track_good_values__saves)