Test bleed, some docstrings
This commit is contained in:
parent
b8423f0ed1
commit
5e4e678800
5 changed files with 92 additions and 56 deletions
|
|
@ -2,45 +2,48 @@ import { describe, bench } from 'vitest';
|
||||||
|
|
||||||
import { calculateSteps, rand, useOldRandom } from '../index.mjs';
|
import { calculateSteps, rand, useOldRandom } from '../index.mjs';
|
||||||
|
|
||||||
const testingResolution = 1024;
|
const testingResolution = 128;
|
||||||
|
|
||||||
const _generateRandomPattern = () => rand.iter(testingResolution).fast(testingResolution).firstCycle();
|
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', () => {
|
describe('old random', () => {
|
||||||
calculateSteps(true);
|
calculateSteps(true);
|
||||||
bench(
|
bench(
|
||||||
'+tactus',
|
'+tactus',
|
||||||
() => {
|
() => {
|
||||||
useOldRandom();
|
useOldRandom();
|
||||||
_generateRandomPattern();
|
_generateRandomPattern();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
time: 1000,
|
||||||
|
teardown() {
|
||||||
|
useOldRandom(false);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{ time: 1000 },
|
|
||||||
);
|
);
|
||||||
|
|
||||||
calculateSteps(false);
|
calculateSteps(false);
|
||||||
bench(
|
bench(
|
||||||
'-tactus',
|
'-tactus',
|
||||||
() => {
|
() => {
|
||||||
useOldRandom();
|
useOldRandom();
|
||||||
_generateRandomPattern();
|
_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);
|
calculateSteps(true);
|
||||||
|
|
|
||||||
|
|
@ -201,9 +201,13 @@ function _murmurHashFinalizer(x) {
|
||||||
return x >>> 0; // unsigned
|
return x >>> 0; // unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to decorrelate nearby t and i prior to hashing
|
// Convert t to a 32 bit integer, preserving temporal resolution down to 1/2^29
|
||||||
function _decorrelate(t, i = 0) {
|
function _tToT(t) {
|
||||||
const T = Math.floor(t * 536870912); // set 2^29 resolution
|
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 lowBits = (T >>> 0) >>> 0;
|
||||||
const highBits = Math.floor(T / 4294967296) >>> 0; // 2^32
|
const highBits = Math.floor(T / 4294967296) >>> 0; // 2^32
|
||||||
let key = lowBits ^ Math.imul(highBits ^ 0x85ebca6b, 0xc2b2ae35);
|
let key = lowBits ^ Math.imul(highBits ^ 0x85ebca6b, 0xc2b2ae35);
|
||||||
|
|
@ -211,8 +215,19 @@ function _decorrelate(t, i = 0) {
|
||||||
return key >>> 0;
|
return key >>> 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function randAt(t, i = 0) {
|
function randAt(T, i = 0) {
|
||||||
return _murmurHashFinalizer(_decorrelate(t, i)) / 4294967296; // 2^32
|
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
|
// 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 __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) => Math.abs(__intSeedToRand(__timeToIntSeed(x)));
|
|
||||||
const __timeToRandsPrime = (seed, n) => {
|
const __timeToRandsPrime = (seed, n) => {
|
||||||
|
if (n === 1) {
|
||||||
|
return Math.abs(__intSeedToRand(seed));
|
||||||
|
}
|
||||||
const result = [];
|
const result = [];
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
result.push(__intSeedToRand(seed));
|
result.push(__intSeedToRand(seed));
|
||||||
|
|
@ -240,6 +257,10 @@ const __timeToRands = (t, n) => __timeToRandsPrime(__timeToIntSeed(t), n);
|
||||||
// End old random
|
// End old random
|
||||||
|
|
||||||
let useOldRandomBool = false;
|
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
|
* 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
|
* @example
|
||||||
* useOldRandom(true)
|
* useOldRandom(true)
|
||||||
* // Repeats every 300 cycles
|
* // 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(88, 32)
|
||||||
* $: n(irand(50)).seg(16).scale("C:minor").ribbon(388, 32)._punchcard()
|
* $: n(irand(50)).seg(16).scale("C:minor").ribbon(388, 32)
|
||||||
*/
|
*/
|
||||||
export const useOldRandom = (b = true) => useOldRandomBool = b;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A discrete pattern of numbers from 0 to n-1
|
* A discrete pattern of numbers from 0 to n-1
|
||||||
|
|
@ -313,7 +316,7 @@ export const binaryN = (n, nBits = 16) => {
|
||||||
export const randrun = (n) => {
|
export const randrun = (n) => {
|
||||||
return signal((t) => {
|
return signal((t) => {
|
||||||
// Without adding 0.5, the first cycle is always 0,1,2,3,...
|
// 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
|
const nums = rands
|
||||||
.map((n, i) => [n, i])
|
.map((n, i) => [n, i])
|
||||||
.sort((a, b) => (a[0] > b[0]) - (a[0] < b[0]))
|
.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))
|
* 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
|
* A continuous pattern of random numbers, between -1 and 1
|
||||||
*/
|
*/
|
||||||
|
|
@ -545,7 +548,7 @@ function _perlin(t) {
|
||||||
let tb = ta + 1;
|
let tb = ta + 1;
|
||||||
const smootherStep = (x) => 6.0 * x ** 5 - 15.0 * x ** 4 + 10.0 * x ** 3;
|
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 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;
|
return v;
|
||||||
}
|
}
|
||||||
export const perlinWith = (tpat) => {
|
export const perlinWith = (tpat) => {
|
||||||
|
|
@ -556,8 +559,8 @@ function _berlin(t) {
|
||||||
const prevRidgeStartIndex = Math.floor(t);
|
const prevRidgeStartIndex = Math.floor(t);
|
||||||
const nextRidgeStartIndex = prevRidgeStartIndex + 1;
|
const nextRidgeStartIndex = prevRidgeStartIndex + 1;
|
||||||
|
|
||||||
const prevRidgeBottomPoint = timeToRand(prevRidgeStartIndex);
|
const prevRidgeBottomPoint = getRandsAtTime(prevRidgeStartIndex);
|
||||||
const nextRidgeTopPoint = timeToRand(nextRidgeStartIndex) + prevRidgeBottomPoint;
|
const nextRidgeTopPoint = getRandsAtTime(nextRidgeStartIndex) + prevRidgeBottomPoint;
|
||||||
|
|
||||||
const currentPercent = (t - prevRidgeStartIndex) / (nextRidgeStartIndex - prevRidgeStartIndex);
|
const currentPercent = (t - prevRidgeStartIndex) / (nextRidgeStartIndex - prevRidgeStartIndex);
|
||||||
const interp = (a, b, t) => {
|
const interp = (a, b, t) => {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,17 @@ const DEFAULT_AUDIO_DEVICE_NAME = 'System Standard';
|
||||||
|
|
||||||
let maxPolyphony = DEFAULT_MAX_POLYPHONY;
|
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) {
|
export function setMaxPolyphony(polyphony) {
|
||||||
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
|
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +59,17 @@ export function applyGainCurve(val) {
|
||||||
return gainCurveFunc(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) {
|
export function setGainCurve(newGainCurveFunc) {
|
||||||
gainCurveFunc = newGainCurveFunc;
|
gainCurveFunc = newGainCurveFunc;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
reporters: 'verbose',
|
reporters: 'verbose',
|
||||||
isolate: false,
|
isolate: false,
|
||||||
silent: true,
|
silent: false,
|
||||||
exclude: [
|
exclude: [
|
||||||
'**/node_modules/**',
|
'**/node_modules/**',
|
||||||
'**/dist/**',
|
'**/dist/**',
|
||||||
|
|
@ -16,5 +16,6 @@ export default defineConfig({
|
||||||
'**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress}.config.*',
|
'**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress}.config.*',
|
||||||
'**/shared.test.mjs',
|
'**/shared.test.mjs',
|
||||||
],
|
],
|
||||||
|
setupFiles: './vitest.setup.mjs',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
7
vitest.setup.mjs
Normal file
7
vitest.setup.mjs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { afterEach } from 'vitest';
|
||||||
|
import { useOldRandom } from './packages/core/signal.mjs';
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// Avoid bleed between tests
|
||||||
|
useOldRandom(false);
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue