Max8の新機能RNBOのWeb出力を試したときの備忘録です
まず
Maxで音が鳴るRnboを使ったパッチを作る。
パッチ内容
これは、frequencyとvolumeで
サイン波形が鳴るパッチ
と
パラメータ drum というのに0.00 1.00の値を入れることで
ドラムの音が鳴るパッチになります。
wavファイルはパッチと同じところに置いておきます。
export時にCopy Sample Dependencesを入れておくとmediaフォルダに波形がコピーされます。
Cyclingのrnbo.exampleで動かす
https://github.com/Cycling74/rnbo.example.webpage
このページにあるものを動かしてみます。
これをクローンしてきて、
このexportフォルダにMaxで出力したファイルをコピーします
Webサーバーを起動する
コマンドラインから
npx http-server
を実行してサーバーをうごかします。
ブラウザで
URLに
http://10.16.191.211:8080
を入れて実行すると
スライダーのdrumを動かすと音がします
キャッシュ無効にしておく
作成中キャッシュが残っていると更新されないので
ブラウザでF12キーを押してNetworkにある
Disable cacheをチェックしておく
P5JSで音を鳴らしてみる
index.htmlを以下のように書き換える
<html>
<head>
</head>
<body>
<script type="text/javascript" src="js/guardrails.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>
<script src="sketch.js"></script>
</body>
</html>
index.htmlと同じ階層に
sketch.jsを用意し
以下のようなコードを書く
function loadRNBOScript(version) {
return new Promise((resolve, reject) => {
if (/^\d+\.\d+\.\d+-dev$/.test(version)) {
throw new Error("Patcher exported with a Debug Version!\nPlease specify the correct RNBO version to use in the code.");
}
const el = document.createElement("script");
el.src = "https://c74-public.nyc3.digitaloceanspaces.com/rnbo/" + encodeURIComponent(version) + "/rnbo.min.js";
el.onload = resolve;
el.onerror = function(err) {
console.log(err);
reject(new Error("Failed to load rnbo.js v" + version));
};
document.body.append(el);
});
}
let frequency = null;
let volume = null;
let drum = null;
async function setuptat() {
// Create AudioContext
const WAContext = window.AudioContext || window.webkitAudioContext;
const context = new WAContext();
// Create gain node and connect it to audio output
const outputNode = context.createGain();
outputNode.connect(context.destination);
const patchExportURL = "export/patch.export.json";
response = await fetch(patchExportURL);
patcher = await response.json();
if (!window.RNBO) {
// Load RNBO script dynamically
// Note that you can skip this by knowing the RNBO version of your patch
// beforehand and just include it using a <script> tag
await loadRNBOScript(patcher.desc.meta.rnboversion);
}
rawPatcher = await fetch("export/patch.export.json");
patcher = await rawPatcher.json();
device = await RNBO.createDevice({ context, patcher });
frequency = device.parametersById.get("frequency");
volume = device.parametersById.get("volume");
drum = device.parametersById.get("drum");
// (Optional) Fetch the dependencies
let dependencies = [];
try {
const dependenciesResponse = await fetch("export/dependencies.json");
dependencies = await dependenciesResponse.json();
// Prepend "export" to any file dependenciies
dependencies = dependencies.map(d => d.file ? Object.assign({}, d, { file: "export/" + d.file }) : d);
} catch (e) {}
// (Optional) Load the samples
if (dependencies.length)
await device.loadDataBufferDependencies(dependencies);
// Connect the device to the web audio graph
device.node.connect(outputNode);
}
function setup(){
//キャンバスを作成
createCanvas(600,425);
//背景色
background(0);
//オブジェクトの色
fill(0,255,0);
//キャンバスの中心に直径100pxの丸を描画
//ellipse(width/2,height/2,100);0
fill(0,255,0);
}
class Robot {
constructor( inX, inY, inDx, inDy)
{
this.x = inX;
this.y = inY;
this.dx = inDx;
this.dy = inDy;
}
update()
{
this.x = this.x+this.dx;
this.y = this.y+this.dy;
if (this.x < 0 || this.x > width){
this.dx = -this.dx;
}
if (this.y < 0 || this.y > height){
this.dy = -this.dy;
}
ellipse(this.x, this.y, 80, 80);
if(frequency != null)
{
frequency.value = 220+this.x;
volume.value = 0.5 + (height-this.y)/height*0.5;
drum.value = robot.x/width;
//print(drum.value);
}
}
}
let robot = new Robot(100,100,10,10);
var t = 0;
function draw() {
if (isUserStarted) {
background(0);
t+=5;
// t = t%50;
// ellipse(mouseX+t, mouseY, 80, 80);
//
// if(frequency != null)
// {
// frequency.value = 220+mouseX+t;
// volume.value = (height-mouseY)/height;
// }
if(robot != null){
robot.update();
}
}
}
var isUserStarted = false;
function touchStarted() {
if (!isUserStarted) {
// touchStarted()を1回だけ呼び出されるようにする
print('touch');
setuptat();
isUserStarted = true;
}
}
function mouseClicked() {
robot.x = mouseX;
robot.y = mouseY;
robot.dx = mouseX;
robot.dy = mouseY;
}
やっていることは、WebAudioの初期化と接続
RNBOのexport.json読み込み
frequency,volume,drumのパラメータ関連付け
dependenciesからbuffer読み込み
を初回タッチした時にしています。
こんな感じに動きます
(Cycleを鳴らす場合は多少修正必要)
追記メモ:
音声入力とかを試したい場合、Chromeとかだとhttpの場合localhost:8080とかでないとマイクデバイスがブロック解除できないかも