読者です 読者をやめる 読者になる 読者になる

わどぅー

記事については、中間出力の場合も多いので間違ってたらごめんなさい。twitter は waddlaw です。どうぞよろしく。

関数プログラミングの楽しみ4章 (1/3)

「4.2 音楽を表現する」の内容を解説しようと思います[1]。しかし、音楽の素養を持っているわけでもないので、わからない単語などは適宜引用させてもらいます。

準備

鍵盤の画像があると理解しやすいと思います。

用語解説

本文中に出てくる音楽用語についてまとめます。

音名

本文中の音程クラスは以下の表の英語の行のことです。

音程 (interval)

2つの音がどれだけ隔たっているかを表すのに、音程という概念を用い、単位として度 (Degree) を用いる。

オクターヴ (octave)

振動数 (周波数) が 1:2 の関係にある2つの音は同時に鳴った時にほとんど1音の様に響くことが知られている。この2音の成す音程をオクターヴという。

異名同音 (enharmonics)

異名同音(いめいどうおん)とは、西洋音楽において、音名が異なっても実質演奏される音が同じ音となる複数 (一組だけ2つ、他は3つ) の音のことをいう。

移調 (transposition)

ある調に属する旋律 (Melody) を他の調に移しかえる作業を移調という。(詳しく説明しようとすると音階 (Scale) のことも言わないといけなくなるので、ここでは旋律の全ての音符を決まった分だけ上下させることで他の調にできると認識してほしいです、)

跳躍進行

ある音から3度以上離れた音へ跳ぶ進行のこと。例えば、ドを弾いて次にミを弾くと、レをとばすので跳躍進行である。

アルペジオ

アルペジオ (Arpeggio) は和音(コード)を1音ずつ素早く鳴らしながら演奏します。

カノン

カノン (canon) は、複数の声部が同じ旋律を異なる時点からそれぞれ開始して演奏する様式の曲を指す。

オスティナート

オスティナート(ostinato)とは、ある種の音楽的なパターンを続けて何度も繰り返す事をさす。

トリル

トリルは書かれている音符と、その1音上の音を交互に速く演奏して、波状の音を出す演奏方法です。トリルのスピードは人それぞれでいいと思います。記号は音符の上にtrと書きます。

モード

音階 (Scale) のことだと思うのですが、詳しくは参考文献[10][11][12]とかを見てください。

本文の補足

  • Data.Ratio

P.66 の音の長さの定義において Ratio がいきなり出現する。実際にコーディングする際には以下の import 文を挿入する。

import Data.Ratio (Ratio, (%))

% 演算子は Ratio 型のデータを作る際に利用する。

  • 並列合成について
    • 同時に始まって、長いほうが終われば全体も終了

    • 同時に始まって、短いほうが終われば全体も終了 (したがって、長いほうは切り詰められる)

    • 2つを「真ん中」の時間で揃えて、2つの時間差の半分が経過したあとに短い方を開始

  • quot (rem) と div (mod) の違い
    • x = qy + r の形で、r の符号が x と同じ (quot / rem)、y と同じ (div / mod)
    • 具体例
10 = (-3) * q + r
    • このとき、(quot と rem) はx と同じ符号なので + になる。よって、 q = -3, r = 1。
    • 同様に、 (div / mod) は y と同じ符号なので - になる。よって、 q = -4, r = -2。

練習問題の解答 (間違ってたらごめんなさい)

  • 練習問題4.1

問題文の「同音異名」は「異名同音」の間違いだと思う。

absPitch . pitch = id
 absPitch . pitch
 = {(.) とpitchの定義}
 absPitch (λap → [C..B] !! mod ap 12, quot ap 12)
 = {absPitchの定義}
 λap → 12 * (quot ap 12) + pcToInt ([C..B] !! mod ap 12)
 = {pcToInt ([C..B] !! mod ap 12) = mod ap 12)}
 λap → 12 * (quot ap 12) + (mod ap 12)
 = {x = y * q + r の形なので}
 λap → ap
 = id
pitch . absPitch
 = {(.)とabsPitchの定義}
 pitch (λ(pc, oct) → 12 * oct + pcToInt pc)
 = {pitchの定義}
 λ(pc, oct) → ([C..B] !! mod (12 * oct + pcToInt pc) 12, quot (12 * oct + pcToInt pc) 12)
 = {mod (12 * oct + pcToInt pc) 12 = mod (pcToInt pc) 12}
 λ(pc, oct) → ([C..B] !! mod (pcToInt pc) 12, quot (12 * oct + pcToInt pc) 12)
 = {quot (12 * oct + pcToInt pc) 12 = oct + div (pcToInt pc) 12}
 λ(pc, oct) → ([C..B] !! mod (pcToInt pc) 12, oct + div (pcToInt pc) 12)
 = {div (pcToInt pc) 12 はCf のとき -1, Bs のとき +1, その他は 0 となるが異名同音なので問題ない }
 λ(pc, oct) → ([C.B] !! mod (pcToInt pc) 12, oct)
 = {[C..B] !! mod (pcToInt pc) 12 = pc}
 λ(pc, oct) → (pc, oct)
 = id
  • 練習問題4.2
trans i (trans j p) = trans (i + j) p
 = {transの定義}
 pitch (absPitch (pitch (absPitch p + j)) + i)
 = {absPitch . pitch = id}
 pitch *1
 = {transの定義を逆適用}
 trans (i + j) p
  • 練習問題4.3
trilln :: Int -> Int -> Music -> Music
trilln i n note@(Prim (Note p nd)) = trill i (1%n * nd) note

trilln' :: Int -> Int -> Music -> Music
trilln' i n (Prim (Note p nd)) = trilln (negate i) n (Prim (Note (trans i p) nd))
  • 練習問題4.4

この問題・・・自信ない・・・。

negate (negate i) = i
 = {negate の定義}
 negate (-i)
 = {nagete の定義}
 i
trans (negate i) (trans i p) = p
 = {練習問題4.2より}
 trans (negate i + i) p
 = {negate の定義}
 trans 0 p
 = {trans の定義}
 pitch (absPitch p + 0)
 = {練習問題4.1 pitch . absPitch = id より}
 p

目的である durM (trill i d n) = durM n を示す.まず,nのままでは少しや
りずらいので形を変更する.

durM (trill i d n) = durM n
 = {nの形を (Prim (Note p nd)) に変更}
 durM (trill i d (Prim (Note p nd))) = durM (Prim (Note p nd))

メインはここ

 durM (trill i d (Prim (Note p nd)))
 = {trill の定義}
 durM (Prim (Note p d) :+: trill (negate i) d (Prim (Note (trans i p) (nd-d))))
 = {durM の定義}
 d + durM (trill (negate i) d (Prim (Note (trans i p) (nd-d))))
 = {trill の定義}
 d + durM (Prim (Note (trans i p) d) :+: trill (negate (negate i)) d (Prim (Note (trans (negate i) (trans i p)) *2 d (Prim (Note (trans (negate
 i) (trans i p)) ((nd-d)-d))))
 = {negate (negate i) = i, trans (negate i) (trans i p) = p より}
 d + d :+: durM (trill i d (Prim (Note p ((nd-d)-d))))

ループの不変条件として,式全体の Note の長さは常に一定であることがわかる.
よって,d ≧ nd が満たされればループ回数分の d を減算した nd が返る.
よって,durM (trill i d (Prim (Note p nd))) = nd となり題意を満たす.

  • 練習問題4.5
    • 面倒なのでパス。
  • 練習問題4.6
data Mode = Ionian | Dorian | Phrygian | Lydian | Mixolydian | Aeolian | Locrian
	deriving (Show, Eq)

scale :: Mode -> Note -> Music
scale mode n =
	case mode of
		Ionian     -> m :+: applyM m ionian
		Dorian     -> m :+: applyM m dorian
		Phrygian   -> m :+: applyM m phrygian
		Lydian     -> m :+: applyM m lydian
		Mixolydian -> m :+: applyM m mixolydian
		Aeolian    -> m :+: applyM m aeolian
		Locrian    -> m :+: applyM m locrian
	where
		m = Prim n
		major = Trans 2
		minor = Trans 1
		locate (x:xs) = xs ++ [x]
		applyM m [] = m
		applyM m (trans:ts) = trans m :+: applyM (trans m) ts
		ionian = [major, major, minor, major, major, major, minor]
		dorian = locate ionian
		phrygian = locate dorian
		lydian = locate phrygian
		mixolydian = locate lydian
		aeolian = locate mixolydian
		locrian = locate aeolian

*1:absPitch p + j) + i) = {加法の結合性} pitch (absPitch p + (j + i

*2:nd-d)-d)))) = {durM の定義} d + d :+: durM (trill (negate (negate i