Search guides and the APICtrl K
  1. API reference
  2. System, devices and network

audio_cd.h

Audio CDs: reading them (AudioCDReader) and burning them (AudioCDBurner). Windows only; elsewhere both report that nothing is there.

#include <sonore/audio_cd.h>
On this page

Design notes

Reading

An audio CD has no files. Explorer shows "Track01.cda", but those are 44-byte stubs the file system driver invents; the audio is raw sectors of 2352 bytes -- 588 stereo frames of 16-bit little-endian PCM at 44.1 kHz, with no header and no checksum the drive will let us see. So the reader talks to the drive directly: IOCTL_CDROM_READ_TOC_EX for the table of contents (where each track starts, in sectors, and which are data), and IOCTL_CDROM_RAW_READ in CDDA mode for the sectors themselves.

The TOC is parsed from the bytes the drive returns (CDToc::parse), not through the SDK's C structs, so it can be tested without a drive and read with suspicion: a drive's answer is input like any other, and a TOC whose tracks go backwards or past the lead-out is refused, not trusted.

What this does NOT do is what secure rippers do: re-read every sector until two reads agree, correct for the drive's read offset, and check the result against AccurateRip. A scratched disc reads here as whatever the drive's own error concealment produced. That is the reference's behaviour too.

Burning

Through IMAPI2, Windows' own burning service: IDiscFormat2TrackAtOnce writes each track as 16-bit stereo 44.1 kHz PCM from a stream, then closes the disc so any CD player reads it. Tracks are padded with silence to a whole sector and to the four-second minimum the Red Book sets, because a drive refuses (or a player skips) a shorter one.

IMAPI2 reports progress through a COM connection point, and those events arrive on IMAPI's own thread -- and deadlock if the burning thread is a single-threaded apartment that is busy inside the blocking AddAudioTrack. So burn() does the COM work on a thread of its own, in the multithreaded apartment, and the caller's thread only polls: the progress callback runs on the CALLER's thread, as the reference's does, and returning true from it cancels.

What has been run

The machine this was written on has no optical drive. The TOC parser, the sector arithmetic, the CDDB id, the track preparation and every "no drive" path are tested (audio_io_test); the DeviceIoControl and IMAPI2 calls compile and are written to Microsoft's documentation, and have not read or burned a real disc.

Types 3

A CD's table of contents: where each track starts, and where the disc's program area ends (the lead-out). Addresses are LBAs -- sector numbers counted from the start of the first track's index 1, which is the "00:02:00" of MSF time; kPregapSectors is that two seconds.

Reading an audio CD in a drive: its table of contents, and its audio as 44.1 kHz stereo float.

Burning an audio CD: add tracks, then burn() writes them track-at-once and closes the disc.

↑↓ to move↵ to openEvery public name in the headers, and every guide