feat(qt): open a SACD image and play it — the disc names itself

`Open > Open SACD image…` picks a .iso, reads its stereo area and publishes it
as the ephemeral session. Nothing lands in library.db.

Unlike a CD, a SACD needs no network to be named: the Master TOC carries the
album title and artist, and the area TOC a title per track. The owner's disc
opens as "Wagner: Das Rheingold", 24 tracks, every one with its German title
and "Berliner Philharmoniker, Herbert von Karajan, etc." — all of it read off
the image.

Routing is one line in `LocalSource::playback` and none in the player: a
`sacd:` reference rides the existing DsdFile ticket, because `open_dsd` is the
funnel all six player-side DSD constructions already go through. Teaching it
there is what makes the PCM, DoP, native and gapless paths inherit disc images
for free.

Driven end to end on the owner's Rheingold: the tab reads "Wagner: Das
Rheingold 24", the badges read HI-RES / DSD64, and pressing play took the DoP
route —

  Player: DSD track — DSD64 via DoP (176400 Hz carrier)
  [ALSA Direct] DoP hardware configured: 176400Hz, 2ch, S32_LE
  Audio thread: DoP playback STARTED

which is the outcome that matters: the disc's DSD bits reach the DAC without
being converted to PCM at all.

Six new strings in all eight locales. Unsupported cases are named rather than
approximated — a multichannel-only area, a DST-compressed one and a file that
is not an image each get their own message.

cc
This commit is contained in:
vicrodh committed 2026-08-21 01:34:23 -06:00
1 parent 06405969e9
commit 452589ddaa
15 files changed
+537 -70

No files matched your search

@@ -197,11 +197,14 @@ Item {
{ "label": QbzSession.tr("Open folder…", QbzSession.trRev),
"icon": "folder-open", "action": "folder" },
{ "label": QbzSession.tr("Open audio CD", QbzSession.trRev),
"icon": "disc", "action": "cd" }
"icon": "disc", "action": "cd" },
{ "label": QbzSession.tr("Open SACD image…", QbzSession.trRev),
"icon": "disc-3", "action": "sacd" }
]
onPicked: function (action) {
if (action === "folder") QbzLocal.ephemeralOpen()
else if (action === "cd") QbzLocal.ephemeralOpenCd()
else if (action === "sacd") QbzLocal.ephemeralOpenSacd()
}
}