Skip to content

Commit

Permalink
Add uniform pattern function doc
Browse files Browse the repository at this point in the history
  • Loading branch information
TristanCacqueray committed Oct 21, 2024
1 parent 1baa6da commit f8a2414
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 14 deletions.
3 changes: 1 addition & 2 deletions packages/shader/shader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
52 changes: 40 additions & 12 deletions packages/shader/uniform.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://www.gnu.org/licenses/>.
*/

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
Expand All @@ -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;
Expand All @@ -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];
Expand All @@ -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) => {

Check failure on line 89 in packages/shader/uniform.mjs

View workflow job for this annotation

GitHub Actions / build (20)

'stack' is not defined
// Collect the current options
let dest;
let gain = 1;
let slow = 10;
Expand All @@ -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;
});
});

0 comments on commit f8a2414

Please sign in to comment.