FaustをWasmにコンパイルしてp5.jsから使う

Faustで作ったサウンドをp5.jsから使う方法のメモ

GitHub Repository

Sample page

Faustに関する説明はこちらがわかりやすかったです。

https://matsuuratomoya.com/blog/2016-12-01/faust_introduction/

FaustをWasmビルドする

公式サンプルの gameaudio > bubble.dsp を使います。 グラフィック的にbubbleというよりはdropなので、 ファイル名は drop.dsp としました。

import("stdfaust.lib");


bubble(f0,trig) = os.osc(f) * (exp(-damp*time) : si.smooth(0.99))
	with {
		damp = 0.043*f0 + 0.0014*f0^(3/2);
		f = f0*(1+sigma*time);
		sigma = eta * damp;
		eta = 0.075;
		time = 0 : (select2(trig>trig'):+(1)) ~ _ : ba.samp2sec;
	};

process = button("drop") : bubble(hslider("v:freq", 600, 150, 2000, 1)) <: dm.freeverb_demo;

ローカルでビルドするなら faust2wasm でビルドできます。 macOSならHomebrewから brew install faust でインストールできます。 ビルドコマンドはこちらです。 ビルドすると drop.wasm drop.js が出力されます。

faust2wasm drop.dsp

p5.jsのコード

Wasmを扱うためのJSのコードは、先ほど出力した drop.js に含まれています。 以下のように ScriptProcessorNode に設定できるパラメータを確認することができます。

drop.createDSP(audioContext, 1024)
    .then(node => {
        dropNode = node;
        dropNode.connect(audioContext.destination);
        console.log('params: ', dropNode.getParams());
    });

例えば、鳴らす音の周波数を変更するなら /drop/freq/0x00 を設定します。 dropNode.setParamValue('/drop/freq/0x00', 440) と呼び出すことで440Hzに設定されます。

こちらが出力結果のWasmをp5.jsから使うためのHTMLとJSです。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>p5.js faust example</title>
    <script src="https://cdn.jsdelivr.net/npm/p5@1.9.0/lib/p5.js"></script>
    <script src="drop.js"></script>
    <script src="sketch.js"></script>
</head>
<body>
</body>
</html>
class Drop {
    constructor(pos) {
        this.pos = pos;
        this.rad = 0;
        this.life = 255;
    }

    update() {
        this.rad++;
        this.life -= 3;
    }

    draw() {
        push();
        stroke(255, this.life);
        noFill();
        circle(this.pos.x, this.pos.y, this.rad * 2);
        pop();
    }
}


const audioContext = new AudioContext();
let dropNode = null;
let drops = [];


function setup() {
    createCanvas(600, 600);
    drop.createDSP(audioContext, 1024)
        .then(node => {
            dropNode = node;
            dropNode.connect(audioContext.destination);
            console.log('params: ', dropNode.getParams());
        });
}

function draw() {
    background(0);

    for (const drop of drops) {
        drop.update();
        drop.draw();
    }
    drops = drops.filter(b => b.life > 0);
}

function mousePressed() {
    if (!dropNode) {
        return;
    }
    if (audioContext.state === 'suspended') {
        audioContext.resume();
    }
    dropNode.setParamValue('/drop/drop', 1.0);
    // dropNode.setParamValue('/drop/Freeverb/Wet', random());
    // dropNode.setParamValue('/drop/Freeverb/0x00/Damp', random());
    // dropNode.setParamValue('/drop/Freeverb/0x00/RoomSize', random());
    // dropNode.setParamValue('/drop/Freeverb/0x00/Stereo_Spread', random());
    dropNode.setParamValue('/drop/freq/0x00', random(440, 880));
    drops.push(new Drop(createVector(mouseX, mouseY)));
}

function mouseReleased() {
    if (!dropNode) {
        return;
    }
    dropNode.setParamValue('/drop/drop', 0.0);
}

FaustをWasmにコンパイルしてp5.jsから使う方法

By Katsuya Endoh, 2024-01-11