Shorten compresses the sound of a file, not the file. To give back the original byte for byte, the stream
carries the original’s other bytes as well: those in front of the sound go in VERBATIM
commands at the start of the stream, and those after it in VERBATIM commands at the end. Decoding the stream with
the program’s -x option writes all of it out in order, so the result is the file that was compressed.
A decoder that only wants sound can ignore the stored bytes, but it gets the sample rate from them.
What the decoded file is made of
- Any bytes in front of the
ajkgmarker. The decoder looks for the marker in the file and passes what comes before it straight through. The encoder’s-aoption (alignment) leaves that many leading bytes of the input in front of the marker like this, and tags put there by other programs (ID3v2) are passed through the same way. - The skipped bytes of the header, stored as 7-bit-code bytes.
- The stored header, in VERBATIM commands before the first block.
- The sound, rebuilt from the blocks, the samples of the channels interleaved one frame at a time in the type’s byte order.
- The stored trailer, in VERBATIM commands after the last block.
The explorer rebuilds the file in this order to check itself: for every test stream that came with a copy of the original, the rebuilt bytes are identical to it.
A RIFF WAVE header
When the encoder is given a WAV file (the default file type) it reads the header itself and stores it. It reads chunks
from the start: the RIFF size and WAVE signature, then each chunk’s id and size; every chunk before
data is stored whole, and the data chunk’s id and size are stored last. The stored header therefore ends just
before the first sample, so for a plain 16-bit WAV it is the usual 44 bytes (a fmt chunk of 16 bytes) or longer when
the file has other chunks (fact, LIST) in front of the sound. A header is stored as VERBATIM commands of
at most 256 bytes each.
Format tag in the fmt chunk | Bits per sample | File type the encoder picks |
|---|---|---|
| 1 (PCM) | 8 | 2, U8 |
| 1 (PCM) | 16 | 5, S16LH |
| 6 (A-law) | 8 | A-law: 9 (AU3), or 10 (ALAW) for a lossy stream |
| 7 (µ-law) | 8 | µ-law: 0 (AU1) in format versions below 2 or with the -u option, 8 (AU2) otherwise, or 7 (ULAW) for a lossy stream |
| anything else, or PCM of another width | refused: the encoder cannot handle the file |
The number of channels is the fmt chunk’s. After the header the encoder reads exactly the data
chunk’s length in samples, and what follows it in the file (a LIST chunk, padding, other chunks) becomes the
trailer. The trailer is stored by reading the rest of the input in pieces of 256 bytes.
A decoder takes the sample rate from the stored fmt chunk: the stream itself has no rate. The explorer reads the stored
header and shows its chunks, and reports where it disagrees with the stream (a channel count, a sample width, or a data
length that is not the number of frames the stream holds).
An AIFF header
The encoder also takes AIFF files (a FORM with AIFF or AIFC as its form type, both
handled the same way). It stores every chunk up to the SSND chunk, then the string SSND and its length.
The COMM chunk gives the channels and the sample size: 8 bits is stored as U8 (type 2) and 16 bits as S16HL (type 3, high
byte first, as AIFF has it); other sizes are refused.
The program does not take the 8 bytes after the SSND length (the sound data’s offset and block size, both normally
0) into the header: it reads them as the first samples. The stream of an AIFF file therefore starts with a few frames that are not
music: 8 bytes are 4 frames of a mono 16-bit file or 2 frames of a stereo one. The test streams show this: the mono AIFF test
stream decodes to 16,302 frames where its COMM chunk says 16,298. When the stream is decoded the bytes come out in
the right place, so the rebuilt file is the original; a program that plays the stream as it is plays those few zero samples first.
The explorer leaves them out of the waveform.
Streams without a stored header
When the input is given as a raw type (-t s16, a bare sample file) there is no header, and a decoder has only the type
and the channel count: the sample rate is not in the stream. The explorer then assumes 44,100 Hz (8,000 Hz for µ-law and A-law) and says so.
An FFmpeg decoder requires a stored header and refuses a stream that begins with anything else.
Sizes that must agree
| Stored value | Equals |
|---|---|
WAV RIFF size + 8 | The length of the whole original file |
WAV data size | frames × channels × bytes per sample |
| WAV channels, bits per sample | The stream header’s channels and file type |
AIFF COMM frames | The stream’s frames minus the few of the SSND fields |
A decoder does not check them. A stream that was cut short, or whose header was edited, can disagree; the explorer lists the differences under Checks.
Links
Specification and source
- shorten 3.6.1 – the reference program (
riffwave.c,aiff.candshorten.cdo the work described here)