diff --git a/packages/webdirt/sampler.mjs b/packages/webdirt/sampler.mjs index b50b134e..39a15fea 100644 --- a/packages/webdirt/sampler.mjs +++ b/packages/webdirt/sampler.mjs @@ -1,11 +1,20 @@ const bufferCache = {}; // string: Promise +const loadCache = {}; // string: Promise export const loadBuffer = (url, ac) => { - if (!bufferCache[url]) { - bufferCache[url] = fetch(url) + if (!loadCache[url]) { + loadCache[url] = fetch(url) .then((res) => res.arrayBuffer()) - .then((res) => ac.decodeAudioData(res)); + .then(async (res) => { + const decoded = await ac.decodeAudioData(res); + bufferCache[url] = decoded; + return decoded; + }); } + return loadCache[url]; +}; + +export const getLoadedBuffer = (url) => { return bufferCache[url]; }; @@ -70,6 +79,32 @@ export const loadGithubSamples = async (path, nameFn) => { return githubCache[path]; }; +/** + * load the given sample map for webdirt + * + * @example + * loadSamples({ + * bd: '808bd/BD0000.WAV', + * sd: ['808sd/SD0000.WAV','808sd/SD0010.WAV','808sd/SD0050.WAV'] + * }, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/'); + * s("bd ").n(2).webdirt() + * + */ + +export const samples = (sampleMap, baseUrl = '') => { + sampleCache.current = { + ...sampleCache.current, + ...Object.fromEntries( + Object.entries(sampleMap).map(([key, value]) => [ + key, + (typeof value === 'string' ? [value] : value).map((v) => + (baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/'), + ), + ]), + ), + }; +}; + export const resetLoadedSamples = () => { sampleCache.current = undefined; }; diff --git a/packages/webdirt/webdirt.mjs b/packages/webdirt/webdirt.mjs index 0e6e63b0..36637818 100644 --- a/packages/webdirt/webdirt.mjs +++ b/packages/webdirt/webdirt.mjs @@ -1,7 +1,7 @@ import * as strudel from '@strudel.cycles/core'; const { Pattern } = strudel; import * as WebDirt from 'WebDirt'; -import { getLoadedSamples, loadBuffer } from './sampler.mjs'; +import { getLoadedSamples, loadBuffer, getLoadedBuffer } from './sampler.mjs'; let webDirt; @@ -70,7 +70,7 @@ Pattern.prototype.webdirt = function () { const deadline = time - currentTime; const { s, n = 0, ...rest } = e.value || {}; if (!s) { - console.warn('webdirt: no "s" was set!'); + console.warn('Pattern.webdirt: no "s" was set!'); } const samples = getLoadedSamples(); if (!samples?.[s]) { @@ -79,13 +79,18 @@ Pattern.prototype.webdirt = function () { return; } if (!samples?.[s]) { - console.warn(`webdirt: sample "${s}" not found in loaded samples`, samples); + console.warn(`Pattern.webdirt: sample "${s}" not found in loaded samples`, samples); } else { const bank = samples[s]; const sampleUrl = bank[n % bank.length]; - const buffer = await loadBuffer(sampleUrl, webDirt.ac); - const msg = { buffer: { buffer }, ...rest }; - webDirt.playSample(msg, deadline); + const buffer = getLoadedBuffer(sampleUrl); + if (!buffer) { + console.log(`Pattern.webdirt: load ${s}:${n} from ${sampleUrl}`); + loadBuffer(sampleUrl, webDirt.ac); + } else { + const msg = { buffer: { buffer }, ...rest }; + webDirt.playSample(msg, deadline); + } } }; return hap.setContext({ ...hap.context, onTrigger });