diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 044cfa96d..2545047fe 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -413,6 +413,32 @@ export const { begin } = registerControl('begin'); * */ export const { end } = registerControl('end'); +/** + * the offset of the sample buffer in seconds + * + * @memberof Pattern + * @name beginSeconds + * @param {number | Pattern} seconds + * @example + * samples('github:switchangel/pad') + * s("swpad!4").clip(1).beginSeconds("2 5 .2 3").fast(2) + * @example + * samples('github:switchangel/pad') + * $: s("swpad!16").beginseconds(time).dec(.1) + * + */ +export const { beginSeconds, beginseconds } = registerControl('beginSeconds', 'beginseconds'); +/** + * The end of the sample buffer in seconds + * + * @memberof Pattern + * @name endSeconds + * @param {number | Pattern} seconds + * @example + * s("bd*2,oh*4").endSeconds("<.1 .05 .2 1>").fast(2) + * + */ +export const { endSeconds, endseconds } = registerControl('endSeconds', 'endseconds'); /** * Loops the sample. * Note that the tempo of the loop is not synced with the cycle tempo. diff --git a/packages/core/logger.mjs b/packages/core/logger.mjs index 4f2002319..488bce5e8 100644 --- a/packages/core/logger.mjs +++ b/packages/core/logger.mjs @@ -6,7 +6,7 @@ let debounce = 1000, export function errorLogger(e, origin = 'cyclist') { //TODO: add some kind of debug flag that enables this while in dev mode - // console.error(e); + console.error(e); logger(`[${origin}] error: ${e.message}`); } diff --git a/packages/superdough/logger.mjs b/packages/superdough/logger.mjs index b3c9c34f3..596ca7c7a 100644 --- a/packages/superdough/logger.mjs +++ b/packages/superdough/logger.mjs @@ -2,7 +2,7 @@ let log = (msg) => console.log(msg); export function errorLogger(e, origin = 'cyclist') { //TODO: add some kind of debug flag that enables this while in dev mode - // console.error(e); + console.error(e); logger(`[${origin}] error: ${e.message}`); } diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 9188c17c3..50ffde903 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -78,13 +78,23 @@ export const getSampleBufferSource = async (hapValue, bank, resolveUrl) => { const bufferSource = ac.createBufferSource(); bufferSource.buffer = buffer; bufferSource.playbackRate.value = playbackRate; - - const { s, loopBegin = 0, loopEnd = 1, begin = 0, end = 1 } = hapValue; - + const { s, loopBegin = 0, loopEnd = 1, begin, end, beginSeconds, endSeconds } = hapValue; + let offset = 0; + let endTime = bufferSource.buffer.duration; // "The computation of the offset into the sound is performed using the sound buffer's natural sample rate, // rather than the current playback rate, so even if the sound is playing at twice its normal speed, // the midway point through a 10-second audio buffer is still 5." - const offset = begin * bufferSource.buffer.duration; + if (begin != null) { + offset = begin * bufferSource.buffer.duration; + } else if (beginSeconds != null) { + offset = beginSeconds; + } + + if (end != null) { + endTime = end * bufferSource.buffer.duration; + } else if (endSeconds != null) { + endTime = endSeconds; + } const loop = s.startsWith('wt_') ? 1 : hapValue.loop; if (loop) { @@ -93,7 +103,7 @@ export const getSampleBufferSource = async (hapValue, bank, resolveUrl) => { bufferSource.loopEnd = loopEnd * bufferSource.buffer.duration - offset; } const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; - const sliceDuration = (end - begin) * bufferDuration; + const sliceDuration = (endTime - offset) / bufferSource.playbackRate.value; return { bufferSource, offset, bufferDuration, sliceDuration }; }; @@ -347,6 +357,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { out.disconnect(); onended(); }; + let envEnd = holdEnd + release + 0.01; bufferSource.stop(envEnd); const stop = (endTime) => { diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index f91503ca2..77fc93ad4 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1051,6 +1051,112 @@ exports[`runs examples > example "begin" example index 0 1`] = ` ] `; +exports[`runs examples > example "beginSeconds" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 1/8 → 1/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 1/4 → 3/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 3/8 → 1/2 | s:swpad clip:1 beginSeconds:3 ]", + "[ 1/2 → 5/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 5/8 → 3/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 3/4 → 7/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 7/8 → 1/1 | s:swpad clip:1 beginSeconds:3 ]", + "[ 1/1 → 9/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 9/8 → 5/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 5/4 → 11/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 11/8 → 3/2 | s:swpad clip:1 beginSeconds:3 ]", + "[ 3/2 → 13/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 13/8 → 7/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 7/4 → 15/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 15/8 → 2/1 | s:swpad clip:1 beginSeconds:3 ]", + "[ 2/1 → 17/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 17/8 → 9/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 9/4 → 19/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 19/8 → 5/2 | s:swpad clip:1 beginSeconds:3 ]", + "[ 5/2 → 21/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 21/8 → 11/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 11/4 → 23/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 23/8 → 3/1 | s:swpad clip:1 beginSeconds:3 ]", + "[ 3/1 → 25/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 25/8 → 13/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 13/4 → 27/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 27/8 → 7/2 | s:swpad clip:1 beginSeconds:3 ]", + "[ 7/2 → 29/8 | s:swpad clip:1 beginSeconds:2 ]", + "[ 29/8 → 15/4 | s:swpad clip:1 beginSeconds:5 ]", + "[ 15/4 → 31/8 | s:swpad clip:1 beginSeconds:0.2 ]", + "[ 31/8 → 4/1 | s:swpad clip:1 beginSeconds:3 ]", +] +`; + +exports[`runs examples > example "beginSeconds" example index 1 1`] = ` +[ + "[ 0/1 → 1/16 | s:swpad beginSeconds:0 decay:0.1 ]", + "[ 1/16 → 1/8 | s:swpad beginSeconds:0.0625 decay:0.1 ]", + "[ 1/8 → 3/16 | s:swpad beginSeconds:0.125 decay:0.1 ]", + "[ 3/16 → 1/4 | s:swpad beginSeconds:0.1875 decay:0.1 ]", + "[ 1/4 → 5/16 | s:swpad beginSeconds:0.25 decay:0.1 ]", + "[ 5/16 → 3/8 | s:swpad beginSeconds:0.3125 decay:0.1 ]", + "[ 3/8 → 7/16 | s:swpad beginSeconds:0.375 decay:0.1 ]", + "[ 7/16 → 1/2 | s:swpad beginSeconds:0.4375 decay:0.1 ]", + "[ 1/2 → 9/16 | s:swpad beginSeconds:0.5 decay:0.1 ]", + "[ 9/16 → 5/8 | s:swpad beginSeconds:0.5625 decay:0.1 ]", + "[ 5/8 → 11/16 | s:swpad beginSeconds:0.625 decay:0.1 ]", + "[ 11/16 → 3/4 | s:swpad beginSeconds:0.6875 decay:0.1 ]", + "[ 3/4 → 13/16 | s:swpad beginSeconds:0.75 decay:0.1 ]", + "[ 13/16 → 7/8 | s:swpad beginSeconds:0.8125 decay:0.1 ]", + "[ 7/8 → 15/16 | s:swpad beginSeconds:0.875 decay:0.1 ]", + "[ 15/16 → 1/1 | s:swpad beginSeconds:0.9375 decay:0.1 ]", + "[ 1/1 → 17/16 | s:swpad beginSeconds:1 decay:0.1 ]", + "[ 17/16 → 9/8 | s:swpad beginSeconds:1.0625 decay:0.1 ]", + "[ 9/8 → 19/16 | s:swpad beginSeconds:1.125 decay:0.1 ]", + "[ 19/16 → 5/4 | s:swpad beginSeconds:1.1875 decay:0.1 ]", + "[ 5/4 → 21/16 | s:swpad beginSeconds:1.25 decay:0.1 ]", + "[ 21/16 → 11/8 | s:swpad beginSeconds:1.3125 decay:0.1 ]", + "[ 11/8 → 23/16 | s:swpad beginSeconds:1.375 decay:0.1 ]", + "[ 23/16 → 3/2 | s:swpad beginSeconds:1.4375 decay:0.1 ]", + "[ 3/2 → 25/16 | s:swpad beginSeconds:1.5 decay:0.1 ]", + "[ 25/16 → 13/8 | s:swpad beginSeconds:1.5625 decay:0.1 ]", + "[ 13/8 → 27/16 | s:swpad beginSeconds:1.625 decay:0.1 ]", + "[ 27/16 → 7/4 | s:swpad beginSeconds:1.6875 decay:0.1 ]", + "[ 7/4 → 29/16 | s:swpad beginSeconds:1.75 decay:0.1 ]", + "[ 29/16 → 15/8 | s:swpad beginSeconds:1.8125 decay:0.1 ]", + "[ 15/8 → 31/16 | s:swpad beginSeconds:1.875 decay:0.1 ]", + "[ 31/16 → 2/1 | s:swpad beginSeconds:1.9375 decay:0.1 ]", + "[ 2/1 → 33/16 | s:swpad beginSeconds:2 decay:0.1 ]", + "[ 33/16 → 17/8 | s:swpad beginSeconds:2.0625 decay:0.1 ]", + "[ 17/8 → 35/16 | s:swpad beginSeconds:2.125 decay:0.1 ]", + "[ 35/16 → 9/4 | s:swpad beginSeconds:2.1875 decay:0.1 ]", + "[ 9/4 → 37/16 | s:swpad beginSeconds:2.25 decay:0.1 ]", + "[ 37/16 → 19/8 | s:swpad beginSeconds:2.3125 decay:0.1 ]", + "[ 19/8 → 39/16 | s:swpad beginSeconds:2.375 decay:0.1 ]", + "[ 39/16 → 5/2 | s:swpad beginSeconds:2.4375 decay:0.1 ]", + "[ 5/2 → 41/16 | s:swpad beginSeconds:2.5 decay:0.1 ]", + "[ 41/16 → 21/8 | s:swpad beginSeconds:2.5625 decay:0.1 ]", + "[ 21/8 → 43/16 | s:swpad beginSeconds:2.625 decay:0.1 ]", + "[ 43/16 → 11/4 | s:swpad beginSeconds:2.6875 decay:0.1 ]", + "[ 11/4 → 45/16 | s:swpad beginSeconds:2.75 decay:0.1 ]", + "[ 45/16 → 23/8 | s:swpad beginSeconds:2.8125 decay:0.1 ]", + "[ 23/8 → 47/16 | s:swpad beginSeconds:2.875 decay:0.1 ]", + "[ 47/16 → 3/1 | s:swpad beginSeconds:2.9375 decay:0.1 ]", + "[ 3/1 → 49/16 | s:swpad beginSeconds:3 decay:0.1 ]", + "[ 49/16 → 25/8 | s:swpad beginSeconds:3.0625 decay:0.1 ]", + "[ 25/8 → 51/16 | s:swpad beginSeconds:3.125 decay:0.1 ]", + "[ 51/16 → 13/4 | s:swpad beginSeconds:3.1875 decay:0.1 ]", + "[ 13/4 → 53/16 | s:swpad beginSeconds:3.25 decay:0.1 ]", + "[ 53/16 → 27/8 | s:swpad beginSeconds:3.3125 decay:0.1 ]", + "[ 27/8 → 55/16 | s:swpad beginSeconds:3.375 decay:0.1 ]", + "[ 55/16 → 7/2 | s:swpad beginSeconds:3.4375 decay:0.1 ]", + "[ 7/2 → 57/16 | s:swpad beginSeconds:3.5 decay:0.1 ]", + "[ 57/16 → 29/8 | s:swpad beginSeconds:3.5625 decay:0.1 ]", + "[ 29/8 → 59/16 | s:swpad beginSeconds:3.625 decay:0.1 ]", + "[ 59/16 → 15/4 | s:swpad beginSeconds:3.6875 decay:0.1 ]", + "[ 15/4 → 61/16 | s:swpad beginSeconds:3.75 decay:0.1 ]", + "[ 61/16 → 31/8 | s:swpad beginSeconds:3.8125 decay:0.1 ]", + "[ 31/8 → 63/16 | s:swpad beginSeconds:3.875 decay:0.1 ]", + "[ 63/16 → 4/1 | s:swpad beginSeconds:3.9375 decay:0.1 ]", +] +`; + exports[`runs examples > example "berlin" example index 0 1`] = ` [ "[ 0/1 → 1/16 | note:D3 ]", @@ -3501,6 +3607,59 @@ exports[`runs examples > example "end" example index 0 1`] = ` ] `; +exports[`runs examples > example "endSeconds" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | s:oh endSeconds:0.1 ]", + "[ 0/1 → 1/4 | s:bd endSeconds:0.1 ]", + "[ 1/8 → 1/4 | s:oh endSeconds:0.1 ]", + "[ 1/4 → 3/8 | s:oh endSeconds:0.1 ]", + "[ 1/4 → 1/2 | s:bd endSeconds:0.1 ]", + "[ 3/8 → 1/2 | s:oh endSeconds:0.1 ]", + "[ 1/2 → 5/8 | s:oh endSeconds:0.05 ]", + "[ 1/2 → 3/4 | s:bd endSeconds:0.05 ]", + "[ 5/8 → 3/4 | s:oh endSeconds:0.05 ]", + "[ 3/4 → 7/8 | s:oh endSeconds:0.05 ]", + "[ 3/4 → 1/1 | s:bd endSeconds:0.05 ]", + "[ 7/8 → 1/1 | s:oh endSeconds:0.05 ]", + "[ 1/1 → 9/8 | s:oh endSeconds:0.2 ]", + "[ 1/1 → 5/4 | s:bd endSeconds:0.2 ]", + "[ 9/8 → 5/4 | s:oh endSeconds:0.2 ]", + "[ 5/4 → 11/8 | s:oh endSeconds:0.2 ]", + "[ 5/4 → 3/2 | s:bd endSeconds:0.2 ]", + "[ 11/8 → 3/2 | s:oh endSeconds:0.2 ]", + "[ 3/2 → 13/8 | s:oh endSeconds:1 ]", + "[ 3/2 → 7/4 | s:bd endSeconds:1 ]", + "[ 13/8 → 7/4 | s:oh endSeconds:1 ]", + "[ 7/4 → 15/8 | s:oh endSeconds:1 ]", + "[ 7/4 → 2/1 | s:bd endSeconds:1 ]", + "[ 15/8 → 2/1 | s:oh endSeconds:1 ]", + "[ 2/1 → 17/8 | s:oh endSeconds:0.1 ]", + "[ 2/1 → 9/4 | s:bd endSeconds:0.1 ]", + "[ 17/8 → 9/4 | s:oh endSeconds:0.1 ]", + "[ 9/4 → 19/8 | s:oh endSeconds:0.1 ]", + "[ 9/4 → 5/2 | s:bd endSeconds:0.1 ]", + "[ 19/8 → 5/2 | s:oh endSeconds:0.1 ]", + "[ 5/2 → 21/8 | s:oh endSeconds:0.05 ]", + "[ 5/2 → 11/4 | s:bd endSeconds:0.05 ]", + "[ 21/8 → 11/4 | s:oh endSeconds:0.05 ]", + "[ 11/4 → 23/8 | s:oh endSeconds:0.05 ]", + "[ 11/4 → 3/1 | s:bd endSeconds:0.05 ]", + "[ 23/8 → 3/1 | s:oh endSeconds:0.05 ]", + "[ 3/1 → 25/8 | s:oh endSeconds:0.2 ]", + "[ 3/1 → 13/4 | s:bd endSeconds:0.2 ]", + "[ 25/8 → 13/4 | s:oh endSeconds:0.2 ]", + "[ 13/4 → 27/8 | s:oh endSeconds:0.2 ]", + "[ 13/4 → 7/2 | s:bd endSeconds:0.2 ]", + "[ 27/8 → 7/2 | s:oh endSeconds:0.2 ]", + "[ 7/2 → 29/8 | s:oh endSeconds:1 ]", + "[ 7/2 → 15/4 | s:bd endSeconds:1 ]", + "[ 29/8 → 15/4 | s:oh endSeconds:1 ]", + "[ 15/4 → 31/8 | s:oh endSeconds:1 ]", + "[ 15/4 → 4/1 | s:bd endSeconds:1 ]", + "[ 31/8 → 4/1 | s:oh endSeconds:1 ]", +] +`; + exports[`runs examples > example "euclid" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:c3 ]",