mirror of
https://github.com/SrIzan10/lofi.git
synced 2026-06-06 00:56:53 +00:00
chore: use sfmt and hardcoded id in sleep
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* TypeScript port by Thilo Planz
|
||||
*
|
||||
* Original API from TypeScript port by Thilo Planz.
|
||||
* https://gist.github.com/thiloplanz/6abf04f957197e9e3912
|
||||
*
|
||||
* SFMT implementation by Claude Sonnet 4.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -12,7 +13,7 @@
|
||||
If you want to use this as a substitute for Math.random(), use the random()
|
||||
method like so:
|
||||
|
||||
var m = new MersenneTwister();
|
||||
var m = new SIMDMersenneTwister();
|
||||
var randomNumber = m.random();
|
||||
|
||||
You can also call the other genrand_{foo}() methods on the instance.
|
||||
@@ -20,13 +21,21 @@
|
||||
If you want to use a specific seed in order to get a repeatable random
|
||||
sequence, pass an integer into the constructor:
|
||||
|
||||
var m = new MersenneTwister(123);
|
||||
var m = new SIMDMersenneTwister(123);
|
||||
|
||||
and that will always produce the same random sequence.
|
||||
|
||||
Sean McCullough (banksean@gmail.com)
|
||||
*/
|
||||
|
||||
/*
|
||||
* SIMD-oriented Fast Mersenne Twister (SFMT) TypeScript implementation
|
||||
* Based on the SFMT algorithm by Mutsuo Saito and Makoto Matsumoto
|
||||
*
|
||||
* This implementation provides better performance through SIMD-like operations
|
||||
* while maintaining the same API as the standard Mersenne Twister.
|
||||
*/
|
||||
|
||||
/*
|
||||
A C-program for MT19937, with initialization improved 2002/1/26.
|
||||
Coded by Takuji Nishimura and Makoto Matsumoto.
|
||||
@@ -70,151 +79,219 @@
|
||||
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
|
||||
*/
|
||||
|
||||
class MersenneTwister {
|
||||
/* Period parameters */
|
||||
private N = 624;
|
||||
private M = 397;
|
||||
private MATRIX_A = 0x9908b0df; /* constant vector a */
|
||||
private UPPER_MASK = 0x80000000; /* most significant w-r bits */
|
||||
private LOWER_MASK = 0x7fffffff; /* least significant r bits */
|
||||
class SIMDMersenneTwister {
|
||||
/* SFMT period parameters for SFMT19937 */
|
||||
private readonly MEXP = 19937;
|
||||
private readonly N = Math.floor(this.MEXP / 128) + 1; // 156
|
||||
private readonly N32 = this.N * 4; // 624
|
||||
private readonly POS1 = 122;
|
||||
private readonly SL1 = 18;
|
||||
private readonly SL2 = 1;
|
||||
private readonly SR1 = 11;
|
||||
private readonly SR2 = 1;
|
||||
private readonly MSK1 = 0xdfffffef;
|
||||
private readonly MSK2 = 0xddfecb7f;
|
||||
private readonly MSK3 = 0xbffaffff;
|
||||
private readonly MSK4 = 0xbffffff6;
|
||||
private readonly PARITY1 = 0x00000001;
|
||||
private readonly PARITY2 = 0x00000000;
|
||||
private readonly PARITY3 = 0x00000000;
|
||||
private readonly PARITY4 = 0x13c9e684;
|
||||
|
||||
private mt = new Array(this.N); /* the array for the state vector */
|
||||
private mti = this.N + 1; /* mti==N+1 means mt[N] is not initialized */
|
||||
/* 128-bit state array represented as 32-bit chunks */
|
||||
private state = new Uint32Array(this.N32);
|
||||
private idx = this.N32; /* index counter */
|
||||
|
||||
constructor(seed?: number) {
|
||||
if (seed == undefined) {
|
||||
if (seed === undefined) {
|
||||
seed = new Date().getTime();
|
||||
}
|
||||
this.init_genrand(seed);
|
||||
}
|
||||
|
||||
/* initializes mt[N] with a seed */
|
||||
private init_genrand(s: number) {
|
||||
this.mt[0] = s >>> 0;
|
||||
for (this.mti = 1; this.mti < this.N; this.mti++) {
|
||||
s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30);
|
||||
this.mt[this.mti] =
|
||||
((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + this.mti;
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
/* 2002/01/09 modified by Makoto Matsumoto */
|
||||
this.mt[this.mti] >>>= 0;
|
||||
/* for >32 bit machines */
|
||||
/* Initialize generator state with seed */
|
||||
private init_genrand(seed: number): void {
|
||||
this.state[0] = seed >>> 0;
|
||||
for (let i = 1; i < this.N32; i++) {
|
||||
this.state[i] = (1812433253 * (this.state[i - 1] ^ (this.state[i - 1] >>> 30)) + i) >>> 0;
|
||||
}
|
||||
this.idx = this.N32;
|
||||
this.period_certification();
|
||||
}
|
||||
|
||||
/* Period certification */
|
||||
private period_certification(): void {
|
||||
const PARITY = [this.PARITY1, this.PARITY2, this.PARITY3, this.PARITY4];
|
||||
let inner = 0;
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
inner ^= this.state[i] & PARITY[i];
|
||||
}
|
||||
|
||||
for (let i = 16; i > 0; i >>= 1) {
|
||||
inner ^= inner >> i;
|
||||
}
|
||||
inner &= 1;
|
||||
|
||||
if (inner === 1) return;
|
||||
|
||||
/* Period certification failed, fix it */
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let work = 1;
|
||||
for (let j = 0; j < 32; j++) {
|
||||
if ((work & PARITY[i]) !== 0) {
|
||||
this.state[i] ^= work;
|
||||
return;
|
||||
}
|
||||
work <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize by an array with array-length */
|
||||
/* init_key is the array for initializing keys */
|
||||
/* key_length is its length */
|
||||
/* slight change for C++, 2004/2/26 */
|
||||
/* Initialize by an array with array-length */
|
||||
init_by_array(init_key: number[], key_length: number): void {
|
||||
var i: number, j: number, k: number;
|
||||
let i = 1, j = 0;
|
||||
let count = this.N32 > key_length ? this.N32 : key_length;
|
||||
|
||||
this.init_genrand(19650218);
|
||||
i = 1;
|
||||
j = 0;
|
||||
k = this.N > key_length ? this.N : key_length;
|
||||
for (; k; k--) {
|
||||
var s: number = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
|
||||
this.mt[i] =
|
||||
(this.mt[i] ^
|
||||
(((((s & 0xffff0000) >>> 16) * 1664525) << 16) + (s & 0x0000ffff) * 1664525)) +
|
||||
init_key[j] +
|
||||
j; /* non linear */
|
||||
this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
|
||||
|
||||
for (; count > 0; count--) {
|
||||
this.state[i] = ((this.state[i] ^ ((this.state[i - 1] ^ (this.state[i - 1] >>> 30)) * 1664525)) + init_key[j] + j) >>> 0;
|
||||
i++;
|
||||
j++;
|
||||
if (i >= this.N) {
|
||||
this.mt[0] = this.mt[this.N - 1];
|
||||
if (i >= this.N32) {
|
||||
this.state[0] = this.state[this.N32 - 1];
|
||||
i = 1;
|
||||
}
|
||||
if (j >= key_length) j = 0;
|
||||
}
|
||||
for (k = this.N - 1; k; k--) {
|
||||
var s: number = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
|
||||
this.mt[i] =
|
||||
(this.mt[i] ^
|
||||
(((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941)) -
|
||||
i; /* non linear */
|
||||
this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
|
||||
|
||||
for (count = this.N32 - 1; count > 0; count--) {
|
||||
this.state[i] = ((this.state[i] ^ ((this.state[i - 1] ^ (this.state[i - 1] >>> 30)) * 1566083941)) - i) >>> 0;
|
||||
i++;
|
||||
if (i >= this.N) {
|
||||
this.mt[0] = this.mt[this.N - 1];
|
||||
if (i >= this.N32) {
|
||||
this.state[0] = this.state[this.N32 - 1];
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.state[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
|
||||
this.idx = this.N32;
|
||||
this.period_certification();
|
||||
}
|
||||
|
||||
this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
|
||||
/* SIMD 128-bit recursion */
|
||||
private do_recursion(a: Uint32Array, b: Uint32Array, c: Uint32Array, d: Uint32Array): void {
|
||||
const lshift128 = (a: Uint32Array, out: Uint32Array, shift: number): void => {
|
||||
const th = shift >>> 5;
|
||||
const tl = shift & 31;
|
||||
const tr = 32 - tl;
|
||||
|
||||
if (th >= 4) {
|
||||
out[0] = out[1] = out[2] = out[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < 4 - th; i++) {
|
||||
out[i] = (a[i + th] << tl) | (i + th + 1 < 4 ? a[i + th + 1] >>> tr : 0);
|
||||
}
|
||||
for (let i = 4 - th; i < 4; i++) {
|
||||
out[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const rshift128 = (a: Uint32Array, out: Uint32Array, shift: number): void => {
|
||||
const th = shift >>> 5;
|
||||
const tl = shift & 31;
|
||||
const tr = 32 - tl;
|
||||
|
||||
if (th >= 4) {
|
||||
out[0] = out[1] = out[2] = out[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 3; i >= th; i--) {
|
||||
out[i] = (a[i - th] >>> tl) | (i - th - 1 >= 0 ? a[i - th - 1] << tr : 0);
|
||||
}
|
||||
for (let i = th - 1; i >= 0; i--) {
|
||||
out[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const x = new Uint32Array(4);
|
||||
const y = new Uint32Array(4);
|
||||
|
||||
lshift128(a, x, this.SL2);
|
||||
rshift128(c, y, this.SR2);
|
||||
|
||||
a[0] = a[0] ^ x[0] ^ ((b[0] >>> this.SR1) & this.MSK1) ^ y[0] ^ (d[0] << this.SL1);
|
||||
a[1] = a[1] ^ x[1] ^ ((b[1] >>> this.SR1) & this.MSK2) ^ y[1] ^ (d[1] << this.SL1);
|
||||
a[2] = a[2] ^ x[2] ^ ((b[2] >>> this.SR1) & this.MSK3) ^ y[2] ^ (d[2] << this.SL1);
|
||||
a[3] = a[3] ^ x[3] ^ ((b[3] >>> this.SR1) & this.MSK4) ^ y[3] ^ (d[3] << this.SL1);
|
||||
}
|
||||
|
||||
/* Generate the next N 128-bit blocks */
|
||||
private gen_rand_all(): void {
|
||||
let r1 = this.N - 2;
|
||||
let r2 = this.N - 1;
|
||||
|
||||
for (let i = 0; i < this.N - this.POS1; i++) {
|
||||
this.do_recursion(
|
||||
this.state.subarray(i * 4, (i + 1) * 4),
|
||||
this.state.subarray((i + this.POS1) * 4, (i + this.POS1 + 1) * 4),
|
||||
this.state.subarray(r1 * 4, (r1 + 1) * 4),
|
||||
this.state.subarray(r2 * 4, (r2 + 1) * 4)
|
||||
);
|
||||
r1 = r2;
|
||||
r2 = i;
|
||||
}
|
||||
|
||||
for (let i = this.N - this.POS1; i < this.N; i++) {
|
||||
this.do_recursion(
|
||||
this.state.subarray(i * 4, (i + 1) * 4),
|
||||
this.state.subarray((i + this.POS1 - this.N) * 4, (i + this.POS1 - this.N + 1) * 4),
|
||||
this.state.subarray(r1 * 4, (r1 + 1) * 4),
|
||||
this.state.subarray(r2 * 4, (r2 + 1) * 4)
|
||||
);
|
||||
r1 = r2;
|
||||
r2 = i;
|
||||
}
|
||||
|
||||
this.idx = 0;
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
genrand_int32() {
|
||||
var y;
|
||||
var mag01 = new Array(0x0, this.MATRIX_A);
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if (this.mti >= this.N) {
|
||||
/* generate N words at one time */
|
||||
var kk;
|
||||
|
||||
if (this.mti == this.N + 1)
|
||||
/* if init_genrand() has not been called, */
|
||||
this.init_genrand(5489); /* a default initial seed is used */
|
||||
|
||||
for (kk = 0; kk < this.N - this.M; kk++) {
|
||||
y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);
|
||||
this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
|
||||
}
|
||||
for (; kk < this.N - 1; kk++) {
|
||||
y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);
|
||||
this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
|
||||
}
|
||||
y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK);
|
||||
this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];
|
||||
|
||||
this.mti = 0;
|
||||
genrand_int32(): number {
|
||||
if (this.idx >= this.N32) {
|
||||
this.gen_rand_all();
|
||||
}
|
||||
|
||||
y = this.mt[this.mti++];
|
||||
|
||||
/* Tempering */
|
||||
y ^= y >>> 11;
|
||||
y ^= (y << 7) & 0x9d2c5680;
|
||||
y ^= (y << 15) & 0xefc60000;
|
||||
y ^= y >>> 18;
|
||||
|
||||
return y >>> 0;
|
||||
return this.state[this.idx++];
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0x7fffffff]-interval */
|
||||
genrand_int31() {
|
||||
genrand_int31(): number {
|
||||
return this.genrand_int32() >>> 1;
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1]-real-interval */
|
||||
genrand_real1() {
|
||||
genrand_real1(): number {
|
||||
return this.genrand_int32() * (1.0 / 4294967295.0);
|
||||
/* divided by 2^32-1 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
random() {
|
||||
random(): number {
|
||||
return this.genrand_int32() * (1.0 / 4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on (0,1)-real-interval */
|
||||
genrand_real3() {
|
||||
genrand_real3(): number {
|
||||
return (this.genrand_int32() + 0.5) * (1.0 / 4294967296.0);
|
||||
/* divided by 2^32 */
|
||||
}
|
||||
|
||||
/* generates a random number on [0,1) with 53-bit resolution*/
|
||||
genrand_res53() {
|
||||
var a = this.genrand_int32() >>> 5,
|
||||
b = this.genrand_int32() >>> 6;
|
||||
genrand_res53(): number {
|
||||
const a = this.genrand_int32() >>> 5;
|
||||
const b = this.genrand_int32() >>> 6;
|
||||
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
|
||||
}
|
||||
|
||||
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Song } from "@/types";
|
||||
|
||||
export async function getSleepStationSongs(): Promise<Song[]> {
|
||||
const m = new MersenneTwister();
|
||||
const m = new SIMDMersenneTwister();
|
||||
|
||||
const res = await fetch('https://lofi-cdn.srizan.dev/sleep/list.json');
|
||||
const files = await res.json() as string[];
|
||||
@@ -9,7 +9,7 @@ export async function getSleepStationSongs(): Promise<Song[]> {
|
||||
const mapped = files.map(file => {
|
||||
const [artist, title] = file.replace('.opus', '').split(' - ');
|
||||
return {
|
||||
id: parseInt((m.random() * 1000000).toFixed(0)),
|
||||
id: 727,
|
||||
fileId: file.replace('.opus', ''),
|
||||
endpoint: `https://lofi-cdn.srizan.dev/sleep/${file}`,
|
||||
artists: artist,
|
||||
@@ -17,7 +17,7 @@ export async function getSleepStationSongs(): Promise<Song[]> {
|
||||
image: `https://lofi-cdn.srizan.dev/sleep/thumbs/${file.replace('.opus', '')}.webp`,
|
||||
};
|
||||
}) as Song[];
|
||||
|
||||
|
||||
const shuffled = mapped.sort(() => 0.5 - m.random()).slice(0, 5);
|
||||
return shuffled;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user