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

103 lines
3.9 KiB
TypeScript
Raw Normal View History

import { useState, useRef, useCallback } from "react";
import { decodeCustomBase64 } from "@/lib/luxsinApi";
/* ── Module-level cache: survives route switches ── */
const rawCurveCache = new Map<string, number[] | null>();
export function useRawCurve() {
const [currentRawCurve, setCurrentRawCurve] = useState<number[] | null>(null);
const [rawCurveLoading, setRawCurveLoading] = useState(false);
const rawCurveCacheRef = useRef(rawCurveCache);
const getModelCurve = async (brand: string, name: string) => {
try {
console.log("[modelCurve] request", { brand, name });
const resp = await fetch(
`//api.luxsin.com.cn/audio/modelCurve?brand=${encodeURIComponent(brand)}&name=${encodeURIComponent(name)}`
);
const data = await resp.text();
// 使用自定义 Base64 解码
const decoded = decodeCustomBase64(data);
const parsed = JSON.parse(decoded);
console.log("[modelCurve] decoded", {
hasFrRaw:
!!(parsed &&
typeof parsed === "object" &&
"fr" in (parsed as Record<string, unknown>) &&
(parsed as { fr?: unknown }).fr &&
typeof (parsed as { fr?: unknown }).fr === "object" &&
"raw" in ((parsed as { fr?: Record<string, unknown> }).fr ?? {})),
});
console.log("[modelCurve] fr.raw", (parsed as { fr?: { raw?: unknown } }).fr?.raw);
return parsed;
} catch (error) {
console.log("[modelCurve] request failed", error);
return null;
}
};
const loadRawCurveForPeq = useCallback(
async (peq: { brand?: string; model?: string; name?: string } | undefined): Promise<number[] | null> => {
const brand = peq?.brand?.trim() ?? "";
const model = peq?.model?.trim() ?? "";
if (!brand || !model) return null;
const cacheKey = `${brand}|${model}`;
if (rawCurveCacheRef.current.has(cacheKey)) {
const cached = rawCurveCacheRef.current.get(cacheKey);
if (cached) {
console.log("[modelCurve] cache hit", { brand, model, rawLength: cached.length });
} else {
console.log("[modelCurve] cache hit (no raw)", { brand, model });
}
return cached ?? null;
}
const modelCurve = await getModelCurve(brand, model);
if (modelCurve && typeof modelCurve === "object") {
const payload = modelCurve as {
fr?: { raw?: unknown } | unknown;
};
const rawCandidate =
payload.fr && typeof payload.fr === "object" && Array.isArray((payload.fr as { raw?: unknown }).raw)
? (payload.fr as { raw?: unknown }).raw
: null;
const raw = Array.isArray(rawCandidate)
? rawCandidate
.map((point) => {
if (typeof point === "number" && Number.isFinite(point)) return point;
if (Array.isArray(point) && point.length >= 2 && typeof point[1] === "number") return point[1];
if (point && typeof point === "object") {
const y = (point as Record<string, unknown>).y
?? (point as Record<string, unknown>).value
?? (point as Record<string, unknown>).db
?? (point as Record<string, unknown>).gain;
if (typeof y === "number" && Number.isFinite(y)) return y;
}
return NaN;
})
: null;
const cleanedRaw = raw && raw.every((v) => Number.isFinite(v)) ? (raw as number[]) : null;
rawCurveCacheRef.current.set(cacheKey, cleanedRaw);
console.log("[modelCurve] raw check", {
brand,
model,
hasRaw: !!cleanedRaw,
rawLength: cleanedRaw?.length ?? 0,
});
return cleanedRaw;
}
return null;
},
[],
);
return {
currentRawCurve,
setCurrentRawCurve,
rawCurveLoading,
setRawCurveLoading,
loadRawCurveForPeq,
};
}