mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-22 09:52:50 +00:00
fix chord serialization
This commit is contained in:
@@ -1,8 +1,56 @@
|
|||||||
import {describe, it, expect} from "vitest"
|
import {describe, it, expect} from "vitest"
|
||||||
import {serializeActions} from "$lib/serial/chord"
|
import {
|
||||||
|
chordAsCommandCompatible,
|
||||||
|
chordFromCommandCompatible,
|
||||||
|
chordsFromFile,
|
||||||
|
chordsToFile,
|
||||||
|
deserializeActions,
|
||||||
|
serializeActions,
|
||||||
|
} from "./chord"
|
||||||
|
import type {Chord} from "./chord"
|
||||||
|
|
||||||
describe("chords", function () {
|
describe("chords", function () {
|
||||||
it("should serialize actions", function () {
|
describe("actions", function () {
|
||||||
expect(serializeActions([67, 2])).toBe(0xcc200000000000000000000000000n)
|
it("should serialize actions", function () {
|
||||||
|
expect(serializeActions([32, 51]).toString(16)).toEqual(0xcc200000000000000000000000000n.toString(16))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should deserialize actions", function () {
|
||||||
|
expect(deserializeActions(0xcc200000000000000000000000000n)).toEqual([32, 51])
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let i = 0; i < 12; i++) {
|
||||||
|
it(`should serialize back-forth ${i} actions`, function () {
|
||||||
|
const actions = Array.from({length: i}).map((_, i) => i + 1)
|
||||||
|
expect(deserializeActions(serializeActions(actions))).toEqual(actions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("commands", function () {
|
||||||
|
it("should convert to a command", function () {
|
||||||
|
expect(chordAsCommandCompatible({actions: [32, 51], phrase: [0x01, 0x68, 0x72, 0xd4, 0x65]})).toEqual(
|
||||||
|
"000CC200000000000000000000000000 016872D465",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should parse a command", function () {
|
||||||
|
expect(chordFromCommandCompatible("000CC200000000000000000000000000 016872D465")).toEqual({
|
||||||
|
actions: [32, 51],
|
||||||
|
phrase: [0x01, 0x68, 0x72, 0xd4, 0x65],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("chl file format", function () {
|
||||||
|
const fileData: Chord[] = [
|
||||||
|
{phrase: [1, 2, 3, 4], actions: [5, 6, 7, 8, 9]},
|
||||||
|
{phrase: [10, 11], actions: [12, 13, 14, 15]},
|
||||||
|
{phrase: [16], actions: [17]},
|
||||||
|
]
|
||||||
|
|
||||||
|
it("should should convert back-forth a file", function () {
|
||||||
|
expect(chordsFromFile(chordsToFile(fileData))).toEqual(fileData)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ export interface Chord {
|
|||||||
* @example "000CC200000000000000000000000000 7468726565"
|
* @example "000CC200000000000000000000000000 7468726565"
|
||||||
*/
|
*/
|
||||||
export function chordAsCommandCompatible(chord: Chord): string {
|
export function chordAsCommandCompatible(chord: Chord): string {
|
||||||
return `${serializeActions(chord.actions).toString(16).padStart(32)} ${chord.phrase.map(it =>
|
return `${serializeActions(chord.actions).toString(16).padStart(32, "0")} ${chord.phrase
|
||||||
it.toString(16),
|
.map(it => it.toString(16).padStart(2, "0"))
|
||||||
)}`
|
.join("")}`.toUpperCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +36,8 @@ export function chordFromCommandCompatible(command: string): Chord {
|
|||||||
*/
|
*/
|
||||||
export function serializeActions(actions: number[]): bigint {
|
export function serializeActions(actions: number[]): bigint {
|
||||||
let native = 0n
|
let native = 0n
|
||||||
for (let i = 0; i < actions.length; i++) {
|
for (let i = 1; i <= actions.length; i++) {
|
||||||
native |= BigInt(actions[i] & 0x3ff) << BigInt((11 - i) * 10)
|
native |= BigInt(actions[actions.length - i] & 0x3ff) << BigInt((12 - i) * 10)
|
||||||
}
|
}
|
||||||
return native
|
return native
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ export function chordsToFile(chords: Chord[]): ArrayBuffer {
|
|||||||
const view = new DataView(buffer)
|
const view = new DataView(buffer)
|
||||||
let byteOffset = 0
|
let byteOffset = 0
|
||||||
|
|
||||||
for (const byte of CHL_MAGIC) {
|
for (const byte of CHL_MAGIC.split("")) {
|
||||||
view.setUint8(byteOffset++, byte.codePointAt(0)!)
|
view.setUint8(byteOffset++, byte.codePointAt(0)!)
|
||||||
}
|
}
|
||||||
view.setUint8(byteOffset++, CHL_VERSION)
|
view.setUint8(byteOffset++, CHL_VERSION)
|
||||||
@@ -99,7 +99,7 @@ export function chordsToFile(chords: Chord[]): ArrayBuffer {
|
|||||||
byteOffset += 4
|
byteOffset += 4
|
||||||
for (const chord of chords) {
|
for (const chord of chords) {
|
||||||
const actions = serializeActions(chord.actions)
|
const actions = serializeActions(chord.actions)
|
||||||
view.setBigUint64(byteOffset, actions << 64n, true)
|
view.setBigUint64(byteOffset, actions >> 64n, true)
|
||||||
byteOffset += 8
|
byteOffset += 8
|
||||||
view.setBigUint64(byteOffset, actions & 0xffff_ffff_ffff_ffffn, true)
|
view.setBigUint64(byteOffset, actions & 0xffff_ffff_ffff_ffffn, true)
|
||||||
byteOffset += 8
|
byteOffset += 8
|
||||||
@@ -121,17 +121,18 @@ export function chordsFromFile(buffer: ArrayBuffer): Chord[] {
|
|||||||
const view = new DataView(buffer)
|
const view = new DataView(buffer)
|
||||||
let byteOffset = 0
|
let byteOffset = 0
|
||||||
|
|
||||||
let magic = ""
|
const magic = []
|
||||||
for (let i = 0; i < CHL_MAGIC.length; i++) {
|
for (let i = 0; i < CHL_MAGIC.length; i++) {
|
||||||
magic += view.getUint8(byteOffset++)
|
magic.push(view.getUint8(byteOffset++))
|
||||||
}
|
}
|
||||||
if (magic !== CHL_MAGIC) throw new Error("Not a .chl file")
|
const magicString = String.fromCodePoint(...magic)
|
||||||
|
if (magicString !== CHL_MAGIC) throw new Error(`Not a .chl file [magic ${magicString}]`)
|
||||||
if (view.getUint8(byteOffset++) !== CHL_VERSION) throw Error("Invalid .chl [version]")
|
if (view.getUint8(byteOffset++) !== CHL_VERSION) throw Error("Invalid .chl [version]")
|
||||||
|
|
||||||
const chords: Chord[] = Array.from({length: view.getUint32(byteOffset, true)})
|
const chords: Chord[] = Array.from({length: view.getUint32(byteOffset, true)})
|
||||||
byteOffset += 4
|
byteOffset += 4
|
||||||
for (let i = 0; i < chords.length; i++) {
|
for (let i = 0; i < chords.length; i++) {
|
||||||
let actions = view.getBigUint64(byteOffset, true) >> 64n
|
let actions = view.getBigUint64(byteOffset, true) << 64n
|
||||||
byteOffset += 8
|
byteOffset += 8
|
||||||
actions |= view.getBigUint64(byteOffset, true)
|
actions |= view.getBigUint64(byteOffset, true)
|
||||||
byteOffset += 8
|
byteOffset += 8
|
||||||
|
|||||||
Reference in New Issue
Block a user