mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-16 11:19:18 +01:00
242 lines
7.0 KiB
C++
242 lines
7.0 KiB
C++
#ifndef PRESET_CHOOSER_HPP
|
|
#define PRESET_CHOOSER_HPP
|
|
|
|
#include "Preset.hpp"
|
|
|
|
#include "PresetLoader.hpp"
|
|
#include "RandomNumberGenerators.hpp"
|
|
#include <cassert>
|
|
#include <memory>
|
|
#include <iostream>
|
|
class PresetChooser;
|
|
|
|
/// A simple iterator class to traverse back and forth a preset directory
|
|
class PresetIterator {
|
|
|
|
public:
|
|
PresetIterator() {}
|
|
|
|
/// Instantiate a preset iterator at the given starting position
|
|
PresetIterator(std::size_t start);
|
|
|
|
/// Move iterator forward
|
|
void operator++();
|
|
|
|
/// Move iterator backword
|
|
void operator--() ;
|
|
|
|
/// Not equal comparator
|
|
bool operator !=(const PresetIterator & presetPos) const ;
|
|
|
|
/// Equality comparator
|
|
bool operator ==(const PresetIterator & presetPos) const ;
|
|
|
|
/// Returns an integer value representing the iterator position
|
|
/// @bug might become internal
|
|
/// \brief Returns the indexing value used by the current iterator.
|
|
std::size_t operator*() const;
|
|
|
|
/// Allocate a new preset given this iterator's associated preset name
|
|
/// \param presetInputs the preset inputs to associate with the preset upon construction
|
|
/// \param presetOutputs the preset outputs to associate with the preset upon construction
|
|
/// \returns an autopointer of the newly allocated preset
|
|
std::auto_ptr<Preset> allocate();
|
|
|
|
/// Set the chooser asocciated with this iterator
|
|
void setChooser(const PresetChooser & chooser);
|
|
|
|
private:
|
|
std::size_t _currentIndex;
|
|
const PresetChooser * _presetChooser;
|
|
|
|
};
|
|
|
|
/// Provides functions and iterators to select presets. Requires a preset loader upon construction
|
|
class PresetChooser {
|
|
|
|
public:
|
|
typedef PresetIterator iterator;
|
|
|
|
/// Initializes a chooser with an established preset loader.
|
|
/// \param presetLoader an initialized preset loader to choose presets from
|
|
/// \note The preset loader is refreshed via events or otherwise outside this class's scope
|
|
PresetChooser(const PresetLoader & presetLoader, bool softCutRatingsEnabled);
|
|
|
|
inline void setSoftCutRatingsEnabled(bool enabled) {
|
|
_softCutRatingsEnabled = enabled;
|
|
}
|
|
|
|
/// Choose a preset via the passed in index. Must be between 0 and num valid presets in directory
|
|
/// \param index An index lying in the interval [0, this->getNumPresets())
|
|
/// \param presetInputs the preset inputs to associate with the preset upon construction
|
|
/// \param presetOutputs the preset outputs to associate with the preset upon construction
|
|
/// \returns an auto pointer of the newly allocated preset
|
|
std::auto_ptr<Preset> directoryIndex(std::size_t index) const;
|
|
|
|
/// Gets the number of presets last believed to exist in the preset loader's filename collection
|
|
/// \returns the number of presets in the collection
|
|
std::size_t size() const;
|
|
|
|
/// An STL-esque iterator to begin traversing presets from a directory
|
|
/// \param index the index to begin iterating at. Assumed valid between [0, num presets)
|
|
/// \returns the position of the first preset in the collection
|
|
PresetIterator begin(unsigned int index) const;
|
|
|
|
/// An STL-esque iterator to begin traversing presets from a directory
|
|
/// \returns the position of the first preset in the collection
|
|
PresetIterator begin();
|
|
|
|
/// An STL-esque iterator to retrieve an end position from a directory
|
|
/// \returns the end position of the collection
|
|
PresetIterator end() const;
|
|
|
|
/// Perform a weighted sample to select a preset (uses preset rating values)
|
|
/// \returns an iterator to the randomly selected preset
|
|
iterator weightedRandom(bool hardCut) const;
|
|
|
|
/// True if no presets in directory
|
|
bool empty() const;
|
|
|
|
|
|
inline void nextPreset(PresetIterator & presetPos);
|
|
inline void previousPreset(PresetIterator & presetPos);
|
|
|
|
private:
|
|
std::vector<float> sampleWeights;
|
|
const PresetLoader * _presetLoader;
|
|
bool _softCutRatingsEnabled;
|
|
};
|
|
|
|
|
|
inline PresetChooser::PresetChooser(const PresetLoader & presetLoader, bool softCutRatingsEnabled):_presetLoader(&presetLoader), _softCutRatingsEnabled(softCutRatingsEnabled) {
|
|
|
|
}
|
|
|
|
inline std::size_t PresetChooser::size() const {
|
|
return _presetLoader->size();
|
|
}
|
|
|
|
inline void PresetIterator::setChooser(const PresetChooser & chooser) {
|
|
_presetChooser = &chooser;
|
|
}
|
|
|
|
inline std::size_t PresetIterator::operator*() const {
|
|
return _currentIndex;
|
|
}
|
|
|
|
inline PresetIterator::PresetIterator(std::size_t start):_currentIndex(start) {}
|
|
|
|
inline void PresetIterator::operator++() {
|
|
assert(_currentIndex < _presetChooser->size());
|
|
_currentIndex++;
|
|
}
|
|
|
|
inline void PresetIterator::operator--() {
|
|
assert(_currentIndex > 0);
|
|
_currentIndex--;
|
|
}
|
|
|
|
inline bool PresetIterator::operator !=(const PresetIterator & presetPos) const {
|
|
return (*presetPos != **this);
|
|
}
|
|
|
|
|
|
inline bool PresetIterator::operator ==(const PresetIterator & presetPos) const {
|
|
return (*presetPos == **this);
|
|
}
|
|
|
|
inline std::auto_ptr<Preset> PresetIterator::allocate() {
|
|
return _presetChooser->directoryIndex(_currentIndex);
|
|
}
|
|
|
|
inline void PresetChooser::nextPreset(PresetIterator & presetPos) {
|
|
|
|
if (this->empty()) {
|
|
return;
|
|
}
|
|
|
|
// Case: idle preset currently running, selected first preset of chooser
|
|
else if (presetPos == this->end())
|
|
presetPos = this->begin();
|
|
else
|
|
++(presetPos);
|
|
|
|
// Case: already at last preset, loop to beginning
|
|
if (((presetPos) == this->end())) {
|
|
presetPos = this->begin();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
inline void PresetChooser::previousPreset(PresetIterator & presetPos) {
|
|
if (this->empty())
|
|
return;
|
|
|
|
// Case: idle preset currently running, selected last preset of chooser
|
|
else if (presetPos == this->end()) {
|
|
--(presetPos);
|
|
}
|
|
|
|
else if (presetPos != this->begin()) {
|
|
--(presetPos);
|
|
}
|
|
|
|
else {
|
|
presetPos = this->end();
|
|
--(presetPos);
|
|
}
|
|
}
|
|
|
|
inline PresetIterator PresetChooser::begin() {
|
|
PresetIterator pos(0);
|
|
pos.setChooser(*this);
|
|
return pos;
|
|
}
|
|
|
|
inline PresetIterator PresetChooser::begin(unsigned int index) const{
|
|
PresetIterator pos(index);
|
|
pos.setChooser(*this);
|
|
return pos;
|
|
}
|
|
|
|
inline PresetIterator PresetChooser::end() const {
|
|
PresetIterator pos(_presetLoader->size());
|
|
pos.setChooser(*this);
|
|
return pos;
|
|
}
|
|
|
|
|
|
inline bool PresetChooser::empty() const {
|
|
return _presetLoader->size() == 0;
|
|
}
|
|
|
|
inline std::auto_ptr<Preset> PresetChooser::directoryIndex(std::size_t index) const {
|
|
|
|
return _presetLoader->loadPreset(index);
|
|
}
|
|
|
|
|
|
inline PresetChooser::iterator PresetChooser::weightedRandom(bool hardCut) const {
|
|
|
|
|
|
|
|
|
|
// TODO make a sophisticated function object interface to determine why a certain rating
|
|
// category is chosen, or weighted distribution thereover.
|
|
const PresetRatingType ratingType = hardCut || (!_softCutRatingsEnabled) ?
|
|
HARD_CUT_RATING_TYPE : SOFT_CUT_RATING_TYPE;
|
|
|
|
const std::size_t ratingsTypeIndex = static_cast<std::size_t>(ratingType);
|
|
|
|
const std::vector<int> & weights = _presetLoader->getPresetRatings()[ratingsTypeIndex];
|
|
|
|
const std::size_t index = RandomNumberGenerators::weightedRandom
|
|
(weights,
|
|
_presetLoader->getPresetRatingsSums()[ratingsTypeIndex]);
|
|
|
|
return begin(index);
|
|
}
|
|
|
|
#endif
|