From 33fef379ada6fd96001510f5dc2f64eb01756738 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:35:09 -0400 Subject: [PATCH 1/9] Get a basic version of binary working --- packages/core/signal.mjs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 215eac2f4..c5eff43d6 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -159,6 +159,17 @@ const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n); */ export const run = (n) => saw.range(0, n).floor().segment(n); +/** + * A discrete binary pattern using a decimal/hex number as input + * @example + * "c a f e".struct(binary(0xA5B5)).note().piano() + * // "c a f e".struct("0 1 0 1 0 1 0 1 1 0 1 0 1").note().piano() + */ +export const binary = (n) => { + const binLen = 16; + return reify(n).segment(binLen).brshift(run(binLen)).band(pure(1)); +}; + export const randrun = (n) => { return signal((t) => { // Without adding 0.5, the first cycle is always 0,1,2,3,... From 0d660277f6c1c4f83e8163e98b616d35a0af77fc Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:36:29 -0400 Subject: [PATCH 2/9] Put msb on the right --- packages/core/signal.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index c5eff43d6..8d033499c 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -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, reify, silence, stack, register } from './pattern.mjs'; +import { Pattern, fastcat, pure, register, reify, silence, stack } from './pattern.mjs'; import Fraction from './fraction.mjs'; import { id, _mod } from './util.mjs'; @@ -167,7 +167,9 @@ export const run = (n) => saw.range(0, n).floor().segment(n); */ export const binary = (n) => { const binLen = 16; - return reify(n).segment(binLen).brshift(run(binLen)).band(pure(1)); + // Shift right and mask, with msb at the end/right-side + const i = run(binLen).mul(-1).add(binLen - 1) + return reify(n).segment(binLen).brshift(i).band(pure(1)); }; export const randrun = (n) => { From 0a408e464a7c9b32f0ba2c56081d5d0d919787a3 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:39:45 -0400 Subject: [PATCH 3/9] Make example more concise --- packages/core/signal.mjs | 4 +-- test/__snapshots__/examples.test.mjs.snap | 41 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 8d033499c..8340bc9f1 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -162,8 +162,8 @@ export const run = (n) => saw.range(0, n).floor().segment(n); /** * A discrete binary pattern using a decimal/hex number as input * @example - * "c a f e".struct(binary(0xA5B5)).note().piano() - * // "c a f e".struct("0 1 0 1 0 1 0 1 1 0 1 0 1").note().piano() + * "hh".s().struct(binary(55532)) + * // "hh".s().struct("1 1 0 1 1 0 0 0 1 1 1 0 1 1 0 0") */ export const binary = (n) => { const binLen = 16; diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 3ad6ea01e..fd7169c5a 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -967,6 +967,47 @@ exports[`runs examples > example "begin" example index 0 1`] = ` ] `; +exports[`runs examples > example "binary" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | s:hh ]", + "[ 1/16 → 1/8 | s:hh ]", + "[ 3/16 → 1/4 | s:hh ]", + "[ 1/4 → 5/16 | s:hh ]", + "[ 1/2 → 9/16 | s:hh ]", + "[ 9/16 → 5/8 | s:hh ]", + "[ 5/8 → 11/16 | s:hh ]", + "[ 3/4 → 13/16 | s:hh ]", + "[ 13/16 → 7/8 | s:hh ]", + "[ 1/1 → 17/16 | s:hh ]", + "[ 17/16 → 9/8 | s:hh ]", + "[ 19/16 → 5/4 | s:hh ]", + "[ 5/4 → 21/16 | s:hh ]", + "[ 3/2 → 25/16 | s:hh ]", + "[ 25/16 → 13/8 | s:hh ]", + "[ 13/8 → 27/16 | s:hh ]", + "[ 7/4 → 29/16 | s:hh ]", + "[ 29/16 → 15/8 | s:hh ]", + "[ 2/1 → 33/16 | s:hh ]", + "[ 33/16 → 17/8 | s:hh ]", + "[ 35/16 → 9/4 | s:hh ]", + "[ 9/4 → 37/16 | s:hh ]", + "[ 5/2 → 41/16 | s:hh ]", + "[ 41/16 → 21/8 | s:hh ]", + "[ 21/8 → 43/16 | s:hh ]", + "[ 11/4 → 45/16 | s:hh ]", + "[ 45/16 → 23/8 | s:hh ]", + "[ 3/1 → 49/16 | s:hh ]", + "[ 49/16 → 25/8 | s:hh ]", + "[ 51/16 → 13/4 | s:hh ]", + "[ 13/4 → 53/16 | s:hh ]", + "[ 7/2 → 57/16 | s:hh ]", + "[ 57/16 → 29/8 | s:hh ]", + "[ 29/8 → 59/16 | s:hh ]", + "[ 15/4 → 61/16 | s:hh ]", + "[ 61/16 → 31/8 | s:hh ]", +] +`; + exports[`runs examples > example "bite" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:Bb3 ]", From 947b263b9ccccf10279cfe31746c7f69b5a48e42 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:40:29 -0400 Subject: [PATCH 4/9] Add tests --- packages/core/test/pattern.test.mjs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 31ec48681..03f2c60f0 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -46,6 +46,7 @@ import { rev, time, run, + binary, pick, stackLeft, stackRight, @@ -958,6 +959,18 @@ describe('Pattern', () => { expect(run(4).firstCycle()).toStrictEqual(sequence(0, 1, 2, 3).firstCycle()); }); }); + describe('binary', () => { + it('Can make a binary pattern from a decimal', () => { + expect(binary(55532).firstCycle()).toStrictEqual( + sequence(1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0).firstCycle(), + ); + }); + it('Can make a binary pattern from a numerical pattern', () => { + expect(binary(pure(0x1337)).firstCycle()).toStrictEqual( + sequence(0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1).firstCycle(), + ); + }); + }); describe('ribbon', () => { it('Can ribbon', () => { expect(cat(0, 1, 2, 3, 4, 5, 6, 7).ribbon(2, 4).fast(4).firstCycle()).toStrictEqual( From 34f4afad0158fe8de7c251f588ccd76357160855 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:41:37 -0400 Subject: [PATCH 5/9] Rework binary to binaryN --- packages/core/signal.mjs | 17 ++++++++++------- packages/core/test/pattern.test.mjs | 12 ++++++------ test/__snapshots__/examples.test.mjs.snap | 3 ++- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 8340bc9f1..6c905b552 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -160,16 +160,19 @@ const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n); export const run = (n) => saw.range(0, n).floor().segment(n); /** - * A discrete binary pattern using a decimal/hex number as input + * @name binaryN + * Creates a discrete pattern using binary representation. + * @param {number} n - input number to convert to binary + * @param {number} nBits - pattern length, defaults to 16 * @example - * "hh".s().struct(binary(55532)) + * "hh".s().struct(binaryN(55532, 16)) * // "hh".s().struct("1 1 0 1 1 0 0 0 1 1 1 0 1 1 0 0") */ -export const binary = (n) => { - const binLen = 16; - // Shift right and mask, with msb at the end/right-side - const i = run(binLen).mul(-1).add(binLen - 1) - return reify(n).segment(binLen).brshift(i).band(pure(1)); +export const binaryN = (n, nBits = 16) => { + nBits = reify(nBits); + // Shift and mask, putting msb on the right-side + const i = run(nBits).mul(-1).add(nBits.sub(1)); + return reify(n).segment(nBits).brshift(i).band(pure(1)); }; export const randrun = (n) => { diff --git a/packages/core/test/pattern.test.mjs b/packages/core/test/pattern.test.mjs index 03f2c60f0..7e6d8fd82 100644 --- a/packages/core/test/pattern.test.mjs +++ b/packages/core/test/pattern.test.mjs @@ -46,7 +46,7 @@ import { rev, time, run, - binary, + binaryN, pick, stackLeft, stackRight, @@ -959,15 +959,15 @@ describe('Pattern', () => { expect(run(4).firstCycle()).toStrictEqual(sequence(0, 1, 2, 3).firstCycle()); }); }); - describe('binary', () => { + describe('binaryN', () => { it('Can make a binary pattern from a decimal', () => { - expect(binary(55532).firstCycle()).toStrictEqual( + expect(binaryN(55532).firstCycle()).toStrictEqual( sequence(1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0).firstCycle(), ); }); - it('Can make a binary pattern from a numerical pattern', () => { - expect(binary(pure(0x1337)).firstCycle()).toStrictEqual( - sequence(0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1).firstCycle(), + it('Can make a binary pattern from patterned inputs', () => { + expect(binaryN(pure(0x1337), pure(14)).firstCycle()).toStrictEqual( + sequence(0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1).firstCycle(), ); }); }); diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index fd7169c5a..6dce57390 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -967,7 +967,8 @@ exports[`runs examples > example "begin" example index 0 1`] = ` ] `; -exports[`runs examples > example "binary" example index 0 1`] = ` +exports[`runs examples > example "binaryN +Creates a discrete pattern using binary representation." example index 0 1`] = ` [ "[ 0/1 → 1/16 | s:hh ]", "[ 1/16 → 1/8 | s:hh ]", From 4cc019f038cec10ca01bac08f5c8e4303f528404 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:48:47 -0400 Subject: [PATCH 6/9] Rename variable --- packages/core/signal.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 6c905b552..c29c0399b 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -171,8 +171,8 @@ export const run = (n) => saw.range(0, n).floor().segment(n); export const binaryN = (n, nBits = 16) => { nBits = reify(nBits); // Shift and mask, putting msb on the right-side - const i = run(nBits).mul(-1).add(nBits.sub(1)); - return reify(n).segment(nBits).brshift(i).band(pure(1)); + const bitPos = run(nBits).mul(-1).add(nBits.sub(1)); + return reify(n).segment(nBits).brshift(bitPos).band(pure(1)); }; export const randrun = (n) => { From f87f2791984057dcd8aa9da3e4931c0a204f47a0 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:43:13 -0400 Subject: [PATCH 7/9] Support those who prefer no left padding --- packages/core/pattern.mjs | 1 + packages/core/signal.mjs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index f3f19f874..35f9cb6a8 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1023,6 +1023,7 @@ function _composeOp(a, b, func) { div: [numeralArgs((a, b) => a / b)], mod: [numeralArgs(_mod)], pow: [numeralArgs(Math.pow)], + log2: [numeralArgs(Math.log2)], band: [numeralArgs((a, b) => a & b)], bor: [numeralArgs((a, b) => a | b)], bxor: [numeralArgs((a, b) => a ^ b)], diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index c29c0399b..5f61fe7ac 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -159,6 +159,19 @@ const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n); */ export const run = (n) => saw.range(0, n).floor().segment(n); +/** + * @name binary + * Creates a discrete pattern using binary representation. + * @param {number} n - input number to convert to binary + * @example + * "hh".s().struct(binary(5)) + * // "hh".s().struct("1 0 1") + */ +export const binary = (n) => { + const nBits = reify(n).log2(0).floor().add(1); + return binaryN(n, nBits) +}; + /** * @name binaryN * Creates a discrete pattern using binary representation. From 111cea23819ded11232d3687d0e81f70427771ea Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Mon, 16 Dec 2024 21:31:21 -0500 Subject: [PATCH 8/9] Fix lint --- packages/core/signal.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 5f61fe7ac..746b207d2 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -169,7 +169,7 @@ export const run = (n) => saw.range(0, n).floor().segment(n); */ export const binary = (n) => { const nBits = reify(n).log2(0).floor().add(1); - return binaryN(n, nBits) + return binaryN(n, nBits); }; /** From 7cf7575e6d5b61fcab87ab1f84499844227ca502 Mon Sep 17 00:00:00 2001 From: Luke Heerman <43624284+heerman@users.noreply.github.com> Date: Tue, 17 Dec 2024 08:49:49 -0500 Subject: [PATCH 9/9] Make the docs friendlier --- packages/core/signal.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 746b207d2..31fdbb6ab 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -161,7 +161,7 @@ export const run = (n) => saw.range(0, n).floor().segment(n); /** * @name binary - * Creates a discrete pattern using binary representation. + * Creates a pattern from a binary number. * @param {number} n - input number to convert to binary * @example * "hh".s().struct(binary(5)) @@ -174,7 +174,7 @@ export const binary = (n) => { /** * @name binaryN - * Creates a discrete pattern using binary representation. + * Creates a pattern from a binary number, padded to n bits long. * @param {number} n - input number to convert to binary * @param {number} nBits - pattern length, defaults to 16 * @example