Fix envelope generator freezing when envelope period is 0#13
Open
lxpollitt wants to merge 1 commit into
Open
Conversation
When a program set the envelope period registers (R11/R12) to 0, the emulated envelope stopped advancing entirely: the period value of 0 tripped a guard in the per-sample envelope logic that skipped the envelope counter. A subsequent envelope shape write (R13) unconditionally presents the envelope's starting volume (15 for the attack-low shapes), so any channel in envelope mode froze at maximum DAC level, producing a large persistent DC offset. This was the root cause of the loud click on PLAY 0,0,0,0 (the Oric BASIC idiom for silencing sound), as the DC blocker took seconds to drain the stuck level away. On the real chip an envelope period of 0 does not freeze: it runs at twice the speed of period 1, completing a full 16-step envelope cycle in 128us at 1 MHz. (This is unlike the tone and noise periods, where 0 behaves the same as 1.) The fix maps an envelope period value of 0 to half of the period 1 value in the R11/R12 handler, initialises the envelope period consistently at reset, and removes the freezing guard. The envelope now also starts in the holding state at reset, matching the real chip's steady state shortly after power-on (the reset-default shape 0 decays to 0 and holds within 128us); previously the never-ticking guard masked this.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Second in the series of AY-3-8912 sound emulation improvements, web version first as before. The WIP deployment with the whole series applied is available here if you want to hear the overall impact: https://joric-wip.pages.dev
Problem
The current emulation effectively treats an envelope period of 0 as a freeze (doesn't advance the envelope) whereas on the real chip an envelope period of 0 does not freeze the envelope: it runs at twice the speed of period 1. (Note, this is unlike the
SOUNDtone and noise periods, where 0 behaves the same as 1.)Example symptoms / repros scenarios
PLAY 0,0,0,0(the usual BASIC idiom for silencing sound) produces a loud click/pop on the current web version. An easy way to hear it: disable keyboard-click (CTRL-F), typePING, thenPLAY 0,0,0,0. ThePLAYmakes a loud click/pop, and repeatedPLAY 0,0,0,0s after it then do not generate any audible output. In contrast, on a real Oric-1 the first PLAY generates a very quiet click, and the subsequent PLAYs do the same. (Verified on real hardware.)PLAY 1,0,0,0:SOUND1,100,4:WAIT300:SOUND1,100,0should play a quiet tone and then silence, but the current emulator code plays a short chirp of whatever tone was previously on channel 1, then plays the quiet tone, then plays max volume tone instead of silence.The cause is the special case handling of an envelope period of 0 by the emulation code. When a program writes 0 to the envelope period registers (R11/R12), the emulated envelope generator stops advancing entirely - a
period != 0guard skips the envelope tick. A subsequent envelope shape write (R13) presents the envelope's starting level (15 for the attack-low shapes), so any channel in envelope mode freezes at maximum output, producing a large persistent DC offset. The DC blocker then takes a small amount of time to drain that offset away, which is why the click/pop is particularly loud.On a real chip an envelope period of 0 running at twice the speed of period 1 executes the full 16-step envelope cycle in 128us at 1 MHz. This results in a much briefer signal peak and quieter click.
Fix
The envelope period handler now maps a written value of 0 to half the period-1 value (the correct 2x rate), the envelope period is initialised to a non-zero value at reset, and the freezing guard is removed. The envelope also now starts in its "holding" state at reset, matching the real chip's steady state shortly after power-on (the reset-default shape decays to 0 and holds within 128us); previously the never-ticking guard happened to mask this.
With the fix,
PLAY 0,0,0,0after a sound produces a very brief quiet click as the envelope completes its fast decay to 0, rather than freezing at full level. SubsequentPLAY 0,0,0,0commands produce the same quiet click.Scope
Web platform only - one file (GwtAYPSG). No changes to core or the other platforms. Only the envelope-period-0 case is affected; envelope periods of 1 and above are unaffected.
Testing
Tested on macOS in Chrome. Confirmed that
PINGfollowed byPLAY 0,0,0,0now produces a brief quiet click instead of a louder click/pop, and that repeatedPLAY 0,0,0,0commands each behave consistently rather than the first popping and the rest doing nothing.