diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/soundlib/tuning.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/soundlib/tuning.h | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/soundlib/tuning.h b/Src/external_dependencies/openmpt-trunk/soundlib/tuning.h new file mode 100644 index 00000000..c6dc90a6 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/soundlib/tuning.h @@ -0,0 +1,252 @@ +/* + * tuning.h + * -------- + * Purpose: Alternative sample tuning. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#include <map> + +#include "tuningbase.h" + + +OPENMPT_NAMESPACE_BEGIN + + +namespace Tuning { + + +class CTuning +{ + +public: + + static constexpr char s_FileExtension[5] = ".tun"; + + static constexpr RATIOTYPE s_DefaultFallbackRatio = 1.0f; + static constexpr NOTEINDEXTYPE s_NoteMinDefault = -64; + static constexpr UNOTEINDEXTYPE s_RatioTableSizeDefault = 128; + static constexpr USTEPINDEXTYPE s_RatioTableFineSizeMaxDefault = 1000; + +public: + + // To return ratio of certain note. + RATIOTYPE GetRatio(const NOTEINDEXTYPE note) const; + + // To return ratio from a 'step'(noteindex + stepindex) + RATIOTYPE GetRatio(const NOTEINDEXTYPE baseNote, const STEPINDEXTYPE baseFineSteps) const; + + //Tuning might not be valid for arbitrarily large range, + //so this can be used to ask where it is valid. Tells the lowest and highest + //note that are valid. + MPT_FORCEINLINE NoteRange GetNoteRange() const + { + return NoteRange{m_NoteMin, static_cast<NOTEINDEXTYPE>(m_NoteMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()) - 1)}; + } + + // Return true if note is within note range + MPT_FORCEINLINE bool IsValidNote(const NOTEINDEXTYPE n) const + { + return (GetNoteRange().first <= n && n <= GetNoteRange().last); + } + + MPT_FORCEINLINE UNOTEINDEXTYPE GetGroupSize() const + { + return m_GroupSize; + } + + RATIOTYPE GetGroupRatio() const {return m_GroupRatio;} + + // To return (fine)stepcount between two consecutive mainsteps. + MPT_FORCEINLINE USTEPINDEXTYPE GetFineStepCount() const + { + return m_FineStepCount; + } + + //To return 'directed distance' between given notes. + STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& from, const NOTEINDEXTYPE& to) const + {return (to - from)*(static_cast<NOTEINDEXTYPE>(GetFineStepCount())+1);} + + //To return 'directed distance' between given steps. + STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& noteFrom, const STEPINDEXTYPE& stepDistFrom, const NOTEINDEXTYPE& noteTo, const STEPINDEXTYPE& stepDistTo) const + {return GetStepDistance(noteFrom, noteTo) + stepDistTo - stepDistFrom;} + + //To set finestepcount between two consecutive mainsteps. + //Finestep count == 0 means that + //stepdistances become the same as note distances. + void SetFineStepCount(const USTEPINDEXTYPE& fs); + + // Multiply all ratios by given number. + bool Multiply(const RATIOTYPE r); + + bool SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r); + + MPT_FORCEINLINE Tuning::Type GetType() const + { + return m_TuningType; + } + + mpt::ustring GetNoteName(const NOTEINDEXTYPE &x, bool addOctave = true) const; + + void SetNoteName(const NOTEINDEXTYPE &, const mpt::ustring &); + + static std::unique_ptr<CTuning> CreateDeserialize(std::istream &f, mpt::Charset defaultCharset) + { + std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning()); + if(pT->InitDeserialize(f, defaultCharset) != SerializationResult::Success) + { + return nullptr; + } + return pT; + } + + //Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr. + static std::unique_ptr<CTuning> CreateDeserializeOLD(std::istream &f, mpt::Charset defaultCharset) + { + std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning()); + if(pT->InitDeserializeOLD(f, defaultCharset) != SerializationResult::Success) + { + return nullptr; + } + return pT; + } + + static std::unique_ptr<CTuning> CreateGeneral(const mpt::ustring &name) + { + std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning()); + pT->SetName(name); + return pT; + } + + static std::unique_ptr<CTuning> CreateGroupGeometric(const mpt::ustring &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount) + { + std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning()); + pT->SetName(name); + if(!pT->CreateGroupGeometric(groupsize, groupratio, 0)) + { + return nullptr; + } + pT->SetFineStepCount(finestepcount); + return pT; + } + + static std::unique_ptr<CTuning> CreateGroupGeometric(const mpt::ustring &name, const std::vector<RATIOTYPE> &ratios, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount) + { + std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning()); + pT->SetName(name); + NoteRange range = NoteRange{s_NoteMinDefault, static_cast<NOTEINDEXTYPE>(s_NoteMinDefault + s_RatioTableSizeDefault - 1)}; + range.last = std::max(range.last, mpt::saturate_cast<NOTEINDEXTYPE>(ratios.size() - 1)); + range.first = 0 - range.last - 1; + if(!pT->CreateGroupGeometric(ratios, groupratio, range, 0)) + { + return nullptr; + } + pT->SetFineStepCount(finestepcount); + return pT; + } + + static std::unique_ptr<CTuning> CreateGeometric(const mpt::ustring &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount) + { + std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning()); + pT->SetName(name); + if(!pT->CreateGeometric(groupsize, groupratio)) + { + 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 mpt::ustring &s) + { + m_TuningName = s; + } + + mpt::ustring GetName() const + { + return m_TuningName; + } + +private: + + CTuning(); + + SerializationResult InitDeserialize(std::istream &inStrm, mpt::Charset defaultCharset); + + //Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr. + SerializationResult InitDeserializeOLD(std::istream &inStrm, mpt::Charset defaultCharset); + + //Create GroupGeometric tuning of *this using virtual ProCreateGroupGeometric. + bool CreateGroupGeometric(const std::vector<RATIOTYPE> &v, const RATIOTYPE &r, const NoteRange &range, const NOTEINDEXTYPE &ratiostartpos); + + //Create GroupGeometric of *this using ratios from 'itself' and ratios starting from + //position given as third argument. + bool CreateGroupGeometric(const NOTEINDEXTYPE &s, const RATIOTYPE &r, const NOTEINDEXTYPE &startindex); + + //Create geometric tuning of *this using ratio(0) = 1. + bool CreateGeometric(const UNOTEINDEXTYPE &p, const RATIOTYPE &r); + bool CreateGeometric(const UNOTEINDEXTYPE &s, const RATIOTYPE &r, const NoteRange &range); + + void UpdateFineStepTable(); + + // GroupPeriodic-specific. + // Get the corresponding note in [0, period-1]. + // For example GetRefNote(-1) is to return note :'groupsize-1'. + MPT_FORCEINLINE NOTEINDEXTYPE GetRefNote(NOTEINDEXTYPE note) const + { + MPT_ASSERT(GetType() == Type::GROUPGEOMETRIC || GetType() == Type::GEOMETRIC); + return static_cast<NOTEINDEXTYPE>(mpt::wrapping_modulo(note, GetGroupSize())); + } + + static bool IsValidRatio(RATIOTYPE ratio) + { + return (ratio > static_cast<RATIOTYPE>(0.0)); + } + +private: + + Tuning::Type m_TuningType; + + //Noteratios + std::vector<RATIOTYPE> m_RatioTable; + + //'Fineratios' + std::vector<RATIOTYPE> m_RatioTableFine; + + // The lowest index of note in the table + NOTEINDEXTYPE m_NoteMin; + + //For groupgeometric tunings, tells the 'group size' and 'group ratio' + //m_GroupSize should always be >= 0. + NOTEINDEXTYPE m_GroupSize; + RATIOTYPE m_GroupRatio; + + USTEPINDEXTYPE m_FineStepCount; // invariant: 0 <= m_FineStepCount <= FINESTEPCOUNT_MAX + + mpt::ustring m_TuningName; + + std::map<NOTEINDEXTYPE, mpt::ustring> m_NoteNameMap; + +}; // class CTuning + + +} // namespace Tuning + + +OPENMPT_NAMESPACE_END |