From 5d5159a08f62c171ab4477ff4aeca87caa5f6ba9 Mon Sep 17 00:00:00 2001 From: Aria Date: Sun, 24 Aug 2025 11:56:11 -0500 Subject: [PATCH] Add option to use old random and a benchmark --- packages/core/bench/signal.bench.mjs | 46 ++++++++++++++++++++++++++++ packages/core/signal.mjs | 35 ++++++++++++++++++++- website/src/repl/tunes.mjs | 19 ++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 packages/core/bench/signal.bench.mjs diff --git a/packages/core/bench/signal.bench.mjs b/packages/core/bench/signal.bench.mjs new file mode 100644 index 00000000..c79cedc0 --- /dev/null +++ b/packages/core/bench/signal.bench.mjs @@ -0,0 +1,46 @@ +import { describe, bench } from 'vitest'; + +import { calculateSteps, rand, useOldRandom } from '../index.mjs'; + +const testingResolution = 1024; + +const _generateRandomPattern = () => rand.iter(testingResolution).fast(testingResolution).firstCycle(); + +describe('random', () => { + calculateSteps(true); + bench( + '+tactus', + _generateRandomPattern, + { time: 1000 }, + ); + + calculateSteps(false); + bench( + '-tactus', + _generateRandomPattern, + { time: 1000 }, + ); +}); + +describe('old random', () => { + calculateSteps(true); + bench( + '+tactus', + () => { + useOldRandom(); + _generateRandomPattern(); + }, + { time: 1000 }, + ); + + calculateSteps(false); + bench( + '-tactus', + () => { + useOldRandom(); + _generateRandomPattern(); + }, + { time: 1000 }, + ); +}); +calculateSteps(true); diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 1c3ae464..91901f86 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -186,7 +186,7 @@ export const mouseY = signal(() => _mouseY); export const mousex = signal(() => _mouseX); export const mouseX = signal(() => _mouseX); -// random signals +// Random number generators // Produce "Avalanche effect" where flipping a single bit of x // results in all output bits flipping with probability 0.5 @@ -215,8 +215,38 @@ function randAt(t, i = 0) { return _murmurHashFinalizer(_decorrelate(t, i)) / 4294967296; // 2^32 } +// Deprecated: Old random signals. Configuration `useOldRandom` may be used for legacy songs + +// stretch 300 cycles over the range of [0,2**29 == 536870912) then apply the xorshift algorithm +const __xorwise = (x) => { + const a = (x << 13) ^ x; + const b = (a >> 17) ^ a; + return (b << 5) ^ b; +}; +const __frac = (x) => x - Math.trunc(x); +const __timeToIntSeed = (x) => __xorwise(Math.trunc(__frac(x / 300) * 536870912)); +const __intSeedToRand = (x) => (x % 536870912) / 536870912; +const __timeToRand = (x) => Math.abs(__intSeedToRand(__timeToIntSeed(x))); +const __timeToRandsPrime = (seed, n) => { + const result = []; + for (let i = 0; i < n; i++) { + result.push(__intSeedToRand(seed)); + seed = __xorwise(seed); + } + return result; +}; +const __timeToRands = (t, n) => __timeToRandsPrime(__timeToIntSeed(t), n); + +// End old random + +let useOldRandomBool = false; +export const useOldRandom = (b = true) => useOldRandomBool = b; + // N samples at time t function timeToRands(t, n) { + if (useOldRandomBool) { + return __timeToRands(t, n); + } const out = new Array(n); for (let i = 0; i < n; i++) out[i] = randAt(t, i); return out; @@ -224,6 +254,9 @@ function timeToRands(t, n) { // Single sample at time t function timeToRand(t) { + if (useOldRandomBool) { + return __timeToRand(t); + } return randAt(t, 0); } diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs index f1c72b12..23efb606 100644 --- a/website/src/repl/tunes.mjs +++ b/website/src/repl/tunes.mjs @@ -393,6 +393,8 @@ samples({ bass: { d2: 'https://cdn.freesound.org/previews/608/608286_13074022-lq.mp3' } }) +useOldRandom(true) + stack( // bells n("0").euclidLegato(3,8) @@ -430,6 +432,7 @@ export const festivalOfFingers3 = `// "Festival of fingers 3" // @by Felix Roos setcps(1) +useOldRandom(true) n("[-7*3],0,2,6,[8 7]") .echoWith( @@ -454,6 +457,8 @@ export const meltingsubmarine = `// "Melting submarine" // @by Felix Roos samples('github:tidalcycles/dirt-samples') +useOldRandom(true) + stack( s("bd:5,[~ ],hh27(3,4,1)") // drums .speed(perlin.range(.7,.9)) // random sample speed variation @@ -602,6 +607,9 @@ export const belldub = `// "Belldub" samples({ bell: {b4:'https://cdn.freesound.org/previews/339/339809_5121236-lq.mp3'}}) // "Hand Bells, B, Single.wav" by InspectorJ (www.jshaw.co.uk) of Freesound.org + +useOldRandom(true) + stack( // bass note("[0 ~] [2 [0 2]] [4 4*2] [[4 ~] [2 ~] 0@2]".scale('g1 dorian').superimpose(x=>x.add(.02))) @@ -638,6 +646,7 @@ export const dinofunk = `// "Dinofunk" // @by Felix Roos setcps(1) +useOldRandom(true) samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3', dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}}) @@ -666,6 +675,8 @@ export const sampleDemo = `// "Sample demo" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @by Felix Roos +useOldRandom(true) + stack( // percussion s("[woodblock:1 woodblock:2*2] snare_rim:0,gong/8,brakedrum:1(3,8),~@3 cowbell:3") @@ -684,6 +695,8 @@ export const holyflute = `// "Holy flute" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @by Felix Roos +useOldRandom(true) + "c3 eb3(3,8) c4/2 g3*2" .superimpose( x=>x.slow(2).add(12), @@ -699,6 +712,8 @@ export const flatrave = `// "Flatrave" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @by Felix Roos +useOldRandom(true) + stack( s("bd*2,~ [cp,sd]").bank('RolandTR909'), @@ -727,6 +742,8 @@ export const amensister = `// "Amensister" samples('github:tidalcycles/dirt-samples') +useOldRandom(true) + stack( // amen n("0 1 2 3 4 5 6 7") @@ -834,6 +851,8 @@ export const arpoon = `// "Arpoon" // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @by Felix Roos +useOldRandom(true) + samples('github:tidalcycles/dirt-samples') n("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).clip(2)