LoginSignup
2
1

More than 3 years have passed since last update.

GLSLで音楽(メロディーいってみます)

Last updated at Posted at 2018-06-27

メロディーのシーケンス

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

#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で聞けます。

note2freq()関数の説明

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

sequenceOrder()関数について

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

今回のメロディーのデータについて

メロディーのデータ部分は

    int i = int[](1672,10,2842,156,0,0,7152192,10
        )[b]>>(o*3)&7;

これです。
どういう事かというと以下のscriptをintに書き換えたもの。

    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()の2つで用は足りそうです。あとは応用かな。

おまけ

スケールをGipsyScaleにしても面白い。

#define Scale C3+int[](0,1,4,5,7,9,10)

追記

データをshaderの中で作るようにしました。2019/12/10
_Melody sequence

#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で音楽(はじめに)
GLSLで音楽(まずは、ドラムだ)
GLSLで音楽(和音を使ってみる)
GLSLで音楽(今までの応用の一つ)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1