Skip to content

lv100tomato/ClassicMusicTheoryForProgrammer

Repository files navigation

プログラマーのための古典派音楽理論

BNF

<program> ::= <info> \n <bars> | <bars>
<info>    ::= <bpm> <number> | <tempo>
<bpm>     ::= "BPM" | "bpm"
<number>  ::= ["1"-"9"]["0"-"9"]* | "0"
<tempo>   ::= "Grave" | "Largo" | "Lento" | "Adagio" | 
              "Larghetto" | "Adagietto" | "Andante" | "Maestoso" |
              "Moderate" | "Allegletto" | "Animato" | "Allegro" |
              "Assai" | "Vivace" | "Presto" | "Prestissimo"
<bars>    ::= <line> | <line> \n <bar> \n <bar> \n <bar> \n <bar> \n <bars>
<line>    ::= "|" | "|:" | ":|"
<bar>     ::= <tone> | <tone> <tone> | <tone> <tone> <tone> <tone>
<tone>    ::= <number> | ["A"-"G"](|"-")["0"-"9"](|"#"|"b") | "R" | "T"

また、// を書くと、以降が行末までコメントとみなされます。

処理

楽曲情報

最初の行には楽曲のテンポを指定することができます(プログラムの実行には関係ありません)。 省略した場合、Moderate が指定されます。

toneレベル処理

ソースコードは小節線(||::|)によって区切られる4行のbarごとに解釈されます。小節線のうち |::| は括弧と同様の構造で1対1に対応しており、出現が同数でない場合はエラーとなります。
以下にbarの一例を示します。

R   A5  F5  E5
E5      C5
G4  A4  T   G4
C4

C4T などはtoneと呼び、音符の情報を示します。C4 などは音高を表し、これはMIDIのノートナンバーに準拠します。TR については後述します。
toneは1行に1つ又は2つ又は4つ書くことができ、1行のtoneが1つ又は2つの場合、T が補完されます。上記の例は以下と等価です。

R   A5  F5  E5
E5  T   C5  T
G4  A4  T   G4
C4  T   T   T

また、toneの記法のうち上記のような数字とアルファベット(と臨時記号 # b)を組み合わせて書くものについては、数字のみで書き表すことができます。この場合の対応はこのページの国際式に準じます。
上記のソースコードは以下のように書き換えることができます。

R   81  77  76
76      72
67  69  T   67
60

各行の音符については補完がなされたのち、1~4行目の左から1番目、2番目、3番目、4番目の音符の組からchordに解釈されます。解釈にあたり、各toneはC C#(Db) D D#(Eb) E F F#(Gb) G G#(Ab) A A#(Bb) B の音名に置き換えられます。置き換えの際、R は無視され、T は直前の音符と同じ音名とみなします(直前に音符が存在しない場合は無視されます)。

置き換えたのち、音符の組が以下の表に過不足なく対応するかどうかを調べ(音高の重複は許します)、chordへの解釈を行います。解釈できない場合はエラーとなります(1st、3rd、5th、7thについては気にしないで下さい、より難解にしようとした名残です)。

chord 1st 3rd 5th 7th
I C E G
II D F A
II7 D F# A C
II7 omit5 D F# C
II7 F# A C
IV F A C
V G B D
V7 G B D F
V7 omit5 G B F
V7 B D F
VI A C E

上記のソースコードをchordに解釈すると、以下のようになります。

I VI IV I

chordレベル処理

chordは先頭から順に読んでいき、小節線の直後の I を区切りとしてprogressionというまとまりごとに解釈を行います。ただし、その際に以下のように変換がなされます。

変換対象 変換後
II7、II7 omit5、II7 II
V7、V7 omit5、V7 V

この変換ののち、同じchordが連続して並んでいるものが現れた場合は、2つ目以降を無視します。
例えば、ソースコードをchordに解釈した結果が以下のようになった場合、これは I IV II VI IV II V VI IV V 、… のprogression列として解釈されます。

 |  I   IV  II  V
 |  I   IV  II  II7
 |  V   VI  IV  V
 |  I   ...

progression列として解釈されたものは、命令として実行できるものから逐次的に実行されていきます。chord列の終端に達した場合は、そこで正常終了します。命令については後述します。

chordを読んでいく際に小節線として |::| が現れるとき、直前に実行した命令の値(後述)によって読む場所が変化することがあります。

  • |: に到達した時点での直前の命令の値が0の時、対応する :| まで飛ばします。
  • :| に到達した時点での直前の命令の値が0でない時、対応する |: まで戻ります。

以下のchord列の場合、直前の命令の値によって得られるprogression列が変わります。

...
 |  I   V   VI  IV
 |: V   I   II  V
 |  I   VI  IV  II
:|  II  V   I   IV
 |  I   ...
  • 直前の命令の値が0でないとき … 、I V VI IV V I II V 、… を得ます。
  • 直前の命令の値が0のとき … 、I V VI IV II V I IV、 … を得ます。

命令

基本的に1~3つの連続したprogressionが命令として解釈されます。解釈できないprogressionが現れた場合は実行時エラーになります。また、各命令には命令の値があり、|::| での分岐に用います。

  • I V 、(変数)
    変数を32bit整数型で宣言し、0を代入します。既に宣言されている変数の場合は、その変数に0を代入します。
    変数名に指定できるのは、予約語(命令の先頭に来る定型のprogression)以外のprogressionです。それ以外を指定すると実行時エラーになります。
    命令の値は常に0になります。

  • I IV 、(変数)
    変数の値を1増やします。
    命令の値は計算後の変数の値です。

  • I V I V 、(変数)
    入力からUnicodeとして1文字分取得した値を数値として変数に代入します。
    命令の値は代入後の変数の値です。

  • I IV I V 、(変数)
    変数の値をUnicode文字として出力します。値が0~65535の範囲外の場合は、値を65536で割った正剰余の値を文字として出力します。
    命令の値は変数の値です。

  • I IV V 、(変数1) 、(変数2)
    変数1に変数2の値を加算します。
    命令の値は計算後の変数1の値です。

  • I IV II V 、(変数1) 、(変数2)
    変数1から変数2の値を減算します。
    命令の値は計算後の変数1の値です。

  • I VI V 、(変数1) 、(変数2)
    変数1に変数2の値を乗算します。
    命令の値は計算後の変数1の値です。

  • I VI IV V 、(変数1) 、(変数2)
    変数1から変数2の値を除算します。小数点以下は0に近いほうに丸めます。
    命令の値は計算後の変数1の値です。

  • I VI II V 、(変数1) 、(変数2)
    変数1を変数2の値で割った剰余の値にします。計算前後で変数1の符号は変化しません。
    命令の値は計算後の変数1の値です。

以下に入力をそのまま出力する処理(cat)を行うchord列の例を示します。

 |  I   I   V   V
 |  I   I   II  V
 |  I   I   IV  IV
 |  I   I   II  V
 |  I   I   V   V
 |  I   V   VI  V
 |  I   V   I   V
 |  I   V   VI  V
 |  I   I   IV  IV
 |  I   V   VI  V
 |  I   IV  II  V
 |: I   V   VI  V
 |  I   I   II  V
 |  I   IV  I   V
 |  I   V   VI  V
 |  I   V   I   V
 |  I   V   VI  V
 |  I   I   IV  IV
 |  I   V   VI  V
 |  I   IV  II  V
:|  I   I   I   I
 |

禁則

さて、ここからは音楽理論の話です。

※ここで紹介する禁則などは実際の音楽理論のそれとは異なる部分もあります。予めご了承ください。

曲を綺麗に聴こえるものにするためには、どんなtoneやchordなどでも良いという訳ではなく、一定の法則に則ったものにする必要があります。
この言語では、以下に示す法則に反するものは音楽理論エラーとなり、検出された時点で実行不可となります。
ただし、オプションで-IgnoreTheoryExを指定した場合はエラーを無視して実行を行うことができます(エラーメッセージは表示されます)。

toneの禁則

この言語では、弦楽四重奏で演奏できる曲を基本としており、1つのbar内にある4行のtone列は、上から順にソプラノ・アルト・テノール・バスにあたります。これを声部といいます。

R   A5  F5  E5  <- ソプラノ
E5      C5      <- アルト
G4  A4  T   G4  <- テノール
C4              <- バス
                   ↑これを声部という

音域

ソプラノ・アルトはバイオリン、テノールはビオラ、バスはチェロで演奏されるため、それぞれの声部におけるtoneはそれぞれの楽器で弾くことのできる音域の中に収まっている必要があります。以下にそれぞれの音域を示します。

声部 最低音 最高音
ソプラノ、アルト G3(55) C7(96)
テノール C3(48) C6(84)
バス C2(36) C5(72)

声部と音高

それぞれの声部について、下の声部の音高が上の声部の音高以上となってはいけません
以下に良くない例を示します。

E4
G4  <- ソプラノより高い音高になっているのでエラー
C4
C4  <- テノールと同じ音高になっているのでエラー

連続五度、連続八度

各声部がバランスのいい綺麗なハーモニーを奏でるために気を付けなければならないのが、連続五度と連続八度です。
まず、五度・八度の関係について解説します。これは、2つの声部で鳴っている音の関係を表す言葉であり、低いほうの声部から数えて音高の差が半音7個分(、半音19個分、半音31個分…)の時に五度の関係、半音12個分(、半音24個分、36個分…)の時に八度の関係といいます。

C5  <- バスから見て半音12個分なので八度の関係
G4  <- バスから見て半音7個分なので五度の関係
E4  <- バスから見て半音4個分
C4  <- この例ではここが基準

この五度・八度の関係にある2つの声部は他の声部より音が強く感じられるため、なるべく連続して同じ声部群が五度・八度の関係になることは好ましくないと考えられます。そのため、同じ声部同士で3回以上連続で五度の関係に、または八度の関係になってはいけません(五度の関係から八度の関係になる等は連続していないとみなします)。ただし、T については判定をせず、次に音高が変化するまで連続の回数を持ち越します。
以下に良くない例を示します。

C5  G4  A4  D5  <- テノールと4回連続八度になっている(エラー)
G4  D4  C4  F4  <- 最初の2つがテノールと2回連続五度になっている
C4  G3  A3  D4  <- ソプラノと4回連続八度、アルトと2回連続五度になっている(エラー)
E3  B2  E3  A3

限定進行音

toneの構成するchordが一定の条件を満たすものにおいて、メロディの流れを美しいものにするために一部のtoneについては次に鳴らすべき音が定められています
以下にその条件と音を示します。

chord 条件 次の音
V、V7、V7 omit5、V7 音名がB 半音上のC
V7、V7 omit5、V7 音名がF 半音下のE
II7、II7 omit5、II7 音名がF#(Gb) 半音上のG
II7、II7 omit5、II7 音名がC 半音下のB

不自然な音程の移動

演奏するにあたって弾きづらい音程についてはなるべく避ける必要があり、音高が変化する際に半音10個分以上の移動を行ってはいけません(ただし、半音12個分の移動は例外的に大丈夫です)。

chordの禁則

chordが変化する際は、その流れが違和感なく綺麗に聴こえる必要があります。そのため、ほぼ全てのchordに進行先が決まっています
chordの進行先は以下の通りです。

chord 進行先
I 全て
II、II7、II7 omit5、II7 V、V7、V7 omit5、V7
IV VI 以外
V I、V7、V7 omit5、V7、VI
V7、V7 omit5、V7 I、VI
VI I 以外

また、曲が終わる(プログラムが終了する)際は必ずchordが I である必要があります

おまけ

オプションで-MakeMidiを指定した場合はソースコードは実行せず、ソースコードに従ってmidiファイルを生成します。
この際、|::| で囲まれた部分は必ず2回づつ演奏されます。

サンプルコード

cat

Vivace
| //I       V
    C5      G4
    E4      D4
    G3      G3
    C3      B2
| //I       II  V
    C5  T   A4  B4
    E4  T   F4  D4
    G3  T   F3  G3
    C3  T   D3  D3
| //I       IV
    C5      T
    E4      F4
    G3      A3
    C3      T
| //I       II  V
    C5  T   A4  B4
    E4  T   F4  D4
    G3  T   F3  G3
    C3  T   D3  D3
| //I       V
    C5      G4
    E4      D4
    G3      G3
    C3      B2
| //I   V   VI  V
    C5  D5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I   V   I   V
    C5  B4  C5  D5
    E4  D4  E4  G4
    G3
    C3  D3  C3  B2
| //I   V   VI  V
    C5  F5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I       IV
    C5      T
    E4      F4
    G3      A3
    C3      T
| //I   V   VI  V
    C5  F5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I   IV  II  V
    C5  A4  T   B4
    E4  F4  T   D4
    G3  C4  F3  G3
    C3  F3  D3  D3
|://I   V   VI  V
    C5  F5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I       II  V
    C5  T   A4  B4
    E4  T   F4  D4
    G3  T   F3  G3
    C3  T   D3  D3
| //I   IV  I   V
    C5  A4  G4  B4
    E4  F4  E4  D4
    G3  C4  T   G3
    C3  F3  G3  D3
| //I   V   VI  V
    C5  D5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I   V   I   V
    C5  B4  C5  D5
    E4  D4  E4  G4
    G3
    C3  D3  C3  B2
| //I   V   VI  V
    C5  F5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I       IV
    C5      T
    E4      F4
    G3      A3
    C3      T
| //I   V   VI  V
    C5  F5  E5  B4
    E4  G4  A4  G4
    G3  B3  C4  G3
    C3  D3  C3  D3
| //I   IV  II  V
    C5  A4  T   B4
    E4  F4  T   D4
    G3  C4  F3  G3
    C3  F3  D3  D3
:|//I
    C5
    E4
    G3
    C3
|

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages