mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-30 00:06:59 -04:00
add node-web-audio-api variant
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { createClock, evalScope } from '@strudel/core';
|
||||
import { evaluate } from '@strudel/transpiler';
|
||||
import watch from 'node-watch';
|
||||
import fs from 'node:fs/promises';
|
||||
import { AudioContext, OscillatorNode, GainNode } from 'node-web-audio-api';
|
||||
|
||||
const audioContext = new AudioContext();
|
||||
|
||||
let file = 'pattern.mjs';
|
||||
let pattern;
|
||||
async function evaluateFile() {
|
||||
try {
|
||||
console.log('// file evaluated:');
|
||||
const code = await fs.readFile(file, { encoding: 'utf8' });
|
||||
console.log(code);
|
||||
const res = await evaluate(code);
|
||||
pattern = res.pattern;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// const getTime = () => performance.now() / 1000;
|
||||
const getTime = () => audioContext.currentTime;
|
||||
let minLatency = 50;
|
||||
async function main() {
|
||||
await evalScope(import('@strudel/core'), import('@strudel/mini'), import('@strudel/tonal'));
|
||||
await evaluateFile();
|
||||
watch(file, { recursive: true }, () => evaluateFile());
|
||||
let lastEnd;
|
||||
const clock = createClock(getTime, (phase) => {
|
||||
if (!lastEnd) {
|
||||
lastEnd = phase;
|
||||
return;
|
||||
}
|
||||
const haps = pattern.queryArc(lastEnd, phase);
|
||||
lastEnd = phase;
|
||||
const cps = 1;
|
||||
const cycle = Math.floor(phase);
|
||||
haps
|
||||
.filter((h) => h.hasOnset())
|
||||
.forEach((hap) => {
|
||||
const env = new GainNode(audioContext, { gain: 0 });
|
||||
const { attack = 0.01, gain = 1 } = hap.value;
|
||||
env.connect(audioContext.destination);
|
||||
const now = hap.whole.begin;
|
||||
const duration = hap.duration;
|
||||
env.gain
|
||||
.setValueAtTime(0, now)
|
||||
.linearRampToValueAtTime(gain * 0.2, now + attack)
|
||||
.exponentialRampToValueAtTime(0.0001, now + duration);
|
||||
const frequency = hap.value.freq;
|
||||
|
||||
const osc = new OscillatorNode(audioContext, { frequency });
|
||||
osc.connect(env);
|
||||
osc.start(now);
|
||||
osc.stop(now + duration);
|
||||
});
|
||||
});
|
||||
|
||||
clock.start();
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -8,7 +8,8 @@
|
||||
},
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
"start": "node index.mjs"
|
||||
"osc": "node osc-superdirt.mjs",
|
||||
"waa": "node node-web-audio-api.mjs"
|
||||
},
|
||||
"keywords": [
|
||||
"tidalcycles",
|
||||
@@ -25,11 +26,12 @@
|
||||
"homepage": "https://github.com/tidalcycles/strudel#readme",
|
||||
"dependencies": {
|
||||
"@strudel/core": "workspace:*",
|
||||
"@strudel/mini": "workspace:*",
|
||||
"@strudel/osc": "workspace:*",
|
||||
"@strudel/tonal": "workspace:*",
|
||||
"@strudel/mini": "workspace:*",
|
||||
"@strudel/transpiler": "workspace:*",
|
||||
"node-watch": "^0.7.4",
|
||||
"node-web-audio-api": "^0.20.0",
|
||||
"osc-js": "^2.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
stack(
|
||||
s("bd*2"),
|
||||
s("jvbass(3,8)"),
|
||||
n(run(8)).s("feel").jux(rev).lpf(800)
|
||||
).hush()
|
||||
freq("110 220 [330 440,550,660]")
|
||||
.attack(.1).gain(.4)
|
||||
Generated
+33
@@ -322,6 +322,9 @@ importers:
|
||||
node-watch:
|
||||
specifier: ^0.7.4
|
||||
version: 0.7.4
|
||||
node-web-audio-api:
|
||||
specifier: ^0.20.0
|
||||
version: 0.20.0
|
||||
osc-js:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0
|
||||
@@ -3491,6 +3494,22 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@napi-rs/cli@2.18.2:
|
||||
resolution: {integrity: sha512-IXQji3IF5eStxTHe/PxDSRjPrFymYAQ5FbIvqurxzxyWR8nJql9mtvmCP8y2g8tSoW5xhaToLQW0+mO3lUZq4w==}
|
||||
engines: {node: '>= 10'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/@napi-rs/triples@1.2.0:
|
||||
resolution: {integrity: sha512-HAPjR3bnCsdXBsATpDIP5WCrw0JcACwhhrwIAQhiR46n+jm+a2F8kBsfseAuWtSyQ+H3Yebt2k43B5dy+04yMA==}
|
||||
dev: false
|
||||
|
||||
/@node-rs/helper@1.6.0:
|
||||
resolution: {integrity: sha512-2OTh/tokcLA1qom1zuCJm2gQzaZljCCbtX1YCrwRVd/toz7KxaDRFeLTAPwhs8m9hWgzrBn5rShRm6IaZofCPw==}
|
||||
dependencies:
|
||||
'@napi-rs/triples': 1.2.0
|
||||
dev: false
|
||||
|
||||
/@nodelib/fs.scandir@2.1.5:
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -10746,6 +10765,15 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/node-web-audio-api@0.20.0:
|
||||
resolution: {integrity: sha512-DPsRSG3IsI8cLCdejpruir+XgSwUFFJBSfilrtoT+BU/uFcXv/eFyKkulnKIE2642j5b00z9aOHxTHbzdUvTtw==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
'@napi-rs/cli': 2.18.2
|
||||
'@node-rs/helper': 1.6.0
|
||||
webidl-conversions: 7.0.0
|
||||
dev: false
|
||||
|
||||
/nopt@7.1.0:
|
||||
resolution: {integrity: sha512-ZFPLe9Iu0tnx7oWhFxAo4s7QTn8+NNDDxYNaKLjE7Dp0tbakQ3M1QhQzsnzXHQBTUO3K9BmwaxnyO8Ayn2I95Q==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
@@ -14222,6 +14250,11 @@ packages:
|
||||
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
||||
dev: true
|
||||
|
||||
/webidl-conversions@7.0.0:
|
||||
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/webmidi@3.1.8:
|
||||
resolution: {integrity: sha512-PCRic1iTpKxeheb888G0mDe6MBdz/u+s/xfdV6+1ZhZnS6dKtV9gMBth5cpmMip2Livv5lL+ep4/S9DCzHfumg==}
|
||||
engines: {node: '>=8.5'}
|
||||
|
||||
Reference in New Issue
Block a user