Files
qbz/crates/qbz-qt/qml/immersive/WaveBedPanel.qml
T

74 lines
2.7 KiB
QML

// WaveBedPanel — FOCUS mode 6, the full-screen VERTICAL-mirror waveform
// (§6.1 of the 2026-08-02 immersive-port contract), port of
// crates/qbz-ui/ui/immersive/ImmersiveWaveBedPanel.slint:24-74.
//
// OPAQUE #000 (:49) — hides the atmosphere, intended (§5.1). This is NOT the
// Spectrum panel: every column is centered on the viewport Y midline and
// grows up AND down symmetrically (the full-screen twin of the dock's
// WaveCol, :5-13).
//
// GEOMETRY (:52-72): 48 downsampled L-channel columns (waveform indices
// 0..235 step 5 — the L half is samples 0..255), slot = vw/48, bar =
// slot-4, x = i*slot + 2, colH = max(2, amp*0.7*vh) with amp = min(1, |w|),
// y = (H - h)/2 (the vertical mirror), radius 1, color
// QbzShell.ambientPrimary (the Slint ImmersiveState.spectrum-primary — same
// album-derived pipeline, SpectrumBand.qml:109-113 precedent).
//
// FFT CONSUMPTION (trap 6): ONE VizSettle on QbzViz.waveform; the
// |sample|-fold + downsample happens ONCE per publish in the settle's
// `target` binding (48 ops — the SpectrumBand.qml:239-248 idiom), never per
// column per frame. The inter-frame settle is VizSettle's (the Slint
// `animate col-h 70ms` equivalent, :31).
//
// The bottom-right ImmersiveSongCard is mounted by ImmersiveView (layer 4),
// NOT inside this panel (:15-16).
import QtQuick
import com.blitzfc.qbz
import "../shell"
Rectangle {
id: root
color: "#000000"
readonly property real slot: root.width / 48
// Max half-amplitude reach ~0.35*H up and down (full bar = 0.7*H tall).
readonly property real maxColH: root.height * 0.7
// ONE VizSettle for the whole stream (trap 6). The |sample| envelope is
// folded HERE, once per publish, instead of an abs+min per column per
// rendered frame (VizSettle branches on Array.isArray and skips its own
// copy for this arm).
VizSettle {
id: waveSettle
live: root.visible && QbzImmersive.open
target: {
var s = QbzViz.waveform
var out = new Array(48)
for (var i = 0; i < 48; ++i) {
var v = s[i * 5] || 0
if (v < 0) v = -v
out[i] = v > 1 ? 1 : v
}
return out
}
}
// STATIC Repeater model (48 columns); only each column's HEIGHT binds to
// the stream.
Repeater {
model: 48
delegate: Rectangle {
required property int index
x: index * root.slot + 2
width: root.slot - 4
height: Math.max(2, waveSettle.at(index) * root.maxColH)
// Centered on the viewport Y-mid -> vertical mirror (:37-38).
anchors.verticalCenter: parent.verticalCenter
radius: 1
color: QbzShell.ambientPrimary
}
}
}