Hi Maxim,
I've implemented DSD Disc ISO direct reading support for foo_input_sacd,
and I'd like to contribute it to the upstream project.
DSD Disc is a disc image format for publishing DSD audio on recordable
media, standardized by Sony. Unlike SACD ISOs (which use a proprietary
filesystem with SACDMTOC), DSD Disc stores individual DSF files inside
a standard UDF 1.02 volume — the same filesystem used by DVD-Video and
BDMV. Current versions of foo_input_sacd reject these ISOs because
they lack the SACDMTOC signature, even though the audio data is
standard DSD64/128/256.
Rather than requiring an external UDF library (a heavyweight dependency
for a single purpose), I wrote a lightweight UDF 1.02 parser directly
inside the plugin. Two new files under src/foo_input_sacd/:
udsd_reader_dsd_disc.h (254 lines)
udsd_reader_dsd_disc.cpp (797 lines)
The reader inherits from udsd_reader_t and plugs into the existing
dispatch mechanism in udsd_core.cpp, with essentially zero changes to
the existing SACD/DSF/DFF code paths.
Detection (g_is_dsd_disc): Opens the ISO with filesystem::g_open_read
(same pattern as g_is_sacd), reads AVDP at LSN 256, walks VDS to find
LVD/PD, reads FSD, and scans the root directory for a "DSD_DISC"
subdirectory.
UDF file traversal: Starting from the root File Entry, traverse
directory entries recursively. Each FID with directory flag set and
name != "DSD_DISC" enters a subdirectory; FIDs with .dsf extension
become tracks.
DSF header parsing: For each found file, read_and validate the
"DSD " magic, fmt chunk (sample rate, channel count, format_id),
and data chunk offset. The data offset is used by read_frame()
for streaming DSD audio direct from the ISO.
ID3 tag extraction: If the DSF header's id3_offset field is non-zero,
parse the ID3v2 tag for TIT2, TPE1, and TALB frames (title, artist,
album). UTF-16 and UTF-8 with BOM are handled.
Playback: read_frame() computes the byte offset within the ISO for
the current frame and reads via udsd_media_t::read(). seek() works
by frame index. Multi-channel DSD (up to 6ch) is supported.
UDF stores all multi-byte fields in little-endian, while DSF/ID3 fields
are big-endian (network byte order). The reader keeps the two worlds
separate: UDF struct members are read directly without swap on x86
(where host order matches LE), and DSF fields use ntoh32/ntoh64 macros
(aliases for hton32/hton64, symmetric on all architectures).
Added DSDDISC = 4 to media_type_e enum
src/foo_input_sacd/udsd_core.cpp
udsd_reader_dsd_disc_t — class declaration (inherits udsd_reader_t)
src/foo_input_sacd/udsd_reader_dsd_disc.cpp
797 lines, full implementation:
The patch is against the current foo_input_sacd snapshot (based on
sacddecoder-0.9.6 from SourceForge, foobar2000 SDK 2023-08-23). The
new code compiles cleanly and follows the existing coding style
(underscore naming, foobar2000 SDK conventions).
I'm happy to adjust anything — formatting, naming, structural
decisions. Let me know if you prefer a different approach (e.g. a
separate file input module, or a factored UDF mini-library shared
between readers).
Best regards
Aaron Leung/aaronleung@vip.qq.com
Anonymous
Hi Aaron,
It would be great to have some Sony DSD Disc ISO file for testing as well. Could you please point me where to download this?
Sincerely,
Maxim
Line 693 in patch file:
offset is undeclared identifier.
tks