mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 14:26:58 -04:00
d164b5e7f5
This reverts commit c0bf86d11e.
131 lines
3.9 KiB
JavaScript
131 lines
3.9 KiB
JavaScript
import { Pattern } from '@strudel/core';
|
|
import { connectToDestination, getAudioContext, getWorklet } from 'superdough';
|
|
|
|
let doughWorklet;
|
|
|
|
function initDoughWorklet() {
|
|
const ac = getAudioContext();
|
|
doughWorklet = getWorklet(
|
|
ac,
|
|
'dough-processor',
|
|
{},
|
|
{
|
|
outputChannelCount: [2],
|
|
},
|
|
);
|
|
connectToDestination(doughWorklet); // channels?
|
|
}
|
|
|
|
const soundMap = new Map();
|
|
const loadedSounds = new Map();
|
|
|
|
Pattern.prototype.supradough = function () {
|
|
return this.onTrigger((hap, __, cps, begin) => {
|
|
hap.value._begin = begin;
|
|
hap.value._duration = hap.duration / cps;
|
|
!doughWorklet && initDoughWorklet();
|
|
const s = (hap.value.bank ? hap.value.bank + '_' : '') + hap.value.s;
|
|
const n = hap.value.n ?? 0;
|
|
const soundKey = `${s}:${n}`;
|
|
if (soundMap.has(s)) {
|
|
hap.value.s = soundKey; // dough.mjs is unaware of bank and n (only maps keys to buffers)
|
|
}
|
|
if (soundMap.has(s) && !loadedSounds.has(soundKey)) {
|
|
const urls = soundMap.get(s);
|
|
const url = urls[n % urls.length];
|
|
console.log(`load ${soundKey} from ${url}`);
|
|
const loadSample = fetchSample(url);
|
|
loadedSounds.set(soundKey, loadSample);
|
|
loadSample.then(({ channels, sampleRate }) =>
|
|
doughWorklet.port.postMessage({
|
|
sample: soundKey,
|
|
channels,
|
|
sampleRate,
|
|
}),
|
|
);
|
|
}
|
|
|
|
doughWorklet.port.postMessage({ spawn: hap.value });
|
|
}, 1);
|
|
};
|
|
|
|
function githubPath(base, subpath = '') {
|
|
if (!base.startsWith('github:')) {
|
|
throw new Error('expected "github:" at the start of pseudoUrl');
|
|
}
|
|
let [_, path] = base.split('github:');
|
|
path = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
if (path.split('/').length === 2) {
|
|
// assume main as default branch if none set
|
|
path += '/main';
|
|
}
|
|
return `https://raw.githubusercontent.com/${path}/${subpath}`;
|
|
}
|
|
export async function fetchSampleMap(url) {
|
|
if (url.startsWith('github:')) {
|
|
url = githubPath(url, 'strudel.json');
|
|
}
|
|
if (url.startsWith('local:')) {
|
|
url = `http://localhost:5432`;
|
|
}
|
|
if (url.startsWith('shabda:')) {
|
|
let [_, path] = url.split('shabda:');
|
|
url = `https://shabda.ndre.gr/${path}.json?strudel=1`;
|
|
}
|
|
if (url.startsWith('shabda/speech')) {
|
|
let [_, path] = url.split('shabda/speech');
|
|
path = path.startsWith('/') ? path.substring(1) : path;
|
|
let [params, words] = path.split(':');
|
|
let gender = 'f';
|
|
let language = 'en-GB';
|
|
if (params) {
|
|
[language, gender] = params.split('/');
|
|
}
|
|
url = `https://shabda.ndre.gr/speech/${words}.json?gender=${gender}&language=${language}&strudel=1'`;
|
|
}
|
|
if (typeof fetch !== 'function') {
|
|
// not a browser
|
|
return;
|
|
}
|
|
const base = url.split('/').slice(0, -1).join('/');
|
|
if (typeof fetch === 'undefined') {
|
|
// skip fetch when in node / testing
|
|
return;
|
|
}
|
|
const json = await fetch(url)
|
|
.then((res) => res.json())
|
|
.catch((error) => {
|
|
console.error(error);
|
|
throw new Error(`error loading "${url}"`);
|
|
});
|
|
return [json, json._base || base];
|
|
}
|
|
|
|
// for some reason, only piano and flute work.. is it because mp3??
|
|
|
|
async function fetchSample(url) {
|
|
const buffer = await fetch(url)
|
|
.then((res) => res.arrayBuffer())
|
|
.then((buf) => getAudioContext().decodeAudioData(buf));
|
|
let channels = [];
|
|
for (let i = 0; i < buffer.numberOfChannels; i++) {
|
|
channels.push(buffer.getChannelData(i));
|
|
}
|
|
return { channels, sampleRate: buffer.sampleRate };
|
|
}
|
|
|
|
export async function doughsamples(sampleMap, baseUrl) {
|
|
if (typeof sampleMap === 'string') {
|
|
const [json, base] = await fetchSampleMap(sampleMap);
|
|
// console.log('json', json, 'base', base);
|
|
return doughsamples(json, base);
|
|
}
|
|
Object.entries(sampleMap).map(async ([key, urls]) => {
|
|
if (key !== '_base') {
|
|
urls = urls.map((url) => baseUrl + url);
|
|
// console.log('set', key, urls);
|
|
soundMap.set(key, urls);
|
|
}
|
|
});
|
|
}
|