diff options
author | Adam Szmigin <smidge@xsco.net> | 2020-06-12 23:10:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-12 23:10:10 +0100 |
commit | 8f4c54e27fa1924c15cd3a9e9d300a979123decb (patch) | |
tree | fe98633fb333ec544a0899a6964bc7c6898e8a71 | |
parent | e159163e8ff02dc14a4f26a538ced9b0a483fdb6 (diff) | |
parent | 95ca21ee6cc7c58694c64feee27e24d8aed74f78 (diff) |
Merge pull request #7 from haslersn/enhancement/allow-reading-malformed-beatgrid
enginelibrary: Allow reading beat data even if the beatgrid is malformed
-rw-r--r-- | .clang-format | 2 | ||||
-rw-r--r-- | default.nix | 5 | ||||
-rw-r--r-- | include/djinterop/performance_data.hpp | 42 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/el_track_impl.cpp | 9 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/el_track_impl.hpp | 16 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/performance_data_format.cpp | 17 | ||||
-rw-r--r-- | src/djinterop/enginelibrary/performance_data_format.hpp | 72 |
7 files changed, 143 insertions, 20 deletions
diff --git a/.clang-format b/.clang-format index a90ead2..2112752 100644 --- a/.clang-format +++ b/.clang-format @@ -94,7 +94,7 @@ PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left RawStringFormats: - - Delimiter: 'pb' + - Delimiters: [ 'pb' ] Language: TextProto BasedOnStyle: google ReflowComments: true diff --git a/default.nix b/default.nix index 88c2fe4..17f27a0 100644 --- a/default.nix +++ b/default.nix @@ -6,8 +6,8 @@ let name = "git-clang-format"; version = "2019-06-21"; src = fetchurl { - url = "https://raw.githubusercontent.com/llvm-mirror/clang/2bb8e0fe002e8ffaa9ce5fa58034453c94c7e208/tools/clang-format/git-clang-format"; - sha256 = "1kby36i80js6rwi11v3ny4bqsi6i44b9yzs23pdcn9wswffx1nlf"; + url = "https://raw.githubusercontent.com/llvm-mirror/clang/e8c2d2746b1e718b607b78a830534fd3a981d250/tools/clang-format/git-clang-format"; + sha256 = "sha256:1wp7zw2jgpgnv9cr648nlk6gs26yadvs14qnll3vnay1y0n79nd7"; executable = true; }; nativeBuildInputs = [ @@ -42,6 +42,7 @@ stdenv.mkDerivation { outputs = [ "out" "dev" ]; buildInputs = [ boost + sqlite zlib ]; } diff --git a/include/djinterop/performance_data.hpp b/include/djinterop/performance_data.hpp index 67e22e2..620e676 100644 --- a/include/djinterop/performance_data.hpp +++ b/include/djinterop/performance_data.hpp @@ -35,12 +35,26 @@ struct sampling_info { double sample_rate = 0; // usually 44100.0 or 48000.0 int64_t sample_count = 0; + + friend bool operator==( + const sampling_info& first, const sampling_info& second) noexcept + { + return first.sample_rate == second.sample_rate && + first.sample_count == second.sample_count; + } }; struct beatgrid_marker { int32_t index = 0; double sample_offset = 0; + + friend bool operator==( + const beatgrid_marker& first, const beatgrid_marker& second) noexcept + { + return first.index == second.index && + first.sample_offset == second.sample_offset; + } }; struct hot_cue @@ -48,6 +62,13 @@ struct hot_cue std::string label; double sample_offset = 0; pad_color color; + + friend bool operator==(const hot_cue& first, const hot_cue& second) noexcept + { + return first.label == second.label && + first.sample_offset == second.sample_offset && + first.color == second.color; + } }; struct loop @@ -56,12 +77,26 @@ struct loop double start_sample_offset = 0; double end_sample_offset = 0; pad_color color; + + friend bool operator==(const loop& first, const loop& second) noexcept + { + return first.label == second.label && + first.start_sample_offset == second.start_sample_offset && + first.end_sample_offset == second.end_sample_offset && + first.color == second.color; + } }; struct waveform_point { uint8_t value = 0; uint8_t opacity = 255; + + friend bool operator==( + const waveform_point& first, const waveform_point& second) noexcept + { + return first.value == second.value && first.opacity == second.opacity; + } }; /** @@ -82,6 +117,13 @@ struct waveform_entry waveform_point low; waveform_point mid; waveform_point high; + + friend bool operator==( + const waveform_entry& first, const waveform_entry& second) noexcept + { + return first.low == second.low && first.mid == second.mid && + first.high == second.high; + } }; } // namespace djinterop diff --git a/src/djinterop/enginelibrary/el_track_impl.cpp b/src/djinterop/enginelibrary/el_track_impl.cpp index fe1ddca..3ab3d7e 100644 --- a/src/djinterop/enginelibrary/el_track_impl.cpp +++ b/src/djinterop/enginelibrary/el_track_impl.cpp @@ -201,6 +201,15 @@ overview_waveform_data el_track_impl::get_overview_waveform_data() void el_track_impl::set_overview_waveform_data(overview_waveform_data data) { + // As the overview waveform does not store opacity, it is defaulted to 255 + // when read back. If we also set it to 255 here, we can apply a check in + // `set_perfdata` that a round-trip encode/decode gives the same data. + for (auto&& entry : data.waveform) + { + entry.low.opacity = 255; + entry.mid.opacity = 255; + entry.high.opacity = 255; + } set_perfdata("overviewWaveFormData", data); } diff --git a/src/djinterop/enginelibrary/el_track_impl.hpp b/src/djinterop/enginelibrary/el_track_impl.hpp index bd934e1..bf82ee6 100644 --- a/src/djinterop/enginelibrary/el_track_impl.hpp +++ b/src/djinterop/enginelibrary/el_track_impl.hpp @@ -135,6 +135,20 @@ public: template <typename T> void set_perfdata(const char* column_name, const T& content) { + auto encoded_content = content.encode(); + // Check that subsequent reads can correctly decode what we are about to + // write. + if (!(T::decode(encoded_content) == content)) + { + // TODO (haslersn): As soon as warnings are implemented, add the + // wording similar to "Either you got a warning above which tells + // you what is wrong, or this is a bug in libdjinterop." + throw std::logic_error{ + "Data supplied for column " + std::string(column_name) + + " is not invariant under encoding and subsequent decoding. " + "This is a bug in libdjinterop."}; + } + bool found = false; storage_->db << "SELECT COUNT(*) FROM PerformanceData WHERE id = ?" << id() >> @@ -182,7 +196,7 @@ public: storage_->db << (std::string{"UPDATE PerformanceData SET "} + column_name + " = ?, isAnalyzed = 1 WHERE id = ?") - << content.encode() << id(); + << encoded_content << id(); } beat_data get_beat_data(); diff --git a/src/djinterop/enginelibrary/performance_data_format.cpp b/src/djinterop/enginelibrary/performance_data_format.cpp index e346448..58a9a42 100644 --- a/src/djinterop/enginelibrary/performance_data_format.cpp +++ b/src/djinterop/enginelibrary/performance_data_format.cpp @@ -193,8 +193,21 @@ beat_data beat_data::decode(const std::vector<char>& compressed_data) // TODO (haslersn): print a warning that "Is beat data set" is not 1 } - std::tie(result.default_beatgrid, ptr) = decode_beatgrid(ptr, end); - std::tie(result.adjusted_beatgrid, ptr) = decode_beatgrid(ptr, end); + try + { + std::vector<beatgrid_marker> default_beatgrid; + std::vector<beatgrid_marker> adjusted_beatgrid; + std::tie(default_beatgrid, ptr) = decode_beatgrid(ptr, end); + std::tie(adjusted_beatgrid, ptr) = decode_beatgrid(ptr, end); + // If there's an exception, then the following will intentially not be + // executed. + result.default_beatgrid = std::move(default_beatgrid); + result.adjusted_beatgrid = std::move(adjusted_beatgrid); + } + catch (const std::invalid_argument& e) + { + // TODO (haslersn): print a warning with e.what(). + } if (ptr != end) { diff --git a/src/djinterop/enginelibrary/performance_data_format.hpp b/src/djinterop/enginelibrary/performance_data_format.hpp index e96fb71..acf1cb6 100644 --- a/src/djinterop/enginelibrary/performance_data_format.hpp +++ b/src/djinterop/enginelibrary/performance_data_format.hpp @@ -33,23 +33,39 @@ namespace enginelibrary { struct beat_data { - beat_data() noexcept = default; - boost::optional<sampling_info> sampling; std::vector<beatgrid_marker> default_beatgrid; std::vector<beatgrid_marker> adjusted_beatgrid; + beat_data() noexcept = default; + + friend bool operator==( + const beat_data& first, const beat_data& second) noexcept + { + return first.sampling == second.sampling && + first.default_beatgrid == second.default_beatgrid && + first.adjusted_beatgrid == second.adjusted_beatgrid; + } + std::vector<char> encode() const; static beat_data decode(const std::vector<char>& compressed_data); }; struct high_res_waveform_data { - high_res_waveform_data() noexcept = default; - double samples_per_entry; std::vector<waveform_entry> waveform; + high_res_waveform_data() noexcept = default; + + friend bool operator==( + const high_res_waveform_data& first, + const high_res_waveform_data& second) noexcept + { + return first.samples_per_entry == second.samples_per_entry && + first.waveform == second.waveform; + } + std::vector<char> encode() const; static high_res_waveform_data decode( const std::vector<char>& compressed_data); @@ -57,10 +73,16 @@ struct high_res_waveform_data struct loops_data { - loops_data() = default; - std::array<boost::optional<loop>, 8> loops; // Don't use curly braces here! + loops_data() noexcept = default; + + friend bool operator==( + const loops_data& first, const loops_data& second) noexcept + { + return first.loops == second.loops; + } + std::vector<char> encode() const; static loops_data decode( const std::vector<char>& raw_data); // not compressed @@ -68,11 +90,19 @@ struct loops_data struct overview_waveform_data { - overview_waveform_data() noexcept = default; - double samples_per_entry; std::vector<waveform_entry> waveform; + overview_waveform_data() noexcept = default; + + friend bool operator==( + const overview_waveform_data& first, + const overview_waveform_data& second) noexcept + { + return first.samples_per_entry == second.samples_per_entry && + first.waveform == second.waveform; + } + std::vector<char> encode() const; static overview_waveform_data decode( const std::vector<char>& compressed_data); @@ -80,27 +110,41 @@ struct overview_waveform_data struct quick_cues_data { - quick_cues_data() = default; - std::array<boost::optional<hot_cue>, 8> hot_cues; double adjusted_main_cue = 0; double default_main_cue = 0; - std::vector<char> encode() const; + quick_cues_data() noexcept = default; + + friend bool operator==( + const quick_cues_data& first, const quick_cues_data& second) noexcept + { + return first.hot_cues == second.hot_cues && + first.adjusted_main_cue == second.adjusted_main_cue && + first.default_main_cue == second.default_main_cue; + } + std::vector<char> encode() const; static quick_cues_data decode(const std::vector<char>& compressed_data); }; struct track_data { - track_data() noexcept = default; - boost::optional<sampling_info> sampling; boost::optional<double> average_loudness; // range (0, 1] boost::optional<musical_key> key; - std::vector<char> encode() const; + track_data() noexcept = default; + + friend bool operator==( + const track_data& first, const track_data& second) noexcept + { + return first.sampling == second.sampling && + first.average_loudness == second.average_loudness && + first.key == second.key; + } + std::vector<char> encode() const; static track_data decode(const std::vector<char>& compressed_data); }; |