diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index e8c66171..fd924cbc 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -1,5 +1,5 @@ import { Hap } from './hap.mjs'; -import { Pattern, fastcat } from './pattern.mjs'; +import { Pattern, fastcat, reify, silence } from './pattern.mjs'; import Fraction from './fraction.mjs'; export function steady(value) { @@ -29,23 +29,22 @@ export const square2 = square._toBipolar(); export const tri = fastcat(isaw, saw); export const tri2 = fastcat(isaw2, saw2); - // random signals -const xorwise = x => { - const a = (x << 13) ^ x - const b = (a >> 17) ^ a - return (b << 5) ^ b -} +const xorwise = (x) => { + const a = (x << 13) ^ x; + const b = (a >> 17) ^ a; + return (b << 5) ^ b; +}; // stretch 300 cycles over the range of [0,2**29 == 536870912) then apply the xorshift algorithm -const _frac = x => x - Math.trunc(x); +const _frac = (x) => x - Math.trunc(x); -const timeToIntSeed = x => xorwise(Math.trunc(_frac(x / 300) * 536870912)); +const timeToIntSeed = (x) => xorwise(Math.trunc(_frac(x / 300) * 536870912)); -const intSeedToRand = x => (x % 536870912) / 536870912; +const intSeedToRand = (x) => (x % 536870912) / 536870912; -const timeToRand = x => intSeedToRand(timeToIntSeed(x)); +const timeToRand = (x) => intSeedToRand(timeToIntSeed(x)); const timeToRandsPrime = (seed, n) => { const result = []; @@ -53,9 +52,26 @@ const timeToRandsPrime = (seed, n) => { result.push(intSeedToRand(seed)); seed = xorwise(seed); } - return(result); -} + return result; +}; -const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n) +const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n); -export const rand = signal(timeToRand) +export const rand2 = signal(timeToRand); +export const rand = rand2.fmap(Math.abs); + +export const _brandBy = (p) => rand.fmap((x) => x < p); +export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin(); +export const brand = _brandBy(0.5); + +export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i)); +export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); + +export const chooseWith = (pat, xs) => { + if (xs.length == 0) { + return silence; + } + return pat.range(0, xs.length).fmap((i) => xs[Math.floor(i)]); +}; + +export const choose = (...xs) => chooseWith(rand, xs); diff --git a/repl/src/useCycle.mjs b/repl/src/useCycle.mjs index 908193f9..2e6cad42 100644 --- a/repl/src/useCycle.mjs +++ b/repl/src/useCycle.mjs @@ -39,7 +39,7 @@ function useCycle(props) { // schedule events for next cycle events - ?.filter((event) => event.part.begin.equals(event.whole.begin)) + ?.filter((event) => event.part.begin.equals(event.whole?.begin)) .forEach((event) => { Tone.getTransport().schedule((time) => { onEvent(time, event, Tone.getContext().currentTime);