diff --git a/client/src/lib/luxsinApi.ts b/client/src/lib/luxsinApi.ts index 7a196a3..7779a05 100644 --- a/client/src/lib/luxsinApi.ts +++ b/client/src/lib/luxsinApi.ts @@ -171,6 +171,9 @@ export interface PeqApplyPayload { export const INPUT_LABELS = ["USB", "USB-C", "Coaxial", "Optical", "Bluetooth", "IIS", "RCA"]; export const OUTPUT_LABELS = ["XLR", "RCA", "Headset", "XLR/RCA"]; +/** Device `input` index for Bluetooth source. */ +export const INPUT_BLUETOOTH_INDEX = 4; + /** Device `output` index for headphone / headset. */ export const OUTPUT_HEADSET_INDEX = 2; export const LANGUAGE_LABELS = ["English", "繁體中文", "简体中文"]; @@ -345,6 +348,19 @@ export function parseFirmwareVersion(version: unknown): number { return Number(parts[parts.length - 1]); } +/** Display firmware version as X.Y.0.Z (e.g. 2005 → 2.0.0.5). */ +export function formatFirmwareVersionDisplay(version: unknown): string { + if (version === null || version === undefined || String(version).trim() === "") { + return "—"; + } + const n = parseFirmwareVersion(version); + const major = Math.floor(n / 1000); + const minor = Math.floor((n % 1000) / 100); + const patch = 0; + const build = n % 10; + return `${major}.${minor}.${patch}.${build}`; +} + /** Pre-out volume passthrough mode selected (0dB or -12dB). */ export function isVolumePassthroughActive(dacVolumeDirect: number | undefined): boolean { return dacVolumeDirect === 1 || dacVolumeDirect === 2; diff --git a/client/src/locales/data-en.json b/client/src/locales/data-en.json index 5aa8f79..3a43054 100644 --- a/client/src/locales/data-en.json +++ b/client/src/locales/data-en.json @@ -404,11 +404,11 @@ }, { "index": 4, - "label": "De-emphasis filter" + "label": "Super Slow Roll-off" }, { "index": 5, - "label": "Non-oversampling" + "label": "Low Dispersion Short Delay" } ] }, diff --git a/client/src/locales/data-zh-HK.json b/client/src/locales/data-zh-HK.json index 7ce6fea..563fb50 100644 --- a/client/src/locales/data-zh-HK.json +++ b/client/src/locales/data-zh-HK.json @@ -326,8 +326,8 @@ { "index": 1, "label": "慢速衰減" }, { "index": 2, "label": "短延遲快速衰減" }, { "index": 3, "label": "短延遲慢速衰減" }, - { "index": 4, "label": "去重強調" }, - { "index": 5, "label": "非過采樣(NOS)" } + { "index": 4, "label": "超慢速滾降" }, + { "index": 5, "label": "低離散短延遲" } ] }, "dacGain": { diff --git a/client/src/locales/data-zh.json b/client/src/locales/data-zh.json index b01249e..6afa824 100644 --- a/client/src/locales/data-zh.json +++ b/client/src/locales/data-zh.json @@ -326,8 +326,8 @@ { "index": 1, "label": "慢速滚降" }, { "index": 2, "label": "短延迟快速滚降" }, { "index": 3, "label": "短延迟慢速滚降" }, - { "index": 4, "label": "去重强调" }, - { "index": 5, "label": "非过采样(NOS)" } + { "index": 4, "label": "超慢速滚降" }, + { "index": 5, "label": "低离散短延迟" } ] }, "dacGain": { diff --git a/client/src/pages/AudioPage.tsx b/client/src/pages/AudioPage.tsx index 62837da..ea503c3 100644 --- a/client/src/pages/AudioPage.tsx +++ b/client/src/pages/AudioPage.tsx @@ -235,7 +235,7 @@ export default function AudioPage() { const bootSoundSelectIdx = Math.min(bootSoundVal, bootSoundMaxIdx); const BOOT_VOLUME_OPTIONS = bootVolumeOptions(dacText, bootSoundMaxIdx); - const FILTER_OPTIONS = optionLabels(dacText.filters?.options, ["快速滚降", "慢速滚降", "短延迟快速滚降", "短延迟慢速滚降", "去重强调", "非过采样(NOS)"]); + const FILTER_OPTIONS = optionLabels(dacText.filters?.options, ["快速滚降", "慢速滚降", "短延迟快速滚降", "短延迟慢速滚降", "超慢速滚降", "低离散短延迟"]); const GAIN_OPTIONS = optionLabels(dacText.dacGain?.options, ["低", "中", "高"]); const DAC_VOLUME_DIRECT_OPTIONS = optionLabels(dacText.dacVolumeDirect?.options, ["关闭", "0dB", "-12dB"]); const DAC_ARC_OPTIONS = optionLabels(dacText.dacArc?.options, ["ARC", "EARC"]); diff --git a/client/src/pages/EffectsPage.tsx b/client/src/pages/EffectsPage.tsx index e823a42..6f2b26f 100644 --- a/client/src/pages/EffectsPage.tsx +++ b/client/src/pages/EffectsPage.tsx @@ -144,27 +144,31 @@ function IOSToggle({ checked, onChange }: { checked: boolean; onChange: (v: bool ); } -function CyanSlider({ value, min, max, step = 0.1, onChange, onRelease }: { +function CyanSlider({ value, min, max, step = 0.1, disabled = false, onChange, onRelease }: { value: number; min: number; max: number; step?: number; + disabled?: boolean; onChange: (v: number) => void; /** Fires once when the user releases the thumb (pointer/mouse/touch). Read value from DOM to avoid stale React state. */ onRelease?: (v: number) => void; }) { const fillPct = ((value - min) / (max - min)) * 100; const emitRelease = (el: EventTarget | null) => { - if (!(el instanceof HTMLInputElement)) return; + if (disabled || !(el instanceof HTMLInputElement)) return; onRelease?.(Number(el.value)); }; return ( -