pick.mjs - methods that use one pattern to pick events from other patterns. Copyright (C) 2024 Strudel contributors - see https://codeberg.org/uzu/strudel/src/branch/main/packages/core/signal.mjs 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/.
7import { Pattern, reify, silence, register } from './pattern.mjs';
9import { _mod, clamp, objectMap } from './util.mjs'; 10 11const _pick = function (lookup, pat, modulo = true) { 12 const array = Array.isArray(lookup); 13 const len = Object.keys(lookup).length; 14 15 lookup = objectMap(lookup, reify); 16 17 if (len === 0) { 18 return silence; 19 } 20 return pat.fmap((i) => { 21 let key = i; 22 if (array) { 23 key = modulo ? Math.round(key) % len : clamp(Math.round(key), 0, lookup.length - 1); 24 } 25 return lookup[key]; 26 }); 27};
- Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
Similar to
inhabit, but maintains the structure of the original patterns. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern} @example note("<0 1 2!2 3>".pick(["g a", "e f", "f g f g" , "g c d"])) @example sound("<0 1 [2,0]>".pick(["bd sd", "cp cp", "hh hh"])) @example sound("<0!2 [0,1] 1>".pick(["bd(3,8)", "sd sd"])) @example s("<a!2 [a,b] b>".pick({a: "bd(3,8)", b: "sd sd"}))
- The same as
pick, but if you pick a number greater than the size of the list, it wraps around, rather than sticking at the maximum value. For example, if you pick the fifth pattern of a list of three, you'll get the second one. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
- pickF lets you use a pattern of numbers to pick which function to apply to another pattern. @tags combiners, functional @param {Pattern} pat @param {Pattern} lookup a pattern of indices or names @param {function[] | object} lookup the array or lookup object of functions from which to pull @returns {Pattern} @example s("bd [rim hh]").pickF("<0 1 2>", [rev,jux(rev),fast(2)]) @example note("<c2 d2>(3,8)").s("square") .pickF("<0 2> 1", [jux(rev), fast(2), x=>x.lpf(800)]) @example note("<c2 d2>(3,8)").s("square") .pickF("<jr l> f", { jr:jux(rev), f:fast(2), l:x=>x.lpf(800) })
- The same as
pickF, but if you pick a number greater than the size of the functions list, it wraps around, rather than sticking at the maximum value. @tags combiners @param {Pattern} pat @param {Pattern} lookup a pattern of indices or names @param {function[] | object} lookup the array or lookup object of functions from which to pull @returns {Pattern}
- Similar to
pick, but it applies an outerJoin instead of an innerJoin. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
- The same as
pickOut, but if you pick a number greater than the size of the list, it wraps around, rather than sticking at the maximum value. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
- Similar to
pick, but the choosen pattern is restarted when its index is triggered. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
- The same as
pickRestart, but if you pick a number greater than the size of the list, it wraps around, rather than sticking at the maximum value. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern} @example "<a@2 b@2 c@2 d@2>".pickRestart({ a: n("0 1 2 0"), b: n("2 3 4 ~"), c: n("[4 5] [4 3] 2 0"), d: n("0 -3 0 ~") }).scale("C:major").s("piano")
- Similar to
pick, but the choosen pattern is reset when its index is triggered. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
- The same as
pickReset, but if you pick a number greater than the size of the list, it wraps around, rather than sticking at the maximum value. @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
Similar to pick, but cycles are squeezed into the target ('inhabited') pattern.
@name inhabit
@tags combiners
@synonyms pickSqueeze
@param {Pattern} pat
@param {*} xs
@returns {Pattern}
@example
let a = s("bd(3,8)")
let b = s("cp sd")
"<a b [a,b]>".inhabit({ a, b })
@example
s("a@2 [a b] a"
.inhabit({a: "bd(3,8)", b: "sd sd"}))
.slow(4)
- The same as
inhabit, but if you pick a number greater than the size of the list, it wraps around, rather than sticking at the maximum value. For example, if you pick the fifth pattern of a list of three, you'll get the second one. @name inhabitmod @synonyms pickmodSqueeze @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern}
Pick from the list of values (or patterns of values) via the index using the given pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event @tags combiners @param {Pattern} pat @param {*} xs @returns {Pattern} @example note(squeeze("<0@2 [1!2] 2>", ["g a", "f g f g" , "g a c d"]))