92 lines
2.7 KiB
QML
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
|
|
}
|
|
}
|