diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index f17e667c..72d4cc9b 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -503,6 +503,10 @@ "top_left": "Oben links", "top_right": "Oben rechts" }, + "visualizer-quality": { + "high": "Hoch", + "low": "Niedrig" + }, "visualizer-types": { "linear": "Linear", "mirrored": "Gespiegelt", @@ -693,6 +697,10 @@ "description": "Bevorzugte und ignorierte Medienanwendungen festlegen.", "label": "Medienplayer" }, + "visualizer-quality": { + "description": "Hohe Qualität verbraucht mehr GPU-Ressourcen.", + "label": "Visualisierungsqualität" + }, "visualizer-type": { "description": "Visualisierungstyp für Medienwiedergabe wählen.", "label": "Visualisierungstyp" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "Hintergrundbild-Farben deaktiviert", "enabled": "Hintergrundbild-Farben aktiviert", + "label": "Hintergrundfarbengenerierung", "not-installed": "Matugen nicht installiert - erforderlich für Hintergrundbild-Farbextraktion" }, "wifi": { diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 5a00ad0c..bd3e9820 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -503,6 +503,10 @@ "top_left": "Top left", "top_right": "Top right" }, + "visualizer-quality": { + "high": "High", + "low": "Low" + }, "visualizer-types": { "linear": "Linear", "mirrored": "Mirrored", @@ -682,19 +686,23 @@ "placeholder": "e.g. spotify, vlc, mpv" }, "scrolling-speed": { - "description": "Time in seconds for the title to scroll from start to end", + "description": "Time in seconds for the title to scroll from start to end.", "label": "Scrolling speed" }, "scrolling-title": { - "description": "Enable continuous scrolling for long media titles", + "description": "Enable continuous scrolling for long media titles.", "label": "Scrolling title" }, "section": { "description": "Set your preferred and ignored media applications.", "label": "Media players" }, + "visualizer-quality": { + "description": "High quality use more GPU ressources.", + "label": "Visualization quality" + }, "visualizer-type": { - "description": "Choose a visualization type for media playback", + "description": "Choose a visualization type for media playback.", "label": "Visualization type" } }, @@ -1757,9 +1765,9 @@ "title-predefined": "Predefined color cheme processing failed" }, "wallpaper-colors": { - "label": "Wallpaper colors generation", "disabled": "Wallpaper colors disabled", "enabled": "Wallpaper colors enabled", + "label": "Wallpaper colors generation", "not-installed": "Matugen not installed - required for wallpaper color extraction" }, "wifi": { diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 91ffaa57..a68676bb 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -503,6 +503,10 @@ "top_left": "Superior izquierda", "top_right": "Superior derecha" }, + "visualizer-quality": { + "high": "Alto/Alta", + "low": "Bajo" + }, "visualizer-types": { "linear": "Lineal", "mirrored": "Espejado", @@ -693,6 +697,10 @@ "description": "Establece tus aplicaciones multimedia preferidas e ignoradas.", "label": "Reproductores multimedia" }, + "visualizer-quality": { + "description": "Alta calidad usa más recursos de la GPU.", + "label": "Calidad de visualización" + }, "visualizer-type": { "description": "Elige un tipo de visualización para la reproducción de medios.", "label": "Tipo de visualización" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "Colores del fondo de pantalla desactivados", "enabled": "Colores del fondo de pantalla activados", + "label": "Generación de colores para fondos de pantalla", "not-installed": "Matugen no instalado - requerido para extraer colores del fondo de pantalla" }, "wifi": { diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 0ce5ef9d..c4ca352f 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -503,6 +503,10 @@ "top_left": "En haut à gauche", "top_right": "En haut à droite" }, + "visualizer-quality": { + "high": "Haut/Haute", + "low": "Bas" + }, "visualizer-types": { "linear": "Linéaire", "mirrored": "Miroir", @@ -693,6 +697,10 @@ "description": "Définissez vos applications multimédias préférées et ignorées.", "label": "Lecteurs multimédias" }, + "visualizer-quality": { + "description": "L'utilisation de haute qualité nécessite plus de ressources GPU.", + "label": "Qualité de la visualisation" + }, "visualizer-type": { "description": "Choisissez un type de visualisation pour la lecture multimédia.", "label": "Type de visualisation" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "Couleurs du fond d'écran désactivées", "enabled": "Couleurs du fond d'écran activées", + "label": "Génération de couleurs pour fonds d'écran", "not-installed": "Matugen non installé - requis pour l'extraction des couleurs du fond d'écran" }, "wifi": { diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index c3baf25e..46d05463 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -503,6 +503,10 @@ "top_left": "Superior esquerda", "top_right": "Superior direita" }, + "visualizer-quality": { + "high": "Alto(a)", + "low": "Baixo(a)" + }, "visualizer-types": { "linear": "Linear", "mirrored": "Espelhado", @@ -693,6 +697,10 @@ "description": "Defina seus aplicativos de mídia preferidos e ignorados.", "label": "Reprodutores de mídia" }, + "visualizer-quality": { + "description": "Alta qualidade usa mais recursos da GPU.", + "label": "Qualidade da visualização" + }, "visualizer-type": { "description": "Escolha um tipo de visualização para a reprodução de mídia", "label": "Tipo de visualização" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "Cores do papel de parede desativadas", "enabled": "Cores do papel de parede ativadas", + "label": "Geração de cores para papel de parede", "not-installed": "Matugen não instalado - necessário para extração de cores do papel de parede" }, "wifi": { diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 43e038ce..5aa2474f 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -503,6 +503,10 @@ "top_left": "Sol üst", "top_right": "Sağ üst" }, + "visualizer-quality": { + "high": "Yüksek", + "low": "Düşük" + }, "visualizer-types": { "linear": "Doğrusal", "mirrored": "Yansıtılmış", @@ -693,6 +697,10 @@ "description": "Tercih ettiğiniz ve yoksayacağınız medya uygulamalarını ayarlayın.", "label": "Medya oynatıcılar" }, + "visualizer-quality": { + "description": "Yüksek kalite daha fazla GPU kaynağı kullanır.", + "label": "Görselleştirme kalitesi" + }, "visualizer-type": { "description": "Medya oynatımı için bir görselleştirme türü seçin", "label": "Görselleştirme türü" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "Duvar kağıdı renkleri devre dışı", "enabled": "Duvar kağıdı renkleri etkin", + "label": "Duvar kağıdı renkleri oluşturma", "not-installed": "Matugen kurulu değil - duvar kağıdı renk çıkarmak için gerekli" }, "wifi": { diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index 3969ea44..fbcead9d 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -503,6 +503,10 @@ "top_left": "Згори ліворуч", "top_right": "Згори праворуч" }, + "visualizer-quality": { + "high": "Високий", + "low": "Низький" + }, "visualizer-types": { "linear": "Лінійний", "mirrored": "Дзеркальний", @@ -693,6 +697,10 @@ "description": "Встановіть бажані та ігноровані медіапрограми.", "label": "Медіаплеєри" }, + "visualizer-quality": { + "description": "Висока якість використовує більше ресурсів GPU.", + "label": "Якість візуалізації" + }, "visualizer-type": { "description": "Виберіть тип візуалізації для відтворення медіа", "label": "Тип візуалізації" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "Кольори шпалер вимкнено", "enabled": "Кольори шпалер увімкнено", + "label": "Генерація кольорів шпалер", "not-installed": "Matugen не встановлено - потрібний для витягу кольорів зі шпалер" }, "wifi": { diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 371faa55..924dc1c9 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -503,6 +503,10 @@ "top_left": "左上", "top_right": "右上" }, + "visualizer-quality": { + "high": "高", + "low": "低" + }, "visualizer-types": { "linear": "线性", "mirrored": "镜像", @@ -693,6 +697,10 @@ "description": "设置您首选和要忽略的媒体应用程序。", "label": "媒体播放器" }, + "visualizer-quality": { + "description": "高质量使用更多 GPU 资源。", + "label": "可视化质量" + }, "visualizer-type": { "description": "选择媒体播放的可视化类型", "label": "可视化类型" @@ -1759,6 +1767,7 @@ "wallpaper-colors": { "disabled": "壁纸颜色已禁用", "enabled": "壁纸颜色已启用", + "label": "壁纸颜色生成", "not-installed": "Matugen 未安装 - 壁纸颜色提取所需" }, "wifi": { diff --git a/Assets/settings-default.json b/Assets/settings-default.json index ed319e04..70f52191 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -228,6 +228,7 @@ "volumeOverdrive": false, "cavaFrameRate": 60, "visualizerType": "linear", + "visualizerQuality": "high", "mprisBlacklist": [], "preferredPlayer": "" }, diff --git a/Commons/Settings.qml b/Commons/Settings.qml index d1a811f7..3d7be7f1 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -368,6 +368,7 @@ Singleton { property bool volumeOverdrive: false property int cavaFrameRate: 30 property string visualizerType: "linear" + property string visualizerQuality: "high" property list mprisBlacklist: [] property string preferredPlayer: "" } diff --git a/Modules/Panels/Settings/Tabs/AudioTab.qml b/Modules/Panels/Settings/Tabs/AudioTab.qml index 96fa6dc5..d47fe949 100644 --- a/Modules/Panels/Settings/Tabs/AudioTab.qml +++ b/Modules/Panels/Settings/Tabs/AudioTab.qml @@ -331,7 +331,6 @@ ColumnLayout { } // AudioService Visualizer section NComboBox { - id: audioVisualizerCombo label: I18n.tr("settings.audio.media.visualizer-type.label") description: I18n.tr("settings.audio.media.visualizer-type.description") model: [{ @@ -351,6 +350,20 @@ ColumnLayout { onSelected: key => Settings.data.audio.visualizerType = key } + NComboBox { + label: I18n.tr("settings.audio.media.visualizer-quality.label") + description: I18n.tr("settings.audio.media.visualizer-quality.description") + model: [{ + "key": "low", + "name": I18n.tr("options.visualizer-quality.low") + }, { + "key": "high", + "name": I18n.tr("options.visualizer-quality.high") + }] + currentKey: Settings.data.audio.visualizerQuality + onSelected: key => Settings.data.audio.visualizerQuality = key + } + NComboBox { label: I18n.tr("settings.audio.media.frame-rate.label") description: I18n.tr("settings.audio.media.frame-rate.description") diff --git a/Services/Media/CavaService.qml b/Services/Media/CavaService.qml index 2619229b..8e58c92e 100644 --- a/Services/Media/CavaService.qml +++ b/Services/Media/CavaService.qml @@ -19,12 +19,20 @@ Singleton { property bool shouldRun: BarService.hasAudioVisualizer || PanelService.lockScreen?.active || (PanelService.openedPanel && PanelService.openedPanel.objectName.startsWith("controlCenterPanel")) property var values: Array(barsCount).fill(0) - property int barsCount: 48 + property int barsCount: 32 // Idle detection to reduce GPU usage when there's no audio property bool isIdle: true property int idleFrameCount: 0 readonly property int idleThreshold: 30 // Frames of silence before considered idle (0.5s at 60fps) + + // Frame skipping for GPU optimization - skip every Nth frame when playing + property int frameCounter: 0 + readonly property int frameSkip: 1 // Update every N frames (1 = no skip, 2 = every other frame, etc) + + // Change detection - only update if values changed significantly + property var lastValues: Array(barsCount).fill(0) + readonly property real changeThreshold: 0.005 // Minimum change (1%) to trigger update property var config: ({ "general": { "bars": barsCount, @@ -35,8 +43,9 @@ Singleton { "higher_cutoff_freq": 12000 }, "smoothing": { - "monstercat": 0, - "noise_reduction": 77 + "monstercat": 1, + "noise_reduction"// Enable monstercat smoothing for less jittery animation + : 77 }, "output": { "method": "raw", @@ -92,6 +101,7 @@ Singleton { root.isIdle = true // Set all values to 0 one final time root.values = Array(root.barsCount).fill(0) + root.lastValues = Array(root.barsCount).fill(0) Logger.d("Cava", "Idle detected - stopped rendering") } // Don't update values while idle @@ -106,8 +116,28 @@ Singleton { } } - // Update values (only when not idle) - root.values = newValues + // Frame skipping optimization - skip frames to reduce GPU load + root.frameCounter++ + if (root.frameSkip > 1 && root.frameCounter % root.frameSkip !== 0) { + // Skip this frame + return + } + + // Change detection - only update if values changed significantly + let hasSignificantChange = false + for (var i = 0; i < newValues.length; i++) { + const delta = Math.abs(newValues[i] - root.lastValues[i]) + if (delta > root.changeThreshold) { + hasSignificantChange = true + break + } + } + + // Update values only if there's a significant change + if (hasSignificantChange) { + root.lastValues = newValues.slice() // Copy array + root.values = newValues + } } } stderr: StdioCollector { diff --git a/Widgets/AudioSpectrum/NLinearSpectrum.qml b/Widgets/AudioSpectrum/NLinearSpectrum.qml index 0224fd9e..596f7d10 100644 --- a/Widgets/AudioSpectrum/NLinearSpectrum.qml +++ b/Widgets/AudioSpectrum/NLinearSpectrum.qml @@ -17,6 +17,7 @@ Item { readonly property int valuesCount: (values && Array.isArray(values)) ? values.length : 0 readonly property int totalBars: valuesCount * 2 readonly property real barSlotSize: totalBars > 0 ? (vertical ? height : width) / totalBars : 0 + readonly property bool highQuality: (Settings.data.audio.visualizerType === "low") ? false : true Repeater { model: root.totalBars @@ -33,7 +34,8 @@ Item { color: root.fillColor border.color: root.strokeColor border.width: root.strokeWidth - antialiasing: true + antialiasing: root.highQuality + smooth: root.highQuality // Only update when value actually changes - reduces GPU load width: vertical ? root.width * amp : root.barSlotSize * 0.5 diff --git a/Widgets/AudioSpectrum/NMirroredSpectrum.qml b/Widgets/AudioSpectrum/NMirroredSpectrum.qml index 2d6b05ee..4da22d6d 100644 --- a/Widgets/AudioSpectrum/NMirroredSpectrum.qml +++ b/Widgets/AudioSpectrum/NMirroredSpectrum.qml @@ -17,7 +17,7 @@ Item { readonly property int valuesCount: (values && Array.isArray(values)) ? values.length : 0 readonly property int totalBars: valuesCount * 2 readonly property real barSlotSize: totalBars > 0 ? (vertical ? height : width) / totalBars : 0 - + readonly property bool highQuality: (Settings.data.audio.visualizerType === "low") ? false : true readonly property real centerY: height / 2 readonly property real centerX: width / 2 @@ -38,7 +38,8 @@ Item { color: root.fillColor border.color: root.strokeColor border.width: root.strokeWidth - antialiasing: true + antialiasing: root.highQuality + smooth: root.highQuality width: vertical ? barSize : root.barSlotSize * 0.8 height: vertical ? root.barSlotSize * 0.8 : barSize diff --git a/Widgets/AudioSpectrum/NWaveSpectrum.qml b/Widgets/AudioSpectrum/NWaveSpectrum.qml index 9211fdd1..e2a3cfc7 100644 --- a/Widgets/AudioSpectrum/NWaveSpectrum.qml +++ b/Widgets/AudioSpectrum/NWaveSpectrum.qml @@ -46,7 +46,9 @@ Item { Canvas { id: canvas anchors.fill: parent - antialiasing: true + antialiasing: false // Disable for better performance - shape is smooth enough without it + renderStrategy: Canvas.Threaded // Render in separate thread to reduce main thread load + renderTarget: Canvas.FramebufferObject // Use FBO for better performance onPaint: { var ctx = getContext("2d")