Fix argument parsing, --dump-iso output, and a Windows libisofs data-corruption bug Closes #7, #11, and #12 See merge request simulant/mkdcdisc!33 |
||
|---|---|---|
| .gitlab-ci | ||
| assets | ||
| docs | ||
| src | ||
| tests | ||
| .gitattributes | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| BUILDING.md | ||
| LICENSE | ||
| meson.build | ||
| README.md | ||
mkdcdisc
A modern command-line tool (CLI) to generate Sega Dreamcast bootable disc image files.
This intends to be a one-stop-shop for creating Sega Dreamcast images, doing what
scramble, makeip, objcopy, and img4dc (e.g., cdi4dc or mds4dc) do but
with additional features like automatic disc padding, CDDA audio tracks, alternative
disc layouts, and the ability to wrap externally-built ISOs (e.g. from mkisofs)
into a CDI, MDS/MDF, or NRG image.
Three output formats are supported: DiscJuggler (.cdi, the default), Alcohol
120% (.mds/.mdf), and Nero Burning ROM (.nrg).
Building
mkdcdisc is cross-platform and builds on Linux, macOS, and Windows
with meson. See BUILDING.md for platform-specific
dependencies and instructions (including the two Windows variants).
git clone https://gitlab.com/simulant/mkdcdisc
cd mkdcdisc
meson setup builddir
meson compile -C builddir
# run
./builddir/mkdcdisc -h
Usage
mkdcdisc --help
Usage: mkdcdisc [OPTION]... [-e EXECUTABLE | -t ISO] -o OUTPUT
Generate a Padus DiscJuggler (.cdi), Alcohol 120% (.mds/.mdf), or Nero Burning ROM (.nrg) image for
use with the Sega Dreamcast.
-a, --author author of the disc/game
-b, --unscrambled-binary executable file to use as 1ST_READ.BIN, in unscrambled binary format
-B, --scrambled-binary executable file to use as 1ST_READ.BIN, in scrambled binary format
-c, --cdda audio track (.wav or raw CD-DA). Specify multiple times for multiple
tracks
-d, --directory directory to include (recursively) in the data track. Repeat for
multiple directories
-D, --directory-contents directory whose contents should be included (recursively) in the data
track. Repeat for multiple directories
-e, --elf executable file to use as 1ST_READ.BIN
-f, --file file to include in the data track. Repeat for multiple files
-F, --format output image format: 'cdi' (DiscJuggler, default), 'mds' (Alcohol 120%
MDS/MDF), or 'nrg' (Nero Burning ROM, DAO). Inferred from the output
file extension when omitted
-h, --help this help screen
-i, --image path to a suitable MR format image for the license screen
-m, --no-mr disable the default MR boot image
-M, --print-msinfo print the MSINFO (data-track start LBA) for the given -c audio tracks
and exit, then feed it to mkisofs as -C 0,MSINFO when building an ISO
for -t. With no -c tracks, prints the Audio/Data default. With
-L/--data-data-layout, always prints 0. With -K/--merged-data-layout
and a single -t ISO given, prints the session 2 start LBA computed
from that ISO's size, to feed mkisofs as -C 0,MSINFO -M <iso> when
building session 2
-I, --dump-iso if specified, the data track will be written to a .iso alongside the
output image
-K, --merged-data-layout produce a Data/Data image where the second data session is a full ISO
merging the first session's files with new ones (built externally via
mkisofs -M), instead of a boot-head duplicate. Requires exactly two
-t/--external-iso-track ISOs (session 1, then session 2). Incompatible
with --cdda and -L/--data-data-layout
-L, --data-data-layout produce a Data/Data image (a second data session holds a boot track)
instead of the default Audio/Data layout. Incompatible with --cdda and
-K/--merged-data-layout
-o, --output output filename
-n, --name name of the game (must be fewer than 128 characters)
-N, --no-padding specify to disable padding of the data track
-p, --ipbin ip.bin file to use instead of the default one
-P, --product-version product version (IP.BIN, must be fewer than 6 characters). Defaults to
the template IP.BIN's own value
-q, --quiet disable logging. equivalent to 'v 0'
-r, --release release date in YYYYMMDD format
-s, --serial disk serial number
-S, --sort-file path to sort file
-t, --external-iso-track use a pre-built ISO (made by mkisofs with IP.BIN embedded via -G) as
the data track, delegating filesystem/IP.BIN creation to external
tools. Produces an Audio/Data image by default, a Data/Data image with
-L, or a Data/Data image with a merged second session with -K, in cdi,
mds, or nrg format per -F/--format (or the output extension). With -K,
-t must be given twice (session 1 ISO, then session 2 ISO). Build the
ISO with -C 0,MSINFO (see -M); CDDA tracks (-c) are supported in
Audio/Data mode. Disables all other data-track and IP.BIN related
options
-V, --volume-label ISO9660 volume label. Sanitized to at most 32 uppercase characters
(non alphanumeric characters become '_'). Defaults to the IP.BIN title
(see -n/--name)
-v, --verbosity a number between 0 and 3, 0 == no output
Output formats
mkdcdisc can write three image formats. By default it produces a DiscJuggler
.cdi image; pass --format mds/--format nrg (or simply use a
.mds/.mdf/.nrg extension on -o) to produce an Alcohol 120% or Nero
Burning ROM image instead.
# DiscJuggler (default)
mkdcdisc -e game.elf -o game.cdi
# Alcohol 120%, selected explicitly
mkdcdisc -e game.elf -o game.mds --format mds
# Alcohol 120%, inferred from the extension
mkdcdisc -e game.elf -o game.mds
# Nero Burning ROM, inferred from the extension
mkdcdisc -e game.elf -o game.nrg
About the CDI format
DiscJuggler .cdi is the single-file image format created by Padus
DiscJuggler burning software. Unlike the MDS/MDF pair, a CDI keeps
everything in one file: the raw track data comes first, followed by a
descriptor appended at the very end that lists the sessions, tracks, track
modes and disc metadata. A small offset stored in the last four bytes of the
file tells a reader where that trailing descriptor begins, so the image is
parsed back-to-front.
It became the de-facto format for Dreamcast homebrew because it cleanly
represents the console's two-session "trick" layout (an audio session
followed by a bootable data session) in a single file that emulators and
burning tools read directly. This is the format mkdcdisc produces by default,
and the role historically filled by the cdi4dc tool.
About the MDS/MDF format
Alcohol 120% images come as a pair of files sharing the same base name:
.mds: the Media Descriptor, a small file holding the disc layout: sessions, tracks, track modes, pregaps, LBAs and the offsets of each track inside the data file..mdf: the Media Data File, containing the actual disc contents as full raw 2352-byte sectors.
For a Dreamcast disc, mkdcdisc writes the usual two-session layout: a first session holding the CDDA audio track(s) (or a short silent placeholder track when no audio is supplied), followed by a second data session in XA Mode 2 Form 1. Data sectors are fully encoded; sync, header, subheader and EDC/ECC are generated via libedc, exactly as on a real disc, so the resulting image boots in emulators and can be burned as-is.
Track pregaps are declared in the descriptor but not stored in the .mdf,
which is the convention Alcohol uses for disc-at-once images; the burning
software synthesizes them on the fly. The .mds footer references its data
file with a *.mdf wildcard, so the pair keeps working even if both files
are renamed together.
This support is a modern reimplementation of the MDS/MDF writer originally
shipped in mds4dc.
About the NRG format
Nero Burning ROM .nrg is, like CDI, a single-file format: raw track data
(including pregaps, which are physically stored here) comes first, followed
by a trailer of self-describing chunks, followed by a 12-byte footer at the
very end of the file pointing back at the start of that trailer -- so, like
CDI, it's parsed back-to-front.
Nero images can be written in two very different recording modes, which show
up as different trailer chunks: TAO (Track-At-Once, ETNF/ETN2
chunks), which has no cue sheet and imposes automatic gaps between tracks,
and DAO (Disc-At-Once, CUEX/DAOX/SINF chunks), a full cue sheet
plus per-track descriptors with sector-accurate offsets. mkdcdisc only ever
produces DAO images: the Dreamcast's two-session layout needs a
sector-precise MSINFO, a -150 pregap on track 1, and precise session
boundaries, none of which TAO's automatic gaps can guarantee.
For each session, mkdcdisc writes a CUEX cue sheet (pregap/data start LBAs
for every track, plus the session's lead-out), a DAOX chunk (per-track
byte offsets into the file, sector size and mode), and a SINF chunk
(that session's track count) -- mirroring the same Audio + XA Mode 2 Form 1
raw-sector encoding (sync, header, subheader, EDC/ECC via libedc) that the
CDI and MDS/MDF writers already produce.
Disc Image Layouts
mkdcdisc supports three disc layout modes, each with different compatibility profiles:
Audio/Data Layout (default, Mil-CD format)
The classic layout used by SEGA's mastering tools, implementing the Mil-CD (Music Interactive Live CD) format. Mil-CD is a digital optical storage format created by Sega that allows code to be loaded on the Dreamcast via standard compact disc media, consisting of audio tracks before the track containing Dreamcast-bootable data. Session 1 contains a CDDA audio track (either from your .wav files with -c, or a 4-second silence filler), and Session 2 contains the data track (the ISO9660 filesystem).
This layout was supported by early Dreamcast revisions and is the most feature-rich (you can include background music or multimedia content via CDDA). However, Mil-CD support was removed from the final Dreamcast revisions toward the end of the console's life, meaning later hardware variants may have trouble booting Audio/Data images.
Use audio tracks with -c (e.g., -c intro.wav -c music.wav).
Data/Data Layout (-L/--data-data-layout)
An alternative layout where both sessions are data tracks. Session 1 holds the full ISO (built as MSINFO 0), and Session 2 holds a "boot head", a duplicate of the ISO's first 18 sectors (the IP.BIN system area plus ISO9660 volume descriptors, padded to the 300-sector minimum). This layout is more compatible with later Dreamcast hardware revisions that dropped Mil-CD support, but it comes at the cost of not supporting CDDA audio tracks. If you specify both --data-data-layout and -c, mkdcdisc will error and exit.
Use Data/Data mode with -L/--data-data-layout (incompatible with -c/--cdda). Works with both Standard Mode and External ISO Mode (-t).
Merged Data/Data Layout (-K/--merged-data-layout)
Another Data/Data variant, but where the second session is a genuine, independently-built ISO instead of a boot-head duplicate: it's the full merge (via mkisofs -M) of session 1's files with new ones, plus its own IP.BIN. Unlike -L, session 1 needs no IP.BIN of its own -- it's never booted from directly, only its files are read (either directly, or through session 2's merged view of them).
This mode only exists as an External ISO Mode variant (-t, given twice): mkdcdisc does not build either filesystem itself here, it only wraps the two ISOs you already built with mkisofs into the final disc image. There is no Standard Mode equivalent. Incompatible with -c/--cdda and -L/--data-data-layout.
Choosing a layout
If audio tracks are important to your project, stick with Audio/Data (default). If you're targeting maximum hardware compatibility or working around reported disc-reading issues on certain Dreamcast units, you may try Data/Data (-L) or Merged Data/Data (-K). However, those
Dreamcast revisions are pretty rare on the market, so sticking with Audio/Data shouldn't be a problem in most cases.
Modes of Operation
mkdcdisc supports two workflows:
Standard Mode (default)
Build everything from scratch: you provide an ELF/binary, mkdcdisc creates the filesystem, embeds the IP.BIN, generates the ISO internally, and assembles the disc image (CDI, MDS/MDF, or NRG).
mkdcdisc -e game.elf -d data/ -o game.cdi
External ISO Mode (-t/--external-iso-track)
Delegate filesystem and IP.BIN creation to external tools like mkisofs, then wrap the resulting ISO into a CDI, MDS/MDF, or NRG image, per -F/--format (or the output extension, same as the normal build). Useful when you need fine control over the filesystem (e.g. Joliet, Rock Ridge, custom sort order) or when reusing ISOs built elsewhere.
When using -t, options that build the filesystem (-a, -b, -B, -d, -D, -e, -f, -i, -I, -m, -n, -N, -p, -r, -s, -S) are rejected; only -c (CDDA tracks), -F/--format, -L/--data-data-layout, -K/--merged-data-layout, and -o are allowed alongside -t.
# Step 1: compute MSINFO for your audio tracks
MSINFO=$(mkdcdisc -M -c track01.wav -c track02.raw)
# Step 2: build the ISO with that MSINFO
# Where "cd_root" is a directory containing game data files
mkisofs -C 0,$MSINFO -V "GAME_NAME" -G IP.BIN -joliet -rock -l -o data.iso cd_root/
# Step 3: wrap into CDI with the same audio tracks
mkdcdisc -t data.iso -c track01.wav -c track02.raw -o disc.cdi
# ...or wrap into an Alcohol 120% image instead
mkdcdisc -t data.iso -c track01.wav -c track02.raw -o disc.mds
# ...or wrap into a Nero Burning ROM image instead
mkdcdisc -t data.iso -c track01.wav -c track02.raw -o disc.nrg
Data/Data layout (-L) is also supported with -t; since it has no audio session, build the ISO at MSINFO 0 instead:
# You may omit -C 0,0 in that case
# Where "cd_root" is a directory containing game data files
mkisofs -C 0,0 -V "GAME_NAME" -G IP.BIN -joliet -rock -l -o data.iso cd_root/
mkdcdisc -t data.iso -L -o disc.cdi
Merged Data/Data layout (-K) always goes through -t, given twice: session 1's ISO is built first (no -G, it never boots directly), then session 2 is built as a mkisofs -M merge of session 1 plus new files, with the real -G IP.BIN:
# Step 1: build session 1's ISO -- no -G, it's never booted from directly
# (session1_data/ must be at most 68,808,704 bytes for this example's MSINFO to hold)
mkisofs -V "GAME_NAME" -o session1.iso session1_data/
# Step 2: compute session 2's MSINFO from session 1's ISO
MSINFO2=$(mkdcdisc -M -K -t session1.iso)
# Output: 45000
# Step 3: build session 2 as a merge of session 1's files with new ones,
# with the real IP.BIN this time
mkisofs -C 0,$MSINFO2 -V "GAME_NAME" -G IP.BIN -M session1.iso -o session2.iso session2_data/
# Step 4: wrap both ISOs into the final disc image
mkdcdisc -K -t session1.iso -t session2.iso -o disc.cdi
CDDA Audio Tracks and MSINFO (LBA value)
When your disc has audio tracks in the first session, the data track does not start at a fixed LBA; it depends on the total size of the audio. This starting LBA is called MSINFO.
mkisofs needs to know the MSINFO before building the ISO (via -C 0,<msinfo>) so it can place the correct absolute addresses inside the ISO. This is why the workflow above uses -M to pre-compute the value.
Computing MSINFO (LBA value)
Use -M / --print-msinfo to compute the data-track LBA:
mkdcdisc -M -c track1.wav -c track2.raw
# Output: 12608
If you specify no -c tracks, it prints the Audio/Data default (11702). With -L/--data-data-layout, it always prints 0, since a Data/Data image has no audio session.
Audio Track Formats
Both .wav (RIFF PCM, 44100 Hz, stereo, 16-bit) and .raw CD-DA (headerless PCM in the same format) are supported. Detection is automatic: if a file has a RIFF header, it's treated as WAV; otherwise, it's assumed to be raw. No file extension checking occurs.
Examples:
-c intro.wav: WAV file (auto-detected)-c audio.raw: raw CD-DA data (auto-detected)-c track.bin: raw CD-DA data, detected by content, not extension
Raw CD-DA Requirements:
- 44100 Hz sample rate
- Stereo (2 channels)
- 16-bit samples
- Little-endian PCM
- Exactly 2352 bytes per sector (44100 Hz × 4 bytes/sample / 75 sectors/sec)
- Minimum 300 sectors (~4 seconds)
Files smaller than 300 sectors will trigger a warning but are not rejected.
Sort file
When using the -S flag, you must provide a sort file that specifies the order
in which files and directories are written to the ISO image. This ordering can
influence the performance of data retrieval, where data on the outer edges of
the disc can be read faster.
Understanding the Sort File:
- Structure: Each line in the sort file corresponds to a file or directory path, followed by a weight value. The format is:
/path/to/file_or_directory weight
Weights:
- Default Weight: All files/directories are assigned a default value of 0.
- Positive Weights: Higher positive values place files closer to the center of the disc.
- Negative Weights: Lower negative values place files nearer to the outer edge of the disc for faster read times.
- Directory Handling: Assigning a weight to a directory applies that weight to all its contents recursively.
- Comments and Blank Lines: Lines starting with
#are treated as comments and ignored. Blank lines are also ignored.
Example Sort File:
# Position the introductory video at the outer edge for immediate playback
/media/videos/intro.mp4 -1000
# Place high-resolution images for quick access
/media/images/high_res/image1.jpg -800
/media/images/high_res/image2.jpg -800
# Default weight files are written before the files below
# Standard resolution images can be placed closer to the center
/media/images/standard_res/image3.jpg 200
/media/images/standard_res/image4.jpg 200