Reorganized sources, better accuracy for similarities based on features

This commit is contained in:
emeric
2019-02-05 14:08:46 +01:00
parent 3e142b5507
commit 6fcb693261
34 changed files with 1324 additions and 1218 deletions
+4 -7
View File
@@ -40,7 +40,7 @@
#include "SimilaritySettings.hpp"
#include "Track.hpp"
#include "TrackList.hpp"
#include "TrackFeature.hpp"
#include "TrackFeatures.hpp"
namespace Database {
@@ -106,11 +106,11 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
_session.mapClass<TrackListEntry>("tracklist_entry");
_session.mapClass<Release>("release");
_session.mapClass<Track>("track");
_session.mapClass<TrackFeature>("track_feature");
_session.mapClass<TrackFeatureType>("track_feature_type");
_session.mapClass<TrackFeatures>("track_features");
_session.mapClass<ScanSettings>("scan_settings");
_session.mapClass<SimilaritySettings>("similarity_settings");
_session.mapClass<SimilaritySettingsFeature>("similarity_settings_feature");
_session.mapClass<AuthInfo>("auth_info");
_session.mapClass<AuthInfo::AuthIdentityType>("auth_identity");
@@ -142,10 +142,7 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
_session.execute("CREATE INDEX IF NOT EXISTS cluster_name_idx ON cluster(name)");
_session.execute("CREATE INDEX IF NOT EXISTS cluster_type_name_idx ON cluster_type(name)");
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_name_idx ON tracklist(name)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_type_name_idx ON track_feature_type(name)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_type_idx ON track_feature(type_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_track_idx ON track_feature(track_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_feature_type_track_idx ON track_feature(type_id, track_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_features_track_idx ON track_features(track_id)");
}
_users = new UserDatabase(_session);
+1
View File
@@ -59,6 +59,7 @@ class Release : public Wt::Dbo::Dbo<Release>
bool& moreExpected);
std::vector<Wt::Dbo::ptr<Track>> getTracks(const std::set<IdType>& clusters = std::set<IdType>()) const;
// Get the cluster of the tracks that belong to this release
// Each clusters are grouped by cluster type, sorted by the number of occurence
// size is the max number of cluster per cluster type
+39 -84
View File
@@ -22,53 +22,42 @@
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
#include "TrackFeature.hpp"
namespace {
std::set<std::string> defaultTrackFeaturesNames =
{
"lowlevel.average_loudness",
"lowlevel.barkbands_flatness_db.mean",
"lowlevel.dissonance.mean",
"lowlevel.dynamic_complexity",
"lowlevel.hfc.mean", // GOOD
"lowlevel.melbands_crest.mean",
"lowlevel.melbands_kurtosis.mean",
"lowlevel.melbands_skewness.mean",
"lowlevel.melbands_spread.mean",
"lowlevel.pitch_salience.mean",
"lowlevel.pitch_salience.var",
"lowlevel.silence_rate_30dB.mean",
"lowlevel.silence_rate_60dB.mean",
"lowlevel.spectral_centroid.mean",
"lowlevel.spectral_complexity.mean",
"lowlevel.spectral_decrease.mean",
"lowlevel.spectral_energy.mean",
"lowlevel.spectral_energyband_high.mean",
"lowlevel.spectral_energyband_low.mean",
"lowlevel.spectral_energyband_middle_high.mean",
"lowlevel.spectral_energyband_middle_low.mean",
"lowlevel.spectral_entropy.mean",
"lowlevel.spectral_flux.mean",
"lowlevel.spectral_kurtosis.mean",
"lowlevel.spectral_rms.mean",
"lowlevel.spectral_skewness.mean",
"lowlevel.spectral_spread.mean",
"lowlevel.spectral_strongpeak.mean",
"lowlevel.zerocrossingrate.mean",
"rhythm.beats_loudness.mean", // BAD
"rhythm.bpm",
"tonal.chords_changes_rate", // OK
"tonal.chords_number_rate", // BAD
"tonal.chords_strength.mean", // OK
"tonal.hpcp_entropy.mean", // GOOD
};
} // namespace
#include "TrackFeatures.hpp"
namespace Database {
struct TrackFeatureInfo
{
std::string name;
std::size_t nbDimensions;
double weight;
};
static std::vector<TrackFeatureInfo> defaultFeatures =
{
{ "lowlevel.spectral_contrast_coeffs.median", 6, 1. },
{ "lowlevel.erbbands.median", 40, 1. },
{ "tonal.hpcp.median", 36, 1. },
{ "lowlevel.melbands.median", 40, 1. },
{ "lowlevel.barkbands.median", 27, 1. },
{ "lowlevel.mfcc.mean", 13, 1. },
{ "lowlevel.gfcc.mean", 13, 1. },
};
SimilaritySettingsFeature::SimilaritySettingsFeature(Wt::Dbo::ptr<SimilaritySettings> settings, const std::string& name, std::size_t nbDimensions, double weight)
: _name(name),
_nbDimensions(nbDimensions),
_weight(weight),
_settings(settings)
{
}
SimilaritySettingsFeature::pointer
SimilaritySettingsFeature::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<SimilaritySettings> settings, const std::string& name, std::size_t nbDimensions, double weight)
{
return session.add(std::make_unique<SimilaritySettingsFeature>(settings, name, nbDimensions, weight));
}
SimilaritySettings::pointer
SimilaritySettings::get(Wt::Dbo::Session& session)
@@ -77,54 +66,20 @@ SimilaritySettings::get(Wt::Dbo::Session& session)
if (!settings)
{
settings = session.add(std::make_unique<SimilaritySettings>());
settings.modify()->setTrackFeatureTypes(defaultTrackFeaturesNames);
for (const auto& feature : defaultFeatures)
SimilaritySettingsFeature::create(session, settings, feature.name, feature.nbDimensions, feature.weight);
}
return settings;
}
std::vector<Wt::Dbo::ptr<TrackFeatureType>>
SimilaritySettings::getTrackFeatureTypes() const
std::vector<Wt::Dbo::ptr<SimilaritySettingsFeature>>
SimilaritySettings::getFeatures() const
{
return std::vector<Wt::Dbo::ptr<TrackFeatureType>>(_trackFeatureTypes.begin(), _trackFeatureTypes.end());
return std::vector<Wt::Dbo::ptr<SimilaritySettingsFeature>>(_features.begin(), _features.end());
}
void
SimilaritySettings::setTrackFeatureTypes(const std::set<std::string>& featuresNames)
{
bool needRescan = false;
assert(session());
// Create any missing feature type
for (const auto& featureName : featuresNames)
{
auto featureType = TrackFeatureType::getByName(*session(), featureName);
if (!featureType)
{
LMS_LOG(DB, INFO) << "Creating feature type " << featureName;
featureType = TrackFeatureType::create(*session(), featureName);
_trackFeatureTypes.insert(featureType);
needRescan = true;
}
}
// Delete no longer existing feature type
for (auto trackFeatureType : _trackFeatureTypes)
{
if (std::none_of(featuresNames.begin(), featuresNames.end(),
[trackFeatureType](const std::string& name) { return name == trackFeatureType->getName(); }))
{
LMS_LOG(DB, INFO) << "Deleting track feature type " << trackFeatureType->getName();
trackFeatureType.remove();
}
}
if (needRescan)
_scanVersion += 1;
}
} // namespace Database
+55 -22
View File
@@ -23,42 +23,75 @@
namespace Database {
class TrackFeature;
class TrackFeatureType;
class SimilaritySettings;
class SimilaritySettings : public Wt::Dbo::Dbo<SimilaritySettings>
class SimilaritySettingsFeature : public Wt::Dbo::Dbo<SimilaritySettingsFeature>
{
public:
using pointer = Wt::Dbo::ptr<SimilaritySettings>;
using pointer = Wt::Dbo::ptr<SimilaritySettingsFeature>;
static pointer get(Wt::Dbo::Session& session);
SimilaritySettingsFeature() = default;
SimilaritySettingsFeature(Wt::Dbo::ptr<SimilaritySettings> settings, const std::string& name, std::size_t nbDimensions, double weight);
std::size_t getVersion() const { return _scanVersion; }
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<SimilaritySettings> settings, const std::string& name, std::size_t nbDimensions, double weight = 1);
std::vector<Wt::Dbo::ptr<TrackFeatureType>> getTrackFeatureTypes() const;
void setTrackFeatureTypes(const std::set<std::string>& featureTypeNames);
void setNetworkData(std::string data) { _refFeaturesData = data; }
const std::string& getNetworkData() const { return _refFeaturesData; }
void setNormalizationData(std::string data) { _normalizationData = data; }
const std::string& getNormalizationData() const { return _normalizationData; }
const std::string& getName() const { return _name; } ;
std::size_t getNbDimensions() const { return static_cast<std::size_t>(_nbDimensions); }
double getWeight() const { return _weight; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _scanVersion, "settings_version");
Wt::Dbo::field(a, _normalizationData, "normalization_data");
Wt::Dbo::field(a, _refFeaturesData, "ref_features_data");
Wt::Dbo::hasMany(a, _trackFeatureTypes, Wt::Dbo::ManyToOne, "similarity_settings");
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _nbDimensions, "dimension_count");
Wt::Dbo::field(a, _weight, "weight");
Wt::Dbo::belongsTo(a, _settings, "similarity_settings", Wt::Dbo::OnDeleteCascade);
}
private:
std::string _name;
int _nbDimensions;
double _weight;
Wt::Dbo::ptr<SimilaritySettings> _settings;
};
class SimilaritySettings : public Wt::Dbo::Dbo<SimilaritySettings>
{
public:
enum class PreferredMethod
{
Auto,
Features,
Clusters,
};
using pointer = Wt::Dbo::ptr<SimilaritySettings>;
// Utils
static pointer get(Wt::Dbo::Session& session);
// Accessors
std::size_t getVersion() const { return _settingsVersion; }
PreferredMethod getPreferredMethod() const { return _preferredMethod; }
std::vector<Wt::Dbo::ptr<SimilaritySettingsFeature>> getFeatures() const;
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _settingsVersion, "settings_version");
Wt::Dbo::field(a, _preferredMethod, "preferred_method");
Wt::Dbo::hasMany(a, _features, Wt::Dbo::ManyToOne, "similarity_settings");
}
private:
int _scanVersion = 0;
std::string _normalizationData;
std::string _refFeaturesData;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackFeatureType>> _trackFeatureTypes;
int _settingsVersion = 0;
PreferredMethod _preferredMethod = PreferredMethod::Auto;
Wt::Dbo::collection<Wt::Dbo::ptr<SimilaritySettingsFeature>> _features;
};
+7 -13
View File
@@ -26,7 +26,7 @@
#include "Artist.hpp"
#include "Cluster.hpp"
#include "Release.hpp"
#include "TrackFeature.hpp"
#include "TrackFeatures.hpp"
#include "SqlQuery.hpp"
namespace Database {
@@ -114,7 +114,7 @@ Track::getAllWithMBIDAndMissingFeatures(Wt::Dbo::Session& session)
Wt::Dbo::collection<pointer> res = session.query<pointer>
("SELECT t FROM track t")
.where("LENGTH(t.mbid) > 0")
.where("NOT EXISTS (SELECT * FROM track_feature t_f WHERE t_f.track_id = t.id)");
.where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)");
return std::vector<pointer>(res.begin(), res.end());
}
@@ -123,7 +123,7 @@ Track::getAllWithFeatures(Wt::Dbo::Session& session)
{
Wt::Dbo::collection<pointer> res = session.query<pointer>
("SELECT t FROM track t")
.where("EXISTS (SELECT * from track_feature t_f WHERE t_f.track_id = t.id)");
.where("EXISTS (SELECT * from track_features t_f WHERE t_f.track_id = t.id)");
return std::vector<pointer>(res.begin(), res.end());
}
@@ -138,7 +138,7 @@ Track::getClusters(void) const
bool
Track::hasTrackFeatures() const
{
return !_trackFeatures.empty();
return (_trackFeatures.lock() != Database::TrackFeatures::pointer());
}
static
@@ -262,16 +262,10 @@ Track::getCopyrightURL() const
return _copyrightURL != "" ? boost::make_optional<std::string>(_copyrightURL) : boost::none;
}
Wt::Dbo::ptr<TrackFeature>
Track::getTrackFeature(Wt::Dbo::ptr<TrackFeatureType> type) const
Wt::Dbo::ptr<TrackFeatures>
Track::getTrackFeatures() const
{
assert(self());
assert(IdIsValid(self()->id()));
assert(session());
return session()->find<TrackFeature>()
.where("type_id = ?").bind(type.id())
.where("track_id = ?").bind(self()->id());
return _trackFeatures.lock();
}
std::vector<std::vector<Cluster::pointer>>
+5 -11
View File
@@ -37,8 +37,7 @@ class Artist;
class Cluster;
class ClusterType;
class Release;
class TrackFeature;
class TrackFeatureType;
class TrackFeatures;
class TrackListEntry;
class TrackStats;
@@ -81,7 +80,6 @@ class Track : public Wt::Dbo::Dbo<Track>
// Accessors
void setScanVersion(std::size_t version) { _scanVersion = version; }
void setSimilarityScanVersion(std::size_t version) { _similarityScanVersion = version; }
void setTrackNumber(int num) { _trackNumber = num; }
void setTotalTrackNumber(int num) { _totalTrackNumber = num; }
void setDiscNumber(int num) { _discNumber = num; }
@@ -101,10 +99,9 @@ class Track : public Wt::Dbo::Dbo<Track>
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
void eraseClusters() { _clusters.clear(); }
void eraseFeatures() { _trackFeatures.clear(); }
void eraseFeatures() { /*_trackFeatures.reset();*/ }
std::size_t getScanVersion() const { return _scanVersion; }
std::size_t getSimilarityScanVersion() const { return _similarityScanVersion; }
boost::optional<std::size_t> getTrackNumber() const;
boost::optional<std::size_t> getTotalTrackNumber() const;
boost::optional<std::size_t> getDiscNumber() const;
@@ -124,9 +121,8 @@ class Track : public Wt::Dbo::Dbo<Track>
Wt::Dbo::ptr<Artist> getArtist() const { return _artist; }
Wt::Dbo::ptr<Release> getRelease() const { return _release; }
std::vector<Wt::Dbo::ptr<Cluster>> getClusters() const;
std::vector<Wt::Dbo::ptr<TrackFeature>> getTrackFeatures() const; // ordered by feature's name
bool hasTrackFeatures() const;
Wt::Dbo::ptr<TrackFeature> getTrackFeature(Wt::Dbo::ptr<TrackFeatureType> type) const;
Wt::Dbo::ptr<TrackFeatures> getTrackFeatures() const;
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> getClusterGroups(std::vector<Wt::Dbo::ptr<ClusterType>> clusterTypes, std::size_t size) const;
@@ -134,7 +130,6 @@ class Track : public Wt::Dbo::Dbo<Track>
void persist(Action& a)
{
Wt::Dbo::field(a, _scanVersion, "scan_version");
Wt::Dbo::field(a, _similarityScanVersion, "similarity_version");
Wt::Dbo::field(a, _trackNumber, "track_number");
Wt::Dbo::field(a, _totalTrackNumber, "total_track_number");
Wt::Dbo::field(a, _discNumber, "disc_number");
@@ -156,7 +151,7 @@ class Track : public Wt::Dbo::Dbo<Track>
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
Wt::Dbo::hasMany(a, _trackFeatures, Wt::Dbo::ManyToOne, "track");
Wt::Dbo::hasOne(a, _trackFeatures);
}
private:
@@ -166,7 +161,6 @@ class Track : public Wt::Dbo::Dbo<Track>
static const std::size_t _maxCopyrightURLLength = 128;
int _scanVersion = 0;
int _similarityScanVersion = 0;
int _trackNumber = 0;
int _totalTrackNumber = 0;
int _discNumber = 0;
@@ -191,7 +185,7 @@ class Track : public Wt::Dbo::Dbo<Track>
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _playlistEntries;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackFeature>> _trackFeatures;
Wt::Dbo::weak_ptr<TrackFeatures> _trackFeatures;
};
-58
View File
@@ -1,58 +0,0 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TrackFeature.hpp"
#include "SimilaritySettings.hpp"
#include "Track.hpp"
namespace Database {
TrackFeatureType::TrackFeatureType(std::string name)
: _name(name)
{
}
TrackFeatureType::pointer
TrackFeatureType::getByName(Wt::Dbo::Session& session, std::string name)
{
return session.find<TrackFeatureType>().where("name = ?").bind(name);
}
TrackFeatureType::pointer
TrackFeatureType::create(Wt::Dbo::Session& session, std::string name)
{
return session.add(std::make_unique<TrackFeatureType>(name));
}
TrackFeature::TrackFeature(Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value)
: _type(type),
_track(track),
_value(value)
{
}
TrackFeature::pointer
TrackFeature::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value)
{
return session.add(std::make_unique<TrackFeature>(type, track, value));
}
} // namespace Database
-97
View File
@@ -1,97 +0,0 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <Wt/Dbo/Dbo.h>
#include "Types.hpp"
namespace Database {
class Track;
class SimilaritySettings;
class TrackFeatureType : public Wt::Dbo::Dbo<TrackFeatureType>
{
public:
using pointer = Wt::Dbo::ptr<TrackFeatureType>;
TrackFeatureType() = default;
TrackFeatureType(std::string name);
// Find utility
static pointer getByName(Wt::Dbo::Session& session, std::string name);
// Create utility
static pointer create(Wt::Dbo::Session& session, std::string name);
// Accessors
const std::string& getName() const { return _name; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::belongsTo(a, _similaritySettings, "similarity_settings", Wt::Dbo::OnDeleteCascade);
}
private:
std::string _name;
Wt::Dbo::ptr<SimilaritySettings> _similaritySettings;
};
class TrackFeature : public Wt::Dbo::Dbo<TrackFeature>
{
public:
using pointer = Wt::Dbo::ptr<TrackFeature>;
TrackFeature() = default;
TrackFeature(Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value);
// Create utility
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<TrackFeatureType> type, Wt::Dbo::ptr<Track> track, double value);
Wt::Dbo::ptr<TrackFeatureType> getType() const { return _type; }
double getValue() const { return _value; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _value, "value");
Wt::Dbo::belongsTo(a, _type, "type", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
}
private:
Wt::Dbo::ptr<TrackFeatureType> _type;
Wt::Dbo::ptr<Track> _track;
double _value = 0.;
};
} // namespace database
+93
View File
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TrackFeatures.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "utils/Logger.hpp"
#include "Track.hpp"
namespace Database {
TrackFeatures::TrackFeatures(Wt::Dbo::ptr<Track> track, const std::string& jsonEncodedFeatures)
: _data(jsonEncodedFeatures),
_track(track)
{
}
TrackFeatures::pointer
TrackFeatures::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, const std::string& jsonEncodedFeatures)
{
return session.add(std::make_unique<TrackFeatures>(track, jsonEncodedFeatures));
}
std::vector<double>
TrackFeatures::getFeatures(const std::string& featureNode) const
{
std::vector<double> res;
std::map<std::string, std::vector<double>> features = { {featureNode, {}} };
if (!getFeatures( features ))
return res;
res = std::move(features[featureNode]);
return res;
}
bool
TrackFeatures::getFeatures(std::map<std::string /*name*/, std::vector<double> /*values*/>& features) const
{
try
{
boost::property_tree::ptree root;
std::istringstream iss(_data);
boost::property_tree::read_json(iss, root);
for (auto& featureNode : features)
{
auto node = root.get_child(featureNode.first);
bool hasChildren = false;
for (const auto& child : node.get_child(""))
{
hasChildren = true;
featureNode.second.push_back(child.second.get_value<double>());
}
if (!hasChildren)
{
featureNode.second.push_back(node.get_value<double>());
}
}
return true;
}
catch (boost::property_tree::ptree_error& error)
{
LMS_LOG(DB, ERROR) << "ptree exception: " << error.what();
std::cout << "ptree exception: " << error.what() << std::endl;
return false;
}
}
} // namespace Database
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS 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.
*
* LMS 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 LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <Wt/Dbo/Dbo.h>
#include "Types.hpp"
namespace Database {
class Track;
class TrackFeatures : public Wt::Dbo::Dbo<TrackFeatures>
{
public:
using pointer = Wt::Dbo::ptr<TrackFeatures>;
TrackFeatures() = default;
TrackFeatures(Wt::Dbo::ptr<Track> track, const std::string& jsonEncodedFeatures);
// Create utility
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, const std::string& jsonEncodedFeatures);
std::vector<double> getFeatures(const std::string& featureNode) const;
bool getFeatures(std::map<std::string /*featureNode*/, std::vector<double> /*values*/>& featureNodes) const;
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _data, "data");
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
}
private:
std::string _data;
Wt::Dbo::ptr<Track> _track;
};
} // namespace database