#pragma once
#include "BuildSettings.h"
#include <map>
#include "tuningbase.h"
OPENMPT_NAMESPACE_BEGIN
namespace Tuning {
class CTuningRTI
{
public:
static const char s_FileExtension[5];
enum
{
TT_GENERAL = 0,
TT_GROUPGEOMETRIC = 1,
TT_GEOMETRIC = 3,
};
static const RATIOTYPE s_DefaultFallbackRatio;
enum : NOTEINDEXTYPE { s_StepMinDefault = -64 };
enum : UNOTEINDEXTYPE { s_RatioTableSizeDefault = 128 };
enum : USTEPINDEXTYPE { s_RatioTableFineSizeMaxDefault = 1000 };
public:
RATIOTYPE GetRatio(const NOTEINDEXTYPE& stepsFromCentre) const;
RATIOTYPE GetRatio(const NOTEINDEXTYPE& stepsFromCentre, const STEPINDEXTYPE& fineSteps) const;
UNOTEINDEXTYPE GetRatioTableSize() const {return static_cast<UNOTEINDEXTYPE>(m_RatioTable.size());}
NOTEINDEXTYPE GetRatioTableBeginNote() const {return m_StepMin;}
VRPAIR GetValidityRange() const {return VRPAIR(m_StepMin, static_cast<NOTEINDEXTYPE>(m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()) - 1));}
bool IsValidNote(const NOTEINDEXTYPE n) const {return (n >= GetValidityRange().first && n <= GetValidityRange().second);}
UNOTEINDEXTYPE GetGroupSize() const {return m_GroupSize;}
RATIOTYPE GetGroupRatio() const {return m_GroupRatio;}
USTEPINDEXTYPE GetFineStepCount() const {return m_FineStepCount;}
STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& from, const NOTEINDEXTYPE& to) const
{return (to - from)*(static_cast<NOTEINDEXTYPE>(GetFineStepCount())+1);}
STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& noteFrom, const STEPINDEXTYPE& stepDistFrom, const NOTEINDEXTYPE& noteTo, const STEPINDEXTYPE& stepDistTo) const
{return GetStepDistance(noteFrom, noteTo) + stepDistTo - stepDistFrom;}
void SetFineStepCount(const USTEPINDEXTYPE& fs);
bool Multiply(const RATIOTYPE&);
bool SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r);
TUNINGTYPE GetType() const {return m_TuningType;}
std::string GetNoteName(const NOTEINDEXTYPE& x, bool addOctave = true) const;
void SetNoteName(const NOTEINDEXTYPE&, const std::string&);
static CTuningRTI* CreateDeserialize(std::istream & f)
{
CTuningRTI *pT = new CTuningRTI();
if(pT->InitDeserialize(f) != SerializationResult::Success)
{
delete pT;
return nullptr;
}
return pT;
}
static CTuningRTI* CreateDeserializeOLD(std::istream & f)
{
CTuningRTI *pT = new CTuningRTI();
if(pT->InitDeserializeOLD(f) != SerializationResult::Success)
{
delete pT;
return nullptr;
}
return pT;
}
static CTuningRTI* CreateGeneral(const std::string &name)
{
CTuningRTI *pT = new CTuningRTI();
pT->SetName(name);
return pT;
}
static CTuningRTI* CreateGroupGeometric(const std::string &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
{
CTuningRTI *pT = new CTuningRTI();
pT->SetName(name);
if(pT->CreateGroupGeometric(groupsize, groupratio, 0) != false)
{
delete pT;
return nullptr;
}
pT->SetFineStepCount(finestepcount);
return pT;
}
static CTuningRTI* CreateGroupGeometric(const std::string &name, const std::vector<RATIOTYPE> &ratios, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
{
CTuningRTI *pT = new CTuningRTI();
pT->SetName(name);
VRPAIR range = std::make_pair(s_StepMinDefault, static_cast<NOTEINDEXTYPE>(s_StepMinDefault + s_RatioTableSizeDefault - 1));
range.second = std::max(range.second, mpt::saturate_cast<NOTEINDEXTYPE>(ratios.size() - 1));
range.first = 0 - range.second - 1;
if(pT->CreateGroupGeometric(ratios, groupratio, range, 0) != false)
{
delete pT;
return nullptr;
}
pT->SetFineStepCount(finestepcount);
return pT;
}
static CTuningRTI* CreateGeometric(const std::string &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
{
CTuningRTI *pT = new CTuningRTI();
pT->SetName(name);
if(pT->CreateGeometric(groupsize, groupratio) != false)
{
delete pT;
return nullptr;
}
pT->SetFineStepCount(finestepcount);
return pT;
}
Tuning::SerializationResult Serialize(std::ostream& out) const;
#ifdef MODPLUG_TRACKER
bool WriteSCL(std::ostream &f, const mpt::PathString &filename) const;
#endif
bool ChangeGroupsize(const NOTEINDEXTYPE&);
bool ChangeGroupRatio(const RATIOTYPE&);
void SetName(const std::string& s) { m_TuningName = s; }
std::string GetName() const {return m_TuningName;}
private:
CTuningRTI();
SerializationResult InitDeserialize(std::istream& inStrm);
SerializationResult InitDeserializeOLD(std::istream&);
bool CreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR vr, const NOTEINDEXTYPE ratiostartpos);
bool CreateGroupGeometric(const NOTEINDEXTYPE&, const RATIOTYPE&, const NOTEINDEXTYPE&);
bool CreateGeometric(const UNOTEINDEXTYPE& p, const RATIOTYPE& r) {return CreateGeometric(p,r,GetValidityRange());}
bool CreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR vr);
bool ProCreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR&, const NOTEINDEXTYPE& ratiostartpos);
bool ProCreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR&);
void UpdateFineStepTable();
RATIOTYPE GetRatioFine(const NOTEINDEXTYPE& note, USTEPINDEXTYPE stepDiff) const;
NOTEINDEXTYPE GetRefNote(NOTEINDEXTYPE note) const;
bool IsNoteInTable(const NOTEINDEXTYPE& s) const
{
if(s < m_StepMin || s >= m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()))
return false;
else
return true;
}
private:
TUNINGTYPE m_TuningType;
std::vector<RATIOTYPE> m_RatioTable;
std::vector<RATIOTYPE> m_RatioTableFine;
NOTEINDEXTYPE m_StepMin;
NOTEINDEXTYPE m_GroupSize;
RATIOTYPE m_GroupRatio;
USTEPINDEXTYPE m_FineStepCount;
std::string m_TuningName;
std::map<NOTEINDEXTYPE, std::string> m_NoteNameMap;
};
typedef CTuningRTI CTuning;
}
OPENMPT_NAMESPACE_END