Files
DeviceManager/src/lib/serial/chord.ts

74 lines
1.9 KiB
TypeScript

import { compressActions, decompressActions } from "../serialization/actions";
export interface Chord {
actions: number[];
phrase: number[];
}
export function parsePhrase(phrase: string): number[] {
return decompressActions(
Uint8Array.from({ length: phrase.length / 2 }).map((_, i) =>
Number.parseInt(phrase.slice(i * 2, i * 2 + 2), 16),
),
);
}
export function stringifyPhrase(phrase: number[]): string {
return [...compressActions(phrase)]
.map((it) => it.toString(16).padStart(2, "0"))
.join("")
.toUpperCase();
}
export function parseChordActions(actions: string): number[] {
return deserializeActions(BigInt(`0x${actions}`));
}
export function stringifyChordActions(actions: number[]): string {
return serializeActions(actions).toString(16).padStart(32, "0").toUpperCase();
}
/**
* Binary serialization of actions
*
* Actions are represented as 10-bit codes, for a maximum of 12 actions
*/
export function serializeActions(actions: number[]): bigint {
let native = 0n;
for (let i = 1; i <= actions.length; i++) {
native |=
BigInt(actions[actions.length - i]! & 0x3ff) << BigInt((12 - i) * 10);
}
return native;
}
/**
* @see {serializeActions}
*/
export function deserializeActions(native: bigint): number[] {
const actions = [];
for (let i = 0; i < 12; i++) {
const action = Number(native & 0x3ffn);
actions.push(action);
native >>= 10n;
}
return actions;
}
/**
* Hashes a chord input the same way as CCOS
*/
export function hashChord(actions: number[]) {
const chord = new Uint8Array(16);
const view = new DataView(chord.buffer);
const serialized = serializeActions(actions);
view.setBigUint64(0, serialized & 0xffff_ffff_ffff_ffffn, true);
view.setBigUint64(8, serialized >> 64n, true);
let hash = 2166136261;
for (let i = 0; i < 16; i++) {
hash = Math.imul(hash ^ view.getUint8(i), 16777619);
}
return hash & 0x3fff_ffff;
}