From 612b7d9006655e8f4e428459be65336c6ab14d11 Mon Sep 17 00:00:00 2001 From: Maxim Raznatovski Date: Thu, 16 Jan 2025 18:43:39 +0100 Subject: [PATCH] Feat: Add simple DSP indicator to Streamdetails to display the current DSP state (#822) * feat: add icons for DSP * feat: add models of DSPDetails * feat: add `dsp_grouped_childs` models * feat: update DSPDetails models * feat: add simple indicator to show active/disabled DSP --- src/assets/DSP.png | Bin 0 -> 1436 bytes src/assets/DSP_off.png | Bin 0 -> 1530 bytes src/components/QualityDetailsBtn.vue | 56 ++++++++++++++++++++++++++- src/plugins/api/interfaces.ts | 25 ++++++++++++ src/translations/en.json | 4 +- 5 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/assets/DSP.png create mode 100644 src/assets/DSP_off.png diff --git a/src/assets/DSP.png b/src/assets/DSP.png new file mode 100644 index 0000000000000000000000000000000000000000..33de3a77e86aea1b2e2840e23ccb923c56cf79e1 GIT binary patch literal 1436 zcmaKsdod>f(?SRtky`ljCUjIWNswA^(d)yOa;~C=`85|QIKo0`qAc@&)zabS-d1a6v>>QSi%*3nGmNN$f;1S;8J?2v7^mjj}#=Cgd?i@fM% zJUNHKaF%VCkCQ|wLyj9JRZi%|@kTA# z8O7PRo*2YCv&t*lP{@p#1eB#tm05K?x5;r(MOoOQQ^(_sQJ1NlVf#ys_@|1BmM1WH ztq*~uaHA4`lrLE_wGS1Z)jVntdcU^?FA?sCm(mQSwBo?EGu$Q%kEYWPL%E!N)wO$+rWdbz@q9I~-P$4xZIXA^ipk4~Y zd4Mn_tn993d29#>820{1kUk2sm^@ShOV@*Ih_xv};G!%3%#P?0iEJ}T?qG5~yVF2~ zpm@~!EQG93u8ml*g~(+GFmCq#K1h11;<-8VMnAEB@>cH1!dB)wTF~V_!FQ=+J+%39 zCQNTLsmsi2IpJn`2ZW(M0ysLQCM&~;ydaC62#3>&5y|27*-CQMiYm6|ahw<_ZoIuZ zf)fU8s11sg{y4gXg{T%MCP?cSzY1PxmJQ3gx=yCo zZ_$)7Ax`*u6>4lV0U|)t^;K4W8W0u0zM;fXc&ygYS6!JGdBqsPD*;`+JCJYhEn|ZF zxpy&=yTMj>oF)SXJ-gxpAPw>iBT&}Iyl`pco8}$au4CBtD#m&`k9&_fEPSt8DOnQ#%e=be#+Sz}#x;OF)c%^$nQ3+Dlvf>P$OEB_cLK;NQRxsn5icAx^XVjic z2$q2C-aP}>G7+1q@4Y(FX}JLBn{GKq8`XrM!CBWlSpRE=K8Zf zv>ni{SMgx_T014F3e3^#t?pV37{6slG;Ywbspr8t&o_p5H$Al=12=QBoC#NMFviwr z{kp*o@cjOJiJt`+L54F^M>na>$&W%ze3OTyRQ!?`JNjPuv{S^s2S@$dcodKo1Lf@1&W`RoMAD4XHF15H=&OG<+ z)YN)%g~o-QXW%?pI_Jtco)1tY2&A>^o TyU(Y#$qJBcoKDqQQ?C63AvJ_C literal 0 HcmV?d00001 diff --git a/src/assets/DSP_off.png b/src/assets/DSP_off.png new file mode 100644 index 0000000000000000000000000000000000000000..15bc9a1152b830822e33b5792715c814f4125c26 GIT binary patch literal 1530 zcmVWR02tSv$}VXaaIcjjK(7 z7T`bEa z3-C{w<6a5e4a^57I?uX*?}2r|Dxf2(x5;+_Hv;QDeb2#UgNK1#z*bC1?DBdd=~PKi zN!lkr-j}peQmdp-C2f!D^O816dQeh>BobU>CA}@FJL+Szq?;w389g5@=^jb@qvyvZ zy%dd6Xmdi+eS!W*NLn8Gyw&1xK+-BnjcyyeurMINbk9IDC2g>5{**K?hWtoL-&t+i zBn=7JF0kynE%HYs%?-3^mNeO^Yn1ep)mN9KC6aPJ0cHmTm>L+cUeX%J(ZziT@PT9N zI_qBR9Y5m8AC`2!=h*~Folajb`vkZmAi$J9oE$A_w`2d9$L>PMrXz+tl3py4yd+Hv z*erF%@0N6(E5OWv0O!Uy`mAH$rQ+Y3`}5ir(`So%rhPskc}Y4iVAtf~wayjb(trSy zVw|1fX|utxS>~}BpMd-^g%>=RycC|T<2~aal~iXZLfwIo6}Mmh855IjGy$`$@-R=k zM?7_IoSz50>9L!L36pNWAz$};o}B`Wvjr&kVBjS1qo@8h>wc%_`IEq-R=JcUXB2)> zL&)QQ!6(zo1b?IV8wZ$c-GAk2GYD7?Gy~rP&yZq<=U^mI=hPhpcBdu4K~LTEXwW>c z5i?6J@z~9eE-)!@+T;Pw^3;6+>1~F50t^MlNB6=^@lcLmuz85|$%9#wT)YnbD*%|O zSHLFV24IiJPQd;67raW51MYR|J_6dH|F^^L!t*(1t@z!l>x+C7a7G2==YYk)RaRXa za7Q$5YTMxvf%*fUx@KTfbl(j;fS-IbCe*b9vw;%{{J0vJjG1{;fd!bIC%_-T5}*|; z;`OHhhbZ1ICk=H4^20F4+Y2$LzHwNJ*#_^4u6AH8umSiQU#O4C=p^Z!m`o5!Z+Y5n z>?6ZVn%ft!*|E7O;A`9ltLRE=4Vdbw`^36W`sQ=Ma}*~zGcZvlb)+FcJ;m`o54;=Q zmy+QLvp^kl>g#~hQt-71g97(9;=Zw605mvt?*ZHBP5vawlAIm*Ge>(tb+fvpz81kI zU2dnhI_2G%Ge((w7g6ddMG9g7H|Mq=GY7lv<=khDmx_Jx9?l-jMWyq!lv9 zNWVt)oiaz<*OVCNua`MYy;f3PR5v*4XRS5vHc4}wwhfXNN!k(c^@yZbB+W{i2bA++ zqyv*-ZNaSUkUZ240ajo>UQEHvu1;V~^t==J26zWpO>sCJ3p|m)&mZUs!+j!+e~6U( zxvBy4No-8iZa?rh<)2KIg-QiT{af9CjY=}X0Z$&v7oaN0LwN#J4S6VCfT|)7r3p}V zz>%07*qoM6N<$f`welqW}N^ literal 0 HcmV?d00001 diff --git a/src/components/QualityDetailsBtn.vue b/src/components/QualityDetailsBtn.vue index 7026eb9a..b7c5ebd8 100644 --- a/src/components/QualityDetailsBtn.vue +++ b/src/components/QualityDetailsBtn.vue @@ -75,6 +75,42 @@ /> {{ loudness }} + + +
+ + {{ $t("dsp_disabled_by_unsupported_group") }} +
+
+ + {{ $t("dsp_active") }} +
@@ -85,7 +121,11 @@ import { computed } from "vue"; import ProviderIcon from "@/components/ProviderIcon.vue"; import api from "@/plugins/api"; import { store } from "@/plugins/store"; -import { ContentType, VolumeNormalizationMode } from "@/plugins/api/interfaces"; +import { + ContentType, + DSPState, + VolumeNormalizationMode, +} from "@/plugins/api/interfaces"; import { $t } from "@/plugins/i18n"; // computed properties @@ -123,6 +163,20 @@ const loudness = computed(() => { return null; } }); +// This is tempoary until the details show the whole DSP pipeline +const dsp_state = computed(() => { + const dsp = streamDetails.value?.dsp; + if (!dsp) return DSPState.DISABLED; + let at_least_one_working = Object.values(dsp).some( + (d) => d.state == DSPState.ENABLED, + ); + let at_least_one_unsupported = Object.values(dsp).some( + (d) => d.state == DSPState.DISABLED_BY_UNSUPPORTED_GROUP, + ); + if (at_least_one_unsupported) return DSPState.DISABLED_BY_UNSUPPORTED_GROUP; + else if (at_least_one_working) return DSPState.ENABLED; + else return DSPState.DISABLED; +}); const getContentTypeIcon = function (contentType: ContentType) { if (contentType == ContentType.AAC) return iconAac; if (contentType == ContentType.FLAC) return iconFlac; diff --git a/src/plugins/api/interfaces.ts b/src/plugins/api/interfaces.ts index ae713d5e..95edcf75 100644 --- a/src/plugins/api/interfaces.ts +++ b/src/plugins/api/interfaces.ts @@ -60,6 +60,26 @@ export interface DSPConfig { output_limiter: boolean; } +// DSPDetails used in StreamDetails +export enum DSPState { + ENABLED = "enabled", + DISABLED = "disabled", + DISABLED_BY_UNSUPPORTED_GROUP = "disabled_by_unsupported_group", +} + +// This describes the DSP configuration as applied, +// even when the DSP state is disabled. For example, +// output_limiter can remain true while the DSP is disabled. +// All filters in the list are guaranteed to be enabled. +export interface DSPDetails { + state: DSPState; + is_leader: boolean; + input_gain: number; + filters: DSPFilter[]; + output_gain: number; + output_limiter: boolean; +} + /// enums export enum MediaType { @@ -612,6 +632,11 @@ export interface StreamDetails { prefer_album_loudness?: boolean; target_loudness?: number; volume_normalization_mode?: VolumeNormalizationMode; + // This contains the DSPDetails of all players in the group. + // In case of single player playback, dict will contain only one entry. + // The leader will have is_leader set to True. + // (keep in mind that PlayerGroups have no (explicit) leader!) + dsp?: Record; } // queue_item diff --git a/src/translations/en.json b/src/translations/en.json index 37ffa8fe..f5f5b253 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -606,5 +606,7 @@ "loudness_measurement": "{0} LUFS", "loudness_measurement_album": "{0} LUFS (album)", "loudness_dynamic": "Dynamic volume normalization", - "loudness_fixed": "Fixed gain correction" + "loudness_fixed": "Fixed gain correction", + "dsp_disabled_by_unsupported_group": "Not supported for this group type", + "dsp_active": "Active" }