mirror of
https://codeberg.org/uzu/strudel
synced 2026-09-05 14:58:03 -04:00
ableton link mvp
This commit is contained in:
Generated
+137
@@ -11,8 +11,12 @@
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"node-web-audio-api": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitest/ui": "^0.25.7",
|
||||
"abletonlink": "^0.1.3",
|
||||
"c8": "^7.12.0",
|
||||
"canvas": "^2.11.0",
|
||||
"dependency-tree": "^9.0.0",
|
||||
@@ -1822,6 +1826,34 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/cli": {
|
||||
"version": "2.14.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.14.4.tgz",
|
||||
"integrity": "sha512-JvnJWFGhqjDV+D5MD9HCPH7Bc8uxwyPbpA8jsS5mtAp9+3IhVxpqhQc+eqmJrDAPO9z3a8qAdNnBf9+ZI9bIQg==",
|
||||
"bin": {
|
||||
"napi": "scripts/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/triples": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz",
|
||||
"integrity": "sha512-XQr74QaLeMiqhStEhLn1im9EOMnkypp7MZOwQhGzqp2Weu5eQJbpPxWxixxlYRKWPOmJjsk6qYfYH9kq43yc2w=="
|
||||
},
|
||||
"node_modules/@node-rs/helper": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/helper/-/helper-1.3.3.tgz",
|
||||
"integrity": "sha512-p4OdfQObGN9YFy5WZaGwlPYICQSe7xZYyXB0sxREmvj1HzGKp5bPg2PlfgfMZEfnjIA882B9ZrnagYzZihIwjA==",
|
||||
"dependencies": {
|
||||
"@napi-rs/triples": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"license": "MIT",
|
||||
@@ -2611,6 +2643,20 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/abletonlink": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/abletonlink/-/abletonlink-0.1.3.tgz",
|
||||
"integrity": "sha512-rPMS0X6+wcW607Lpr3XeqfMJ26oNDc/Yx6+5oEtkS9CYr2rKRh6dfiaHpDxhoEqKZtBrZY0JWOlkZhD49tesjQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"node-addon-api": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "7.4.1",
|
||||
"license": "MIT",
|
||||
@@ -3028,6 +3074,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"dev": true,
|
||||
@@ -5399,6 +5454,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/filename-reserved-regex": {
|
||||
"version": "2.0.0",
|
||||
"dev": true,
|
||||
@@ -8509,6 +8570,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
|
||||
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
@@ -8699,6 +8766,18 @@
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-web-audio-api": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/node-web-audio-api/-/node-web-audio-api-0.5.0.tgz",
|
||||
"integrity": "sha512-HMFQHti2RnhgAzIrK6PSpDqgwKHMdeWsVILBwEQcCWzol9nGDK+QQQCJPWpMTfvTuGsfEletzRqz+p6fhcjDuA==",
|
||||
"dependencies": {
|
||||
"@napi-rs/cli": "^2.10.0",
|
||||
"@node-rs/helper": "^1.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "4.0.3",
|
||||
"dev": true,
|
||||
@@ -14477,6 +14556,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@napi-rs/cli": {
|
||||
"version": "2.14.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.14.4.tgz",
|
||||
"integrity": "sha512-JvnJWFGhqjDV+D5MD9HCPH7Bc8uxwyPbpA8jsS5mtAp9+3IhVxpqhQc+eqmJrDAPO9z3a8qAdNnBf9+ZI9bIQg=="
|
||||
},
|
||||
"@napi-rs/triples": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz",
|
||||
"integrity": "sha512-XQr74QaLeMiqhStEhLn1im9EOMnkypp7MZOwQhGzqp2Weu5eQJbpPxWxixxlYRKWPOmJjsk6qYfYH9kq43yc2w=="
|
||||
},
|
||||
"@node-rs/helper": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/helper/-/helper-1.3.3.tgz",
|
||||
"integrity": "sha512-p4OdfQObGN9YFy5WZaGwlPYICQSe7xZYyXB0sxREmvj1HzGKp5bPg2PlfgfMZEfnjIA882B9ZrnagYzZihIwjA==",
|
||||
"requires": {
|
||||
"@napi-rs/triples": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"requires": {
|
||||
@@ -15236,6 +15333,16 @@
|
||||
"version": "1.1.1",
|
||||
"dev": true
|
||||
},
|
||||
"abletonlink": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/abletonlink/-/abletonlink-0.1.3.tgz",
|
||||
"integrity": "sha512-rPMS0X6+wcW607Lpr3XeqfMJ26oNDc/Yx6+5oEtkS9CYr2rKRh6dfiaHpDxhoEqKZtBrZY0JWOlkZhD49tesjQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bindings": "^1.5.0",
|
||||
"node-addon-api": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "7.4.1"
|
||||
},
|
||||
@@ -15489,6 +15596,15 @@
|
||||
"version": "2.2.0",
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.1.0",
|
||||
"dev": true,
|
||||
@@ -17074,6 +17190,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true
|
||||
},
|
||||
"filename-reserved-regex": {
|
||||
"version": "2.0.0",
|
||||
"dev": true
|
||||
@@ -19107,6 +19229,12 @@
|
||||
"version": "2.6.2",
|
||||
"dev": true
|
||||
},
|
||||
"node-addon-api": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
|
||||
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
|
||||
"dev": true
|
||||
},
|
||||
"node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"dev": true
|
||||
@@ -19236,6 +19364,15 @@
|
||||
"@babel/parser": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node-web-audio-api": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/node-web-audio-api/-/node-web-audio-api-0.5.0.tgz",
|
||||
"integrity": "sha512-HMFQHti2RnhgAzIrK6PSpDqgwKHMdeWsVILBwEQcCWzol9nGDK+QQQCJPWpMTfvTuGsfEletzRqz+p6fhcjDuA==",
|
||||
"requires": {
|
||||
"@napi-rs/cli": "^2.10.0",
|
||||
"@node-rs/helper": "^1.3.3"
|
||||
}
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.3",
|
||||
"dev": true,
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"homepage": "https://strudel.tidalcycles.org",
|
||||
"devDependencies": {
|
||||
"@vitest/ui": "^0.25.7",
|
||||
"abletonlink": "^0.1.3",
|
||||
"c8": "^7.12.0",
|
||||
"canvas": "^2.11.0",
|
||||
"dependency-tree": "^9.0.0",
|
||||
@@ -61,5 +62,8 @@
|
||||
"prettier": "^2.8.1",
|
||||
"rollup-plugin-visualizer": "^5.8.1",
|
||||
"vitest": "^0.25.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-web-audio-api": "^0.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//// get pattern
|
||||
|
||||
import { evaluate } from '@strudel.cycles/transpiler';
|
||||
import { evalScope, controls, getFrequency } from '@strudel.cycles/core';
|
||||
|
||||
await evalScope(
|
||||
controls,
|
||||
import('@strudel.cycles/core'),
|
||||
import('@strudel.cycles/tonal'),
|
||||
import('@strudel.cycles/mini'),
|
||||
// import('@strudel.cycles/xen'),
|
||||
// import('@strudel.cycles/osc'),
|
||||
);
|
||||
|
||||
const { pattern } = await evaluate(`note("<Dm7 G7 C^7!2>".voicings('lefthand')).gain(.25).s('sawtooth')`);
|
||||
|
||||
//// web audio
|
||||
|
||||
import { AudioContext, OscillatorNode, GainNode } from 'node-web-audio-api';
|
||||
|
||||
const ac = new AudioContext();
|
||||
|
||||
export function playHaps(ac, haps, beat, cps = 1) {
|
||||
const ct = ac.currentTime;
|
||||
haps
|
||||
.filter((hap) => hap.hasOnset())
|
||||
.forEach((hap) => {
|
||||
const deadline = (hap.whole.begin - beat) / cps;
|
||||
const t = ct + deadline;
|
||||
const freq = getFrequency(hap) ?? 220;
|
||||
const { gain = 1, s = 'triangle' } = hap.value;
|
||||
|
||||
const env = new GainNode(ac);
|
||||
env.connect(ac.destination);
|
||||
env.gain.value = 0;
|
||||
env.gain.setValueAtTime(0, t);
|
||||
env.gain.linearRampToValueAtTime(gain, t + 0.02);
|
||||
env.gain.exponentialRampToValueAtTime(0.0001, t + hap.duration);
|
||||
|
||||
const osc = new OscillatorNode(ac);
|
||||
osc.frequency.value = freq;
|
||||
osc.type = s;
|
||||
osc.connect(env);
|
||||
osc.start(t);
|
||||
osc.stop(t + hap.duration);
|
||||
});
|
||||
}
|
||||
|
||||
//// link
|
||||
|
||||
import abletonlink from 'abletonlink';
|
||||
const link = new abletonlink();
|
||||
|
||||
let lastBeat;
|
||||
link.startUpdate(60, (beat, phase, bpm) => {
|
||||
if (lastBeat !== undefined) {
|
||||
const cps = bpm / 60;
|
||||
const haps = pattern.slow(2).queryArc(lastBeat, beat);
|
||||
playHaps(ac, haps, lastBeat, cps);
|
||||
}
|
||||
lastBeat = beat;
|
||||
});
|
||||
Reference in New Issue
Block a user