From f8a241401c1748b091314b3825de57b87f1495c4 Mon Sep 17 00:00:00 2001 From: Tristan de Cacqueray Date: Sun, 20 Oct 2024 22:00:42 -0400 Subject: [PATCH] Add uniform pattern function doc --- packages/shader/shader.mjs | 3 +-- packages/shader/uniform.mjs | 52 ++++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/shader/shader.mjs b/packages/shader/shader.mjs index f65b23f8a..6e1e0fad9 100644 --- a/packages/shader/shader.mjs +++ b/packages/shader/shader.mjs @@ -44,7 +44,7 @@ class UniformValue { get(elapsed) { // Adjust the value according to the rate of change - const offset = (this.desired - this.value) / (this.slow * Math.min(1, elapsed * 60)); + const offset = (this.desired - this.value) / (this.slow * Math.max(1, elapsed * 60)); // Ignore small changes if (Math.abs(offset) > 1e-3) this.value += offset; return this.value; @@ -72,7 +72,6 @@ export function setUniform(instanceName, name, value, incr, position, slow) { uniformValue = uniform.value[idx]; } uniformValue.slow = slow; - // TODO: handle direct assignment, this is incrementing by default if (incr) uniformValue.desired += value; else uniformValue.desired = value; } else { diff --git a/packages/shader/uniform.mjs b/packages/shader/uniform.mjs index 3e33b68da..58169b993 100644 --- a/packages/shader/uniform.mjs +++ b/packages/shader/uniform.mjs @@ -4,19 +4,31 @@ Copyright (C) 2024 Strudel contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -import { Pattern, reify, register, logger } from '@strudel/core'; +import { reify, register, logger } from '@strudel/core'; import { setUniform } from './shader.mjs'; /** - * Update a shader. + * Update a shader uniform value. A uniform name consists of + * + * - a name + * - optional array position seperated by ':'. The position can be an index number, or 'seq' | 'random' to assign a different index per events. + * + * The uniform can also be configured with an object to pass extra options: * * @name uniform + * @param {string} name: the uniform name and optional position. + * @param {number} gain: the value multiplier - defaults to 1. + * @param {number} slow: the value change rate, set to 1 for instant update - defaults to 10. + * @param {boolean} onTrigger: update the uniform only when the pattern trigger. In that case, the uniform position is mapped to the event note/sound when it is not explicity set. + * * @example * pan(sine.uniform("iColor")) * @example - * gain("<.5 .3>".uniform("rotations:seq")) + * gain(".5 .3").uniform("mod:0 mod:1") * @example - * s("bd sd").uniform({onTrigger: true, dest: "moveFWD"}) + * dist("<.5 .3>".uniform("rotations:seq")) + * @example + * s("bd sd").uniform({name: 'rotations', gain: 0.2, slow: "<5 20>", onTrigger: true}) */ export const uniform = register('uniform', (options, pat) => { // The shader instance name @@ -25,13 +37,7 @@ export const uniform = register('uniform', (options, pat) => { // Are the uniform updated on trigger const onTrigger = options.onTrigger || false; - const setCtx = (uniformParam) => (ctx) => ({ - uniformParam, - onTrigger: () => {}, - dominantTrigger: true, - ...ctx, - }); - + // Helper to assign uniform position const pitches = { _count: 0 }; const getPosition = (value, dest) => { if (typeof dest === 'number') return dest; @@ -45,9 +51,10 @@ export const uniform = register('uniform', (options, pat) => { } return pitches[note]; } else { - throw 'Invalid position' + dest; + logger('Invalid position' + dest, 'error'); } }; + // Helper to decode the uniform position const getUniformPosition = (value, dest) => { if (typeof dest === 'string') { return [dest, 0]; @@ -56,15 +63,31 @@ export const uniform = register('uniform', (options, pat) => { } }; + // The option pattern context + const setCtx = (uniformParam) => (ctx) => ({ + // The option name + uniformParam, + // Disable event trigger + onTrigger: () => {}, + dominantTrigger: true, + ...ctx, + }); + + // Collect the option patterns const optionsPats = []; if (Array.isArray(options) || typeof options === 'string') optionsPats.push(reify(options).withContext(setCtx('dest'))); else { + // dest was the initial name, that can be removed if (options.dest) optionsPats.push(reify(options.dest).withContext(setCtx('dest'))); + if (options.name) optionsPats.push(reify(options.name).withContext(setCtx('dest'))); if (options.gain) optionsPats.push(reify(options.gain).withContext(setCtx('gain'))); if (options.slow) optionsPats.push(reify(options.slow).withContext(setCtx('slow'))); } + + // Run the base pattern along with all the options return stack(pat, ...optionsPats).withHaps((haps) => { + // Collect the current options let dest; let gain = 1; let slow = 10; @@ -80,18 +103,23 @@ export const uniform = register('uniform', (options, pat) => { source = hap; } }); + if (dest && source) { if (onTrigger) { + // Set the uniform when the source trigger source.context.onTrigger = (_, hap) => { const [uniform, position] = getUniformPosition(hap.value, dest); setUniform(instance, uniform, (hap.value.gain || 1) * gain, true, position, slow); }; source.context.dominantTrigger = false; } else { + // Set the uniform now. const [uniform, position] = getUniformPosition(source.value, dest); setUniform(instance, uniform, source.value * gain, false, position, slow); } } + + // The options haps are kept so that the current values are highlighted on screen return haps; }); });