• トップページ
  • project
    • 全ての作品
    • 全てのタグ
  • blog
    • 全ての記事
    • 全てのタグ
  • tag
    • 全てのタグ
    • 全ての作品タグ
    • 全ての記事タグ
  • about
    • p進大好きサークル photo

      p進大好きサークル

      p進大好きサークルのHPです。

    • もっと読む
    • Twitter
    • pixiv
    • 巨大数Wiki

機能和声の実装 - 音度

2020/02/29

トップページ 前の記事 親記事 次の記事

twitter pixiv yukicoder お題箱 マシュマロ

数式での翻訳

\(\textrm{DoSuu} = \mathbb{N} \setminus \{0\}\)と置き、\(\textrm{DoSuu}\)の元を度数と呼びます。\(\textrm{DoSuu}\)を記号の集合とする長さ\(1\)の文字列を、その唯一の成分である度数と同一視します。音度の接頭辞と度数と文字列\(\textrm{Do}\)の文字列としての結合で与えられる文字列を、音度の接頭辞と度数と文字\(\textrm{Do}\)の\(3\)つ組と同一視します。音度の接頭辞と度数と文字列\(\textrm{Do}\)の\(3\)つ組全体の集合 \[ \textrm{OnDo} = \textrm{SetTouJiOfOnDo} \times \textrm{DoSuu} \times \{\textrm{Do}\} \] に属する文字列を音度と呼びます。例えば文字列\(\textrm{KanZen}3\textrm{Do}\)は\(3\)つ組\((\textrm{KanZen},3,\textrm{Do})\)と同一視され、\(\textrm{Kanzen}\)は音度の接頭辞、\(3\)は度数であることからこれは音度となります。一方で文字列\(\textrm{Chou}0\textrm{Do}\)は\(0\)が度数でないことから音度ではありません。ちなみに音度の第\(3\)成分である文字列\(\textrm{Do}\)は幹音でもありますが、だからといって何か意味があるわけではありません。

第\(1\)射影と第\(2\)射影 \[ \begin{align} \textrm{OnDo} & \to \textrm{SetTouJiOfOnDo} \\
\textrm{OnDo} & \to \textrm{DoSuu} \end{align} \] をそれぞれ\(\textrm{GetSetTouJi}\)と\(\textrm{GetDoSuu}\)と置きます。

ピッチ\(P_1\)と\(P_2\)に対し、音度\(\Delta_{P_1,P_2}\)を以下のように定めます:

  1. \(D_1 = \textrm{Represent}(\textrm{GetNum}(\textrm{GetKanOn}(\textrm{GetOnMei}(P_1)))) + 7 \cdot \textrm{GetOctave}(P_1) \in \mathbb{Z}\)と置く。
  2. \(D_2 = \textrm{Represent}(\textrm{GetNum}(\textrm{GetKanOn}(\textrm{GetOnMei}(P_2)))) + 7 \cdot \textrm{GetOctave}(P_2) \in \mathbb{Z}\)と置く。
  3. \(D_1 \leq D_2\)ならば、\(s = 1 \in \{-1,1\}\)と置く。
  4. \(D_1 \gneq D_2\)ならば、\(s = -1 \in \{-1,1\}\)と置く。
  5. \(d = \textrm{GetNoteNumber}(P_2) - \textrm{GetNoteNumber}(P_1) \in \mathbb{Z}\)と置く。
  6. \(D = s(D_2-D_1) \in \textrm{ZeroIndexedDoSuu}\)と置く。
  7. \((D,sd)\)に対応する音度の接頭辞を\(S\)と置く。
  8. \(\Delta_{P_1,P_2} = (S,(D+1)+7 \mathbb{Z},\textrm{Do})\)である。

この\(\Delta_{P_1,P_2}\)を\(P_1\)と\(P_2\)の音度と呼びます。

音度\(\Delta\)が最低音における制限付き協和音程であるおよび協和音程であるという関係を以下のように定めます:

  1. \(S = \textrm{GetSetTouJi}(\Delta) \in \textrm{SetTouJiOfOnDo}\)と置き、\(n = \textrm{GetDoSuu}(\Delta) \in \textrm{DoSuu}\)と置く。
  2. 法\(7\)において\(n \equiv 0,2\)ならば、\(\Delta\)は最低音における制限付き協和音程でも協和音程でもない。
  3. 法\(7\)において\(n \equiv 1,5\)ならば、\(\Delta\)が最低音における制限付き協和音程であることと協和音程であることは、\(S\)が\(\textrm{KanZen}\)であることと同値である。
  4. 法\(7\)において\(n \equiv 3,6\)ならば、\(\Delta\)が最低音における制限付き協和音程であることと協和音程であることは、\(S\)が\(\textrm{Chou}\)または\(\textrm{Tan}\)であることと同値である。
  5. 法\(7\)において\(n \equiv 4\)ならば、\(\Delta\)は最低音における制限付き協和音程でなく、\(\Delta\)が協和音程であることは\(S\)が\(\textrm{KanZen}\)であることと同値である。

C++での宣言

音度のクラスおよび関係する関数たちを以下のように宣言します。


using DoSuu = uint;

class OnDo
{

private:
  const SetTouJiOfOnDo& m_settouji;
  const DoSuu m_dosuu;
  const KaiMei m_dosuu_mod;

public:
  inline OnDo( const Pitch& P1 , const Pitch& P2 ) noexcept;

  bool CheckKyouWaOnTei() const noexcept;
  bool CheckKyouWaOnTeiBottom() const noexcept;

  inline const SetTouJiOfOnDo& GetSetTouJi() const noexcept;
  inline const DoSuu& GetDoSuu() const noexcept;
  inline const KaiMei& GetDoSuuMod() const noexcept;
  
  inline string Display() const noexcept;
  
private:
  inline OnDo( const int& D , const int& d ) noexcept;
  inline OnDo( const int& D , const int& d , const int& sign ) noexcept;
  inline OnDo( const ZeroIndexedDoSuu& D , const PitchDifference& d ) noexcept;

  inline static int PitchToAbsoluteDoSuu( const Pitch& P ) noexcept;
  inline static int ComputeSignedZeroIndexedDoSuu( const Pitch& P1 , const Pitch& P2 ) noexcept;
  inline static int ComputeSignedPitchDifference( const Pitch& P1 , const Pitch& P2 ) noexcept;

};

inline bool operator==( const OnDo& D1 , const OnDo& D2 ) noexcept;
inline bool operator!=( const OnDo& D1 , const OnDo& D2 ) noexcept;


C++での定義

実際の実装例についてはこちらをご覧下さい。実装においては以下の仕様を要請します。

  • inline OnDo::OnDo( const Pitch& P1 , const Pitch& P2 ) noexceptは委譲コンストラクタOnDo( ComputeSignedZeroIndexedDoSuu( P1 , P2 ) , ComputeSignedPitchDifference( P1 , P2 ) )で定める。
  • inline OnDo::OnDo( const int& D , const int& d ) noexceptは委譲コンストラクタOnDo( D , d , D >= 0 ? 1 : -1 )で定める。
  • inline OnDo::OnDo( const int& D , const int& d , const int& sign ) noexceptは委譲コンストラクタOnDo( (uint)( sign * D ) , sign * d )で定める。
  • inline OnDo::OnDo::OnDo( const ZeroIndexedDoSuu& D , const PitchDifference& d ) noexceptはメンバ初期化子m_settouji( SetTouJiOfOnDo::Compute( D , d ) ) , m_dosuu( D + 1 ) , m_dosuu_mod( m_dosuu )で定める。
  • bool OnDo::CheckKyouWaOnTei() const noexceptはCheckKyouWaOnTeiBottom()ならばreturn trueと定め、そうでないならば( m_dosuu_mod == 4 ) && ( m_settouji == SetTouJiOfOnDo::KanZen() )と定める。
  • ` bool OnDo::CheckKyouWaOnTeiBottom() const noexceptはm_dosuu_mod == 1またはm_dosuu_mod == 5ならばreturn m_settouji == SetTouJiOfOnDo::KanZen()と定め、m_dosuu_mod == 3またはm_dosuu_mod == 6ならばreturn ( m_settouji == SetTouJiOfOnDo::Chou() )   ( m_settouji == SetTouJiOfOnDo::Tan() )と定め、それ以外ならばreturn false`と定める。
  • inline const SetTouJiOfOnDo& OnDo::GetSetTouJi() const noexceptはreturn m_settoujiで定める。
  • inline const DoSuu& OnDo::GetDoSuu() const noexceptはreturn m_dosuuで定める。
  • inline const KaiMei& OnDo::GetDoSuuMod() const noexceptはreturn m_dosuu_modで定める。
  • inline string OnDo::Display() const noexceptはreturn m_settouji.Get() + to_string( m_dosuu ) + "Do"で定める。
  • inline int OnDo::PitchToAbsoluteDoSuu( const Pitch& P ) noexceptはreturn ( ( ( P.GetOnMei() ).GetKanOn() ).GetNum() ).Represent() + P.GetOctave() * 7で定める。
  • inline int OnDo::ComputeSignedZeroIndexedDoSuu( const Pitch& P1 , const Pitch& P2 ) noexceptはreturn PitchToAbsoluteDoSuu( P2 ) - PitchToAbsoluteDoSuu( P1 )で定める。
  • inline int OnDo::ComputeSignedPitchDifference( const Pitch& P1 , const Pitch& P2 ) noexceptはreturn P2.GetNoteNumber() - P1.GetNoteNumber()で定める。
  • クラスOnDoに対する等号演算子は自然なものである。
トップページ 前の記事 親記事 次の記事

twitter pixiv yukicoder お題箱 マシュマロ