#和音をどう扱うのか
しばらく音楽理論と格闘して、シンプルなとこ見つけた。sus4とかセブンスを使わないでオーソドックスなところで行くなら、文字数使わずに書けそうです。
キーをC3、ノート番号でいうと60にします。ピアノの白鍵だけがメジャースケールになります。このスケールをこう書きます。
#define Scale 60+int[](0,2,4,5,7,9,11,12,14,16,17)
//例えばドなら
int do = (Scale[0]);
//例えばミなら
int mi = (Scale[2]);
//例えばソなら
int so = (Scale[4]);
メジャーコードとかマイナーコードとかあるけど、スケール使っての和音なら,スケールのインデックスをaとした場合
(Scale[a])
(Scale[a+2])
(Scale[a+4])
この組み合わせが和音になります。この仕組みを使います。
Iはa=0
IImはa=1
IIImはa=2
IVはa=3
Vはa=3
VImはa=5
VIIm_5はa=6
でいけます。
これを踏まえた上でサンプルを書きます。コード進行は王道進行(Ⅳ→Ⅴ→Ⅲm→Ⅵm)を使ってみます
#define BPM 120.
#define A (15./BPM)
#define B (240./BPM)
float distortion(float gain, float d)
{
return clamp(gain * d, -1.0, 1.0);
}
float sound(float f, float time)
{
return distortion(sin(6.2831*f*time), 2.5) *exp(-time*3.0);
}
float note2freq(int n)
{
return 440.0*exp2((float(n)-69.0)/12.0);
}
#define Scale 60+int[](0,2,4,5,7,9,11,12,14,16,17)
float chord(int a, float time)
{
return (
sound(note2freq(Scale[a]), time) +
sound(note2freq(Scale[a + 2]), time) +
sound(note2freq(Scale[a + 4]), time)
)/3.0;
}
float sequenceTime(int s,float time)
{
float n =mod(time,A);
for(int i=0;i<16;i++){
if((s>>(int(time/A)-i)%16&1)==1)break;
n+=A;
}
return n;
}
vec2 mainSound( float time)
{
int n = int[](4,5,3,6)[int(time/B)%4]-1;
return vec2(chord(n, sequenceTime(0x0101, time)));
}
この音はshader toyで聞けます。
#ベースについて
ベースラインはコードのルート音を弾くのが基本らしいので、この応用も利きそうです。
#GLSLで音楽の記事
GLSLで音楽(はじめに)
GLSLで音楽(まずは、ドラムだ)
GLSLで音楽(メロディーいってみます)
GLSLで音楽(今までの応用の一つ)