ADSR Envelope API

Chat about anything CX16 related that doesn't fit elsewhere
ZeroByte
Posts: 714
Joined: Wed Feb 10, 2021 2:40 pm

ADSR Envelope API

Post by ZeroByte »


I think a good way to go about it might be:

Store a set of 6.2 fixed-point values: volume, delta-volume

Store a set of 6-bit (6 LSB) sustain_level values



Set VERA address = $1F9C2 (volume register of voice 0), stride = 4

Cycle through all 16 voices:

if delta=0: read VERA data (to advance the stride) and loop to next voice

volume += delta

volume >> 2 (we'll call it 'level' now to distinguish from the 6.2 fixed-point value 'volume')

if level = sustain_level, delta = 0

if level = 0, delta = 0

if level = $3F then delta = voice's decay rate


write_vera: (label)

level |= $C0 (to enable L+R bits)

store level to VERA data (note that we do this even if the integer part didn't change - it's faster to just do it than to check first)

next voice



Triggering a note sets delta = voice's attack rate, sets volume = 0

Releasing a note sets delta = voice's release rate



This may need a little touching up to handle overflow in case the rates aren't ones that would evenly result in levels of $3F or $00.....



EDIT:

instead of comparing level to 0 and $3F, sta ZP_tmp (assuming A holds the computed 'level' after >>2) and then BIT ZP_tmp

BMI -> set delta=0, level=0, volume=0

BVC -> set delta=decay_rate, level=$3F, volume=$FC

Then do BIT delta and BPL to write_vera

else cmp level $3f... BCS to write_vera

else level=sustain_level, volume = level<<2, delta=0

write_vera:

... (same as initial code above)

BruceMcF
Posts: 1336
Joined: Fri Jul 03, 2020 4:27 am

ADSR Envelope API

Post by BruceMcF »



On 1/28/2022 at 9:46 PM, Ed Minchau said:




Alternatively, suppose the Stage byte is in zero page. I'll use address 7F for this example:



BBS0 7F, StartNote 



BBS1 7F, Attack



BBS2 7F, Decay



BBS3 7F, Sustain



BBS4 7F, Release



JMP SetNoteVolume



 



This saves 6 cycles.



Alternatively, suppose it is stored at any specific address, the four Key-On, Note On, Attack, Decay, Sustain are Bit5=1, so stage 0-3 in Bit6/Bit7, the four Key-Off stages are No Note, Attack, Decay, Release, so Bit5=0, release Bit7=Bit6=1 is Release, bit5=bit6=bit7=0 is note off, and Attack and Decay complete.



LDA #%00100000

BIT ADSRSTAGE

BMI DECAY

BVS ATTACK

BNE NOTEON

RTS ; All bits zero, note off

NOTEON:

; Note on code here

LDA ADSRSTAGE

ORA #%0100

STA ADSRSTAGE

; first Attack

ATTACK:

; Attack Code here

; when advance to sustain, "LDA ADSRSTAGE : CLC : ADC #$40 : STA ADSRSTAGE"

RTS

DECAY: BVS RELEASE

; DECAY code here

; when advance to sustain, "LDA ADRSTAGE : ORA #%01000000 : STA ADRSTAGE"

; also when advance to sustain, set the sustain level (since test is PASSING the level)

RTS

RELEASE:

BNE SUSTAIN ; Sustain if Key is still on

; Release code here

; Advance to note off by "LDA ADSRSTAGE : AND #%00011111 ; STA ADSRSTAGE

SUSTAIN: ; sustain code is "no, you're good"

RTS

_______________________

Edit: Note that if you prefer "Note On/Off" in the high bit, then the stage in bits 5 and 6 work equivalently ...

LDA #%00100000

BIT ADRSTAGE

BVS DECAY

BNE ATTACK

BMI NOTEON

...

DECAY: BNE RELEASE

...

RELEASE: BMI SUSTAIN

...

 

Post Reply