tuning.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * tuning.h
  3. * --------
  4. * Purpose: Alternative sample tuning.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include <map>
  12. #include "tuningbase.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. namespace Tuning {
  15. class CTuning
  16. {
  17. public:
  18. static constexpr char s_FileExtension[5] = ".tun";
  19. static constexpr RATIOTYPE s_DefaultFallbackRatio = 1.0f;
  20. static constexpr NOTEINDEXTYPE s_NoteMinDefault = -64;
  21. static constexpr UNOTEINDEXTYPE s_RatioTableSizeDefault = 128;
  22. static constexpr USTEPINDEXTYPE s_RatioTableFineSizeMaxDefault = 1000;
  23. public:
  24. // To return ratio of certain note.
  25. RATIOTYPE GetRatio(const NOTEINDEXTYPE note) const;
  26. // To return ratio from a 'step'(noteindex + stepindex)
  27. RATIOTYPE GetRatio(const NOTEINDEXTYPE baseNote, const STEPINDEXTYPE baseFineSteps) const;
  28. //Tuning might not be valid for arbitrarily large range,
  29. //so this can be used to ask where it is valid. Tells the lowest and highest
  30. //note that are valid.
  31. MPT_FORCEINLINE NoteRange GetNoteRange() const
  32. {
  33. return NoteRange{m_NoteMin, static_cast<NOTEINDEXTYPE>(m_NoteMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()) - 1)};
  34. }
  35. // Return true if note is within note range
  36. MPT_FORCEINLINE bool IsValidNote(const NOTEINDEXTYPE n) const
  37. {
  38. return (GetNoteRange().first <= n && n <= GetNoteRange().last);
  39. }
  40. MPT_FORCEINLINE UNOTEINDEXTYPE GetGroupSize() const
  41. {
  42. return m_GroupSize;
  43. }
  44. RATIOTYPE GetGroupRatio() const {return m_GroupRatio;}
  45. // To return (fine)stepcount between two consecutive mainsteps.
  46. MPT_FORCEINLINE USTEPINDEXTYPE GetFineStepCount() const
  47. {
  48. return m_FineStepCount;
  49. }
  50. //To return 'directed distance' between given notes.
  51. STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& from, const NOTEINDEXTYPE& to) const
  52. {return (to - from)*(static_cast<NOTEINDEXTYPE>(GetFineStepCount())+1);}
  53. //To return 'directed distance' between given steps.
  54. STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& noteFrom, const STEPINDEXTYPE& stepDistFrom, const NOTEINDEXTYPE& noteTo, const STEPINDEXTYPE& stepDistTo) const
  55. {return GetStepDistance(noteFrom, noteTo) + stepDistTo - stepDistFrom;}
  56. //To set finestepcount between two consecutive mainsteps.
  57. //Finestep count == 0 means that
  58. //stepdistances become the same as note distances.
  59. void SetFineStepCount(const USTEPINDEXTYPE& fs);
  60. // Multiply all ratios by given number.
  61. bool Multiply(const RATIOTYPE r);
  62. bool SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r);
  63. MPT_FORCEINLINE Tuning::Type GetType() const
  64. {
  65. return m_TuningType;
  66. }
  67. mpt::ustring GetNoteName(const NOTEINDEXTYPE &x, bool addOctave = true) const;
  68. void SetNoteName(const NOTEINDEXTYPE &, const mpt::ustring &);
  69. static std::unique_ptr<CTuning> CreateDeserialize(std::istream &f, mpt::Charset defaultCharset)
  70. {
  71. std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning());
  72. if(pT->InitDeserialize(f, defaultCharset) != SerializationResult::Success)
  73. {
  74. return nullptr;
  75. }
  76. return pT;
  77. }
  78. //Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr.
  79. static std::unique_ptr<CTuning> CreateDeserializeOLD(std::istream &f, mpt::Charset defaultCharset)
  80. {
  81. std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning());
  82. if(pT->InitDeserializeOLD(f, defaultCharset) != SerializationResult::Success)
  83. {
  84. return nullptr;
  85. }
  86. return pT;
  87. }
  88. static std::unique_ptr<CTuning> CreateGeneral(const mpt::ustring &name)
  89. {
  90. std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning());
  91. pT->SetName(name);
  92. return pT;
  93. }
  94. static std::unique_ptr<CTuning> CreateGroupGeometric(const mpt::ustring &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
  95. {
  96. std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning());
  97. pT->SetName(name);
  98. if(!pT->CreateGroupGeometric(groupsize, groupratio, 0))
  99. {
  100. return nullptr;
  101. }
  102. pT->SetFineStepCount(finestepcount);
  103. return pT;
  104. }
  105. static std::unique_ptr<CTuning> CreateGroupGeometric(const mpt::ustring &name, const std::vector<RATIOTYPE> &ratios, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
  106. {
  107. std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning());
  108. pT->SetName(name);
  109. NoteRange range = NoteRange{s_NoteMinDefault, static_cast<NOTEINDEXTYPE>(s_NoteMinDefault + s_RatioTableSizeDefault - 1)};
  110. range.last = std::max(range.last, mpt::saturate_cast<NOTEINDEXTYPE>(ratios.size() - 1));
  111. range.first = 0 - range.last - 1;
  112. if(!pT->CreateGroupGeometric(ratios, groupratio, range, 0))
  113. {
  114. return nullptr;
  115. }
  116. pT->SetFineStepCount(finestepcount);
  117. return pT;
  118. }
  119. static std::unique_ptr<CTuning> CreateGeometric(const mpt::ustring &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
  120. {
  121. std::unique_ptr<CTuning> pT = std::unique_ptr<CTuning>(new CTuning());
  122. pT->SetName(name);
  123. if(!pT->CreateGeometric(groupsize, groupratio))
  124. {
  125. return nullptr;
  126. }
  127. pT->SetFineStepCount(finestepcount);
  128. return pT;
  129. }
  130. Tuning::SerializationResult Serialize(std::ostream& out) const;
  131. #ifdef MODPLUG_TRACKER
  132. bool WriteSCL(std::ostream &f, const mpt::PathString &filename) const;
  133. #endif
  134. bool ChangeGroupsize(const NOTEINDEXTYPE&);
  135. bool ChangeGroupRatio(const RATIOTYPE&);
  136. void SetName(const mpt::ustring &s)
  137. {
  138. m_TuningName = s;
  139. }
  140. mpt::ustring GetName() const
  141. {
  142. return m_TuningName;
  143. }
  144. private:
  145. CTuning();
  146. SerializationResult InitDeserialize(std::istream &inStrm, mpt::Charset defaultCharset);
  147. //Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr.
  148. SerializationResult InitDeserializeOLD(std::istream &inStrm, mpt::Charset defaultCharset);
  149. //Create GroupGeometric tuning of *this using virtual ProCreateGroupGeometric.
  150. bool CreateGroupGeometric(const std::vector<RATIOTYPE> &v, const RATIOTYPE &r, const NoteRange &range, const NOTEINDEXTYPE &ratiostartpos);
  151. //Create GroupGeometric of *this using ratios from 'itself' and ratios starting from
  152. //position given as third argument.
  153. bool CreateGroupGeometric(const NOTEINDEXTYPE &s, const RATIOTYPE &r, const NOTEINDEXTYPE &startindex);
  154. //Create geometric tuning of *this using ratio(0) = 1.
  155. bool CreateGeometric(const UNOTEINDEXTYPE &p, const RATIOTYPE &r);
  156. bool CreateGeometric(const UNOTEINDEXTYPE &s, const RATIOTYPE &r, const NoteRange &range);
  157. void UpdateFineStepTable();
  158. // GroupPeriodic-specific.
  159. // Get the corresponding note in [0, period-1].
  160. // For example GetRefNote(-1) is to return note :'groupsize-1'.
  161. MPT_FORCEINLINE NOTEINDEXTYPE GetRefNote(NOTEINDEXTYPE note) const
  162. {
  163. MPT_ASSERT(GetType() == Type::GROUPGEOMETRIC || GetType() == Type::GEOMETRIC);
  164. return static_cast<NOTEINDEXTYPE>(mpt::wrapping_modulo(note, GetGroupSize()));
  165. }
  166. static bool IsValidRatio(RATIOTYPE ratio)
  167. {
  168. return (ratio > static_cast<RATIOTYPE>(0.0));
  169. }
  170. private:
  171. Tuning::Type m_TuningType;
  172. //Noteratios
  173. std::vector<RATIOTYPE> m_RatioTable;
  174. //'Fineratios'
  175. std::vector<RATIOTYPE> m_RatioTableFine;
  176. // The lowest index of note in the table
  177. NOTEINDEXTYPE m_NoteMin;
  178. //For groupgeometric tunings, tells the 'group size' and 'group ratio'
  179. //m_GroupSize should always be >= 0.
  180. NOTEINDEXTYPE m_GroupSize;
  181. RATIOTYPE m_GroupRatio;
  182. USTEPINDEXTYPE m_FineStepCount; // invariant: 0 <= m_FineStepCount <= FINESTEPCOUNT_MAX
  183. mpt::ustring m_TuningName;
  184. std::map<NOTEINDEXTYPE, mpt::ustring> m_NoteNameMap;
  185. }; // class CTuning
  186. } // namespace Tuning
  187. OPENMPT_NAMESPACE_END