Files
2022-07-19 23:42:33 +02:00

77 lines
2.1 KiB
JavaScript

import repl from 'repl';
import { evalScope, evaluate } from '@strudel.cycles/eval';
import { AudioContext } from 'web-audio-api';
import Speaker from 'speaker';
import controls from '@strudel.cycles/core/controls.mjs';
import { prepareSamples, playBuffer } from './sampler.js';
import { randomHeadline } from './headline.js';
/*
This is just a POC of how a strudel cli / repl could look like
*/
// setup audio
const context = new AudioContext();
context.outStream = new Speaker({
channels: context.format.numberOfChannels,
bitDepth: context.format.bitDepth,
sampleRate: context.sampleRate,
});
console.log('now loading samples..');
const buffers = await prepareSamples(context, './samples/');
console.log('');
// scheduler
let tick = 0;
const slice = 0.5;
const latency = 1;
/* console.log('latency', latency);
console.log('querying every', slice, 's'); */
const offset = context.currentTime + latency;
let pattern;
setInterval(() => {
if (pattern) {
try {
pattern
.queryArc(tick * slice, ++tick * slice)
.filter((hap) => hap.hasOnset())
.forEach((hap) => {
const t = hap.whole.begin.valueOf() + offset;
const { s, n } = hap.value;
const bank = buffers[s];
if (bank?.length) {
const index = (n ?? 0) % bank.length;
playBuffer(context, bank[index], t);
}
});
} catch (err) {
console.error('query error', err);
}
}
}, slice * 1000);
await evalScope(controls, import('@strudel.cycles/core'), import('@strudel.cycles/mini'));
console.log(`${randomHeadline()}
welcome to the experimental strudel cli <3
available samples: ${Object.entries(buffers)
.map(([key, samples]) => `${key} (${samples.length})`)
.join(', ')}
you can add samples to the samples folder (.wav, .ogg, .mp3)
please enter a pattern, e.g. s("bd(3,8),~ sd,hh(3,8,1)")
`);
// repl
repl.start({
prompt: '>>>',
eval: async function myEval(cmd, context, filename, callback) {
try {
pattern = (await evaluate(cmd)).pattern;
} catch (err) {
console.error('query error', err.message);
}
callback(null);
},
});