diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 7c96bb662..feb77c550 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -46,8 +46,8 @@ export function repl({ logger(`[eval] code updated`); pattern = editPattern?.(pattern) || pattern; + await afterEval?.({ code, pattern }); scheduler.setPattern(pattern, autostart); - afterEval?.({ code, pattern }); return pattern; } catch (err) { // console.warn(`[repl] eval error: ${err.message}`); diff --git a/packages/react/src/hooks/useStrudel.mjs b/packages/react/src/hooks/useStrudel.mjs index eee1bf7d2..b9852f93b 100644 --- a/packages/react/src/hooks/useStrudel.mjs +++ b/packages/react/src/hooks/useStrudel.mjs @@ -50,13 +50,13 @@ function useStrudel({ setCode(code); await beforeEval?.(); }, - afterEval: (res) => { + afterEval: async (res) => { const { pattern: _pattern, code } = res; setActiveCode(code); setPattern(_pattern); setEvalError(); setSchedulerError(); - afterEval?.(res); + await afterEval?.(res); }, onToggle: (v) => { setStarted(v); diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index c75bde0b1..c2a9b27a5 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -170,7 +170,7 @@ export const webaudioOutput = async (hap, deadline, hapDuration, cps) => { sourceNode = source(t, hap.value, hapDuration); } else if (getSound(s)) { const { onTrigger } = getSound(s); - const soundHandle = await onTrigger(t, hap.value, onended); + const soundHandle = await onTrigger(t, { ...hap.value, s }, onended); if (soundHandle) { sourceNode = soundHandle.node; soundHandle.stop(t + hapDuration); diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 67b368adf..afbea218d 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -118,11 +118,39 @@ export function Repl({ embedded = false }) { cleanupUi(); cleanupDraw(); }, - afterEval: ({ code }) => { + afterEval: async ({ code, pattern }) => { + // preload sounds + const t = scheduler.getTime(); + const lookahead = 16; + const upcoming = pattern + .queryArc(t, t + lookahead) + .filter((h) => h.value.s) + .map((h) => `${h.value.bank ? `${h.value.bank}_` : ''}${h.value.s}:${h.value.n || 0}`) + .filter((v, i, all) => all.indexOf(v) === i); + // console.log('now preloading sounds:', upcoming); + const preload = upcoming.map(async (v) => { + const [s, n] = v.split(':'); + const sound = soundMap.value[s]; + if (!sound) { + throw new Error(`[preload] error: sound not found: "${s}:${n}"`); + } + // TODO: only preload if not already preloaded... + // TODO: add sound.preload interface that only loads the sample, without creating a buffersource + return sound.onTrigger(getAudioContext().currentTime + 0.5, { s, n }, () => { + // console.log('onended'); + }); + }); + await Promise.all(preload); + // console.log('preloading done'); + setPending(false); setLatestCode(code); window.location.hash = '#' + encodeURIComponent(btoa(code)); }, + onEvalError: (err) => { + console.log('errr'); + setPending(false); + }, onToggle: (play) => !play && cleanupDraw(false), drawContext, });