<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>test</title>
    <script src="https://unpkg.com/tone@14.7.77/build/Tone.js"></script>
</head>
<body>
<button onclick="play()">再生</button>
</body>
</html>
let g_sampler;
let g_seed;
let g_random;

class Random {
    constructor(seed = 19681106) {
      this.x = 31415926535;
      this.y = 8979323846;
      this.z = 2643383279;
      this.w = seed;
    }
    
    // XorShift
    next() {
      let t;
   
      t = this.x ^ (this.x << 11);
      this.x = this.y; this.y = this.z; this.z = this.w;
      return this.w = (this.w ^ (this.w >>> 19)) ^ (t ^ (t >>> 8)); 
    }
    
    // min以上max以下の乱数を生成する
    nextInt(min, max) {
      const r = Math.abs(this.next());
      return min + (r % (max + 1 - min));
    }

    // nパーセントの確率でtrueを返す
    isNtrue(n){
        let t = this.nextInt(1,100);
        if(t <= n){
            return true;
        }else{
            return false;
        }
    }
}

//ページを読み込んだ際にしておくべき処理。
const init = () => {

    const sampler = new Tone.Sampler({
        urls: {
            "C4": "C4.mp3",
            "D#4": "Ds4.mp3",
            "F#4": "Fs4.mp3",
            "A4": "A4.mp3",
        },
        baseUrl: "https://tonejs.github.io/audio/salamander/",
    }).toDestination();

    Tone.loaded().then(() => {
        g_sampler = sampler;
    })

}

//パターンを生成する
const createPattern = (chord1, chord2) => {
    //最小の長さを32分音符とする。
    //1パターン2小節とし、1小節に32部音符が32個入るから×2して64
    const maxLength = 64;
    let availableLength = maxLength;

    let pattern = [];
    
    //まず、全音符、2分音符、4分音符で作成
    while(availableLength > 0){
        let s_crd;
        if(availableLength > availableLength / 2){
            s_crd = chord1;
        }else{
            s_crd = chord2;
        }

        let t = g_random.nextInt(0,100);
        if(t<60 && availableLength >= 8){
            pattern.push({note: selectNote(s_crd),pitch: 3, time: "4n", length: 8});
            availableLength -= 8;
        }else if(t<80 && availableLength >= 16){
            pattern.push({note: selectNote(s_crd),pitch: 3, time: "2n", length: 16});
            availableLength -= 16;
        }else if(t<100 && availableLength >= 32){
            pattern.push({note: selectNote(s_crd),pitch: 3, time: "1n", length: 32});
            availableLength -= 32;
        }
    }

    pattern.forEach((note)=>{
        if(g_random.isNtrue(50)){

        }

    });

    return pattern;

}

//コードの構成音から一つをランダムに選択する
const selectNote = (chord) => {
    let t = g_random.nextInt(0,chord.length-1);
    return chord[t];
}

const play = () => {
    let nowTime = Tone.now();
    let offset = nowTime;

    // 乱数生成用インスタンス
    let dt = new Date();
    g_seed = dt.getTime();
    console.log(g_seed);

    let pattern = [];

    g_random = new Random( g_seed );

    let chord1 = ["Bb","Db","F"];
    let chord2 = ["Bb","Eb","G"];
    let t_pattern1 = createPattern(chord1, chord2);
    chord1 = ["Ab","Eb","F"];
    chord2 = ["Bb","Db","F"];
    let t_pattern2 = createPattern(chord1, chord2);

    g_random = new Random( g_seed + 5 );

    chord1 = ["Bb","Db","F"];
    chord2 = ["Bb","Eb","G"];
    let t_pattern3 = createPattern(chord1, chord2);
    chord1 = ["Ab","Eb","F"];
    chord2 = ["Bb","Db","F"];
    let t_pattern4 = createPattern(chord1, chord2);

    pattern = [...t_pattern1, ...t_pattern2,...t_pattern1, ...t_pattern2,...t_pattern3, ...t_pattern4,...t_pattern1, ...t_pattern2];

    console.log(pattern);

    for(let i=0; i<pattern.length; ++i){
        let n = pattern[i];
        let startTime = offset;
        
        g_sampler.triggerAttackRelease(n["note"] + n["pitch"], n["time"], startTime);

        offset = startTime + Tone.Time(n["time"]).toSeconds();
    }
    
}

window.onload = init();

Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.