优化自定义交叉反馈

This commit is contained in:
eafonyang
2026-09-11 19:30:37 +08:00
parent 5a9530eede
commit eff59ddd71
8 changed files with 119 additions and 12 deletions
+6
View File
@@ -105,6 +105,10 @@ export interface DeviceState {
scene_value: number;
crossfeed_enable: number;
crossfeed_value: number;
/** Custom crossfeed cut-off frequency in Hz (500–1000, step 1). */
crossfeed_custom_fc: number;
/** Custom crossfeed attenuation, stored as dB×10 (1.0 dB=10 … 15.0 dB=150). */
crossfeed_custom_gain: number;
subwoofer_enable: number;
subwoofer_value: number;
subwoofer_rate: number;
@@ -565,6 +569,8 @@ export const MOCK_DEVICE_STATE: DeviceState = {
scene_value: 0,
crossfeed_enable: 0,
crossfeed_value: 0,
crossfeed_custom_fc: 700,
crossfeed_custom_gain: 45,
subwoofer_enable: 0,
subwoofer_value: 80,
subwoofer_rate: 0,
+6 -2
View File
@@ -109,8 +109,12 @@
"options": [
"BS2B Standard (700 Hz, 4,5 dB)",
"BS2B Populär (700 Hz, 6 dB)",
"BS2B Entspannt (650 Hz, 9,5 dB)"
]
"BS2B Entspannt (650 Hz, 9,5 dB)",
"Custom"
],
"customTitle": "Benutzerdefinierte Einstellungen",
"freqLabel": "Frequence",
"attenuationLabel": "Attenuation"
},
"hearing": {
"label": "Hörkompensation",
+6 -2
View File
@@ -109,8 +109,12 @@
"options": [
"BS2B default (700 Hz, 4.5 dB)",
"BS2B popular (700 Hz, 6 dB)",
"BS2B relax (650 Hz, 9.5 dB)"
]
"BS2B relax (650 Hz, 9.5 dB)",
"Custom"
],
"customTitle": "Custom Settings",
"freqLabel": "Frequence",
"attenuationLabel": "Attenuation"
},
"hearing": {
"label": "Hearing compensation",
+6 -2
View File
@@ -109,8 +109,12 @@
"options": [
"BS2B predeterminado (700 Hz, 4,5 dB)",
"BS2B popular (700 Hz, 6 dB)",
"BS2B relajado (650 Hz, 9,5 dB)"
]
"BS2B relajado (650 Hz, 9,5 dB)",
"Custom"
],
"customTitle": "Configuración personalizada",
"freqLabel": "Frequence",
"attenuationLabel": "Attenuation"
},
"hearing": {
"label": "Compensación auditiva",
+6 -2
View File
@@ -109,8 +109,12 @@
"options": [
"BS2B défaut (700 Hz, 4,5 dB)",
"BS2B populaire (700 Hz, 6 dB)",
"BS2B relax (650 Hz, 9,5 dB)"
]
"BS2B relax (650 Hz, 9,5 dB)",
"Custom"
],
"customTitle": "Réglages personnalisés",
"freqLabel": "Frequence",
"attenuationLabel": "Attenuation"
},
"hearing": {
"label": "Compensation auditive",
+6 -2
View File
@@ -102,8 +102,12 @@
"options": [
"BS2B default(700Hz,4.5dB)",
"BS2B polular(700Hz,6dB)",
"BS2B relax(650Hz,9.5dB)"
]
"BS2B relax(650Hz,9.5dB)",
"Custom"
],
"customTitle": "自訂設置",
"freqLabel": "截止頻率",
"attenuationLabel": "衰減量"
},
"hearing": {
"label": "聽力補償",
+6 -2
View File
@@ -102,8 +102,12 @@
"options": [
"BS2B default(700Hz,4.5dB)",
"BS2B polular(700Hz,6dB)",
"BS2B relax(650Hz,9.5dB)"
]
"BS2B relax(650Hz,9.5dB)",
"Custom"
],
"customTitle": "自定义设置",
"freqLabel": "截止频率",
"attenuationLabel": "衰减量"
},
"hearing": {
"label": "听力补偿",
+77
View File
@@ -409,6 +409,20 @@ export default function EffectsPage() {
const sceneDisplay = sceneLabels[sceneIdx] ?? "";
const crossIdx = clampPickIndex(crossfeedVal, crossfeedLabels.length);
const crossfeedDisplay = crossfeedLabels[crossIdx] ?? "";
// Custom crossfeed values: fc in Hz, gain stored as dB×10
const crossfeedCustomFc = ds?.crossfeed_custom_fc ?? 700;
const crossfeedCustomGain = (ds?.crossfeed_custom_gain ?? 45) / 10;
const [localCrossfeedFc, setLocalCrossfeedFc] = useState(() => crossfeedCustomFc);
const [localCrossfeedGain, setLocalCrossfeedGain] = useState(() => crossfeedCustomGain);
const isDraggingCrossfeedFc = useRef(false);
const isDraggingCrossfeedGain = useRef(false);
useEffect(() => {
if (!isDraggingCrossfeedFc.current) setLocalCrossfeedFc(crossfeedCustomFc);
if (!isDraggingCrossfeedGain.current) setLocalCrossfeedGain(crossfeedCustomGain);
}, [crossfeedCustomFc, crossfeedCustomGain]);
const hearingIdx = clampPickIndex(hearingSelect, hearingLabels.length);
const hearingDisplay =
hearingLabels[hearingIdx] ?? effectText.hearing?.emptyProfile ?? "—";
@@ -528,6 +542,69 @@ export default function EffectsPage() {
<span className="text-[14px] text-white/45">{crossfeedDisplay}</span>
<ChevronRight size={16} className="ios-chevron" />
</button>
{/* ── Custom crossfeed sub-module (shown when Custom / index 3 selected) ── */}
{crossfeedOn && crossIdx === 3 && (
<div className="mt-4 border-t border-white/10 pt-4 space-y-4">
<div className="text-[13px] font-medium text-white/70 tracking-wide uppercase">
{effectText.crossfeed?.customTitle ?? "自定义设置"}
</div>
{/* Frequence — cut-off frequency 500–1000 Hz */}
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-[14px] text-white/60">
{effectText.crossfeed?.freqLabel ?? "Frequence"}
</span>
<span className="text-[14px] font-bold" style={{ color: "#00FFF6" }}>
{Math.round(localCrossfeedFc)} Hz
</span>
</div>
<CyanSlider
value={localCrossfeedFc}
min={500}
max={1000}
step={1}
onChange={(v) => {
isDraggingCrossfeedFc.current = true;
setLocalCrossfeedFc(Math.round(v));
}}
onRelease={(v) => {
isDraggingCrossfeedFc.current = false;
const fc = Math.round(v);
setLocalCrossfeedFc(fc);
updateSetting({ crossfeed_custom_fc: fc });
}}
/>
</div>
{/* Attenuation — 1.0–15.0 dB, sent as value×10 */}
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-[14px] text-white/60">
{effectText.crossfeed?.attenuationLabel ?? "Attenuation"}
</span>
<span className="text-[14px] font-bold" style={{ color: "#00FFF6" }}>
{localCrossfeedGain.toFixed(1)} dB
</span>
</div>
<CyanSlider
value={localCrossfeedGain}
min={1}
max={15}
step={0.1}
onChange={(v) => {
isDraggingCrossfeedGain.current = true;
setLocalCrossfeedGain(v);
}}
onRelease={(v) => {
isDraggingCrossfeedGain.current = false;
updateSetting({ crossfeed_custom_gain: Math.round(v * 10) });
}}
/>
</div>
</div>
)}
</div>
{/* ── 音调 ── */}