GLSLで音楽（メロディーいってみます）

#メロディーのシーケンス
ドラムのシーケンスは、1小節しか、しなかった。メロディーじゃ足りなさすぎるのを、カバーする為に配列登場です。それと、ノート番号の配列を使うと大きくなりがちなので、スケールの配列を使ってます。
サンプルのshaderを書きました。

```glsl
#define BPM 120.
#define A (15./BPM)
#define B (240./BPM)

#define C3  60
#define Scale C3+int[](0,2,4,5,7,9,11)

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);
}

int sequenceOrder(int s,float time)
{
    int n =-1;
    for(int i=0;i<=int(mod(time,B)/A);i++){
        if((s>>i&1)==1)n++;
    }
	return n;
}

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 b = int(time/B)%8;
    int s = int[](0x1111, 0x0111, 0x0101, 0x5555)[
        		int[](0,1,0,1,2,2,3,1)[b]
        	];
    int o = sequenceOrder(s,time);
    int i = int[](1672,10,2842,156,0,0,7152192,10)[b]>>(o*3)&7;
    int n = Scale[i];
    float t = sequenceTime(s,time);
    return vec2(sound(note2freq(n),t));
}
```
この音は[shader toy](https://www.shadertoy.com/view/MsKfzd)で聞けます。

#note2freq()関数の説明
ノート番号を周波数に変える関数です。シーケンスはノート番号で管理して、音源の関数に周波数を送ります。

# sequenceOrder()関数について
何回目のノートオンかを返します。配列にメロディーのノート番号を仕込んでおいて、この返り値でノート番号を引き出します。

#今回のメロディーのデータについて
メロディーのデータ部分は

```glsl
    int i = int[](1672,10,2842,156,0,0,7152192,10
    	)[b]>>(o*3)&7;
```
これです。
どういう事かというと以下のscriptをintに書き換えたもの。

```glsl
    int i = int[](
            (0<<0)+(1<<3)+(2<<6)+(3<<9),
            (2<<0)+(1<<3)+(0<<6),
            (2<<0)+(3<<3)+(4<<6)+(5<<9),
            (4<<0)+(3<<3)+(2<<6),
            (0<<0)+(0<<3),
            (0<<0)+(0<<3),
            (0<<0)+(0<<3)+(1<<6)+(1<<9)+(2<<12)+(2<<15)+(3<<18)+(3<<21),
            (2<<0)+(1<<3)+(0<<6)
    	)[b]>>(o*3)&7;
```
これはスケールのインデックスを3bitづつ使ってメロディーをデータさせたもの。

```
>>(o*3)&7
```
この部分はデータを3bitづつ取り出す為の処理。マスクをかけるとか言うと思った。



# 使い方のアイディア
オーソドックスに配列に仕込んでおいて使うのも良いけど、乱数と、スケールを使ってのランダムメロディー。まだ試せてないけど、ピンクノイズを使う方法もありそう。

#シーケンスの関数
シーケンスは、sequenceOrder(),sequenceTime()の２つで用は足りそうです。あとは応用かな。

#おまけ
スケールをGipsyScaleにしても面白い。

```
#define Scale C3+int[](0,1,4,5,7,9,10)
```
#追記
データをshaderの中で作るようにしました。2019/12/10
[_Melody sequence](https://www.shadertoy.com/view/wtc3R7)

```glsl
#define BPM 60.
#define A (15./BPM)
#define B (240./BPM)
 
#define C3  60
  
 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);
 }
 
 int major(int n)
 {
     return n/7*12+int[](0,2,4,5,7,9,11)[n%7];
 }
 
 int sequenceOrder(int s,float time)
 {
     int n =-1;
     for(int i=0;i<=int(mod(time,B)/A);i++){
         if((s>>i&1)==1)n++;
     }
     return n;
 }
 
 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;
 }

 #define _ -1
 #define Melody2Int(r,m,a)r=0;m=0;{int s=0;for(int i=0;i<16;i++){if(-1<a[i]){r+=1<<i;m+=a[i]<<s;s+=4;}}}
 
 vec2 mainSound( float time )
 {
     // 使える数字は、0~15 で、1小節に8個まで。
     int[8] r_score, m_score;
     Melody2Int( r_score[0], m_score[0], int[]( 0,_,1,_,2,_,_,_,0,_,1,_,2,_,_,_ ))
     Melody2Int( r_score[1], m_score[1], int[]( 0,_,1,_,2,_,3,_,4,_,5,_,6,_,7,_ ))
     Melody2Int( r_score[2], m_score[2], int[]( 0,_,1,_,2,_,_,_,0,_,1,_,2,_,_,_ ))
     Melody2Int( r_score[3], m_score[3], int[]( 0,_,1,_,2,_,3,_,4,_,5,_,6,_,7,_ ))
     Melody2Int( r_score[4], m_score[4], int[]( 0,_,1,_,2,_,_,_,0,_,1,_,2,_,_,_ ))
     Melody2Int( r_score[5], m_score[5], int[]( 0,_,1,_,2,_,3,_,4,_,5,_,6,_,7,_ ))
     Melody2Int( r_score[6], m_score[6], int[]( 0,_,1,_,2,_,_,_,0,_,1,_,2,_,_,_ ))
     Melody2Int( r_score[7], m_score[7], int[]( 0,_,1,_,2,_,3,_,4,_,5,_,6,_,7,_ ))
     int b = int(time/B)%2;
     int r = r_score[b];
     int o = sequenceOrder(r,time);
     int i = m_score[b]>>(o*4)&0xF;
     int n = C3+major(i);
     float t = sequenceTime(r,time);
     return vec2(sound(note2freq(n),t));
 }

```

#GLSLで音楽の記事
[GLSLで音楽（はじめに）](https://qiita.com/gaziya5/items/e5d058c20bc75c72b5a2)
[GLSLで音楽（まずは、ドラムだ）](https://qiita.com/gaziya5/items/e58f8c1fce3f3f227ca7)
[GLSLで音楽（和音を使ってみる）](https://qiita.com/gaziya5/items/0a3ef4b96a6d173f0895)
[GLSLで音楽（今までの応用の一つ）](https://qiita.com/gaziya5/items/27ba6dedfc3028782f2f)