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:
parent
db3a4adc57
commit
9878b7d87d
12 changed files with 449 additions and 31 deletions
|
|
@ -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,
|
||||
}],
|
||||
&[],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue