Skip to content

Instantly share code, notes, and snippets.

@mohayonao
Created June 9, 2017 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohayonao/a0df107f4d0dac252077748253deb0c9 to your computer and use it in GitHub Desktop.
Save mohayonao/a0df107f4d0dac252077748253deb0c9 to your computer and use it in GitHub Desktop.

sc-dump

SuperColliderのOSCメッセージのやり取りを表示する.

Installation

  1. Node.js v6 以上が必要です
  2. 適当なフォルダに sc-dump.jspackage.json を置く
  3. npm install で依存パッケージをインストールする

Usage

  1. scsynth を起動する scsynth -u 57115
  2. sc-dump を起動する node sc-dump.js
  3. SuperColliderを起動する
  4. (謎) s.reboot を何回かする
  • エラーになる時とならない時がある
  • リブート後 { SinOsc.ar }.play などで音が出ていればOK

Issues

  1. status.reply の結果がIDE下部に反映されない
{
"dependencies": {
"colors": "^1.1.2",
"osc-msg": "^1.1.1",
"synthdef-json-decoder": "^1.0.2"
}
}
"use strict";
const dgram = require("dgram");
const oscmsg = require("osc-msg");
const colors = require("colors");
const sdefDecoder = require("synthdef-json-decoder");
const LANG_PORT = 57120;
const MY_PORT = 57110;
const SYNTH_PORT = 57115;
const langSocket = dgram.createSocket("udp4");
const synthSocket = dgram.createSocket("udp4");
const DONE_QUIT = oscmsg.encode({address: "/done", args:[ "/quit" ]});
const SCCommandIndex = `
none notify status quit cmd d_recv d_load d_loadDir d_freeAll s_new n_trace
n_free n_run n_cmd n_map n_set n_setn n_fill n_before n_after u_cmd g_new g_head
g_tail g_freeAll c_set c_setn c_fill b_alloc b_allocRead b_read b_write b_free
b_close b_zero b_set b_setn b_fill b_gen dumpOSC c_get c_getn b_get b_getn s_get
s_getn n_query b_query n_mapn s_noid g_deepFree clearSched sync d_free
b_allocReadChannel b_readChannel g_dumpTree g_queryTree error s_newargs n_mapa
n_mapan n_order
`.trim().split(/\s+/).map(x => "/" + x);
const UnaryOpUGenIndex = `
neg not isNil notNil bitNot abs asFloat asInt ceil floor frac sign squared cubed sqrt exp reciprocal
midicps cpsmidi midiratio ratiomidi dbamp ampdb octcps cpsoct log log2 log10 sin cos tan asin acos
atan sinh cosh tanh rand rand2 linrand bilinrand sum3rand distort softclip coin digitvalue silence
thru rectWindow hanWindow welWindow triWindow ramp scurve
`.trim().split(/\s+/);
const BinaryOpUGenIndex = `
+ - * / // % == != < > <= >= min max bitAnd bitOr bitXor lcm gcd round roundUp trunc atan2 hypot
hypotApx pow << >> >>> fill ring1 ring2 ring3 ring4 difsqr sumsqr
sqrsum sqrdif absdif thresh amclip scaleneg clip2 excess fold2 wrap2 firstarg rrand exprand
`.trim().split(/\s+/);
let sdef = null
langSocket.bind(MY_PORT);
langSocket.on("message", (buffer) => {
sdef = null
const msg = fmtOSC(oscmsg.decode(buffer));
if (msg.error) {
console.log(colors.red(msg.error));
console.log(colors.gray(JSON.stringify(Array.from(buffer))));
}
if (msg.address === "/quit") {
return langSocket.send(DONE_QUIT, LANG_PORT, "127.0.0.1");
}
if (msg.address !== "/status") {
console.log(colors.cyan(`>> ${ JSON.stringify(msg) }`));
if (sdef !== null) {
console.log(sdef);
}
}
synthSocket.send(buffer, SYNTH_PORT, "127.0.0.1");
});
synthSocket.on("message", (buffer) => {
const msg = fmtOSC(oscmsg.decode(buffer));
if (msg.error) {
console.log(colors.red(msg.error));
console.log(colors.gray(JSON.stringify(Array.from(buffer))));
}
if (msg.address !== "/status.reply") {
console.log(colors.yellow(`<< ${ JSON.stringify(msg) }`));
}
langSocket.send(buffer, LANG_PORT, "127.0.0.1");
});
function fmtOSC(msg) {
if (msg.oscType === "bundle") {
msg.elements = msg.elements.map(fmtOSC);
} else {
msg.address = SCCommandIndex[msg.address] || msg.address;
msg.args = msg.args.map(value => value.value);
if (msg.address === "/d_recv") {
sdef = fmtSDef(sdefDecoder.decode(msg.args[0]));
msg.args[0] = `<SDEF ${ msg.args[0].length }bytes>`;
}
if (msg.args[msg.args.length - 1] instanceof Buffer) {
msg.args[msg.args.length - 1] = fmtOSC(oscmsg.decode(msg.args[msg.args.length - 1]));
}
}
delete msg.oscType;
return msg;
}
function fmtSDef(sdefs) {
const lines = [];
sdefs.forEach((sdef) => {
const args = new Array(sdef.paramIndices.length);
const refs = new Array(sdef.paramValues.length);
const unitNames = [];
sdef.paramIndices.forEach(({ name, index, length }, i) => {
if (length === 1) {
args[i] = `${ name }=${ sdef.paramValues[index] }`;
refs[index] = name;
} else {
const vals = sdef.paramValues.slice(index, index + length);
args[i] = `${ name }=#${ JSON.stringify(vals) }`;
for (let i = 0; i < length; i++) {
refs[index + i] = `${ name }[${ i }]`;
}
}
});
lines.push(sdef.name);
lines.push(`arg ${ args.join(", ")};`)
const align = (i) => {
const len = Math.floor(Math.log10(sdef.units.length) + 1);
return (" ".repeat(len) + i).slice(-len);
};
sdef.units.forEach((unit, i) => {
if (/\b(|Audio|Trig)Control\b/.test(unit[0])) {
return;
}
const unitInputs = unit[3].map(([ nodeid, index ]) => {
if (nodeid === -1) {
return sdef.consts[index];
}
if (/\b(|Audio|Trig)Control\b/.test(sdef.units[nodeid][0])) {
return refs[sdef.units[nodeid][2] + index];
}
if (sdef.units[nodeid][4].length >= 2) {
return `(${ nodeid }: ${ unitNames[nodeid] }[${ index }])`;
}
return `(${ nodeid }: ${ unitNames[nodeid] })`;
});
if (unit[0] === "UnaryOpUGen") {
unitNames[i] = UnaryOpUGenIndex[unit[2]];
lines.push(` ${ align(i) }: ${ unitInputs[0] }.${ UnaryOpUGenIndex[unit[2]] }`);
} else if (unit[0] === "BinaryOpUGen") {
unitNames[i] = BinaryOpUGenIndex[unit[2]];
lines.push(` ${ align(i) }: (${ unitInputs[0] } ${ BinaryOpUGenIndex[unit[2]] } ${ unitInputs[1] })`);
} else {
unitNames[i] = `${ unit[0] }.${ toRate(unit[1]) }`;
lines.push(` ${ align(i) }: ${ unit[0] }.${ toRate(unit[1]) }(${ unitInputs.join(", ") })`);
}
});
lines.push(" ");
});
return lines.join("\n").trim();
}
function toRate(rate) {
return [ "ir", "kr", "ar", "dr" ][rate];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment