音階の調を表すクラス。
成果物
Python.MusicTheory.ScaleKey.201709230939
前回まで
- ClassPropertyを他のclassのclassmethodから参照するとプロパティとして見てくれない
- メタクラスを継承してsetattrによる再代入禁止とsys.modulesへのクラスインスタンス代入を共通化した
- readonlyな定数を音度、変化記号、ピッチクラスに実装した
- 音程から半音数を取得する
- Python音楽理論ライブラリの細かい点を修正した
- 音名から半音数(ピッチクラス)を取得する
- ピッチクラスとオクターブからMIDIノート番号を取得する
- MIDIノート名からMIDIノート番号を取得する
- 変化記号を各国の表記で取得する
- 音名を各国の表記で取得する
- 絶対オクターブ値(国際式,YAMAHA式)から相対オクターブ値(0〜10)を取得する
- 基音を設定、取得するクラスを作った
- 12平均律で周波数を取得する
- ピタゴラス音律で周波数を取得する
- 12平均律の基音クラスを弱参照するよう修正した
- 純正律で周波数を算出する
- 音階と音度からピッチクラスを取得する
今回
音階と音度から音名を得たい。しかし、やってみると厄介なことになってきた。ポイントは以下2点。
C#
とDb
の区別はピッチクラスではつけられない(音名を得たいなら区別が必要)- 異なるクラス間の通知ができない(Observerパターンが必要)
作りながら気づいた経緯を列挙する。
- 音階と音度から音名を得たい
- 調の指定はピッチクラスだと不足。音名で指定すべき
- 第一音の音名が特定できないから
C#
とDb
の場合、それぞれC
とD
の音名を使いたいC#
,Db
は両者ともピッチクラス1
になる。1
ではC
,D
どちらを使うべきか判断できない
- ScaleKeyクラス作成が必要
- 調はピッチクラスでなく、音名で指定するようにする
- 第一音の音名が特定できないから
- ScaleクラスからScaleKeyを参照する
- ScaleKeyから調を設定する
- Scale側でScaleKeyの変更を検知できない
- Scaleの構成音再計算ができない
- Observerパターンの実装が必要
- Observerパターン用メタクラスの作成が必要
- Observerパターンの実装が必要
- Scaleの構成音再計算ができない
- Scale側でScaleKeyの変更を検知できない
- ScaleKeyから調を設定する
- 調の指定はピッチクラスだと不足。音名で指定すべき
肝心なことは以下。上記に気づく過程でクラスを作ったり壊したりしていたので一向に実装までたどりつけなかった。
音階と音度から音名を取得する
C#
かDb
かを選出するアルゴリズム。
- できるだけ各音度ごとにC,D,E,F,G,A,B個別の音名を割り振る
- その音に変化記号
#
かb
どちらを割り振れば構成音になるか判断する
- その音に変化記号
- 調が幹音でない(
C#
など変化記号がある)場合、変化記号をとった音名を基準として上記のように処理する(どこかで必ず音名が被る)
s = Scale(9, ScaleIntervals.Minor) self.assertEqual(9, s.Key) self.assertEqual(ScaleIntervals.Minor, s.Intervals) self.assertEqual([(9,0),(11,0),(0,1),(2,1),(4,1),(5,1),(7,1)], s.PitchClasses)
戻り値は(ピッチクラス, 相対オクターブ)
である。
テストコード | 項目数 |
---|---|
TestScale.py | 9 |
テスト計160項目。
所感
ピッチクラスと絶対オクターブが決まれば、周波数が算出できる。今回、相対オクターブを付与したおかげで、どの音からオクターブ上げる必要があるか算出する必要がなくなる。後々楽になるはず。
ピッチクラスなら問題なく一意に特定できる。しかし、音名は違う。C#
かDb
のどちらにすべきかの処理が面倒。次回、やってみる。