Test bleed, some docstrings

This commit is contained in:
Aria
2025-08-24 21:14:57 -05:00
parent b8423f0ed1
commit 5e4e678800
5 changed files with 92 additions and 56 deletions
+26 -23
View File
@@ -2,45 +2,48 @@ import { describe, bench } from 'vitest';
import { calculateSteps, rand, useOldRandom } from '../index.mjs';
const testingResolution = 1024;
const testingResolution = 128;
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();
useOldRandom();
_generateRandomPattern();
},
{
time: 1000,
teardown() {
useOldRandom(false);
},
},
{ time: 1000 },
);
calculateSteps(false);
bench(
'-tactus',
() => {
useOldRandom();
_generateRandomPattern();
useOldRandom();
_generateRandomPattern();
},
{
time: 1000,
teardown() {
useOldRandom(false);
},
},
{ time: 1000 },
);
});
describe('random', () => {
calculateSteps(true);
bench('+tactus', _generateRandomPattern, { time: 1000 });
calculateSteps(false);
bench('-tactus', _generateRandomPattern, { time: 1000 });
});
calculateSteps(true);
+35 -32
View File
@@ -201,9 +201,13 @@ function _murmurHashFinalizer(x) {
return x >>> 0; // unsigned
}
// Used to decorrelate nearby t and i prior to hashing
function _decorrelate(t, i = 0) {
const T = Math.floor(t * 536870912); // set 2^29 resolution
// Convert t to a 32 bit integer, preserving temporal resolution down to 1/2^29
function _tToT(t) {
return Math.floor(t * 536870912);
}
// Used to decorrelate nearby T and i prior to hashing
function _decorrelate(T, i = 0) {
const lowBits = (T >>> 0) >>> 0;
const highBits = Math.floor(T / 4294967296) >>> 0; // 2^32
let key = lowBits ^ Math.imul(highBits ^ 0x85ebca6b, 0xc2b2ae35);
@@ -211,8 +215,19 @@ function _decorrelate(t, i = 0) {
return key >>> 0;
}
function randAt(t, i = 0) {
return _murmurHashFinalizer(_decorrelate(t, i)) / 4294967296; // 2^32
function randAt(T, i = 0) {
return _murmurHashFinalizer(_decorrelate(T, i)) / 4294967296; // 2^32
}
// n samples at time t
function timeToRands(t, n) {
const T = _tToT(t);
if (n === 1) {
return randAt(T, 0);
}
const out = new Array(n);
for (let i = 0; i < n; i++) out[i] = randAt(T, i);
return out;
}
// Deprecated: Old random signals. Configuration `useOldRandom` may be used for legacy songs
@@ -226,8 +241,10 @@ const __xorwise = (x) => {
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) => {
if (n === 1) {
return Math.abs(__intSeedToRand(seed));
}
const result = [];
for (let i = 0; i < n; i++) {
result.push(__intSeedToRand(seed));
@@ -240,6 +257,10 @@ const __timeToRands = (t, n) => __timeToRandsPrime(__timeToIntSeed(t), n);
// End old random
let useOldRandomBool = false;
const getRandsAtTime = (t, n = 1) => {
return useOldRandomBool ? __timeToRands(t, n) : timeToRands(t, n);
};
/**
* Whether to use the old random number generator or not. Can be used to support legacy projects
*
@@ -248,28 +269,10 @@ let useOldRandomBool = false;
* @example
* useOldRandom(true)
* // Repeats every 300 cycles
* $: n(irand(50)).seg(16).scale("C:minor").ribbon(88, 32)._punchcard()
* $: n(irand(50)).seg(16).scale("C:minor").ribbon(388, 32)._punchcard()
* $: n(irand(50)).seg(16).scale("C:minor").ribbon(88, 32)
* $: n(irand(50)).seg(16).scale("C:minor").ribbon(388, 32)
*/
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;
}
// Single sample at time t
function timeToRand(t) {
if (useOldRandomBool) {
return __timeToRand(t);
}
return randAt(t, 0);
}
export const useOldRandom = (b = true) => (useOldRandomBool = b);
/**
* A discrete pattern of numbers from 0 to n-1
@@ -313,7 +316,7 @@ export const binaryN = (n, nBits = 16) => {
export const randrun = (n) => {
return signal((t) => {
// Without adding 0.5, the first cycle is always 0,1,2,3,...
const rands = timeToRands(t.floor().add(0.5), n);
const rands = getRandsAtTime(t.floor().add(0.5), n);
const nums = rands
.map((n, i) => [n, i])
.sort((a, b) => (a[0] > b[0]) - (a[0] < b[0]))
@@ -363,7 +366,7 @@ export const scramble = register('scramble', (n, pat) => {
* s("bd*4,hh*8").cutoff(rand.range(500,8000))
*
*/
export const rand = signal(timeToRand);
export const rand = signal(getRandsAtTime);
/**
* A continuous pattern of random numbers, between -1 and 1
*/
@@ -545,7 +548,7 @@ function _perlin(t) {
let tb = ta + 1;
const smootherStep = (x) => 6.0 * x ** 5 - 15.0 * x ** 4 + 10.0 * x ** 3;
const interp = (x) => (a) => (b) => a + smootherStep(x) * (b - a);
const v = interp(t - ta)(timeToRand(ta))(timeToRand(tb));
const v = interp(t - ta)(getRandsAtTime(ta))(getRandsAtTime(tb));
return v;
}
export const perlinWith = (tpat) => {
@@ -556,8 +559,8 @@ function _berlin(t) {
const prevRidgeStartIndex = Math.floor(t);
const nextRidgeStartIndex = prevRidgeStartIndex + 1;
const prevRidgeBottomPoint = timeToRand(prevRidgeStartIndex);
const nextRidgeTopPoint = timeToRand(nextRidgeStartIndex) + prevRidgeBottomPoint;
const prevRidgeBottomPoint = getRandsAtTime(prevRidgeStartIndex);
const nextRidgeTopPoint = getRandsAtTime(nextRidgeStartIndex) + prevRidgeBottomPoint;
const currentPercent = (t - prevRidgeStartIndex) / (nextRidgeStartIndex - prevRidgeStartIndex);
const interp = (a, b, t) => {
+22
View File
@@ -19,6 +19,17 @@ const DEFAULT_AUDIO_DEVICE_NAME = 'System Standard';
let maxPolyphony = DEFAULT_MAX_POLYPHONY;
/**
* Set the max polyphony. If notes are ringing out via `release` then they will
* start to die out in first-in-first-out order once the max polyphony has been hit
*
* @name setMaxPolyphony
* @param {number} Max polyphony. Defaults to 128
* @example
* setMaxPolyphony(4)
* n(irand(24).seg(8)).scale("C#3:minor").room(1).release(4).gain(0.5)
*
*/
export function setMaxPolyphony(polyphony) {
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
}
@@ -48,6 +59,17 @@ export function applyGainCurve(val) {
return gainCurveFunc(val);
}
/**
* Apply a function to all gains provided in patterns. Can be used to rescale gain to be
* quadratic, exponential, etc. rather than linear
*
* @name setGainCurve
* @param {Function} function to apply to all gain values
* @example
* setGainCurve((x) => x * x) // quadratic gain
* s("bd*4").gain(0.5) // equivalent to 0.25 gain normally
*
*/
export function setGainCurve(newGainCurveFunc) {
gainCurveFunc = newGainCurveFunc;
}
+2 -1
View File
@@ -7,7 +7,7 @@ export default defineConfig({
test: {
reporters: 'verbose',
isolate: false,
silent: true,
silent: false,
exclude: [
'**/node_modules/**',
'**/dist/**',
@@ -16,5 +16,6 @@ export default defineConfig({
'**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress}.config.*',
'**/shared.test.mjs',
],
setupFiles: './vitest.setup.mjs',
},
});
+7
View File
@@ -0,0 +1,7 @@
import { afterEach } from 'vitest';
import { useOldRandom } from './packages/core/signal.mjs';
afterEach(() => {
// Avoid bleed between tests
useOldRandom(false);
});