diff --git a/packages/webaudio/index.mjs b/packages/webaudio/index.mjs index a3a321ed1..673381ab5 100644 --- a/packages/webaudio/index.mjs +++ b/packages/webaudio/index.mjs @@ -8,3 +8,4 @@ export * from './clockworker.mjs'; export * from './scheduler.mjs'; export * from './webaudio.mjs'; export * from './sampler.mjs'; +export * from './prebake.mjs'; diff --git a/packages/webaudio/prebake.mjs b/packages/webaudio/prebake.mjs new file mode 100644 index 000000000..18c7a28d7 --- /dev/null +++ b/packages/webaudio/prebake.mjs @@ -0,0 +1,83 @@ +import { Pattern, toMidi } from '@strudel.cycles/core'; +import { samples } from '.'; + +let baking; + +export function prebake(props) { + if (baking) { + return baking; + } + baking = prebaker(props); + return baking; +} + +async function prebaker(props = {}) { + const { baseURL = './samples' } = props; // http://localhost:1234 + try { + samples( + { + piano: { + A0: 'A0v8.mp3', + C1: 'C1v8.mp3', + Ds1: 'Ds1v8.mp3', + Fs1: 'Fs1v8.mp3', + A1: 'A1v8.mp3', + C2: 'C2v8.mp3', + Ds2: 'Ds2v8.mp3', + Fs2: 'Fs2v8.mp3', + A2: 'A2v8.mp3', + C3: 'C3v8.mp3', + Ds3: 'Ds3v8.mp3', + Fs3: 'Fs3v8.mp3', + A3: 'A3v8.mp3', + C4: 'C4v8.mp3', + Ds4: 'Ds4v8.mp3', + Fs4: 'Fs4v8.mp3', + A4: 'A4v8.mp3', + C5: 'C5v8.mp3', + Ds4: 'Ds4v8.mp3', + Fs5: 'Fs5v8.mp3', + A5: 'A5v8.mp3', + C6: 'C6v8.mp3', + Ds6: 'Ds6v8.mp3', + Fs6: 'Fs6v8.mp3', + A6: 'A6v8.mp3', + C7: 'C7v8.mp3', + Ds7: 'Ds7v8.mp3', + Fs7: 'Fs7v8.mp3', + A7: 'A7v8.mp3', + C8: 'C8v8.mp3', + }, + }, + // https://archive.org/details/SalamanderGrandPianoV3 + // License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm + baseURL + '/piano/', + ); + + const maxPan = toMidi('C8'); + const panwidth = (pan, width) => pan * width + (1 - width) / 2; + + Pattern.prototype.piano = function () { + return this.clip(1) + .s('piano') + .fmap((value) => { + // pan by pitch + const pan = panwidth(Math.min(toMidi(value.note) / maxPan, 1), 0.5); + return { ...value, pan: (value.pan || 1) * pan }; + }); + }; + + // ping sample server + /* await fetch(samplerURL) + .then(() => { + console.log(`prebake: Using samples from "${baseURL}"`); + }) + .catch(() => { + throw new Error( + `sample server not running at "${samplerURL}"... run "npm run sampler" from the strudel project root.`, + ); + }); */ + } catch (e) { + console.warn('prebake error', e); + } +}