diff options
author | Adam Szmigin <smidge@xsco.net> | 2020-02-19 21:45:21 +0000 |
---|---|---|
committer | Adam Szmigin <smidge@xsco.net> | 2020-02-19 21:45:21 +0000 |
commit | f249029a1672be07a286d99cc1206c5cff754887 (patch) | |
tree | 198bb02a44667ef7a92682d974360cf29879dcc8 | |
parent | 7ea64154ccd94a1e2152315e9c221062521bc145 (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-- | .gitignore | 3 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/el_track_impl.cpp | 55 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/el_track_impl.hpp | 5 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/performance_data_format.cpp | 63 | ||||
-rw-r--r-- | test/enginelibrary/performance_data_test.cpp | 4 |
5 files changed, 89 insertions, 41 deletions
@@ -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) |