blob: 8b645fb98ef300880467dcd7c0ede11b6fe7364c [file] [log] [blame]
#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