Files
dotfiles/.config/quickshell/modules/CavaWidget.qml
T

92 lines
2.7 KiB
QML

// CavaWidget.qml - audio visualiser via cava raw output
import QtQuick
import QtQuick.Layouts
import Quickshell.Io
import ".."
Rectangle {
id: root
property var bars: Array(12).fill(0)
property bool silence: bars.every(v => v === 0)
readonly property var blocks: [" ","▁","▂","▃","▄","▅","▆","▇","█"]
implicitWidth: cavaRow.implicitWidth + Theme.pillPadH * 2
implicitHeight: Theme.barHeight
radius: Theme.radius
color: cavaHover.containsMouse ? Theme.pillHover : Theme.pill
Behavior on color { ColorAnimation { duration: 150 } }
RowLayout {
id: cavaRow
anchors.centerIn: parent
spacing: 1
Repeater {
model: root.bars.length
Text {
required property int index
text: root.silence
? " "
: root.blocks[Math.min(Math.floor(root.bars[index] / 28.5), 8)]
font.family: Theme.fontMono
font.pixelSize: Theme.fontSize + 1
color: Theme.foreground
}
}
}
MouseArea {
id: cavaHover
anchors.fill: parent
hoverEnabled: true
onClicked: Exec.run(["pavucontrol"])
}
// Write the cava config once at startup, then run cava pointing at it.
Component.onCompleted: writeCfg.running = true
Process {
id: writeCfg
running: false
// Plain double-quoted string - no JS interpolation, bash sees ${VAR} verbatim.
command: ["bash", "-c",
"mkdir -p /tmp/qs-cava && cat > /tmp/qs-cava/cava.ini <<'CFG'\n" +
"[general]\n" +
"framerate = 30\n" +
"bars = 12\n" +
"[input]\n" +
"method = pipewire\n" +
"source = auto\n" +
"[smoothing]\n" +
"noise_reduction = 77\n" +
"monstercat = 1\n" +
"[output]\n" +
"method = raw\n" +
"raw_target = /dev/stdout\n" +
"data_format = ascii\n" +
"ascii_max_range = 255\n" +
"bar_delimiter = 59\n" +
"CFG\n"
]
onExited: cavaProc.running = true
}
Process {
id: cavaProc
running: false
command: ["cava", "-p", "/tmp/qs-cava/cava.ini"]
stdout: SplitParser {
onRead: (line) => {
const parts = line.trim().replace(/;$/, "").split(";");
if (parts.length >= root.bars.length) {
root.bars = parts.slice(0, root.bars.length)
.map(v => parseInt(v) || 0);
}
}
}
onExited: cavaProc.running = true
}
}