Command line tool for generating CDI images designed for the SEGA Dreamcast
Find a file
SiZiOUS b22555e59d Merge branch 'bug-fixes' into 'main'
Fix argument parsing, --dump-iso output, and a Windows libisofs data-corruption bug

Closes #7, #11, and #12

See merge request simulant/mkdcdisc!33
2026-07-13 21:59:24 +00:00
.gitlab-ci Move ci/ to .gitlab-ci/ and trim build-stage artifacts 2026-07-09 20:23:05 +02:00
assets Improve arg parsing, add a default disclaimer 2022-06-03 20:20:58 +01:00
docs Adding mds/mdf documentation from Henrik Stokseth 2026-06-14 12:42:03 +02:00
src Fix --dump-iso writing an unusable .iso for non-zero MSINFO layouts 2026-07-13 23:17:24 +02:00
tests Fix NRG DAOX toc_type, CUEX mode flag, and chunk ordering 2026-07-12 21:48:41 +02:00
.gitattributes Give each platform's JUnit report a unique test suite name 2026-07-08 22:30:19 +02:00
.gitignore Add -F nrg / .nrg output, a Nero Burning ROM (DAO) image writer 2026-07-12 13:57:27 +02:00
.gitlab-ci.yml Trim leftover meson/ninja bookkeeping from build-stage artifacts 2026-07-09 21:31:07 +02:00
BUILDING.md Extract build instructions into BUILDING.md 2026-07-10 20:14:48 +02:00
LICENSE Embed Windows version resource via windres and updating licence 2026-07-10 22:31:14 +02:00
meson.build Add -F nrg / .nrg output, a Nero Burning ROM (DAO) image writer 2026-07-12 13:57:27 +02:00
README.md Fix crash on non-numeric or out-of-range -v/--verbosity values 2026-07-13 22:52:40 +02:00

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