Merge branch 'main' into origin/daslyfe/subcycle

This commit is contained in:
Jade (Rose) Rowland 2025-01-15 23:35:06 -05:00
commit 6e5d8eed19
7 changed files with 130 additions and 13 deletions

View file

@ -138,6 +138,18 @@ pnpm --filter "./packages/**" publish --access public
To manually publish a single package, increase the version in the `package.json`, then run `pnpm publish`. To manually publish a single package, increase the version in the `package.json`, then run `pnpm publish`.
Important: Always publish with `pnpm`, as `npm` does not support overriding main files in `publishConfig`, which is done in all the packages. Important: Always publish with `pnpm`, as `npm` does not support overriding main files in `publishConfig`, which is done in all the packages.
## useful commands
```sh
#regenerate the test snapshots (ex: when updating or creating new pattern functions)
pnpm snapshot
#start the OSC server
pnpm run osc
#build the standalone version
pnpm tauri build
```
## Have Fun ## Have Fun
Remember to have fun, and that this project is driven by the passion of volunteers! Remember to have fun, and that this project is driven by the passion of volunteers!

View file

@ -1491,6 +1491,14 @@ function _sequenceCount(x) {
export const mask = curry((a, b) => reify(b).mask(a)); export const mask = curry((a, b) => reify(b).mask(a));
export const struct = curry((a, b) => reify(b).struct(a)); export const struct = curry((a, b) => reify(b).struct(a));
export const superimpose = curry((a, b) => reify(b).superimpose(...a)); export const superimpose = curry((a, b) => reify(b).superimpose(...a));
export const withValue = curry((a, b) => reify(b).withValue(a));
export const bind = curry((a, b) => reify(b).bind(a));
export const innerBind = curry((a, b) => reify(b).innerBind(a));
export const outerBind = curry((a, b) => reify(b).outerBind(a));
export const squeezeBind = curry((a, b) => reify(b).squeezeBind(a));
export const stepBind = curry((a, b) => reify(b).stepBind(a));
export const polyBind = curry((a, b) => reify(b).polyBind(a));
// operators // operators
export const set = curry((a, b) => reify(b).set(a)); export const set = curry((a, b) => reify(b).set(a));
@ -2539,6 +2547,10 @@ Pattern.prototype.stepJoin = function () {
return new Pattern(q, first_t); return new Pattern(q, first_t);
}; };
Pattern.prototype.stepBind = function (func) {
return this.fmap(func).stepJoin();
};
export function _retime(timedHaps) { export function _retime(timedHaps) {
const occupied_perc = timedHaps.filter((t, pat) => pat.hasTactus).reduce((a, b) => a.add(b), Fraction(0)); const occupied_perc = timedHaps.filter((t, pat) => pat.hasTactus).reduce((a, b) => a.add(b), Fraction(0));
const occupied_tactus = removeUndefineds(timedHaps.map((t, pat) => pat.tactus)).reduce( const occupied_tactus = removeUndefineds(timedHaps.map((t, pat) => pat.tactus)).reduce(

View file

@ -7,7 +7,8 @@ This program is free software: you can redistribute it and/or modify it under th
import { Hap } from './hap.mjs'; import { Hap } from './hap.mjs';
import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs'; import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs';
import Fraction from './fraction.mjs'; import Fraction from './fraction.mjs';
import { id, _mod } from './util.mjs';
import { id, keyAlias, getCurrentKeyboardState } from './util.mjs';
export function steady(value) { export function steady(value) {
// A continuous value // A continuous value
@ -639,3 +640,48 @@ export const never = register('never', function (_, pat) {
export const always = register('always', function (func, pat) { export const always = register('always', function (func, pat) {
return func(pat); return func(pat);
}); });
//keyname: string | Array<string>
//keyname reference: https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values
export function _keyDown(keyname) {
if (Array.isArray(keyname) === false) {
keyname = [keyname];
}
const keyState = getCurrentKeyboardState();
return keyname.every((x) => {
const keyName = keyAlias.get(x) ?? x;
return keyState[keyName];
});
}
/**
*
* Do something on a keypress, or array of keypresses
* [Key name reference](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)
*
* @name whenKey
* @memberof Pattern
* @returns Pattern
* @example
* s("bd(5,8)").whenKey("Control:j", x => x.segment(16).color("red")).whenKey("Control:i", x => x.fast(2).color("blue"))
*/
export const whenKey = register('whenKey', function (input, func, pat) {
return pat.when(_keyDown(input), func);
});
/**
*
* returns true when a key or array of keys is held
* [Key name reference](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)
*
* @name keyDown
* @memberof Pattern
* @returns Pattern
* @example
* keyDown("Control:j").pick([s("bd(5,8)"), s("cp(3,8)")])
*/
export const keyDown = register('keyDown', function (pat) {
return pat.fmap(_keyDown);
});

View file

@ -434,6 +434,38 @@ function getUnixTimeSeconds() {
return Date.now() * 0.001; return Date.now() * 0.001;
} }
export const keyAlias = new Map([
['control', 'Control'],
['ctrl', 'Control'],
['alt', 'Alt'],
['shift', 'Shift'],
['down', 'ArrowDown'],
['up', 'ArrowUp'],
['left', 'ArrowLeft'],
['right', 'ArrowRight'],
]);
let keyState;
export function getCurrentKeyboardState() {
if (keyState == null) {
if (typeof window === 'undefined') {
return;
}
keyState = {};
// Listen for the keydown event to mark the key as pressed
window.addEventListener('keydown', (event) => {
keyState[event.key] = true; // Mark the key as pressed
});
// Listen for the keyup event to mark the key as released
window.addEventListener('keyup', (event) => {
keyState[event.key] = false; // Mark the key as released
});
}
return { ...keyState }; // Return a shallow copy of the key state object
}
// Floating point versions, see Fraction for rational versions // Floating point versions, see Fraction for rational versions
// // greatest common divisor // // greatest common divisor
// export const gcd = function (x, y, ...z) { // export const gcd = function (x, y, ...z) {

22
pnpm-lock.yaml generated
View file

@ -331,6 +331,19 @@ importers:
specifier: ^2.1.3 specifier: ^2.1.3
version: 2.1.3(@types/node@22.7.6)(@vitest/ui@2.1.3)(terser@5.36.0) version: 2.1.3(@types/node@22.7.6)(@vitest/ui@2.1.3)(terser@5.36.0)
packages/mqtt:
dependencies:
'@strudel/core':
specifier: workspace:*
version: link:../core
paho-mqtt:
specifier: ^1.1.0
version: 1.1.0
devDependencies:
vite:
specifier: ^5.0.10
version: 5.4.9(@types/node@22.7.6)(terser@5.36.0)
packages/osc: packages/osc:
dependencies: dependencies:
'@strudel/core': '@strudel/core':
@ -623,6 +636,9 @@ importers:
'@strudel/mini': '@strudel/mini':
specifier: workspace:* specifier: workspace:*
version: link:../packages/mini version: link:../packages/mini
'@strudel/mqtt':
specifier: workspace:*
version: link:../packages/mqtt
'@strudel/osc': '@strudel/osc':
specifier: workspace:* specifier: workspace:*
version: link:../packages/osc version: link:../packages/osc
@ -5991,6 +6007,9 @@ packages:
engines: {node: ^16.14.0 || >=18.0.0} engines: {node: ^16.14.0 || >=18.0.0}
hasBin: true hasBin: true
paho-mqtt@1.1.0:
resolution: {integrity: sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA==}
parent-module@1.0.1: parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -7740,6 +7759,7 @@ packages:
workbox-google-analytics@7.0.0: workbox-google-analytics@7.0.0:
resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} 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: workbox-navigation-preload@7.0.0:
resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==} resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==}
@ -14686,6 +14706,8 @@ snapshots:
- bluebird - bluebird
- supports-color - supports-color
paho-mqtt@1.1.0: {}
parent-module@1.0.1: parent-module@1.0.1:
dependencies: dependencies:
callsites: 3.1.0 callsites: 3.1.0

View file

@ -4095,6 +4095,8 @@ exports[`runs examples > example "juxBy" example index 0 1`] = `
] ]
`; `;
exports[`runs examples > example "keyDown" example index 0 1`] = `[]`;
exports[`runs examples > example "lastOf" example index 0 1`] = ` exports[`runs examples > example "lastOf" example index 0 1`] = `
[ [
"[ 0/1 → 1/4 | note:c3 ]", "[ 0/1 → 1/4 | note:c3 ]",
@ -8862,6 +8864,8 @@ exports[`runs examples > example "when" example index 0 1`] = `
] ]
`; `;
exports[`runs examples > example "whenKey" example index 0 1`] = `[]`;
exports[`runs examples > example "withValue" example index 0 1`] = ` exports[`runs examples > example "withValue" example index 0 1`] = `
[ [
"[ 0/1 → 1/3 | 10 ]", "[ 0/1 → 1/3 | 10 ]",

View file

@ -82,18 +82,7 @@ To modify a parameter value, you can either:
<MiniRepl client:only="react" tune={`note("50 60 70").room(.1).add(note("<0 1 2>")).log()`} /> <MiniRepl client:only="react" tune={`note("50 60 70").room(.1).add(note("<0 1 2>")).log()`} />
- Modify _all_ numeral params: Remember the execution of the chained functions goes from left to right.
<MiniRepl client:only="react" tune={`note("50 60 70").room(.1).add("<0 1 2>").log()`} />
Which of these 3 ways to use strongly depends on the context!
Note that the order of chaining param functions also matters!
In the last example, the `room` value would not have changed if it was applied later:
<MiniRepl client:only="react" tune={`note("50 60 70").add("<0 1 2>").room(.1).log()`} />
This shows how the execution of the chained functions goes from left to right.
In this case, the `.add` will only modify what's on the left side.
# Operators # Operators