Allow wchooseCycles probabilities to be patterned (#1292)

* allow wchooseCycles probabilities to be patterned
This commit is contained in:
Alex McLean 2025-02-23 09:52:27 +00:00 committed by GitHub
parent 1f233b9e7d
commit 0925ea56dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 181 additions and 8 deletions

View File

@ -59,6 +59,7 @@
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@tauri-apps/cli": "^2.2.7",
"@vitest/coverage-v8": "3.0.4",
"@vitest/ui": "^3.0.4",
"acorn": "^8.14.0",
"dependency-tree": "^11.0.1",

View File

@ -1244,6 +1244,16 @@ export function reify(thing) {
return pure(thing);
}
/** Takes a list of patterns, and returns a pattern of lists.
*/
export function sequenceP(pats) {
let result = pure([]);
for (const pat of pats) {
result = result.bind((list) => pat.fmap((v) => list.concat([v])));
}
return result;
}
/** The given items are played at the same time at the same length.
*
* @return {Pattern}

View File

@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/
import { Hap } from './hap.mjs';
import { Pattern, fastcat, pure, register, reify, silence, stack } from './pattern.mjs';
import { Pattern, fastcat, pure, register, reify, silence, stack, sequenceP } from './pattern.mjs';
import Fraction from './fraction.mjs';
import { id, keyAlias, getCurrentKeyboardState } from './util.mjs';
@ -433,19 +433,30 @@ export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs);
export const randcat = chooseCycles;
const _wchooseWith = function (pat, ...pairs) {
// A list of patterns of values
const values = pairs.map((pair) => reify(pair[0]));
// A list of weight patterns
const weights = [];
let accum = 0;
let total = pure(0);
for (const pair of pairs) {
accum += pair[1];
weights.push(accum);
// 'add' accepts either values or patterns of values here, so no need
// to explicitly reify
total = total.add(pair[1]);
// accumulate our list of weight patterns
weights.push(total);
}
const total = accum;
// a pattern of lists of weights
const weightspat = sequenceP(weights);
// Takes a number from 0-1, returns a pattern of patterns of values
const match = function (r) {
const find = r * total;
return values[weights.findIndex((x) => x > find, weights)];
const findpat = total.mul(r);
return weightspat.fmap((weights) => (find) => values[weights.findIndex((x) => x > find, weights)]).appLeft(findpat);
};
return pat.fmap(match);
// This returns a pattern of patterns.. The innerJoin is in wchooseCycles
return pat.bind(match);
};
const wchooseWith = (...args) => _wchooseWith(...args).outerJoin();
@ -467,6 +478,9 @@ export const wchoose = (...pairs) => wchooseWith(rand, ...pairs);
* wchooseCycles(["bd",10], ["hh",1], ["sd",1]).s().fast(8)
* @example
* wchooseCycles(["bd bd bd",5], ["hh hh hh",3], ["sd sd sd",1]).fast(4).s()
* @example
* // The probability can itself be a pattern
* wchooseCycles(["bd(3,8)","<5 0>"], ["hh hh hh",3]).fast(4).s()
*/
export const wchooseCycles = (...pairs) => _wchooseWith(rand.segment(1), ...pairs).innerJoin();

95
pnpm-lock.yaml generated
View File

@ -39,6 +39,9 @@ importers:
'@tauri-apps/cli':
specifier: ^2.2.7
version: 2.2.7
'@vitest/coverage-v8':
specifier: 3.0.4
version: 3.0.4(vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.10.10)(@vitest/ui@3.0.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(yaml@2.7.0))
'@vitest/ui':
specifier: ^3.0.4
version: 3.0.4(vitest@3.0.4)
@ -1412,6 +1415,10 @@ packages:
resolution: {integrity: sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==}
engines: {node: '>=6.9.0'}
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
'@codemirror/autocomplete@6.18.4':
resolution: {integrity: sha512-sFAphGQIqyQZfP2ZBsSHV7xQvo9Py0rV0dW7W3IMRdS+zDuNb2l3no78CvUaWKGfzFjI4FTrLdUSj86IGb2hRA==}
@ -1834,6 +1841,10 @@ packages:
'@isaacs/string-locale-compare@1.1.0':
resolution: {integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==}
'@istanbuljs/schema@0.1.3':
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
'@jest/schemas@29.6.3':
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -2818,6 +2829,15 @@ packages:
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
'@vitest/coverage-v8@3.0.4':
resolution: {integrity: sha512-f0twgRCHgbs24Dp8cLWagzcObXMcuKtAwgxjJV/nnysPAJJk1JiKu/W0gIehZLmkljhJXU/E0/dmuQzsA/4jhA==}
peerDependencies:
'@vitest/browser': 3.0.4
vitest: 3.0.4
peerDependenciesMeta:
'@vitest/browser':
optional: true
'@vitest/expect@3.0.4':
resolution: {integrity: sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==}
@ -4487,6 +4507,9 @@ packages:
hs2js@0.1.0:
resolution: {integrity: sha512-THlUIMX8tZf6gtbz5RUZ8xQUyKJEItsx7bxEBcouFIEWjeo90376WMocj3JEz6qTv5nM+tjo3vNvLf89XruMvg==}
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
html-escaper@3.0.3:
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
@ -4837,6 +4860,22 @@ packages:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}
istanbul-lib-coverage@3.2.2:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
engines: {node: '>=10'}
istanbul-lib-source-maps@5.0.6:
resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
engines: {node: '>=10'}
istanbul-reports@3.1.7:
resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
engines: {node: '>=8'}
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
@ -6887,6 +6926,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
test-exclude@7.0.1:
resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
engines: {node: '>=18'}
text-encoding-shim@1.0.5:
resolution: {integrity: sha512-H7yYW+jRn4yhu60ygZ2f/eMhXPITRt4QSUTKzLm+eCaDsdX8avmgWpmtmHAzesjBVUTAypz9odu5RKUjX5HNYA==}
@ -7505,6 +7548,7 @@ packages:
workbox-google-analytics@7.0.0:
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==}
deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
workbox-navigation-preload@7.0.0:
resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==}
@ -8568,6 +8612,8 @@ snapshots:
'@babel/helper-string-parser': 7.25.9
'@babel/helper-validator-identifier': 7.25.9
'@bcoe/v8-coverage@1.0.2': {}
'@codemirror/autocomplete@6.18.4':
dependencies:
'@codemirror/language': 6.10.8
@ -8934,6 +8980,8 @@ snapshots:
'@isaacs/string-locale-compare@1.1.0': {}
'@istanbuljs/schema@0.1.3': {}
'@jest/schemas@29.6.3':
dependencies:
'@sinclair/typebox': 0.27.8
@ -10187,6 +10235,24 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitest/coverage-v8@3.0.4(vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.10.10)(@vitest/ui@3.0.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(yaml@2.7.0))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 1.0.2
debug: 4.4.0
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.1.7
magic-string: 0.30.17
magicast: 0.3.5
std-env: 3.8.0
test-exclude: 7.0.1
tinyrainbow: 2.0.0
vitest: 3.0.4(@types/debug@4.1.12)(@types/node@22.10.10)(@vitest/ui@3.0.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
'@vitest/expect@3.0.4':
dependencies:
'@vitest/spy': 3.0.4
@ -12202,6 +12268,8 @@ snapshots:
dependencies:
web-tree-sitter: 0.20.8
html-escaper@2.0.2: {}
html-escaper@3.0.3: {}
html-void-elements@3.0.0: {}
@ -12540,6 +12608,27 @@ snapshots:
isobject@3.0.1: {}
istanbul-lib-coverage@3.2.2: {}
istanbul-lib-report@3.0.1:
dependencies:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
istanbul-lib-source-maps@5.0.6:
dependencies:
'@jridgewell/trace-mapping': 0.3.25
debug: 4.4.0
istanbul-lib-coverage: 3.2.2
transitivePeerDependencies:
- supports-color
istanbul-reports@3.1.7:
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.1
jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
@ -15262,6 +15351,12 @@ snapshots:
commander: 2.20.3
source-map-support: 0.5.21
test-exclude@7.0.1:
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 10.4.5
minimatch: 9.0.5
text-encoding-shim@1.0.5: {}
text-extensions@1.9.0: {}

View File

@ -9687,6 +9687,59 @@ exports[`runs examples > example "wchooseCycles" example index 1 1`] = `
]
`;
exports[`runs examples > example "wchooseCycles" example index 2 1`] = `
[
"[ 0/1 → 1/32 | s:bd ]",
"[ 3/32 → 1/8 | s:bd ]",
"[ 3/16 → 7/32 | s:bd ]",
"[ 1/4 → 1/3 | s:hh ]",
"[ 1/3 → 5/12 | s:hh ]",
"[ 5/12 → 1/2 | s:hh ]",
"[ 1/2 → 7/12 | s:hh ]",
"[ 7/12 → 2/3 | s:hh ]",
"[ 2/3 → 3/4 | s:hh ]",
"[ 3/4 → 5/6 | s:hh ]",
"[ 5/6 → 11/12 | s:hh ]",
"[ 11/12 → 1/1 | s:hh ]",
"[ 1/1 → 33/32 | s:bd ]",
"[ 35/32 → 9/8 | s:bd ]",
"[ 19/16 → 39/32 | s:bd ]",
"[ 5/4 → 4/3 | s:hh ]",
"[ 4/3 → 17/12 | s:hh ]",
"[ 17/12 → 3/2 | s:hh ]",
"[ 3/2 → 49/32 | s:bd ]",
"[ 51/32 → 13/8 | s:bd ]",
"[ 27/16 → 55/32 | s:bd ]",
"[ 7/4 → 11/6 | s:hh ]",
"[ 11/6 → 23/12 | s:hh ]",
"[ 23/12 → 2/1 | s:hh ]",
"[ 2/1 → 25/12 | s:hh ]",
"[ 25/12 → 13/6 | s:hh ]",
"[ 13/6 → 9/4 | s:hh ]",
"[ 9/4 → 7/3 | s:hh ]",
"[ 7/3 → 29/12 | s:hh ]",
"[ 29/12 → 5/2 | s:hh ]",
"[ 5/2 → 81/32 | s:bd ]",
"[ 83/32 → 21/8 | s:bd ]",
"[ 43/16 → 87/32 | s:bd ]",
"[ 11/4 → 17/6 | s:hh ]",
"[ 17/6 → 35/12 | s:hh ]",
"[ 35/12 → 3/1 | s:hh ]",
"[ 3/1 → 97/32 | s:bd ]",
"[ 99/32 → 25/8 | s:bd ]",
"[ 51/16 → 103/32 | s:bd ]",
"[ 13/4 → 10/3 | s:hh ]",
"[ 10/3 → 41/12 | s:hh ]",
"[ 41/12 → 7/2 | s:hh ]",
"[ 7/2 → 43/12 | s:hh ]",
"[ 43/12 → 11/3 | s:hh ]",
"[ 11/3 → 15/4 | s:hh ]",
"[ 15/4 → 23/6 | s:hh ]",
"[ 23/6 → 47/12 | s:hh ]",
"[ 47/12 → 4/1 | s:hh ]",
]
`;
exports[`runs examples > example "when" example index 0 1`] = `
[
"[ 0/1 → 1/3 | note:c3 ]",