Formats & decoding
Its own decoders first. Everything else is routed, and labelled.
crête ships decoders for every format the parity corpus depends on, so that a measurement never
changes because a library did. The optional FFmpeg tier adds the formats it cannot reasonably
own — and the routing rules that keep it out of the validated paths are strict, deliberate, and
stated in the output.
01 — Native decoders
In every build, with no dependencies
Container parsing and PCM extraction are crête's own, including the FLAC decoder. The FORMAT
suite transcodes every master into all of these and requires bit-identical metrics across them.
The 4 GB ceiling, and the crash it exposed
Plain RIFF stops at 4 GB, which is not an exotic limit for this material — a 43-minute 5.1
96 kHz/24 extract is 4.47 GB. All three containers now share one payload decoder and
measure identically to plain WAV. The rewrite also fixed a reachable crash: a truncated WAV
declaring more data than it holds read past the end of the buffer and segfaulted. All three walkers now clamp to the bytes actually present and
report the audio that is there.
Cue slicing
The sheet is parsed, each referenced file located case-insensitively, decoded once, then
sliced by track boundary and run through the full pipeline per slice. A sheet may name
several files — one per vinyl side or per disc — and INDEX times restart in
each, so since 0.19.1 every track is cut from the file its INDEX 01 sits in;
before that, all of them were cut from the last one. A track whose range is empty is
dropped with a warning and the run exits 2. Track times are held
as CDDA frames and converted at the actual decoded rate, so one sheet works for 44.1 kHz
WAV and 352.8 kHz DSD-decoded PCM without rounding loss. Tracks are named to match what the
common splitters produce, so a sliced monolith pairs cleanly against the per-track album.
A memory warning, not a footnote
crête loads a file before decoding it. At the default DSD output rate a monolithic
60-minute DSD64 album decodes to about 2.6 GB of float64; at 352.8 kHz that is 8× more. Cue
slicing adds one slice plus roughly twice its size as working set. Since 0.19.0 crête
plans for this itself: the default worker count is fitted to free memory, and each unit is
costed by its shape — a cue sheet as its whole monolith, a DVD title set as all its
fragments. The SACD reader is the one exception to holding a whole file: a disc image is
far too large to hold, so it seeks, and an area is costed as its largest track. --memory-limit overrides the budget and -j still pins the
count.
02 — Damaged files
What each container lets crête prove about itself
A meter's worst failure is not refusing a file — it is measuring a broken one and reporting a
number as though nothing happened. Before 0.17.0 crête did exactly that. It now verifies what
each format allows, and says so.
A damaged file is still measured
crête is a meter, not a repair tool: it reports what the bytes decode to and marks every
affected number untrustworthy. That separation is what keeps the intact-file path
bit-identical to the one that existed before these checks — verified across 62 files spanning FLAC, WAV (integer and float), AIFF, RF64, Wave64, ALAC,
TrueHD, AC-3 and DTS-HD MA in mono, stereo, quad, 5.1 and 7.1.
Always present, so it can be tested
Every warning also appears in -f json under warnings, which is
always emitted — an empty array is the positive statement "nothing was wrong", rather than
the absence of evidence a missing key would be. num_tracks counts what was measured, so a file that failed to decode contributes a warning and no track. The
run exits 2.
So a file that is not audio must not be read as damaged audio. Since 0.22.0 a folder scan
skips macOS AppleDouble sidecars, the ._<name> metadata files a Mac writes
next to every file on a USB stick or an SMB share; before, each one was reported as a damaged
track and the run exited 2. A sidecar named on the command line is still attempted.
The limit, stated plainly
WAV and AIFF carry no checksum. Altered sample values in them are
undetectable — by crête or by any other meter — because a run of zeros inside a data chunk is indistinguishable from a passage of digital silence the artist
put there. Only length and range can be checked; FLAC is the one that can prove itself. The
test suite asserts that a WAV with 4 KB of zeros written into its audio comes back clean, so the blind spot stays visible in a green run.
Warning: 04 - damaged.flac: FLAC: CORRUPT -- 1 of 215 frames failed the CRC-16 check (0.5%).
Warning: 04 - damaged.flac: FLAC: TRUNCATED -- STREAMINFO declares 882000 samples per channel but 877904 decoded (4096 missing, 0.5%).
Warning: 04 - damaged.flac: CORRUPT -- sample peak 45.32 dBFS on 16-bit integer PCM, which cannot exceed 0 dBFS.
Error: 05 - unreadable.flac: FLAC: invalid magic
03 — The FFmpeg tier
Opt-in, LGPL-only, decode-only, statically linked
A one-time script builds a minimal static FFmpeg with no GPL and no nonfree components, so crete-ffmpeg is still a single self-contained binary. The default make target remains zero-dependency and nothing about this tier is required for
PCM or DSD analysis.
Routing is strict, for parity reasons
Native formats always use crête's own decoders Even in the FFmpeg build. This is what preserves parity against the reference data.
FFmpeg handles only what crête does not own. In zero-dependency builds these formats are rejected with a hint rather than guessed at.
DSD is never routed through FFmpeg. Its decimation is a different filter chain and would break DSD parity outright.
crete-ffmpeg --version advertises the linked FFmpeg, and the About panel lists every
extra codec. Video containers work directly — crête ignores video and subtitle streams, so music
Blu-ray rips need no preparation. Also accepted in folder scans and dialogs: Vorbis, WMA v1/v2/Pro/Lossless,
WavPack, APE, Musepack and TAK.
04 — Disc audio
Three ways a Blu-ray will hand you the wrong number
Disc audio is where a meter quietly stops measuring what is on the disc. Each of these was
found by measuring, and each is now either fixed or labelled in the output.
It is not one album. It is six.
One UHD remux of a single title carried six audio streams — LPCM 5.1 at 96 kHz, DTS-HD MA
5.1, a TrueHD 7.1 Atmos track, an AC-3 core, and stereo LPCM and DTS-HD MA. Those are different mixes with different DR, not different encodings of one
mix.
With no explicit choice, crête takes FFmpeg's own pick, which ranks by bitrate and
channel count. That is reasonable but it is not the container's default flag and not stable across remuxes: on the full file it selects the 13.8 Mbps LPCM track;
on a 60-second stream copy of the same six streams it selects the TrueHD one, because the
copy carries no bitrate tags. Same audio, different measurement, and originally nothing in
the output said so.
Warning: album.mkv has 6 audio streams;
measured stream 2 (PCM_S24LE, 6 ch, 96000 Hz).
Use --stream N to choose.
The chosen index and the stream count appear in the detail output and in JSON, so a
measurement is reproducible from its own record. Single-stream files gain no warning and
no extra keys — verified byte-identical.
Dolby DRC is disabled
AC-3 and E-AC-3 carry dynamic-range-control metadata and FFmpeg's decoder applies it by default. That is correct for a player and wrong for a meter: DRC is
a playback-time compressor driven by authoring metadata, so measuring it means measuring a
rendition that is not on the disc. crête pins the DRC scale to zero.
The difference is large and easy to miss.
DR barely moves because it is peak minus RMS and DRC scales both. If crête disagrees with
a player's readout, this is usually why.
On one 5.1 bed, leaving DRC enabled moved
| Sample peak | 6.2 dB |
| RMS | 3.9 dB |
| Integrated loudness | 4.0 LU |
| DR | 0.24 |
Object audio is measured as its bed, and now says so
There is no Atmos or DTS:X renderer in the chain. What gets decoded is the underlying
channel bed — TrueHD 7.1, or E-AC-3 5.1 for Dolby Digital Plus with Atmos — and the
object metadata is discarded. crête's numbers for such a file are the bed's numbers,
which is exactly what a non-Atmos playback chain delivers, and not what a
renderer would produce.
That is a complete measurement of something real, but an unqualified "crête measures
Atmos" would be false — so the profile is reported separately from the layout, and JSON
carries codec_profile and an immersive_bed boolean. It is identification, not decode, following the precedent MQA detection already
set: name the premium layer from an authoritative bitstream field, never imply it was
rendered. The field is descriptive — no measured value depends on it.
A non-immersive profile such as DTS-HD MA is reported too, without the bed qualifier:
there is nothing unrendered about it. And the profile comes only from the FFmpeg tier,
since the zero-dependency binary cannot decode these codecs at all.
Format: TRUEHD 24-bit / 48000 Hz
Profile: Dolby TrueHD + Dolby Atmos
Layout: 7.1 · L R C LFE Lrs Rrs Lss Rss
[bed -- Atmos objects not rendered] Auro-3D is not detectable this way
FFmpeg reports an Auro carrier as plain DTS-HD MA, so no profile field can see it. On the
one disc measured here the "Auro-3D 9.1" label was a container title tag, with the height
channels buried in the carrier's low bits — a real signature, since on a solo-piano
recording whose LFE is otherwise digitally silent that carrier held 803,853 non-zero
samples within ±24 against the DTS:X carrier's exact zero. But reading it is inference
rather than a declared field, so if it is ever built it belongs in a confidence-scored
forensics namespace, gated off, never in the metrics.
A discrete Auro-3D file is a different case: one PCM channel per speaker, as
downloads ship and as the Auro encoder takes them. It declares its layout in its channel
mask, and since 0.21.0 crête labels and weights it from that mask — see Standards.
One thing the disc proves about itself
Two of those six streams are the same 5.1 96 kHz master delivered as LPCM and as DTS-HD MA.
Measured on a clip, every metric is exactly equal — DR, per-channel DR, sample
and true peak, all three loudness figures, LRA, PLR, PSR — to 0.000e+00. Only RMS
moves, by 1.2e-04 dB, and the sample counts explain it: one DTS frame of decoder tail, and RMS
is the only metric that divides by total sample count. The file gates itself, with no external
oracle — which matters, because none of these formats has reference data.
05 — DSD
A clean-room decimation kernel, on four declared axes
DSD bitstreams are decimated to PCM by libdsddpcm, vendored and statically
linked. It is a clean-room BSD-2-Clause kernel: linear-phase FIR only, so group delay is
constant, and unity DC gain — the +6 dB SACD makeup gain is not applied.
crête keeps its own container parsing and its one-thread-per-channel decode.
It replaced an LGPL engine transcribed from another player's source, which resolved a
licensing conflict with crête's MIT terms and made the project cleanly MIT plus
BSD-2-Clause. Different clean-room filters mean different numbers, so every
DSD reference baseline was regenerated against the commercial reference rather than carried
over.
--dsd-mode multistage | direct
multistage (default) is the measurement-grade path: LUT decimation to 8fs then a halving cascade, brickwalled at Nyquist at 44.1 kHz out, valid for DSD64 through 512 at every rate. direct is a single wide FIR with a gentle ~30 kHz corner that passes an attenuated top octave — DSD64 to 44.1 kHz only.
--dsd-out-rate 44100 | 88200 | 176400 | 352800
44100 is the default and the parity-guaranteed rate.
--dsd-filter default | firls | kaiser
The ranked final stage, honoured only at 44.1 kHz output: equiripple at 383 taps and roughly 154 dB stopband (the golden default), least-squares at 767 taps as a cross-method check, or a Kaiser window at 4095 taps as the maximum decode.
--dsd-bandwidth default | full | Hz
Since 0.22.0. The output rate sets how densely the signal is sampled; the bandwidth sets how much of it is signal. default appends a linear-phase low-pass with a 50 kHz corner (Scarlet Book Annex D.1), which acts at 176.4 and 352.8 kHz output; at 44.1 kHz the final stage already brickwalls, and at 88.2 kHz the corner sits above Nyquist. full is the ≤ 0.21.0 decode.
Support matrix
| 44100 | 88200 / 176400 / 352800 |
|---|
multistage | DSD64–512, any filter | DSD64–512, default filter only; --dsd-bandwidth acts at
176400 and 352800 |
direct | DSD64 only, default only | unsupported |
Unsupported combinations fail fast with an explanatory message rather than producing a
number. DSD1024 and above are rejected — the library's input enum tops out at DSD512. crete --version prints the resolved chain, decimation, tap count and group delay
for every rate at the current settings.
Read this before quoting a DSD number
DSD dynamic range depends on the output rate, and only 44.1 kHz carries a parity claim. Above
48 kHz output the halving cascade alone keeps the modulator's shaped ultrasonic noise, which
inflates the second-highest block peak far more than it inflates RMS. Up to 0.21.0, at
352.8 kHz, DR read +1 to +3 higher than at 44.1 kHz, and the ultrasonic content alone drove
the meter past full scale — a sample peak of +1.7 dBFS on one track.
Since 0.22.0 the band limit lives in the decoder: --dsd-bandwidth, a 50 kHz
linear-phase low-pass by default, acting at 176.4 and 352.8 kHz. A band-limiting flag had been
refused while it would have produced a number no reference implementation could check; in
the decoder, the exports the reference measures carry it too, and the 352.8 kHz references
were re-recorded with it. DSD64 RMS and DR at 88.2, 176.4 and 352.8 kHz now agree within
0.07, every Thriller track is back under full scale, and in weekly #106 album DR at 352.8 kHz
matches the reference on all eight DSD albums. --dsd-bandwidth full gives the old
numbers back.
It is still not parity. A 50 kHz band keeps 20 to 50 kHz content that the 44.1 kHz decode
removes, and the corner is fixed for every DSD rate, so DSD256 and DSD512 lose clean
content above 50 kHz. Results at 88.2 / 176.4 / 352.8 kHz are offered for analysis. Treat
them as a different measurement, not a more precise one.
Validation
crête on a .dsf and crête on the WAV exported from it agree exactly, because
both go through the same decode. Reference rows come from measuring those 32-bit-float
exports at a pinned decode configuration, at both 44.1 and 352.8 kHz — so the exporter is
load-bearing for the entire DSD corpus, and it has its own gate, which since 0.22.0 also
runs at 352.8 kHz with the band limit on and off. Re-recording the 44.1 kHz references on the
0.22.0 pipeline reproduced all 1869 July values exactly; the July 352.8 kHz rows are kept as
the references for full. The caveat is stated: this
validates metrics end to end, not the decimation, whose correctness rests on the library's
own golden vectors plus crête's internal parity suites.
06 — SACD disc images
The disc is the input. Both areas of it.
SACD rips circulate overwhelmingly as .iso, so for a meter with this much DSD
machinery that was the gap a real collection hits first — until crête read them, a disc had to
be extracted to .dsf or .dff before it could be measured at all.
crête reads the master TOC, both area TOCs, the track list and the audio-sector packet
stream, and hands per-channel DSD to the same decimation chain every .dsf and .dff goes through. So the four DSD axes above apply
unchanged, and crête on an ISO must agree with crête on an extracted rip of the same disc —
a crête-versus-crête gate that needs no external oracle.
A disc image is a third shape alongside "one file" and "cue-sliced": the track list comes
from the disc, and each track is decoded from its own sector range rather than sliced out of
one decode. It is also the one decoder that seeks rather than loading the whole
file — the test image is 3.88 GiB, and its stereo area alone decodes to 1.8 GB of float64
at the default output rate, or 14.6 GB at 352.8 kHz.
--sacd-area auto | stereo | multichannel
auto (default) prefers the 2-channel area: it is the layer crête’s DR references are built on, the layer comparable with every other release of an album, and usually the uncompressed one. A disc with no multichannel area refuses multichannel by name rather than quietly falling back.
crete album.iso # auto: the 2-channel area
crete --sacd-area multichannel album.iso # the 5.1 area
crete --sacd-area stereo album.iso
Dispatch is by content, not extension. .iso names every disc
image ever made, so crête checks for the SACD master TOC signature at a fixed sector and
quietly ignores anything else rather than trying to meter a data DVD. Since 0.19.5 a DVD
image is named as one — DVD-Audio or DVD-Video — with the instruction to mount it and
measure its AUDIO_TS or VIDEO_TS folder. It is identified, not
read: title sets are not read out of an image.
Validation
On the 2018 Dark Side of the Moon SACD all ten stereo-area track durations match the
published running order — 42:57 against the area's own declared 42:59 — and one track
returns peak −5.489 / RMS −19.753 against the −5.49 /
−19.75 already recorded for that album from a .dsf rip. Every non-ISO path was
compared byte-for-byte across the change: FLAC, AC-3, TrueHD, WAV and DFF all identical.
Gated since 0.17.0, and not before — the reader and the DST decoder were
validated by hand once and then left, which is uncomfortable for code whose failure mode is
silence. The suite measures a reduced image: the first tracks of each area, the
multichannel one relocated so the file need not span the 1.85 GB gap before it, 229 MB instead of ~4 GB. Every audio sector in it is the disc's own bytes;
only the TOC fields describing extent are rewritten, and the builder measures every kept
track in both the reduced and the full image and requires identical results, so its own
address arithmetic cannot certify its own mistake. 6 passed / 2 skipped on its first weekly.
The 2 skips are the .dsf parity tier, which is written but needs the DSD64
corpus staged alongside and so is not running in CI yet.
DST, and the only check that caught a wrong decoder
DST is SACD's lossless compression, and multichannel areas commonly use it — on that
disc the stereo area is plain DSD at 1.72 GiB while the 5.1 area is DST at 2.16 GiB
against the 5.16 GiB it would need uncompressed. crête carries its own decoder, written
from the published coding syntax and zero-dependency like everything else, so both areas
of a hybrid disc go through the same chain and nothing downstream can tell which the
disc used. DST is lossless; this is not an approximation.
Every frame must consume exactly its own coded length, and the decoder
asserts it. Arithmetic coding is exact: a decoder consumes the encoder's bits if and only
if it applies the encoder's probabilities. That assertion exists because the first
version of this decoder was wrong in a way nothing else could see.
It read a comparison from a syntax figure that the clause prose contradicts. Every frame
decoded without throwing. Every header parsed to stable, sane values. Mispredictions came
out at a healthy-looking 0.75 %. The output was 1-bit data at the right density that
decimated to audible sound. It was the prediction filter free-running on its own output,
consuming 15 % of each frame.
| The signal that was available | broken | correct |
|---|
| Frames decoded without error | all | all |
| Misprediction rate | 0.75 % | 0.75 % |
| Per-bin probability check | passes | passes |
| Frame bits consumed | 15 % | 100.0 % |
| 2–15 kHz band | +19 dB | −57 dB |
| Sample peak | +2.06 | −13.87 dBFS |
The two checks reached for first are structurally incapable of catching this. The
misprediction rate is low because the decoder consumes few bits, and per-bin
probability consistency is vacuous — an arithmetic decoder fed any probability sequence
produces events matching that sequence. It proves the coder, not the probabilities.
It is not fast: roughly 2× realtime for six channels, so a 43-minute 5.1 disc
takes about 20 minutes. All channels share one arithmetic decoder, so there is no parallelism
inside a frame — but the filter history is reinitialised per frame, so frames are independent
and could be decoded in parallel. Not done yet.
To validate a DSD de-interleave, look at the noise floor
Frames are byte-interleaved across channels. The other reading — contiguous per-channel
blocks — was implemented first and "confirmed" with the obvious test, the left/right
split. That test is worthless here: both readings give a plausible DR and a
plausible L/R difference, because a wrong de-interleave of a 1-bit stream still
decimates to something music-shaped.
What settles it is the property DSD exists for. Byte-interleaved gives the textbook
picture — music at low frequency, a quiet 2–20 kHz band, shaped noise climbing above
40 kHz. Blocks give a floor rising at every frequency with no quiet band anywhere. The
two are 34 dB apart where it matters.
Two more traps in the same reader produced equally plausible wrong answers. The
frame-format value for compressed is zero and the uncompressed forms are 2 and
3, so reading it backwards labels a DST area uncompressed — and DST bytes fed to the DSD
path decode to something that still looks like a measurement. And a DST sector's frame
header carries one byte more than a DSD sector's, which taken unconditionally overruns
the first packet and drops that sector's audio entirely: 14 % of every track
lost with no error, 58.65 seconds of a 68.45-second one. Both are now
cross-checked, and the header length is read from the sector rather than assumed from
the area.
Mean level by band, decimated to 352.8 kHz
Provenance
Both readers are written from the format descriptions — structure layouts and coding
syntax are facts about a format, used as documentation. No implementation was consulted:
the reference extractor is GPL-2.0, which is strictly worse for an MIT project than the
LGPL conflict the DSD engine swap existed to remove, and its DST decoder is a console
SPU offload with no software path in it at all. The other software DST decoder available
is LGPL. crête stays MIT plus BSD-2-Clause.
07 — DVD title sets
One title, several files, one stream
A DVD is the first container crête reads that is not one file holding one stream. The spec caps
a file at 1 GB, so a title's program stream is split at a pack boundary and numbered — and
metering the pieces separately is wrong twice over: each is metered alone, and the split lands
wherever 1 GB fell, so the 3 s DR block straddling it belongs to neither piece.
Point crête at any one fragment and it measures the whole title set. The
pieces are presented to FFmpeg as a single stream through one demuxer, so the boundary costs
nothing. On the test corpus the joined MLP duration is 49.632 s against 25.324 + 24.289 s
read separately — 19 ms longer, that being the frame the split cut in half. DVD
LPCM joins exactly, 23.498 + 23.721 = 47.219 s either way, because its packets are
self-contained within a pack.
It also removes a trap. The FFmpeg stream index is not stable across fragments
of one title: on the DSOTM 50th DVD the same three substreams come back in a
different order in the second fragment than in the first, because the index follows order
of first appearance in the program stream. A --stream pin correct for one
fragment selects a different codec in the next. One stream means one probe and
one answer, which is what makes --stream meaningful here at all.
VIDEO_TS/VTS_02_1.VOB _2.VOB _3.VOB one 43-minute title
AUDIO_TS/ATS_01_1.AOB ... _5.AOB one DVD-Audio title set
VTS_02_1.VOB VTS_02_2.VOB
index 2 ac3 lpcm
index 3 ac3 ac3
index 4 lpcm ac3 Validation
Both test discs carry a lossless stream — MLP on the DVD-Audio, DVD LPCM on the DVD-Video —
and the corpus ships each decoded to FLAC, so crête through the disc container must equal
crête on the FLAC exactly: two independent decode paths over the same
samples, nothing to calibrate. The suite is 10/10 on its first weekly,
#85, and fails all ten against the build before it. With foobar measuring each FLAC it now
holds twelve tests, and has passed all twelve in every weekly since 0.19.5. The whole JSON tracks array is
byte-identical to 0.17.0 on all seven disc-audio carriers, so reading DVDs moved
nothing that was already measured.
A DVD-Audio title set holds more than one mix
Fleetwood Mac's Rumours (2001, Warner) is one title set holding four titles — a
96 kHz 5.1 mix, a 96 kHz stereo mix, a 48 kHz 5.1 version and a one-second tail — 39
tracks across five .aob fragments, and the group boundaries do not
align with the fragments. The 6-to-2-channel change falls partway through ATS_01_3.AOB, so even a single .aob can cross one.
Left to itself FFmpeg decodes straight through the change into a resampler configured for
the previous format, and reports nothing but a parity-check failure and a timestamp
discontinuity on stderr. The numbers stay in range and nothing says they are meaningless.
crête stops at the change, measures the first group, names it, and exits
2 — a warning over the wrong numbers would be the silent wrong answer in camouflage.
The probe had the same blind spot one level up: it can read deep enough to reach a later
group and report 2 channels for a stream whose first frame is 6. So the channel layout and
rate now come from the first decoded frame, not the container — the
decision already taken for the sample format, extended to the two fields the probe can
get wrong the same way.
Warning: audio format changes partway through
this stream (a DVD-Audio title set holds several
audio groups); measured the first group only,
6 ch / 96000 Hz
Reading the disc's own tables
make dvda-info builds a zero-dependency tool that parses a title set's
formats, titles and track lengths without decoding anything — one second on a 4.5 GB
title set. On Rumours the track lengths sum to each title's own stated total exactly, on all four titles, in fields held in separate structures; a
wrong offset or byte order cannot produce four exact matches. The three format entries
agree, in order, with the three groups decoding had already found.
crête does not yet use it to measure per track or per title. Durations
do not give byte offsets — MLP is variable-rate — and the table that would is still a
hypothesis. A wrong offset into a lossless stream yields audio that plays and a DR that
looks reasonable, so it waits for the same arithmetic proof the track table met.
One caveat on --stream for .vob: the compact FFmpeg
lists one more audio stream than the disc carries. It cannot identify the MPEG-2 video,
content-probes it and matches it as MP3, so three audio streams list as four and the extra
decodes to 0.34 s at 16 kHz with a +23 dBFS peak. A full FFmpeg types it correctly. It cannot be
filtered on crête's side, because MPEG audio is a legal DVD audio format. Automatic selection is
unaffected — it ranks by bitrate and the phantom has none — and every genuine stream is reachable
by index; only the listing is wrong.
08 — MQA
Reported unconditionally. There is no flag to turn it off.
MQA is a lossy codec delivered inside an ordinary lossless-looking container — 44.1 or 48 kHz,
stereo, 16 or 24-bit — with the encoded data hidden in the low bits. A dynamic range measurement
on such a file describes lossy audio dressed as hi-res, so crête flags it every time.
Detection is deterministic, not statistical
The primary MQA bitstream is the XOR of one low bit from each left/right sample pair. crête
reconstructs that bitstream across candidate carrier positions — bit 8 for 24-bit hi-res
MQA, bit 0 for 16-bit MQA-CD, which shifts the whole encoding down a byte — and searches for
the datasync packet: a 40-bit sync value followed by a well-formed field structure.
A match is proof rather than a guess; the odds of a coincidental 40-bit magic number plus valid fields are negligible, and in practice only the true carrier plane ever hits.
From the packet crête reads the authored sample rate, the authentication level that distinguishes
Studio from green, the render filter and bit-depth indices, and the carrier bit position.
A raw low-bit entropy figure is exposed in JSON as a diagnostic and is never treated
as a verdict — near-full low-bit entropy is equally consistent with analog tape hiss or a prior
lossy generation, so using it to claim MQA would false-positive on legitimate lossless masters.
==================================================
⚠ MQA LOSSY ENCODING DETECTED
source is not lossless
--------------------------------------------------
11 track(s) · MQA Studio · authored 44.1 kHz
carrier bit 8 · auth level 9
--------------------------------------------------
DR is measured on the delivered PCM stream;
content encoded above the base band is not
reconstructed (no open MQA decoder exists).
==================================================
What it does not do
crête does not unfold or render MQA. That DSP exists only in the proprietary licensed
decoder, so DR is always measured on the delivered base-band PCM and the warning says so
rather than leaving you to infer it.
Provenance: the bitstream layout is a clean-room reimplementation of the format description in a BSD-2-Clause project's specification and in the published patent —
facts and an interface, no decoder code — so crête stays MIT.
09 — Build & platforms
One executable, everywhere it is built
make setup-deps-check
make setup-deps
make
make cli-json
make cli-json-ffmpeg
make setup-imgui && make gui
make gui-ffmpeg
make dsd2wav
make dvda-info
make debug
make STATIC=1
GUI prerequisites are SDL2 and an OpenGL development package; Dear ImGui is fetched once by make setup-imgui. The FFmpeg tier needs its compact static build run once, and pkg-config.
setup-deps checks by capability, not package name, so a
compiler you built yourself still counts; it prints every command before running it,
supports --check and --dry-run, and never installs something
already present. Homebrew, dnf, apt, pacman, zypper and MSYS2 are covered. It installs the toolchain; the three setup-* targets fetch the sources crête vendors.
Two things it checks are easy to get wrong on your own: an x86 host with no assembler fails
the FFmpeg build as a deep, confusing error rather than a missing dependency, and MinGW's win32 threading model ships a standard library with no threads at all — so such
a build links cleanly and then dies on the first album.
Platform status
Linux x86-64 built & gated
CI agent. STATIC=1 produces a genuinely static binary.
Linux aarch64 built & gated
Second CI agent; bit-identical to x86-64 on the gated fields.
macOS builds
Development host, and a Homebrew tap since 0.19.3. One ULP apart from Linux on log10, so its JSON is not equality-comparable.
Windows x86-64 built & self-checked
Built natively under MSYS2 on a Windows 11 agent for 0.20.0 and 0.21.0. 0.22.0 has no Windows build: on its release the agent’s Application Control policy blocked MSYS2’s bash.exe before anything compiled, so that release carries no Windows zip. The JSON build runs check_fix12.sh, check_lfe_peak.sh and a JSON round trip. STATIC=1 is not optional — without it the executable needs three runtime DLLs and the single-binary promise breaks — and an import of a MinGW runtime, SDL2 or FFmpeg DLL fails the build. No weekly result on this site was measured on Windows.
Windows on ARM not buildable yet
Needs a second toolchain; the current one targets x86 only.
Windows GUI built, unverified
Since 0.20.0 crete-gui.exe ships in the release zip with SDL2 linked statically, so the missing-SDL2 blocker is gone. Nothing checks it: the build job exercises only the CLI, and the repo records no run of the GUI on Windows.
There is not one POSIX-threads call in the source — only C++17 standard threading — and file
dialogs and directory walking are already branched per platform. The only thing that ever
mattered for Windows was the toolchain's threading model. Linux packages ship from the openSUSE
Build Service since 0.19.2, a Homebrew tap covers macOS since 0.19.3, and Windows binaries and
a Scoop bucket since 0.20.0, below. None of the binaries is
code-signed; a signed release matrix is scoped but not built.
10 — Packages
The FFmpeg tiers, packaged for Linux, macOS and Windows
Every channel ships the same two builds — crete from make cli-ffmpeg and crete-gui from make gui-ffmpeg — with crête's own compact LGPL
FFmpeg linked statically. Since 0.19.4 a pushed release tag publishes them: OBS first, and the
Homebrew tap only once every OBS repository has built and published that version; since 0.20.0
the Windows build is attached to the Codeberg release and the Scoop bucket follows it.
Linux — the openSUSE Build Service
Published from the project home:abksh:crete since 0.19.2 — one source package, built
offline for every target below. The one-click page generates the right commands for your
distribution.
openSUSE
sudo zypper addrepo https://download.opensuse.org/repositories/home:abksh:crete/openSUSE_Tumbleweed/home:abksh:crete.repo
sudo zypper install crete crete-gui
Fedora
sudo dnf config-manager addrepo --from-repofile=https://download.opensuse.org/repositories/home:abksh:crete/Fedora_44/home:abksh:crete.repo
sudo dnf install crete crete-gui
Debian / Ubuntu
echo 'deb https://download.opensuse.org/repositories/home:/abksh:/crete/Debian_13/ /' | sudo tee /etc/apt/sources.list.d/crete.list
curl -fsSL https://download.opensuse.org/repositories/home:abksh:crete/Debian_13/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/crete.gpg > /dev/null
sudo apt update && sudo apt install crete crete-gui
Substitute the repository name from the table for the one in each URL. The examples use openSUSE_Tumbleweed, Fedora_44 and Debian_13.
macOS — a Homebrew tap
brew tap abksh/crete https://codeberg.org/abksh/homebrew-crete
brew install abksh/crete/crete
brew install abksh/crete/crete-gui
Since 0.19.3. Formulae, not casks, compiled from the release tag on install — so nothing is
quarantined and Gatekeeper does not block the unsigned binaries, and an install takes a few
minutes, because each formula builds FFmpeg 7.1 from source. Homebrew's own ffmpeg is --enable-gpl, and linking it would make crête GPL; both
formula tests fail if the binary links any libav* dylib. Install by the full abksh/crete/… name: that is what tells Homebrew to trust a third-party tap.
There is no macOS build agent. The tap is bumped once the 15 Linux builds of the same source
have published — evidence that the tag builds, not that the formula builds on a Mac, so a
failure there would first surface on a user's brew install.
A Homebrew build is a macOS build, so it is one ULP apart from Linux on log10 and its output is not equality-comparable with the gated Linux agents.
Windows — a Scoop bucket, or the zip
scoop bucket add crete https://codeberg.org/abksh/scoop-crete
scoop install crete/crete
Since 0.20.0. Each Codeberg release carries a Windows x86_64 zip with its .sha256: crete.exe and crete-gui.exe, both STATIC=1, so there are no DLLs and no installer — keep the fonts folder beside the GUI. The Scoop bucket installs that zip, puts both
commands on the path with a Start-menu shortcut for the GUI, and is bumped by the release
job. A winget package is prepared; its first submission is made by hand. The 0.22.0 Windows
build did not run — the agent's Application Control policy blocked MSYS2's bash — so that
release has no zip and the bucket still installs 0.21.0.
Built natively under MSYS2 on a Windows agent. The job runs the synthetic self-checks and a
JSON round trip on its JSON build; the shipped crete.exe is checked for its
version and its DLL imports, and nothing runs the GUI. The binaries are not code-signed.
Built with crête's flags, not the distribution's
Every Linux recipe — the spec for openSUSE and Fedora, the Debian set, the PKGBUILD — removes the
distribution's CFLAGS and LDFLAGS from the build environment and
turns off LTO and debug builds. Injected optimisation flags would give each distribution a
different binary and void the x86_64 / aarch64 bit-identity that -ffp-contract=off exists for.
The compact FFmpeg — LGPL-2.1, decode-only — is built from source inside the package build
and linked statically, exactly as CI builds it; nothing is downloaded at build time. To
produce the upload set yourself: scripts/make_obs_source.sh OUTDIR [REF],
which is deterministic — the same ref gives the same sha256.
What the packages are not
Not the JSON build
The packaged crete, on every channel, is make cli-ffmpeg, which has no -f json. For the CI shape, build make cli-json-ffmpeg from
source.
Smoke-tested, not measured
The only check inside a Linux package build is that the binary runs and reports the
version it was packaged as. The Homebrew crete formula's test measures a
20 s 1 kHz sine at −6 dBFS and asserts DR0, a −6.02 dBFS sample peak and −6.01 LUFS —
but Homebrew runs it only on brew test, not on install. For the Linux packages, bit-identity with the gated builds
holds by construction — the same flags — not by comparison. No figure on this site was measured with a
packaged binary: the current census is weekly #96, on 0.20.0.
Not built on a Mac before release
The release job has no macOS agent. A Homebrew formula is published on the strength
of the Linux builds, and a macOS build failure would first surface on a user's brew install.
x86_64 only outside openSUSE and Fedora
Debian, Ubuntu, Arch and Fedora Rawhide are built for x86_64 alone, and so is Windows:
there is no Windows on ARM build.