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

      p進大好きサークル

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

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

機能和声の実装 - 音名

2020/01/17

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

twitter pixiv yukicoder お題箱 マシュマロ

数式での翻訳

幹音と変化記号の文字列としての結合で与えられる文字列を、幹音と変化記号の組と同一視します。幹音と変化記号の組全体の集合 \[ \textrm{OnMei} = \textrm{KanOn} \times \textrm{HenKaKiGou} \] に属する文字列を音名と呼びます。特に変化記号成分が空文字列\(\textrm{□}\)である音名は文字列として幹音と一致しますので、文字列の結合と組の同一視の下で任意の幹音は音名です。数学ではよく同一視という言葉が多義的に用いられますが、ここでの文脈における同一視をより厳密に表現すると、単射な写像 \[ \begin{align} \textrm{KanOnToOnMei} \colon \textrm{KanOn} & \hookrightarrow \textrm{OnMei} \\
N & \mapsto (N,\textrm{□}) \end{align} \] を略して表記する、ということです。具体的には、「文字列の結合と組の同一視の下で任意の幹音は音名である」という主張は「任意の幹音\(N\)に対し『\(\textrm{KanOnToOnMei}\)による\(N\)の像を\(N\)と略記すると』\(N\)は音名である」ということで、命題における略記のメタな明示である『』部分を解消するとこの主張は「任意の幹音\(N\)に対し\(\textrm{KanOnToOnMei}\)による\(N\)の像は音名である」という主張になります。このように命題の略記のメタな明示やそれに基づく同一視は数学において曖昧さが致命的でない範囲で断りなく多用されるものですので、今後も断りなく使っていきます。また\(\textrm{KanOnToOnMei}\)は再帰的かつ像が\(\textrm{OnMei}\)の再帰的部分集合となるので、このような同一視は何らかの意味で実装をすることも可能です。実際、今回は\(\textrm{KanOnToOnMei}\)に対応するコンストラクタを適切に定義することで幹音から音名への暗黙なキャストを可能にし、また音名が幹音か否か(つまり変化記号成分が空文字列か否か)の判定も変化記号に対応するメンバ変数への参照返しを行うメンバ関数を実装することで可能にします。

第\(1\)射影と第\(2\)射影 \[ \begin{align} \textrm{OnMei} & \to \textrm{KanOn} \\
\textrm{OnMei} & \to \textrm{HenKaKiGou} \end{align} \] をそれぞれ\(\textrm{GetKanOn}\)と\(\textrm{GetHenKaKiGou}\)と置きます。

\(\textrm{PitchClass} = \mathbb{Z}/12 \mathbb{Z}\)と置き、\(\textrm{PitchClass}\)の元をピッチクラスと呼びます。また写像 \[ \begin{align} \textrm{GetPitchClass} \colon \textrm{OnMei} & \to \textrm{PitchClass} \\
N & \mapsto \textrm{GetPitchClass}(N) \end{align} \] を以下のように定めます:

  1. \(N_0 = \textrm{GetKanOn}(N)\)と置き、\(S_0 = \textrm{GetHenKaKiGou}(N)\)と置く。
  2. \(N_0 = \textrm{Do}\)ならば、\(\textrm{GetPitchClass}(N) = 0 + \textrm{GetNum}(S_0)\)である。
  3. \(N_0 = \textrm{Re}\)ならば、\(\textrm{GetPitchClass}(N) = 2 + \textrm{GetNum}(S_0)\)である。
  4. \(N_0 = \textrm{Mi}\)ならば、\(\textrm{GetPitchClass}(N) = 4 + \textrm{GetNum}(S_0)\)である。
  5. \(N_0 = \textrm{Fa}\)ならば、\(\textrm{GetPitchClass}(N) = 5 + \textrm{GetNum}(S_0)\)である。
  6. \(N_0 = \textrm{So}\)ならば、\(\textrm{GetPitchClass}(N) = 7 + \textrm{GetNum}(S_0)\)である。
  7. \(N_0 = \textrm{La}\)ならば、\(\textrm{GetPitchClass}(N) = 9 + \textrm{GetNum}(S_0)\)である。
  8. \(N_0 = \textrm{Ti}\)ならば、\(\textrm{GetPitchClass}(N) = 11 + \textrm{GetNum}(S_0)\)である。

ただし定義中の\(\textrm{GetNum}(S_0)\)は変化記号の記事においてオーバーロードした写像\(\textrm{HenKaKiGou} \to \mathbb{Z}\)に\(S_0\)を代入したものであることに注意しましょう。この写像\(\textrm{GetPitchClass} \colon \textrm{OnMei} \to \textrm{PitchClass}\)は全射ですが、単射ではありません。\(\textrm{GetPitchClass}\)での像が等しい相異なる音名を(平均律における)異名同音と呼びます。

また\(\textrm{KanOnToOnMei}\)と\(\textrm{GetPitchClass}\)の合成写像 \[ \begin{align} \textrm{KanOn} & \to \textrm{PitchClass} \\
N & \mapsto \textrm{GetPitchClass}(\textrm{KanOnToOnMei}(N)) \end{align} \] を\(\textrm{KanOnToPitchClass}\)と呼びます。

C++での宣言

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


using PitchClass = Mod<12>;

class OnMei
{

private:
  KanOn m_N;
  HenKaKiGou m_S;
  PitchClass m_pc;

public:
  inline OnMei( const KanOn& N ) noexcept;
  inline OnMei( const KanOn& N , const HenKaKiGou& S ) noexcept;

  OnMei& operator++() noexcept;
  OnMei& operator--() noexcept;
  
  inline string Display() const noexcept;
  inline const KanOn& GetKanOn() const noexcept;
  inline const HenKaKiGou& GetHenKaKiGou() const noexcept;
  inline const PitchClass& GetPitchClass() const noexcept;
  
  static PitchClass KanOnToPitchClass( const KanOn& N ) noexcept;

};

inline bool operator==( const OnMei& N1 , const OnMei& N2 ) noexcept;
inline bool operator!=( const OnMei& N1 , const OnMei& N2 ) noexcept;


C++での定義

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

  • inline OnMei::OnMei( const KanOn& N ) noexceptは移譲コンストラクタOnMei( N , HenKaKiGou( 0 ) )で定める。
  • inline OnMei::OnMei( const KanOn& N , const HenKaKiGou& S ) noexceptはメンバ初期化子リストm_N( N ) , m_S( S ) , m_num( KanOnToInt( N ) + S.GetNum() )で定める。
  • OnMei& OnMei::operator++() noexceptとOnMei& OnMei::operator--() noexceptはそれぞれ++m_Sと--m_Sを実行し、return *thisと定める。
  • inline string OnMei::Display() const noexceptはreturn m_N.Display() + m_S.Display()と定める。
  • inline const KanOn& OnMei::GetKanOn() const noexceptはreturn m_Nと定める。
  • inline const HenKaKiGou& OnMei::GetHenKaKiGou() const noexceptはreturn m_Sと定める。
  • inline const OnMei::PitchClass& GetPitchClass() const noexceptはreturn m_pcと定める。
  • static PitchClass OnMei::KanOnToPitchClass( const KanOn& N ) noexceptは引数Do()~Ti()に対してそれぞれconst int nを0 , 2 , 4 , 5 , 7 , 11と定め、return PitchClass( n )と定める。
  • クラスOnMeiに対する等号演算子は自然なものである。
トップページ 前の記事 親記事 次の記事

twitter pixiv yukicoder お題箱 マシュマロ