diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs
index d1408809..f48cc55e 100644
--- a/packages/core/signal.mjs
+++ b/packages/core/signal.mjs
@@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
import { Hap } from './hap.mjs';
import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs';
import Fraction from './fraction.mjs';
-import { id } from './util.mjs';
+import { id, _mod, clamp } from './util.mjs';
export function steady(value) {
// A continuous value
@@ -155,6 +155,52 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
*/
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
+/**
+ * pick from the list of values (or patterns of values) via the index using the given
+ * pattern of integers
+ * @param {Pattern} pat
+ * @param {*} xs
+ * @returns {Pattern}
+ * @example
+ * note(pick("<0 1 [2!2] 3>", ["g a", "e f", "f g f g" , "g a c d"]))
+ */
+
+export const pick = (pat, xs) => {
+ xs = xs.map(reify);
+ if (xs.length == 0) {
+ return silence;
+ }
+ return pat
+ .fmap((i) => {
+ const key = clamp(Math.round(i), 0, xs.length - 1);
+ return xs[key];
+ })
+ .innerJoin();
+};
+
+/**
+ * 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
+ * @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"]))
+ */
+
+export const squeeze = (pat, xs) => {
+ xs = xs.map(reify);
+ if (xs.length == 0) {
+ return silence;
+ }
+ return pat
+ .fmap((i) => {
+ const key = _mod(Math.round(i), xs.length);
+ return xs[key];
+ })
+ .squeezeJoin();
+};
+
export const __chooseWith = (pat, xs) => {
xs = xs.map(reify);
if (xs.length == 0) {
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index b37af3e9..d3077e24 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -3275,6 +3275,23 @@ exports[`runs examples > example "perlin" example index 0 1`] = `
]
`;
+exports[`runs examples > example "pick" example index 0 1`] = `
+[
+ "[ 0/1 → 1/2 | note:g ]",
+ "[ 1/2 → 1/1 | note:a ]",
+ "[ 1/1 → 3/2 | note:e ]",
+ "[ 3/2 → 2/1 | note:f ]",
+ "[ 2/1 → 9/4 | note:f ]",
+ "[ 9/4 → 5/2 | note:g ]",
+ "[ 5/2 → 11/4 | note:f ]",
+ "[ 11/4 → 3/1 | note:g ]",
+ "[ 3/1 → 13/4 | note:g ]",
+ "[ 13/4 → 7/2 | note:a ]",
+ "[ 7/2 → 15/4 | note:c ]",
+ "[ 15/4 → 4/1 | note:d ]",
+]
+`;
+
exports[`runs examples > example "ply" example index 0 1`] = `
[
"[ 0/1 → 1/4 | s:bd ]",
@@ -4612,6 +4629,25 @@ exports[`runs examples > example "square" example index 0 1`] = `
]
`;
+exports[`runs examples > example "squeeze" example index 0 1`] = `
+[
+ "[ 0/1 → 1/1 | note:g ]",
+ "[ 1/1 → 2/1 | note:a ]",
+ "[ 2/1 → 17/8 | note:f ]",
+ "[ 17/8 → 9/4 | note:g ]",
+ "[ 9/4 → 19/8 | note:f ]",
+ "[ 19/8 → 5/2 | note:g ]",
+ "[ 5/2 → 21/8 | note:f ]",
+ "[ 21/8 → 11/4 | note:g ]",
+ "[ 11/4 → 23/8 | note:f ]",
+ "[ 23/8 → 3/1 | note:g ]",
+ "[ 3/1 → 13/4 | note:g ]",
+ "[ 13/4 → 7/2 | note:a ]",
+ "[ 7/2 → 15/4 | note:c ]",
+ "[ 15/4 → 4/1 | note:d ]",
+]
+`;
+
exports[`runs examples > example "squiz" example index 0 1`] = `
[
"[ 0/1 → 1/4 | squiz:2 s:bd ]",
diff --git a/website/src/pages/learn/conditional-modifiers.mdx b/website/src/pages/learn/conditional-modifiers.mdx
index 2bc4b42d..d66b2698 100644
--- a/website/src/pages/learn/conditional-modifiers.mdx
+++ b/website/src/pages/learn/conditional-modifiers.mdx
@@ -60,4 +60,12 @@ import { JsDoc } from '../../docs/JsDoc';
+## pick
+
+
+
+## squeeze
+
+
+
After Conditional Modifiers, let's see what [Accumulation Modifiers](/learn/accumulation) have to offer.