Skip to main content

Module provenance

Module provenance 

Source
Expand description

Audio provenance (v2.3.7 “Overtone”) — why does this moment sound like that?

The APU analogue of the PPU’s rustynes_ppu::provenance (a plain code span, not an intra-doc link: rustynes-apu does not depend on rustynes-ppu, and a bracketed link to a crate outside the graph fails RUSTDOCFLAGS=-D warnings while clippy stays green), and deliberately built to the same shape: a register-attribution half that answers “what wrote this, and from which instruction”, and a per-cycle mix trace that answers “what were the channels actually doing”.

§What was missing before this

Every other ingredient already shipped. The frontend’s audio scope plots the per-channel waveforms, the audio mixer exposes per-channel gain, crate::Apu::pulse1_out and its siblings expose live channel outputs, and the trace logger has PC and cycle. What did not exist anywhere is the link between a sample and the instruction that caused it — exactly the gap the pixel-provenance design identified for video.

§Cadence, and why it is per CPU cycle rather than per output sample

The mix is computed once per CPU cycle (1.789 MHz NTSC) and handed to the band-limited blip decimator, which produces output samples at 44.1 kHz — about one per 40.6 CPU cycles. Recording at output rate would therefore require choosing which of those 40 mixes “is” the sample, and band-limited synthesis makes that choice ill-posed: an output sample is a weighted sum of transitions across the filter kernel, not a copy of one instant.

So this records what was genuinely mixed, at the cadence it was mixed. The panel maps a clicked output sample back to its CPU-cycle window; the doc says plainly that the window is a kernel width, not a point. A provenance tool that answers a question it cannot actually answer is worse than one that declines — the whole argument v2.3.6 was built on.

The cost is smaller than it sounds: 29,781 records per NTSC frame against the pixel store’s 61,440 — 0.48x the record count of the video side.

§Determinism

Output-only. Nothing here is read back into synthesis, none of it is part of the save state, and every store is behind a runtime arm that is off by default. With the arm off the cost is one Option discriminant test per register write and per mixed cycle.

Structs§

AudioProvenance
Everything audio provenance owns, behind ONE pointer.
AudioProvenanceStash
Both audio stores, lifted out of the APU so a same-timeline restore can put them back.
MixRecord
The five channel outputs that went into one mixed CPU-cycle sample, plus the result.
MixTrace
One frame’s worth of per-CPU-cycle mix records.
RegWrite
One register write: the byte, the CPU cycle, and the instruction that did it.
RegisterAttribution
Last write to each of $4000-$4017, with its cause.

Enums§

WriteOrigin
What performed a register write.

Constants§

MIX_CAP
Largest CPU-cycle count in one frame across every supported region, which is what MixTrace is sized for.
REG_BASE
First APU/IO register address covered by RegisterAttribution.
REG_COUNT
Number of register slots tracked: $4000-$4017 inclusive.
REG_COUNT_U16
REG_COUNT as a u16, so address arithmetic never needs a cast.