テラByteの時代にキロByte

shader又はdemosceneに関係する事

ChucKにmusic shaderを移植

ChucKにmusic shaderを移植してみた。 まだ覚え始めなので、怪しいところもあると思います。
今回使ってるadsrの関数には、バグがあるので鵜呑みにしないでください。ここでは正常に動いているけど、違うパターンでダメな時がありました。そのうち直します。

元のmusic shaderはこれ。

www.shadertoy.com

#define BPM 140.
#define A (15./BPM)

float adsr(float t, vec4 e, float s)
{  
    return max(0.0,
        min(1.0, t/max(0.0001, e.x)) 
        - min((1.0 - s) ,max(0.0, t - e.x)*(1.0 - s)/max(0.0001, e.y))
        - max(0.0, t - e.z)*s/max(0.0001, e.w));
}

float square(float f)
{
    return sign(fract(f)-0.5);
}

float kick(float t){
    return cos(315.0 * t - 10. * exp( -50. * t )+0.3)*adsr(t,vec4(0.0, 0.3, 0.0, 0.0), 0.0);
            +0.2*square(50.*t)* adsr(t,vec4(0.0, 0.05, 0.0, 0.0), 0.0);
}

float snare(float t)
{
    return square(3063.0*t*sin(t*8000.0)) * adsr(t,vec4(0.005, 0.08, 0.0, 0.0), 0.0);
}

float closeHihat(float t)
{
    return square(2763.0*t*sin(t*8500.0)) * adsr(t,vec4(0.0, 0.03, 0.0, 0.0), 0.0);
}

float openHihat(float t)
{
    return square(2763.0*t*sin(t*8300.0)) * adsr(t,vec4(0.0, 0.05, 0.03, 0.03), 0.5);
}

float sequence(int s,float t)
{
  float n =mod(t,A);
  for(int i=0;i<16;i++){
    if((s>>(int(t/A)-i)%16&1)==1)break;
    n+=A;
  }
  return n;
}

vec2 mainSound( float time )
{
    int i = int(floor(time/(A*16.)))&3;
    int velocity = int[](0x3030,0x3030,0x3030,0x3030)[i]>>(int(floor(time/A))&15)&1;
    float vol = 0.2 *(1.0+1.5*float(velocity));
    return vec2(
        0.0
        + 0.3 * kick(sequence(      int[](0x0c05,0x0c05,0x0c05,0x0c0c)[i],time))
        + 0.3 * snare(sequence(     int[](0x9290,0x9290,0x4290,0x4292)[i],time))
        + vol * closeHihat(sequence(int[](0x5555,0x5555,0x5555,0x5155)[i],time))
        + vol * openHihat(sequence( int[](0x0000,0x0000,0x0000,0x0400)[i],time))
    );
}

Chuckでサンプリング音源を使った奴。

140 => float bpm;
1::second * 15 / bpm=> dur tick;

fun void kick(){
    SndBuf buf => Gain g => dac;
    .25 => g.gain;
    me.dir() + "data/kick.wav" => buf.read;
    [0x0c05,0x0c05,0x0c05,0x0c0c]@=> int seq[];
    0 => int bar;
    while( true ){
        for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => buf.pos;}
            1::tick => now;    
        }
        bar++;
    }
}

fun void snare(){
    SndBuf buf => Gain g => dac;
    .4 => g.gain;
    me.dir() + "data/snare.wav" => buf.read;
    [0x9290,0x9290,0x4290,0x4292]@=> int seq[];
    0 => int bar;
    while( true ){
       for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => buf.pos;}
            1::tick => now;    
        }
        bar++;
    }
}

fun void hihat(){
    SndBuf buf => Gain g => dac;
    .25 => g.gain;
    0 => int bar;
    [0x5555,0x5555,0x5555,0x5155]@=> int seq[];
    me.dir() + "data/hihat.wav" => buf.read;
    while( true ){
        for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => buf.pos;}
            1::tick => now;    
        }
        <<<"bar",bar>>>;
        bar++;
    }
}

fun void openHihat(){
    SndBuf buf => Gain g => dac;
    .25 => g.gain;
    0 => int bar;
    [0x0000,0x0000,0x0000,0x0400]@=> int seq[];
    me.dir() + "data/hihat-open.wav" => buf.read;
    while( true ){
        for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => buf.pos;}
            1::tick => now;    
        }
        bar++;
    }
}

spork ~ kick();
spork ~ snare();
spork ~ hihat();
spork ~ openHihat();
3::minute=> now;    

ChucKで音源をmusic shaderに合わせた奴。

音源のclassをつくるのに参考にしたページ

ChucK : [Extend]

140 => float bpm;
1::second * 15 / bpm=> dur tick;

fun float square(float f)
{
    return (Math.floor(Math.sin(f))+0.5)*2.0;
}

fun float adsr(float t, float a, float d, float s, float r, float gt)
{  
    return Math.max(0.0,
        Math.min(1.0, t/Math.max(0.0001, a)) 
        - Math.min((1.0 - gt) ,Math.max(0.0, t - a)*(1.0 - gt)/Math.max(0.0001, d))
        - Math.max(0.0, t - s)*gt/Math.max(0.0001,r));
}

class MyKick extends Chugen
{
    100 => float time;
    samp/second => float dt;
    fun float tick(float in)
    {
        Math.cos(315*time-10*Math.exp(-50*time)+0.3)*adsr(time,0,0.3,0,0,0) => float g;
        time+dt=>time;
        return g;
    }
}

class MySnare extends Chugen
{
    100 => float time;
    samp/second => float dt;
    fun float tick(float in)
    {
        square(3063.0*time*Math.sin(time*8000.0))*adsr(time,0.005,0.08,0,0,0) => float g;
        time+dt=>time;
        return g;
    }
}

class MyCloseHihat extends Chugen
{
    100 => float time;
    samp/second => float dt;
    fun float tick(float in)
    {
        square(3063.0*time*Math.sin(time*8000.0)) * adsr(time,0.005,0.08,0,0,0) => float g;
        time+dt=>time;
        return g;
    }
}

class MyOpenHihat extends Chugen
{
    100 => float time;
    samp/second => float dt;
    fun float tick(float in)
    {
        square(2763*time*Math.sin(time*8500)) * adsr(time,0.0,0.05,0.03,0.03,0.5) => float g;
        time+dt=>time;
        return g;
    }
}

fun void kick(){
    MyKick o => Gain g => dac;
    0.3 => g.gain;
    [0x0c05,0x0c05,0x0c05,0x0c0c]@=> int seq[];
    0 => int bar;
    while( true ){
        for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0=>o.time;}
            1::tick => now;    
        }
        bar++;
    }
}

fun void snare(){
    MySnare o => Gain g => dac;
    0.2 => g.gain;
    [0x9290,0x9290,0x4290,0x4292]@=> int seq[];
    0 => int bar;
    while( true ){
       for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => o.time;}
            1::tick => now;    
        }
        bar++;
    }
}

fun void closeHihat(){
    MyCloseHihat o => Gain g => dac;
    0.2 => g.gain;
    0 => int bar;
    [0x5555,0x5555,0x5555,0x5155]@=> int seq[];   
    [0x3030,0x3030,0x3030,0x3030]@=> int vel[];
    
    while( true ){
        for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => o.time;}
            if (vel[bar%4]>>i&1==1){0.3 => g.gain;}else{0.2 => g.gain;}
            1::tick => now;    
        }
        bar++;
    }
}

fun void openHihat(){
    MyOpenHihat o => Gain g => dac;
    0.2 => g.gain;
    0 => int bar;
    [0x0000,0x0000,0x0000,0x0400]@=> int seq[];
    [0x3030,0x3030,0x3030,0x3030]@=> int vel[];
    while( true ){
        for(int i; i < 16; i++)
        {
            if (seq[bar%4]>>i&1==1){0 => o.time;}
            if (vel[bar%4]>>i&1==1){0.3 => g.gain;}else{0.2 => g.gain;}
            1::tick => now;    
        }
        bar++;
    }
}

spork ~ kick();
spork ~ snare();
spork ~ closeHihat();
spork ~ openHihat();
3::minute=> now;    

ここで使っているシーケンスについての説明は

qiita.com

ここにあります。

メモ