1/**
2 * Compression measurements off the main thread, so the scrolling view never
3 * stutters while zstd -19 or the LPC fit runs. One message in (the model),
4 * one message out (the nine codec results).
5 */
6import { Pipeline } from '../model/pipeline'
7import {
8 initCodecs,
9 compressAll,
10 ZLIB,
11 ZSTD,
12 ANS,
13 DELTA_ZLIB,
14 DELTA_ZSTD,
15 DELTA_ANS,
16 LPC_ZLIB,
17 LPC_ZSTD,
18 LPC_ANS,
19 type CodecResult,
20} from '../compress/codecs'
22export interface CompressRequest {
23 id: number
24 kernel: Float64Array
25 sigma: number
26 dither: boolean
27 blockSize: number
28 seed: number
29}
31export interface CompressResponse {
32 id: number
33 results: CodecResult[]
34 /** Empirical std of the quantized block, for display sanity. */
35 empiricalStd: number
36 error?: string
37}
39const CODECS = [ZLIB, ZSTD, ANS, DELTA_ZLIB, DELTA_ZSTD, DELTA_ANS, LPC_ZLIB, LPC_ZSTD, LPC_ANS]
41const post = self.postMessage as (message: CompressResponse) => void
43self.onmessage = async (e: MessageEvent<CompressRequest>) => {
44 const { id, kernel, sigma, dither, blockSize, seed } = e.data
45 try {
46 await initCodecs()
47 const samples = new Pipeline(kernel, sigma, dither, seed).next(blockSize)
48 let sum = 0
49 let sumSq = 0
50 for (let i = 0; i < samples.length; i++) {
51 sum += samples[i]
52 sumSq += samples[i] * samples[i]
53 }
54 const mean = sum / samples.length
55 const empiricalStd = Math.sqrt(Math.max(0, sumSq / samples.length - mean * mean))
56 const bytes = new Uint8Array(samples.buffer, 0, samples.byteLength)
57 post({ id, results: compressAll(bytes, CODECS), empiricalStd })
58 } catch (err) {
59 post({ id, results: [], empiricalStd: 0, error: String(err) })
60 }
61}