Files
controller-v2/client/src/pages/eq/eqFormatters.ts
T

150 lines
4.5 KiB
TypeScript

import { getFilterShortName } from "@/lib/peqAudio";
import {
BAND_FREQ_MAX,
BAND_FREQ_MIN,
BAND_GAIN_MAX,
BAND_GAIN_MIN,
BAND_Q_MAX,
BAND_Q_MIN,
} from "./eqConstants";
import type { BandParamKind } from "./types";
export function eqInterp(template: string | undefined, vars: Record<string, string | number>): string {
if (!template) return "";
let s = template;
for (const [k, v] of Object.entries(vars)) {
s = s.split(`{{${k}}}`).join(String(v));
}
return s;
}
/** 将设备/表单中的频率统一为 Hz 数值;无法解析时返回 null */
export function normalizeBandFreqHz(freq: unknown): number | null {
if (typeof freq === "number" && Number.isFinite(freq)) return freq;
if (typeof freq === "string") {
const trimmed = freq.trim().replace(/,/g, "");
if (!trimmed) return null;
let s = trimmed.toLowerCase().replace(/hz$/, "");
const kHz = /k(hz)?$/.test(s);
if (kHz) s = s.replace(/k(hz)?$/, "");
const num = Number.parseFloat(s);
return Number.isFinite(num) ? (kHz ? num * 1000 : num) : null;
}
return null;
}
export function formatBandGainDisplay(gain: unknown) {
const db = typeof gain === "number" && Number.isFinite(gain) ? gain : Number(gain);
if (!Number.isFinite(db)) return "0.0 dB";
const text = db.toFixed(1);
return `${db >= 0 ? `+${text}` : text} dB`;
}
export function formatBandQDisplay(q: unknown) {
const n = typeof q === "number" && Number.isFinite(q) ? q : Number(q);
return Number.isFinite(n) ? n.toFixed(2) : "—";
}
export function formatBandFreqDisplay(freq: unknown) {
const hz = normalizeBandFreqHz(freq);
if (hz === null) return "—";
if (hz >= 1000) {
return `${(hz / 1000).toFixed(2).replace(/\.?0+$/, "")} kHz`;
}
return `${Math.round(hz)} Hz`;
}
export function formatBandParamForInput(
kind: BandParamKind,
band: { freq: number; gain: number; q: number },
) {
switch (kind) {
case "freq":
return String(band.freq);
case "gain":
return band.gain.toFixed(1);
case "q":
return band.q.toFixed(2);
}
}
export function parseBandParamInput(
kind: BandParamKind,
raw: string,
messages: { invalid: string; outOfRange: string },
): { ok: true; value: number } | { ok: false; message: string } {
const trimmed = raw.trim();
if (!trimmed) return { ok: false, message: messages.invalid };
if (kind === "freq") {
let s = trimmed.replace(/\s+/g, "").toLowerCase().replace(/hz$/, "");
const kHz = /k(hz)?$/.test(s);
if (kHz) s = s.replace(/k(hz)?$/, "");
const num = Number.parseFloat(s);
if (!Number.isFinite(num)) return { ok: false, message: messages.invalid };
const hz = Math.round(kHz ? num * 1000 : num);
if (hz < BAND_FREQ_MIN || hz > BAND_FREQ_MAX) {
return { ok: false, message: messages.outOfRange };
}
return { ok: true, value: hz };
}
if (kind === "gain") {
const s = trimmed.replace(/\s*dB\s*$/i, "").trim();
const num = Number.parseFloat(s);
if (!Number.isFinite(num)) return { ok: false, message: messages.invalid };
const gain = Number(num.toFixed(1));
if (gain < BAND_GAIN_MIN || gain > BAND_GAIN_MAX) {
return { ok: false, message: messages.outOfRange };
}
return { ok: true, value: gain };
}
const num = Number.parseFloat(trimmed);
if (!Number.isFinite(num)) return { ok: false, message: messages.invalid };
const q = Number(num.toFixed(2));
if (q < BAND_Q_MIN || q > BAND_Q_MAX) {
return { ok: false, message: messages.outOfRange };
}
return { ok: true, value: q };
}
export function normalizeFilterType(type: string | number | undefined): string {
if (type === undefined || type === null) return "PEAK";
if (typeof type === "number") {
switch (type) {
case 0:
return "LPF";
case 1:
return "HPF";
case 2:
return "BPF";
case 3:
return "NOTCH";
case 4:
return "PEAK";
case 5:
return "LSHELF";
case 6:
return "HSHELF";
case 7:
return "APF";
default:
return "PEAK";
}
}
return getFilterShortName(type);
}
/** 10 段滤波器按钮上的紧凑频率标签(始终为数字,避免被翻译插件改成英文单词) */
export function freqLabel(freq: unknown) {
const hz = normalizeBandFreqHz(freq);
if (hz === null) return "—";
if (hz >= 1000) {
const k = hz / 1000;
const text = k >= 10 ? String(Math.round(k)) : k.toFixed(1).replace(/\.0$/, "");
return `${text}K`;
}
return String(Math.round(hz));
}