1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-12 10:39:31 +00:00

audio: per-frame pitch envelopes for pulse SFX

Pulse-channel sfx with a multi-byte `pitch:` array used to silently
ignore everything past the first byte — the runtime audio tick
latched the period at trigger time and never updated it. Programs
that wanted a frequency sweep had no way to express it.

The compiler now compiles a per-frame pitch envelope blob alongside
the existing volume envelope when `decl.pitch` has more than one
distinct value. The blob is padded (or truncated) to the volume
envelope's length and ends in a zero sentinel so the runtime
walker stops both pointers on the same NMI. Sfx with a single
scalar pitch (or an array where every byte is the same) keep their
historical "no pitch blob, latch once" path and emit byte-identical
ROM bytes.

The runtime gains two new pieces, both gated on a new
`__sfx_pitch_used` codegen marker so programs without varying-pitch
sfx pay zero bytes:

1. `gen_audio_tick` emits a per-frame pitch update block inside
   the SFX tick: read a byte through `(AUDIO_SFX_PITCH_PTR),Y`,
   write it to `$4002` (pulse-1 period low), advance the pointer.
   The block bails on a zero high-byte pointer so a single
   program can mix scalar-pitch and varying-pitch sfx without
   one clobbering the other.

2. `emit_play_pulse` seeds `AUDIO_SFX_PITCH_PTR_LO/HI` with the
   pitch-blob label for varying-pitch sfx and zeros it for
   scalar-pitch sfx. The per-call branch is skipped entirely
   when the program has no varying-pitch sfx anywhere.

The new `examples/sfx_pitch_envelope.ne` exercises the path with
a 16-frame siren sweep. Triangle and noise per-frame pitch are
deferred — they share the same data shape but the runtime ticks
for those channels still write only their volume registers, see
docs/future-work.md for the gap.

https://claude.ai/code/session_01KEczoNUX3WmcFLfq6iAQxB
This commit is contained in:
Claude 2026-04-15 02:54:56 +00:00
parent db3a4adc57
commit 9878b7d87d
No known key found for this signature in database
12 changed files with 449 additions and 31 deletions

View file

@ -187,6 +187,7 @@ fn link_with_audio_data_places_sfx_blobs_in_prg() {
period_lo: 0x50,
period_hi: 0x08,
envelope: vec![0xBF, 0xB8, 0xB4, 0xB0, 0x00],
pitch_envelope: Vec::new(),
channel: Channel::Pulse1,
}];
let rom = linker.link_with_all_assets(&user_code, &[], &sfx, &[]);
@ -239,6 +240,7 @@ fn link_with_audio_resolves_sfx_pointer_references() {
period_lo: 0x50,
period_hi: 0x08,
envelope: vec![0xDE, 0xAD, 0xBE, 0xEF, 0x00],
pitch_envelope: Vec::new(),
channel: Channel::Pulse1,
}];
let rom = linker.link_with_all_assets(&user_code, &[], &sfx, &[]);
@ -282,6 +284,7 @@ fn link_without_audio_marker_does_not_emit_period_table() {
period_lo: 0,
period_hi: 0,
envelope: vec![0xAA, 0xBB, 0x00],
pitch_envelope: Vec::new(),
channel: Channel::Pulse1,
}],
&[],