diff options
Diffstat (limited to 'src/djinterop/enginelibrary/el_track_impl.hpp')
-rw-r--r-- | src/djinterop/enginelibrary/el_track_impl.hpp | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/djinterop/enginelibrary/el_track_impl.hpp b/src/djinterop/enginelibrary/el_track_impl.hpp new file mode 100644 index 0000000..445c0ce --- /dev/null +++ b/src/djinterop/enginelibrary/el_track_impl.hpp @@ -0,0 +1,274 @@ +#pragma once + +#if __cplusplus < 201103L && _MSVC_LANG < 201103L +#error This library needs at least a C++11 compliant compiler +#endif + +#include <chrono> +#include <memory> +#include <stdexcept> +#include <string> +#include <vector> + +#include <boost/optional.hpp> +#include <boost/utility/string_view.hpp> + +#include <djinterop/enginelibrary.hpp> +#include <djinterop/enginelibrary/el_storage.hpp> +#include <djinterop/enginelibrary/performance_data_format.hpp> +#include <djinterop/exceptions.hpp> +#include <djinterop/impl/track_impl.hpp> + +namespace djinterop +{ +class crate; +class database; +enum class musical_key; + +namespace enginelibrary +{ +enum class metadata_str_type +{ + title = 1, + artist = 2, + album = 3, + genre = 4, + comment = 5, + publisher = 6, + composer = 7, + duration_mm_ss = 10, + ever_played = 12, + file_extension = 13 +}; + +enum class metadata_int_type +{ + last_played_ts = 1, + last_modified_ts = 2, + last_accessed_ts = + 3, // NOTE: truncated to date on VFAT (see FAT "ACCDATE") + musical_key = 4, + hash = 10 +}; + +class el_track_impl : public djinterop::track_impl +{ +public: + el_track_impl(std::shared_ptr<el_storage> storage, int64_t id); + + boost::optional<std::string> get_metadata_str(metadata_str_type type); + void set_metadata_str( + metadata_str_type type, boost::optional<boost::string_view> content); + void set_metadata_str(metadata_str_type type, const std::string& content); + boost::optional<int64_t> get_metadata_int(metadata_int_type type); + void set_metadata_int( + metadata_int_type type, boost::optional<int64_t> content); + + template <typename T> + T get_cell(const char* column_name) + { + boost::optional<T> result; + storage_->music_db << (std::string{"SELECT "} + column_name + + " FROM Track WHERE id = ?") + << id() >> + [&](T cell) { + if (!result) + { + result = cell; + } + else + { + throw track_database_inconsistency{ + "More than one track with the same ID", id()}; + } + }; + if (!result) + { + throw track_deleted{id()}; + } + return *result; + } + + template <typename T> + void set_cell(const char* column_name, const T& content) + { + storage_->music_db << (std::string{"UPDATE Track SET "} + column_name + + " = ? WHERE id = ?") + << content << id(); + } + + template <typename T> + T get_perfdata(const char* column_name) + { + boost::optional<T> result; + storage_->perfdata_db << (std::string{"SELECT "} + column_name + + " From PerformanceData WHERE id = ?") + << id() >> + [&](const std::vector<char>& encoded_data) { + if (!result) + { + result = T::decode(encoded_data); + } + else + { + throw track_database_inconsistency{ + "More than one PerformanceData entry for the same " + "track", + id()}; + } + }; + return result.value_or(T{}); + } + + // NOTE: No transaction + template <typename T> + void set_perfdata(const char* column_name, const T& content) + { + bool found = false; + storage_->perfdata_db + << "SELECT COUNT(*) FROM PerformanceData WHERE id = ?" + << id() >> + [&](int32_t count) { + if (count == 1) + { + found = true; + } + else if (count > 1) + { + throw track_database_inconsistency{ + "More than one PerformanceData entry for the same " + "track", + id()}; + } + }; + + if (!found) + { + storage_->perfdata_db + << "INSERT INTO PerformanceData (id, isAnalyzed, isRendered, " + "trackData, highResolutionWaveFormData, " + "overviewWaveFormData, beatData, quickCues, loops, " + "hasSeratoValues) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + << id() // + << 0.0 // isAnalyzed + << 0.0 // isRendered + << track_data{}.encode() // + << high_res_waveform_data{}.encode() // + << overview_waveform_data{}.encode() // + << beat_data{}.encode() // + << quick_cues_data{}.encode() // + << loops_data{}.encode() // + << 0.0; // hasSeratoValues + + // TODO (haslersn): Don't allocate during the version() call + if (db().version() >= version_1_7_1) + { + storage_->perfdata_db + << "UPDATE PerformanceData SET hasRekordboxValues = 0 " + "WHERE id = ?" + << id(); + } + } + + storage_->perfdata_db << (std::string{"UPDATE PerformanceData SET "} + + column_name + " = ? WHERE id = ?") + << content.encode() << id(); + } + + beat_data get_beat_data(); + void set_beat_data(beat_data data); + high_res_waveform_data get_high_res_waveform_data(); + void set_high_res_waveform_data(high_res_waveform_data data); + loops_data get_loops_data(); + 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(); + void set_track_data(track_data data); + + std::vector<beatgrid_marker> adjusted_beatgrid() override; + void set_adjusted_beatgrid(std::vector<beatgrid_marker> beatgrid) override; + double adjusted_main_cue() override; + void set_adjusted_main_cue(double sample_offset) override; + boost::optional<std::string> album() override; + void set_album(boost::optional<boost::string_view> album) override; + boost::optional<int64_t> album_art_id() override; + void set_album_art_id(boost::optional<int64_t> album_art_id) override; + boost::optional<std::string> artist() override; + void set_artist(boost::optional<boost::string_view> artist) override; + boost::optional<double> average_loudness() override; + void set_average_loudness( + boost::optional<double> average_loudness) override; + boost::optional<int64_t> bitrate() override; + void set_bitrate(boost::optional<int64_t> bitrate) override; + boost::optional<double> bpm() override; + void set_bpm(boost::optional<double> bpm) override; + boost::optional<std::string> comment() override; + void set_comment(boost::optional<boost::string_view> comment) override; + boost::optional<std::string> composer() override; + void set_composer(boost::optional<boost::string_view> composer) override; + std::vector<djinterop::crate> containing_crates() override; + database db() override; + std::vector<beatgrid_marker> default_beatgrid() override; + void set_default_beatgrid(std::vector<beatgrid_marker> beatgrid) override; + double default_main_cue() override; + void set_default_main_cue(double sample_offset) override; + boost::optional<std::chrono::milliseconds> duration() override; + std::string file_extension() override; + std::string filename() override; + boost::optional<std::string> genre() override; + void set_genre(boost::optional<boost::string_view> genre) override; + boost::optional<hot_cue> hot_cue_at(int32_t index) override; + void set_hot_cue_at(int32_t index, boost::optional<hot_cue> cue) override; + std::array<boost::optional<hot_cue>, 8> hot_cues() override; + void set_hot_cues(std::array<boost::optional<hot_cue>, 8> cues) override; + boost::optional<track_import_info> import_info() override; + void set_import_info( + const boost::optional<track_import_info>& import_info) override; + bool is_valid() override; + boost::optional<musical_key> key() override; + void set_key(boost::optional<musical_key> key) override; + boost::optional<std::chrono::system_clock::time_point> last_accessed_at() + override; + void set_last_accessed_at( + boost::optional<std::chrono::system_clock::time_point> accessed_at) + override; + boost::optional<std::chrono::system_clock::time_point> last_modified_at() + override; + void set_last_modified_at( + boost::optional<std::chrono::system_clock::time_point> modified_at) + override; + boost::optional<std::chrono::system_clock::time_point> last_played_at() + override; + void set_last_played_at( + boost::optional<std::chrono::system_clock::time_point> played_at) + override; + boost::optional<loop> loop_at(int32_t index) override; + void set_loop_at(int32_t index, boost::optional<loop> l) override; + std::array<boost::optional<loop>, 8> loops() override; + void set_loops(std::array<boost::optional<loop>, 8> cues) override; + std::vector<waveform_entry> overview_waveform() override; + boost::optional<std::string> publisher() override; + void set_publisher(boost::optional<boost::string_view> publisher) override; + int64_t recommended_waveform_size() override; + std::string relative_path() override; + void set_relative_path(boost::string_view relative_path) override; + boost::optional<sampling_info> sampling() override; + void set_sampling(boost::optional<sampling_info> sampling) override; + boost::optional<std::string> title() override; + void set_title(boost::optional<boost::string_view> title) override; + boost::optional<int32_t> track_number() override; + void set_track_number(boost::optional<int32_t> track_number) override; + std::vector<waveform_entry> waveform() override; + void set_waveform(std::vector<waveform_entry> waveform) override; + boost::optional<int32_t> year() override; + void set_year(boost::optional<int32_t> year) override; + +private: + std::shared_ptr<el_storage> storage_; +}; + +} // namespace enginelibrary +} // namespace djinterop |